diff options
Diffstat (limited to 'src/target')
137 files changed, 5570 insertions, 3921 deletions
diff --git a/src/target/aarch64.c b/src/target/aarch64.c index 6a70b2d..ce7808e 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -193,6 +193,20 @@ static int aarch64_mmu_modify(struct target *target, int enable) return retval; } +static int aarch64_read_prsr(struct target *target, uint32_t *prsr) +{ + struct armv8_common *armv8 = target_to_armv8(target); + int retval; + + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_PRSR, prsr); + if (retval != ERROR_OK) + return retval; + + armv8->sticky_reset |= *prsr & PRSR_SR; + return ERROR_OK; +} + /* * Basic debug access, very low level assumes state is saved */ @@ -213,8 +227,7 @@ static int aarch64_init_debug_access(struct target *target) /* Clear Sticky Power Down status Bit in PRSR to enable access to the registers in the Core Power Domain */ - retval = mem_ap_read_atomic_u32(armv8->debug_ap, - armv8->debug_base + CPUV8_DBG_PRSR, &dummy); + retval = aarch64_read_prsr(target, &dummy); if (retval != ERROR_OK) return retval; @@ -281,12 +294,10 @@ static int aarch64_set_dscr_bits(struct target *target, unsigned long bit_mask, static int aarch64_check_state_one(struct target *target, uint32_t mask, uint32_t val, int *p_result, uint32_t *p_prsr) { - struct armv8_common *armv8 = target_to_armv8(target); uint32_t prsr; int retval; - retval = mem_ap_read_atomic_u32(armv8->debug_ap, - armv8->debug_base + CPUV8_DBG_PRSR, &prsr); + retval = aarch64_read_prsr(target, &prsr); if (retval != ERROR_OK) return retval; @@ -506,16 +517,28 @@ static int update_halt_gdb(struct target *target, enum target_debug_reason debug static int aarch64_poll(struct target *target) { + struct armv8_common *armv8 = target_to_armv8(target); enum target_state prev_target_state; int retval = ERROR_OK; - int halted; + uint32_t prsr; - retval = aarch64_check_state_one(target, - PRSR_HALT, PRSR_HALT, &halted, NULL); + retval = aarch64_read_prsr(target, &prsr); if (retval != ERROR_OK) return retval; - if (halted) { + if (armv8->sticky_reset) { + armv8->sticky_reset = false; + if (target->state != TARGET_RESET) { + target->state = TARGET_RESET; + LOG_TARGET_INFO(target, "external reset detected"); + if (armv8->arm.core_cache) { + register_cache_invalidate(armv8->arm.core_cache); + register_cache_invalidate(armv8->arm.core_cache->next); + } + } + } + + if (prsr & PRSR_HALT) { prev_target_state = target->state; if (prev_target_state != TARGET_HALTED) { enum target_debug_reason debug_reason = target->debug_reason; @@ -546,8 +569,11 @@ static int aarch64_poll(struct target *target) break; } } - } else + } else if (prsr & PRSR_RESET) { + target->state = TARGET_RESET; + } else { target->state = TARGET_RUNNING; + } return retval; } @@ -563,8 +589,8 @@ static int aarch64_halt(struct target *target) return aarch64_halt_one(target, HALT_SYNC); } -static int aarch64_restore_one(struct target *target, int current, - uint64_t *address, int handle_breakpoints, int debug_execution) +static int aarch64_restore_one(struct target *target, bool current, + uint64_t *address, bool handle_breakpoints, bool debug_execution) { struct armv8_common *armv8 = target_to_armv8(target); struct arm *arm = &armv8->arm; @@ -576,7 +602,7 @@ static int aarch64_restore_one(struct target *target, int current, if (!debug_execution) target_free_all_working_areas(target); - /* current = 1: continue on current pc, otherwise continue at <address> */ + /* current = true: continue on current pc, otherwise continue at <address> */ resume_pc = buf_get_u64(arm->pc->value, 0, 64); if (!current) resume_pc = *address; @@ -663,8 +689,7 @@ static int aarch64_prepare_restart_one(struct target *target) if (retval == ERROR_OK) { /* clear sticky bits in PRSR, SDR is now 0 */ - retval = mem_ap_read_atomic_u32(armv8->debug_ap, - armv8->debug_base + CPUV8_DBG_PRSR, &tmp); + retval = aarch64_read_prsr(target, &tmp); } return retval; @@ -728,7 +753,8 @@ static int aarch64_restart_one(struct target *target, enum restart_mode mode) /* * prepare all but the current target for restart */ -static int aarch64_prep_restart_smp(struct target *target, int handle_breakpoints, struct target **p_first) +static int aarch64_prep_restart_smp(struct target *target, + bool handle_breakpoints, struct target **p_first) { int retval = ERROR_OK; struct target_list *head; @@ -747,7 +773,8 @@ static int aarch64_prep_restart_smp(struct target *target, int handle_breakpoint continue; /* resume at current address, not in step mode */ - retval = aarch64_restore_one(curr, 1, &address, handle_breakpoints, 0); + retval = aarch64_restore_one(curr, true, &address, handle_breakpoints, + false); if (retval == ERROR_OK) retval = aarch64_prepare_restart_one(curr); if (retval != ERROR_OK) { @@ -774,7 +801,7 @@ static int aarch64_step_restart_smp(struct target *target) LOG_DEBUG("%s", target_name(target)); - retval = aarch64_prep_restart_smp(target, 0, &first); + retval = aarch64_prep_restart_smp(target, false, &first); if (retval != ERROR_OK) return retval; @@ -839,8 +866,8 @@ static int aarch64_step_restart_smp(struct target *target) return retval; } -static int aarch64_resume(struct target *target, int current, - target_addr_t address, int handle_breakpoints, int debug_execution) +static int aarch64_resume(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, bool debug_execution) { int retval = 0; uint64_t addr = address; @@ -1088,8 +1115,8 @@ static int aarch64_post_debug_entry(struct target *target) /* * single-step a target */ -static int aarch64_step(struct target *target, int current, target_addr_t address, - int handle_breakpoints) +static int aarch64_step(struct target *target, bool current, target_addr_t address, + bool handle_breakpoints) { struct armv8_common *armv8 = target_to_armv8(target); struct aarch64_common *aarch64 = target_to_aarch64(target); @@ -1122,7 +1149,7 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres if (retval != ERROR_OK) return retval; - if (target->smp && (current == 1)) { + if (target->smp && current) { /* * isolate current target so that it doesn't get resumed * together with the others @@ -1139,7 +1166,7 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres } /* all other targets running, restore and restart the current target */ - retval = aarch64_restore_one(target, current, &address, 0, 0); + retval = aarch64_restore_one(target, current, &address, false, false); if (retval == ERROR_OK) retval = aarch64_restart_one(target, RESTART_LAZY); @@ -2830,6 +2857,14 @@ static void aarch64_deinit_target(struct target *target) struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; struct arm_dpm *dpm = &armv8->dpm; + uint64_t address; + + if (target->state == TARGET_HALTED) { + // Restore the previous state of the target (gp registers, MMU, caches, etc) + int retval = aarch64_restore_one(target, true, &address, false, false); + if (retval != ERROR_OK) + LOG_TARGET_ERROR(target, "Failed to restore target state"); + } if (armv8->debug_ap) dap_put_ap(armv8->debug_ap); @@ -2883,9 +2918,9 @@ static int aarch64_jim_configure(struct target *target, struct jim_getopt_info * pc = (struct aarch64_private_config *)target->private_config; if (!pc) { - pc = calloc(1, sizeof(struct aarch64_private_config)); - pc->adiv5_config.ap_num = DP_APSEL_INVALID; - target->private_config = pc; + pc = calloc(1, sizeof(struct aarch64_private_config)); + pc->adiv5_config.ap_num = DP_APSEL_INVALID; + target->private_config = pc; } /* @@ -2915,7 +2950,7 @@ static int aarch64_jim_configure(struct target *target, struct jim_getopt_info * switch (n->value) { case CFG_CTI: { - if (goi->isconfigure) { + if (goi->is_configure) { Jim_Obj *o_cti; struct arm_cti *cti; e = jim_getopt_obj(goi, &o_cti); diff --git a/src/target/adi_v5_jtag.c b/src/target/adi_v5_jtag.c index 8d54a50..c9ed5b9 100644 --- a/src/target/adi_v5_jtag.c +++ b/src/target/adi_v5_jtag.c @@ -431,7 +431,7 @@ static int jtagdp_overrun_check(struct adiv5_dap *dap) struct dap_cmd *el, *tmp, *prev = NULL; int found_wait = 0; int64_t time_now; - LIST_HEAD(replay_list); + OOCD_LIST_HEAD(replay_list); /* make sure all queued transactions are complete */ retval = jtag_execute_queue(); @@ -736,7 +736,7 @@ static int jtag_send_sequence(struct adiv5_dap *dap, enum swd_special_seq seq) return retval; } -static int jtag_dp_q_read(struct adiv5_dap *dap, unsigned reg, +static int jtag_dp_q_read(struct adiv5_dap *dap, unsigned int reg, uint32_t *data) { int retval = jtag_limit_queue_size(dap); @@ -749,7 +749,7 @@ static int jtag_dp_q_read(struct adiv5_dap *dap, unsigned reg, return retval; } -static int jtag_dp_q_write(struct adiv5_dap *dap, unsigned reg, +static int jtag_dp_q_write(struct adiv5_dap *dap, unsigned int reg, uint32_t data) { int retval = jtag_limit_queue_size(dap); @@ -763,7 +763,7 @@ static int jtag_dp_q_write(struct adiv5_dap *dap, unsigned reg, } /** Select the AP register bank */ -static int jtag_ap_q_bankselect(struct adiv5_ap *ap, unsigned reg) +static int jtag_ap_q_bankselect(struct adiv5_ap *ap, unsigned int reg) { int retval; struct adiv5_dap *dap = ap->dap; @@ -818,7 +818,7 @@ static int jtag_ap_q_bankselect(struct adiv5_ap *ap, unsigned reg) return ERROR_OK; } -static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned reg, +static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned int reg, uint32_t *data) { int retval = jtag_limit_queue_size(ap->dap); @@ -840,7 +840,7 @@ static int jtag_ap_q_read(struct adiv5_ap *ap, unsigned reg, return retval; } -static int jtag_ap_q_write(struct adiv5_ap *ap, unsigned reg, +static int jtag_ap_q_write(struct adiv5_ap *ap, unsigned int reg, uint32_t data) { int retval = jtag_limit_queue_size(ap->dap); diff --git a/src/target/adi_v5_swd.c b/src/target/adi_v5_swd.c index 1231005..e50f8f1 100644 --- a/src/target/adi_v5_swd.c +++ b/src/target/adi_v5_swd.c @@ -485,7 +485,7 @@ static int swd_queue_ap_abort(struct adiv5_dap *dap, uint8_t *ack) return check_sync(dap); } -static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg, +static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned int reg, uint32_t *data) { int retval = swd_check_reconnect(dap); @@ -499,12 +499,9 @@ static int swd_queue_dp_read(struct adiv5_dap *dap, unsigned reg, return swd_queue_dp_read_inner(dap, reg, data); } -static int swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg, +static int swd_queue_dp_write(struct adiv5_dap *dap, unsigned int reg, uint32_t data) { - const struct swd_driver *swd = adiv5_dap_swd_driver(dap); - assert(swd); - int retval = swd_check_reconnect(dap); if (retval != ERROR_OK) return retval; @@ -517,7 +514,7 @@ static int swd_queue_dp_write(struct adiv5_dap *dap, unsigned reg, } /** Select the AP register bank */ -static int swd_queue_ap_bankselect(struct adiv5_ap *ap, unsigned reg) +static int swd_queue_ap_bankselect(struct adiv5_ap *ap, unsigned int reg) { int retval; struct adiv5_dap *dap = ap->dap; @@ -567,7 +564,7 @@ static int swd_queue_ap_bankselect(struct adiv5_ap *ap, unsigned reg) return ERROR_OK; } -static int swd_queue_ap_read(struct adiv5_ap *ap, unsigned reg, +static int swd_queue_ap_read(struct adiv5_ap *ap, unsigned int reg, uint32_t *data) { struct adiv5_dap *dap = ap->dap; @@ -592,7 +589,7 @@ static int swd_queue_ap_read(struct adiv5_ap *ap, unsigned reg, return check_sync(dap); } -static int swd_queue_ap_write(struct adiv5_ap *ap, unsigned reg, +static int swd_queue_ap_write(struct adiv5_ap *ap, unsigned int reg, uint32_t data) { struct adiv5_dap *dap = ap->dap; diff --git a/src/target/algorithm.c b/src/target/algorithm.c index 64abffc..dee1f36 100644 --- a/src/target/algorithm.c +++ b/src/target/algorithm.c @@ -26,7 +26,8 @@ void destroy_mem_param(struct mem_param *param) param->value = NULL; } -void init_reg_param(struct reg_param *param, char *reg_name, uint32_t size, enum param_direction direction) +void init_reg_param(struct reg_param *param, const char *reg_name, + uint32_t size, enum param_direction direction) { param->reg_name = reg_name; param->size = size; diff --git a/src/target/algorithm.h b/src/target/algorithm.h index 25f1a66..45b3fd9 100644 --- a/src/target/algorithm.h +++ b/src/target/algorithm.h @@ -35,8 +35,8 @@ void init_mem_param(struct mem_param *param, uint32_t address, uint32_t size, enum param_direction dir); void destroy_mem_param(struct mem_param *param); -void init_reg_param(struct reg_param *param, - char *reg_name, uint32_t size, enum param_direction dir); +void init_reg_param(struct reg_param *param, const char *reg_name, + uint32_t size, enum param_direction dir); void destroy_reg_param(struct reg_param *param); #endif /* OPENOCD_TARGET_ALGORITHM_H */ diff --git a/src/target/arc.c b/src/target/arc.c index 72e4d91..8757caf 100644 --- a/src/target/arc.c +++ b/src/target/arc.c @@ -61,7 +61,7 @@ static int arc_single_step_core(struct target *target); void arc_reg_data_type_add(struct target *target, struct arc_reg_data_type *data_type) { - LOG_DEBUG("Adding %s reg_data_type", data_type->data_type.id); + LOG_TARGET_DEBUG(target, "Adding %s reg_data_type", data_type->data_type.id); struct arc_common *arc = target_to_arc(target); assert(arc); @@ -104,7 +104,7 @@ static int arc_reset_caches_states(struct target *target) { struct arc_common *arc = target_to_arc(target); - LOG_DEBUG("Resetting internal variables of caches states"); + LOG_TARGET_DEBUG(target, "Resetting internal variables of caches states"); /* Reset caches states. */ arc->dcache_flushed = false; @@ -127,7 +127,7 @@ static int arc_init_arch_info(struct target *target, struct arc_common *arc, /* The only allowed ir_length is 4 for ARC jtag. */ if (tap->ir_length != 4) { - LOG_ERROR("ARC jtag instruction length should be equal to 4"); + LOG_TARGET_ERROR(target, "ARC jtag instruction length should be equal to 4"); return ERROR_FAIL; } @@ -146,7 +146,7 @@ static int arc_init_arch_info(struct target *target, struct arc_common *arc, sizeof(*std_types)); if (!std_types) { - LOG_ERROR("Unable to allocate memory"); + LOG_TARGET_ERROR(target, "Unable to allocate memory"); return ERROR_FAIL; } @@ -205,7 +205,7 @@ int arc_reg_add(struct target *target, struct arc_reg_desc *arc_reg, } arc->num_regs += 1; - LOG_DEBUG( + LOG_TARGET_DEBUG(target, "added register {name=%s, num=0x%" PRIx32 ", type=%s%s%s%s}", arc_reg->name, arc_reg->arch_num, arc_reg->data_type->id, arc_reg->is_core ? ", core" : "", arc_reg->is_bcr ? ", bcr" : "", @@ -227,7 +227,7 @@ static int arc_get_register(struct reg *reg) uint32_t value; if (reg->valid) { - LOG_DEBUG("Get register (cached) gdb_num=%" PRIu32 ", name=%s, value=0x%" PRIx32, + LOG_TARGET_DEBUG(target, "Get register (cached) gdb_num=%" PRIu32 ", name=%s, value=0x%" PRIx32, reg->number, desc->name, target_buffer_get_u32(target, reg->value)); return ERROR_OK; } @@ -235,7 +235,7 @@ static int arc_get_register(struct reg *reg) if (desc->is_core) { /* Accessing to R61/R62 registers causes Jtag hang */ if (desc->arch_num == ARC_R61 || desc->arch_num == ARC_R62) { - LOG_ERROR("It is forbidden to read core registers 61 and 62."); + LOG_TARGET_ERROR(target, "It is forbidden to read core registers 61 and 62"); return ERROR_FAIL; } CHECK_RETVAL(arc_jtag_read_core_reg_one(&arc->jtag_info, desc->arch_num, @@ -255,7 +255,7 @@ static int arc_get_register(struct reg *reg) reg->dirty = false; - LOG_DEBUG("Get register gdb_num=%" PRIu32 ", name=%s, value=0x%" PRIx32, + LOG_TARGET_DEBUG(target, "Get register gdb_num=%" PRIu32 ", name=%s, value=0x%" PRIx32, reg->number, desc->name, value); @@ -276,12 +276,12 @@ static int arc_set_register(struct reg *reg, uint8_t *buf) /* Accessing to R61/R62 registers causes Jtag hang */ if (desc->is_core && (desc->arch_num == ARC_R61 || desc->arch_num == ARC_R62)) { - LOG_ERROR("It is forbidden to write core registers 61 and 62."); + LOG_TARGET_ERROR(target, "It is forbidden to write core registers 61 and 62"); return ERROR_FAIL; } target_buffer_set_u32(target, reg->value, value); - LOG_DEBUG("Set register gdb_num=%" PRIu32 ", name=%s, value=0x%08" PRIx32, + LOG_TARGET_DEBUG(target, "Set register gdb_num=%" PRIu32 ", name=%s, value=0x%08" PRIx32, reg->number, desc->name, value); reg->valid = true; @@ -355,7 +355,7 @@ static int arc_build_reg_cache(struct target *target) struct reg *reg_list = calloc(num_regs, sizeof(*reg_list)); if (!cache || !reg_list) { - LOG_ERROR("Not enough memory"); + LOG_TARGET_ERROR(target, "Not enough memory"); goto fail; } @@ -368,14 +368,14 @@ static int arc_build_reg_cache(struct target *target) (*cache_p) = cache; if (list_empty(&arc->core_reg_descriptions)) { - LOG_ERROR("No core registers were defined"); + LOG_TARGET_ERROR(target, "No core registers were defined"); goto fail; } list_for_each_entry(reg_desc, &arc->core_reg_descriptions, list) { CHECK_RETVAL(arc_init_reg(target, ®_list[i], reg_desc, i)); - LOG_DEBUG("reg n=%3li name=%3s group=%s feature=%s", i, + LOG_TARGET_DEBUG(target, "reg n=%3li name=%3s group=%s feature=%s", i, reg_list[i].name, reg_list[i].group, reg_list[i].feature->name); @@ -383,27 +383,27 @@ static int arc_build_reg_cache(struct target *target) } if (list_empty(&arc->aux_reg_descriptions)) { - LOG_ERROR("No aux registers were defined"); + LOG_TARGET_ERROR(target, "No aux registers were defined"); goto fail; } list_for_each_entry(reg_desc, &arc->aux_reg_descriptions, list) { - CHECK_RETVAL(arc_init_reg(target, ®_list[i], reg_desc, i)); + CHECK_RETVAL(arc_init_reg(target, ®_list[i], reg_desc, i)); - LOG_DEBUG("reg n=%3li name=%3s group=%s feature=%s", i, + LOG_TARGET_DEBUG(target, "reg n=%3li name=%3s group=%s feature=%s", i, reg_list[i].name, reg_list[i].group, reg_list[i].feature->name); /* PC and DEBUG are essential so we search for them. */ if (!strcmp("pc", reg_desc->name)) { if (arc->pc_index_in_cache != ULONG_MAX) { - LOG_ERROR("Double definition of PC in configuration"); + LOG_TARGET_ERROR(target, "Double definition of PC in configuration"); goto fail; } arc->pc_index_in_cache = i; } else if (!strcmp("debug", reg_desc->name)) { if (arc->debug_index_in_cache != ULONG_MAX) { - LOG_ERROR("Double definition of DEBUG in configuration"); + LOG_TARGET_ERROR(target, "Double definition of DEBUG in configuration"); goto fail; } arc->debug_index_in_cache = i; @@ -413,7 +413,7 @@ static int arc_build_reg_cache(struct target *target) if (arc->pc_index_in_cache == ULONG_MAX || arc->debug_index_in_cache == ULONG_MAX) { - LOG_ERROR("`pc' and `debug' registers must be present in target description."); + LOG_TARGET_ERROR(target, "`pc' and `debug' registers must be present in target description"); goto fail; } @@ -446,7 +446,7 @@ static int arc_build_bcr_reg_cache(struct target *target) unsigned long gdb_regnum = arc->core_and_aux_cache->num_regs; if (!cache || !reg_list) { - LOG_ERROR("Unable to allocate memory"); + LOG_TARGET_ERROR(target, "Unable to allocate memory"); goto fail; } @@ -459,17 +459,17 @@ static int arc_build_bcr_reg_cache(struct target *target) (*cache_p) = cache; if (list_empty(&arc->bcr_reg_descriptions)) { - LOG_ERROR("No BCR registers are defined"); + LOG_TARGET_ERROR(target, "No BCR registers are defined"); goto fail; } list_for_each_entry(reg_desc, &arc->bcr_reg_descriptions, list) { - CHECK_RETVAL(arc_init_reg(target, ®_list[i], reg_desc, gdb_regnum)); + CHECK_RETVAL(arc_init_reg(target, ®_list[i], reg_desc, gdb_regnum)); /* BCRs always semantically, they are just read-as-zero, if there is * not real register. */ reg_list[i].exist = true; - LOG_DEBUG("reg n=%3li name=%3s group=%s feature=%s", i, + LOG_TARGET_DEBUG(target, "reg n=%3li name=%3s group=%s feature=%s", i, reg_list[i].name, reg_list[i].group, reg_list[i].feature->name); i += 1; @@ -501,7 +501,7 @@ static int arc_get_gdb_reg_list(struct target *target, struct reg **reg_list[], *reg_list = calloc(*reg_list_size, sizeof(struct reg *)); if (!*reg_list) { - LOG_ERROR("Unable to allocate memory"); + LOG_TARGET_ERROR(target, "Unable to allocate memory"); return ERROR_FAIL; } @@ -516,18 +516,18 @@ static int arc_get_gdb_reg_list(struct target *target, struct reg **reg_list[], unsigned long i = 0; struct reg_cache *reg_cache = target->reg_cache; while (reg_cache) { - for (unsigned j = 0; j < reg_cache->num_regs; j++, i++) + for (unsigned int j = 0; j < reg_cache->num_regs; j++, i++) (*reg_list)[i] = ®_cache->reg_list[j]; reg_cache = reg_cache->next; } assert(i == arc->num_regs); - LOG_DEBUG("REG_CLASS_ALL: number of regs=%i", *reg_list_size); + LOG_TARGET_DEBUG(target, "REG_CLASS_ALL: number of regs=%i", *reg_list_size); } else { unsigned long i = 0; unsigned long gdb_reg_number = 0; struct reg_cache *reg_cache = target->reg_cache; while (reg_cache) { - for (unsigned j = 0; + for (unsigned int j = 0; j < reg_cache->num_regs && gdb_reg_number <= arc->last_general_reg; j++) { if (reg_cache->reg_list[j].exist) { @@ -539,7 +539,7 @@ static int arc_get_gdb_reg_list(struct target *target, struct reg **reg_list[], reg_cache = reg_cache->next; } *reg_list_size = i; - LOG_DEBUG("REG_CLASS_GENERAL: number of regs=%i", *reg_list_size); + LOG_TARGET_DEBUG(target, "REG_CLASS_GENERAL: number of regs=%i", *reg_list_size); } return ERROR_OK; @@ -551,13 +551,13 @@ int arc_reg_get_field(struct target *target, const char *reg_name, { struct reg_data_type_struct_field *field; - LOG_DEBUG("getting register field (reg_name=%s, field_name=%s)", reg_name, field_name); + LOG_TARGET_DEBUG(target, "getting register field (reg_name=%s, field_name=%s)", reg_name, field_name); /* Get register */ struct reg *reg = arc_reg_get_by_name(target->reg_cache, reg_name, true); if (!reg) { - LOG_ERROR("Requested register `%s' doesn't exist.", reg_name); + LOG_TARGET_ERROR(target, "Requested register `%s' doesn't exist", reg_name); return ERROR_ARC_REGISTER_NOT_FOUND; } @@ -597,7 +597,7 @@ int arc_reg_get_field(struct target *target, const char *reg_name, static int arc_get_register_value(struct target *target, const char *reg_name, uint32_t *value_ptr) { - LOG_DEBUG("reg_name=%s", reg_name); + LOG_TARGET_DEBUG(target, "reg_name=%s", reg_name); struct reg *reg = arc_reg_get_by_name(target->reg_cache, reg_name, true); @@ -615,10 +615,10 @@ static int arc_get_register_value(struct target *target, const char *reg_name, static int arc_set_register_value(struct target *target, const char *reg_name, uint32_t value) { - LOG_DEBUG("reg_name=%s value=0x%08" PRIx32, reg_name, value); + LOG_TARGET_DEBUG(target, "reg_name=%s value=0x%08" PRIx32, reg_name, value); if (!(target && reg_name)) { - LOG_ERROR("Arguments cannot be NULL."); + LOG_TARGET_ERROR(target, "Arguments cannot be NULL"); return ERROR_FAIL; } @@ -655,7 +655,7 @@ static int arc_configure_dccm(struct target *target) if (dccm_build_size0 == 0xF) dccm_size <<= dccm_build_size1; arc->dccm_end = arc->dccm_start + dccm_size; - LOG_DEBUG("DCCM detected start=0x%" PRIx32 " end=0x%" PRIx32, + LOG_TARGET_DEBUG(target, "DCCM detected start=0x%" PRIx32 " end=0x%" PRIx32, arc->dccm_start, arc->dccm_end); } @@ -687,7 +687,7 @@ static int arc_configure_iccm(struct target *target) /* iccm0 start is located in highest 4 bits of aux_iccm */ arc->iccm0_start = aux_iccm & 0xF0000000; arc->iccm0_end = arc->iccm0_start + iccm0_size; - LOG_DEBUG("ICCM0 detected start=0x%" PRIx32 " end=0x%" PRIx32, + LOG_TARGET_DEBUG(target, "ICCM0 detected start=0x%" PRIx32 " end=0x%" PRIx32, arc->iccm0_start, arc->iccm0_end); } @@ -707,7 +707,7 @@ static int arc_configure_iccm(struct target *target) iccm1_size <<= iccm_build_size11; arc->iccm1_start = aux_iccm & 0x0F000000; arc->iccm1_end = arc->iccm1_start + iccm1_size; - LOG_DEBUG("ICCM1 detected start=0x%" PRIx32 " end=0x%" PRIx32, + LOG_TARGET_DEBUG(target, "ICCM1 detected start=0x%" PRIx32 " end=0x%" PRIx32, arc->iccm1_start, arc->iccm1_end); } return ERROR_OK; @@ -716,17 +716,17 @@ static int arc_configure_iccm(struct target *target) /* Configure some core features, depending on BCRs. */ static int arc_configure(struct target *target) { - LOG_DEBUG("Configuring ARC ICCM and DCCM"); + LOG_TARGET_DEBUG(target, "Configuring ARC ICCM and DCCM"); /* Configuring DCCM if DCCM_BUILD and AUX_DCCM are known registers. */ - if (arc_reg_get_by_name(target->reg_cache, "dccm_build", true) && - arc_reg_get_by_name(target->reg_cache, "aux_dccm", true)) - CHECK_RETVAL(arc_configure_dccm(target)); + if (arc_reg_get_by_name(target->reg_cache, "dccm_build", true) + && arc_reg_get_by_name(target->reg_cache, "aux_dccm", true)) + CHECK_RETVAL(arc_configure_dccm(target)); /* Configuring ICCM if ICCM_BUILD and AUX_ICCM are known registers. */ - if (arc_reg_get_by_name(target->reg_cache, "iccm_build", true) && - arc_reg_get_by_name(target->reg_cache, "aux_iccm", true)) - CHECK_RETVAL(arc_configure_iccm(target)); + if (arc_reg_get_by_name(target->reg_cache, "iccm_build", true) + && arc_reg_get_by_name(target->reg_cache, "aux_iccm", true)) + CHECK_RETVAL(arc_configure_iccm(target)); return ERROR_OK; } @@ -770,9 +770,9 @@ static int arc_exit_debug(struct target *target) CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); if (debug_level >= LOG_LVL_DEBUG) { - LOG_DEBUG("core stopped (halted) debug-reg: 0x%08" PRIx32, value); + LOG_TARGET_DEBUG(target, "core stopped (halted) debug-reg: 0x%08" PRIx32, value); CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, &value)); - LOG_DEBUG("core STATUS32: 0x%08" PRIx32, value); + LOG_TARGET_DEBUG(target, "core STATUS32: 0x%08" PRIx32, value); } return ERROR_OK; @@ -783,19 +783,19 @@ static int arc_halt(struct target *target) uint32_t value, irq_state; struct arc_common *arc = target_to_arc(target); - LOG_DEBUG("target->state: %s", target_state_name(target)); + LOG_TARGET_DEBUG(target, "target->state: %s", target_state_name(target)); if (target->state == TARGET_HALTED) { - LOG_DEBUG("target was already halted"); + LOG_TARGET_DEBUG(target, "target was already halted"); return ERROR_OK; } if (target->state == TARGET_UNKNOWN) - LOG_WARNING("target was in unknown state when halt was requested"); + LOG_TARGET_WARNING(target, "target was in unknown state when halt was requested"); if (target->state == TARGET_RESET) { if ((jtag_get_reset_config() & RESET_SRST_PULLS_TRST) && jtag_get_srst()) { - LOG_ERROR("can't request a halt while in reset if nSRST pulls nTRST"); + LOG_TARGET_ERROR(target, "can't request a halt while in reset if nSRST pulls nTRST"); return ERROR_TARGET_FAILURE; } else { target->debug_reason = DBG_REASON_DBGRQ; @@ -825,9 +825,9 @@ static int arc_halt(struct target *target) /* some more debug information */ if (debug_level >= LOG_LVL_DEBUG) { - LOG_DEBUG("core stopped (halted) DEGUB-REG: 0x%08" PRIx32, value); + LOG_TARGET_DEBUG(target, "core stopped (halted) DEGUB-REG: 0x%08" PRIx32, value); CHECK_RETVAL(arc_get_register_value(target, "status32", &value)); - LOG_DEBUG("core STATUS32: 0x%08" PRIx32, value); + LOG_TARGET_DEBUG(target, "core STATUS32: 0x%08" PRIx32, value); } return ERROR_OK; @@ -846,7 +846,7 @@ static int arc_save_context(struct target *target) struct arc_common *arc = target_to_arc(target); struct reg *reg_list = arc->core_and_aux_cache->reg_list; - LOG_DEBUG("Saving aux and core registers values"); + LOG_TARGET_DEBUG(target, "Saving aux and core registers values"); assert(reg_list); /* It is assumed that there is at least one AUX register in the list, for @@ -865,7 +865,7 @@ static int arc_save_context(struct target *target) unsigned int aux_cnt = 0; if (!core_values || !core_addrs || !aux_values || !aux_addrs) { - LOG_ERROR("Unable to allocate memory"); + LOG_TARGET_ERROR(target, "Unable to allocate memory"); retval = ERROR_FAIL; goto exit; } @@ -893,7 +893,7 @@ static int arc_save_context(struct target *target) if (core_cnt > 0) { retval = arc_jtag_read_core_reg(&arc->jtag_info, core_addrs, core_cnt, core_values); if (retval != ERROR_OK) { - LOG_ERROR("Attempt to read core registers failed."); + LOG_TARGET_ERROR(target, "Attempt to read core registers failed"); retval = ERROR_FAIL; goto exit; } @@ -901,7 +901,7 @@ static int arc_save_context(struct target *target) if (aux_cnt > 0) { retval = arc_jtag_read_aux_reg(&arc->jtag_info, aux_addrs, aux_cnt, aux_values); if (retval != ERROR_OK) { - LOG_ERROR("Attempt to read aux registers failed."); + LOG_TARGET_ERROR(target, "Attempt to read aux registers failed"); retval = ERROR_FAIL; goto exit; } @@ -916,7 +916,7 @@ static int arc_save_context(struct target *target) target_buffer_set_u32(target, reg->value, core_values[core_cnt]); reg->valid = true; reg->dirty = false; - LOG_DEBUG("Get core register regnum=%u, name=%s, value=0x%08" PRIx32, + LOG_TARGET_DEBUG(target, "Get core register regnum=%u, name=%s, value=0x%08" PRIx32, i, arc_reg->name, core_values[core_cnt]); core_cnt++; } @@ -931,7 +931,7 @@ static int arc_save_context(struct target *target) target_buffer_set_u32(target, reg->value, aux_values[aux_cnt]); reg->valid = true; reg->dirty = false; - LOG_DEBUG("Get aux register regnum=%u, name=%s, value=0x%08" PRIx32, + LOG_TARGET_DEBUG(target, "Get aux register regnum=%u, name=%s, value=0x%08" PRIx32, i, arc_reg->name, aux_values[aux_cnt]); aux_cnt++; } @@ -1009,14 +1009,14 @@ static int arc_examine_debug_reason(struct target *target) if (actionpoint) { if (!actionpoint->used) - LOG_WARNING("Target halted by an unused actionpoint."); + LOG_TARGET_WARNING(target, "Target halted by an unused actionpoint"); if (actionpoint->type == ARC_AP_BREAKPOINT) target->debug_reason = DBG_REASON_BREAKPOINT; else if (actionpoint->type == ARC_AP_WATCHPOINT) target->debug_reason = DBG_REASON_WATCHPOINT; else - LOG_WARNING("Unknown type of actionpoint."); + LOG_TARGET_WARNING(target, "Unknown type of actionpoint"); } } @@ -1046,7 +1046,7 @@ static int arc_poll(struct target *target) /* check for processor halted */ if (status & ARC_JTAG_STAT_RU) { if (target->state != TARGET_RUNNING) { - LOG_WARNING("target is still running!"); + LOG_TARGET_WARNING(target, "target is still running"); target->state = TARGET_RUNNING; } return ERROR_OK; @@ -1057,21 +1057,19 @@ static int arc_poll(struct target *target) if ((target->state == TARGET_RUNNING) || (target->state == TARGET_RESET)) { CHECK_RETVAL(arc_get_register_value(target, "status32", &value)); if (value & AUX_STATUS32_REG_HALT_BIT) { - LOG_DEBUG("ARC core in halt or reset state."); + LOG_TARGET_DEBUG(target, "ARC core in halt or reset state"); /* Save context if target was not in reset state */ if (target->state == TARGET_RUNNING) CHECK_RETVAL(arc_debug_entry(target)); target->state = TARGET_HALTED; CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_HALTED)); } else { - LOG_DEBUG("Discrepancy of STATUS32[0] HALT bit and ARC_JTAG_STAT_RU, " + LOG_TARGET_DEBUG(target, "Discrepancy of STATUS32[0] HALT bit and ARC_JTAG_STAT_RU, " "target is still running"); } - } else if (target->state == TARGET_DEBUG_RUNNING) { - target->state = TARGET_HALTED; - LOG_DEBUG("ARC core is in debug running mode"); + LOG_TARGET_DEBUG(target, "ARC core is in debug running mode"); CHECK_RETVAL(arc_debug_entry(target)); @@ -1087,7 +1085,7 @@ static int arc_assert_reset(struct target *target) enum reset_types jtag_reset_config = jtag_get_reset_config(); bool srst_asserted = false; - LOG_DEBUG("target->state: %s", target_state_name(target)); + LOG_TARGET_DEBUG(target, "target->state: %s", target_state_name(target)); if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) { /* allow scripts to override the reset event */ @@ -1101,8 +1099,8 @@ static int arc_assert_reset(struct target *target) if (target->state == TARGET_HALTED && !target->reset_halt) { /* Resume the target and continue from the current * PC register value. */ - LOG_DEBUG("Starting CPU execution after reset"); - CHECK_RETVAL(target_resume(target, 1, 0, 0, 0)); + LOG_TARGET_DEBUG(target, "Starting CPU execution after reset"); + CHECK_RETVAL(target_resume(target, true, 0, false, false)); } target->state = TARGET_RESET; @@ -1138,7 +1136,7 @@ static int arc_assert_reset(struct target *target) static int arc_deassert_reset(struct target *target) { - LOG_DEBUG("target->state: %s", target_state_name(target)); + LOG_TARGET_DEBUG(target, "target->state: %s", target_state_name(target)); /* deassert reset lines */ jtag_add_reset(0, 0); @@ -1155,7 +1153,7 @@ static int arc_arch_state(struct target *target) CHECK_RETVAL(arc_get_register_value(target, "pc", &pc_value)); - LOG_DEBUG("target state: %s; PC at: 0x%08" PRIx32, + LOG_TARGET_DEBUG(target, "target state: %s; PC at: 0x%08" PRIx32, target_state_name(target), pc_value); @@ -1174,7 +1172,7 @@ static int arc_restore_context(struct target *target) struct arc_common *arc = target_to_arc(target); struct reg *reg_list = arc->core_and_aux_cache->reg_list; - LOG_DEBUG("Restoring registers values"); + LOG_TARGET_DEBUG(target, "Restoring registers values"); assert(reg_list); const uint32_t core_regs_size = arc->num_core_regs * sizeof(uint32_t); @@ -1187,7 +1185,7 @@ static int arc_restore_context(struct target *target) unsigned int aux_cnt = 0; if (!core_values || !core_addrs || !aux_values || !aux_addrs) { - LOG_ERROR("Unable to allocate memory"); + LOG_TARGET_ERROR(target, "Unable to allocate memory"); retval = ERROR_FAIL; goto exit; } @@ -1201,7 +1199,7 @@ static int arc_restore_context(struct target *target) struct reg *reg = &(reg_list[i]); struct arc_reg_desc *arc_reg = reg->arch_info; if (reg->valid && reg->exist && reg->dirty) { - LOG_DEBUG("Will write regnum=%u", i); + LOG_TARGET_DEBUG(target, "Will write regnum=%u", i); core_addrs[core_cnt] = arc_reg->arch_num; core_values[core_cnt] = target_buffer_get_u32(target, reg->value); core_cnt += 1; @@ -1212,7 +1210,7 @@ static int arc_restore_context(struct target *target) struct reg *reg = &(reg_list[arc->num_core_regs + i]); struct arc_reg_desc *arc_reg = reg->arch_info; if (reg->valid && reg->exist && reg->dirty) { - LOG_DEBUG("Will write regnum=%lu", arc->num_core_regs + i); + LOG_TARGET_DEBUG(target, "Will write regnum=%lu", arc->num_core_regs + i); aux_addrs[aux_cnt] = arc_reg->arch_num; aux_values[aux_cnt] = target_buffer_get_u32(target, reg->value); aux_cnt += 1; @@ -1224,7 +1222,7 @@ static int arc_restore_context(struct target *target) if (core_cnt > 0) { retval = arc_jtag_write_core_reg(&arc->jtag_info, core_addrs, core_cnt, core_values); if (retval != ERROR_OK) { - LOG_ERROR("Attempt to write to core registers failed."); + LOG_TARGET_ERROR(target, "Attempt to write to core registers failed"); retval = ERROR_FAIL; goto exit; } @@ -1233,7 +1231,7 @@ static int arc_restore_context(struct target *target) if (aux_cnt > 0) { retval = arc_jtag_write_aux_reg(&arc->jtag_info, aux_addrs, aux_cnt, aux_values); if (retval != ERROR_OK) { - LOG_ERROR("Attempt to write to aux registers failed."); + LOG_TARGET_ERROR(target, "Attempt to write to aux registers failed"); retval = ERROR_FAIL; goto exit; } @@ -1248,7 +1246,7 @@ exit: return retval; } -static int arc_enable_interrupts(struct target *target, int enable) +static int arc_enable_interrupts(struct target *target, bool enable) { uint32_t value; @@ -1260,26 +1258,26 @@ static int arc_enable_interrupts(struct target *target, int enable) /* enable interrupts */ value |= SET_CORE_ENABLE_INTERRUPTS; CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, value)); - LOG_DEBUG("interrupts enabled"); + LOG_TARGET_DEBUG(target, "interrupts enabled"); } else { /* disable interrupts */ value &= ~SET_CORE_ENABLE_INTERRUPTS; CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, value)); - LOG_DEBUG("interrupts disabled"); + LOG_TARGET_DEBUG(target, "interrupts disabled"); } return ERROR_OK; } -static int arc_resume(struct target *target, int current, target_addr_t address, - int handle_breakpoints, int debug_execution) +static int arc_resume(struct target *target, bool current, target_addr_t address, + bool handle_breakpoints, bool debug_execution) { struct arc_common *arc = target_to_arc(target); uint32_t resume_pc = 0; uint32_t value; struct reg *pc = &arc->core_and_aux_cache->reg_list[arc->pc_index_in_cache]; - LOG_DEBUG("current:%i, address:0x%08" TARGET_PRIxADDR ", handle_breakpoints:%i," + LOG_TARGET_DEBUG(target, "current:%i, address:0x%08" TARGET_PRIxADDR ", handle_breakpoints:%i," " debug_execution:%i", current, address, handle_breakpoints, debug_execution); /* We need to reset ARC cache variables so caches @@ -1299,12 +1297,12 @@ static int arc_resume(struct target *target, int current, target_addr_t address, CHECK_RETVAL(arc_enable_watchpoints(target)); } - /* current = 1: continue on current PC, otherwise continue at <address> */ + /* current = true: continue on current PC, otherwise continue at <address> */ if (!current) { target_buffer_set_u32(target, pc->value, address); pc->dirty = true; pc->valid = true; - LOG_DEBUG("Changing the value of current PC to 0x%08" TARGET_PRIxADDR, address); + LOG_TARGET_DEBUG(target, "Changing the value of current PC to 0x%08" TARGET_PRIxADDR, address); } if (!current) @@ -1314,13 +1312,13 @@ static int arc_resume(struct target *target, int current, target_addr_t address, CHECK_RETVAL(arc_restore_context(target)); - LOG_DEBUG("Target resumes from PC=0x%" PRIx32 ", pc.dirty=%i, pc.valid=%i", + LOG_TARGET_DEBUG(target, "Target resumes from PC=0x%" PRIx32 ", pc.dirty=%i, pc.valid=%i", resume_pc, pc->dirty, pc->valid); /* check if GDB tells to set our PC where to continue from */ if (pc->valid && resume_pc == target_buffer_get_u32(target, pc->value)) { value = target_buffer_get_u32(target, pc->value); - LOG_DEBUG("resume Core (when start-core) with PC @:0x%08" PRIx32, value); + LOG_TARGET_DEBUG(target, "resume Core (when start-core) with PC @:0x%08" PRIx32, value); CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_PC_REG, value)); } @@ -1329,7 +1327,7 @@ static int arc_resume(struct target *target, int current, target_addr_t address, /* Single step past breakpoint at current address */ struct breakpoint *breakpoint = breakpoint_find(target, resume_pc); if (breakpoint) { - LOG_DEBUG("skipping past breakpoint at 0x%08" TARGET_PRIxADDR, + LOG_TARGET_DEBUG(target, "skipping past breakpoint at 0x%08" TARGET_PRIxADDR, breakpoint->address); CHECK_RETVAL(arc_unset_breakpoint(target, breakpoint)); CHECK_RETVAL(arc_single_step_core(target)); @@ -1350,7 +1348,7 @@ static int arc_resume(struct target *target, int current, target_addr_t address, CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, &value)); value &= ~SET_CORE_HALT_BIT; /* clear the HALT bit */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, value)); - LOG_DEBUG("Core started to run"); + LOG_TARGET_DEBUG(target, "Core started to run"); /* registers are now invalid */ register_cache_invalidate(arc->core_and_aux_cache); @@ -1358,11 +1356,11 @@ static int arc_resume(struct target *target, int current, target_addr_t address, if (!debug_execution) { target->state = TARGET_RUNNING; CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED)); - LOG_DEBUG("target resumed at 0x%08" PRIx32, resume_pc); + LOG_TARGET_DEBUG(target, "target resumed at 0x%08" PRIx32, resume_pc); } else { target->state = TARGET_DEBUG_RUNNING; CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED)); - LOG_DEBUG("target debug resumed at 0x%08" PRIx32, resume_pc); + LOG_TARGET_DEBUG(target, "target debug resumed at 0x%08" PRIx32, resume_pc); } return ERROR_OK; @@ -1386,7 +1384,7 @@ static void arc_deinit_target(struct target *target) { struct arc_common *arc = target_to_arc(target); - LOG_DEBUG("deinitialization of target"); + LOG_TARGET_DEBUG(target, "deinitialization of target"); if (arc->core_aux_cache_built) arc_free_reg_cache(arc->core_and_aux_cache); if (arc->bcr_cache_built) @@ -1431,11 +1429,11 @@ static int arc_target_create(struct target *target, Jim_Interp *interp) struct arc_common *arc = calloc(1, sizeof(*arc)); if (!arc) { - LOG_ERROR("Unable to allocate memory"); + LOG_TARGET_ERROR(target, "Unable to allocate memory"); return ERROR_FAIL; } - LOG_DEBUG("Entering"); + LOG_TARGET_DEBUG(target, "Entering"); CHECK_RETVAL(arc_init_arch_info(target, arc, target->tap)); return ERROR_OK; @@ -1452,11 +1450,11 @@ static int arc_write_instruction_u32(struct target *target, uint32_t address, { uint8_t value_buf[4]; if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); + LOG_TARGET_ERROR(target, "Target not examined yet"); return ERROR_FAIL; } - LOG_DEBUG("Address: 0x%08" PRIx32 ", value: 0x%08" PRIx32, address, + LOG_TARGET_DEBUG(target, "Address: 0x%08" PRIx32 ", value: 0x%08" PRIx32, address, instr); if (target->endianness == TARGET_LITTLE_ENDIAN) @@ -1480,7 +1478,7 @@ static int arc_read_instruction_u32(struct target *target, uint32_t address, uint8_t value_buf[4]; if (!target_was_examined(target)) { - LOG_ERROR("Target not examined yet"); + LOG_TARGET_ERROR(target, "Target not examined yet"); return ERROR_FAIL; } @@ -1492,7 +1490,7 @@ static int arc_read_instruction_u32(struct target *target, uint32_t address, else *value = be_to_h_u32(value_buf); - LOG_DEBUG("Address: 0x%08" PRIx32 ", value: 0x%08" PRIx32, address, + LOG_TARGET_DEBUG(target, "Address: 0x%08" PRIx32 ", value: 0x%08" PRIx32, address, *value); return ERROR_OK; @@ -1513,7 +1511,7 @@ static int arc_configure_actionpoint(struct target *target, uint32_t ap_num, if (control_tt != AP_AC_TT_DISABLE) { if (arc->actionpoints_num_avail < 1) { - LOG_ERROR("No free actionpoints, maximum amount is %u", + LOG_TARGET_ERROR(target, "No free actionpoints, maximum amount is %u", arc->actionpoints_num); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -1547,12 +1545,12 @@ static int arc_set_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (breakpoint->is_set) { - LOG_WARNING("breakpoint already set"); + LOG_TARGET_WARNING(target, "breakpoint already set"); return ERROR_OK; } if (breakpoint->type == BKPT_SOFT) { - LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id); + LOG_TARGET_DEBUG(target, "bpid: %" PRIu32, breakpoint->unique_id); if (breakpoint->length == 4) { uint32_t verify = 0xffffffff; @@ -1566,7 +1564,7 @@ static int arc_set_breakpoint(struct target *target, CHECK_RETVAL(arc_read_instruction_u32(target, breakpoint->address, &verify)); if (verify != ARC_SDBBP_32) { - LOG_ERROR("Unable to set 32bit breakpoint at address @0x%" TARGET_PRIxADDR + LOG_TARGET_ERROR(target, "Unable to set 32bit breakpoint at address @0x%" TARGET_PRIxADDR " - check that memory is read/writable", breakpoint->address); return ERROR_FAIL; } @@ -1579,12 +1577,12 @@ static int arc_set_breakpoint(struct target *target, CHECK_RETVAL(target_read_u16(target, breakpoint->address, &verify)); if (verify != ARC_SDBBP_16) { - LOG_ERROR("Unable to set 16bit breakpoint at address @0x%" TARGET_PRIxADDR + LOG_TARGET_ERROR(target, "Unable to set 16bit breakpoint at address @0x%" TARGET_PRIxADDR " - check that memory is read/writable", breakpoint->address); return ERROR_FAIL; } } else { - LOG_ERROR("Invalid breakpoint length: target supports only 2 or 4"); + LOG_TARGET_ERROR(target, "Invalid breakpoint length: target supports only 2 or 4"); return ERROR_COMMAND_ARGUMENT_INVALID; } @@ -1600,7 +1598,7 @@ static int arc_set_breakpoint(struct target *target, } if (bp_num >= arc->actionpoints_num) { - LOG_ERROR("No free actionpoints, maximum amount is %u", + LOG_TARGET_ERROR(target, "No free actionpoints, maximum amount is %u", arc->actionpoints_num); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -1614,12 +1612,12 @@ static int arc_set_breakpoint(struct target *target, ap_list[bp_num].bp_value = breakpoint->address; ap_list[bp_num].type = ARC_AP_BREAKPOINT; - LOG_DEBUG("bpid: %" PRIu32 ", bp_num %u bp_value 0x%" PRIx32, + LOG_TARGET_DEBUG(target, "bpid: %" PRIu32 ", bp_num %u bp_value 0x%" PRIx32, breakpoint->unique_id, bp_num, ap_list[bp_num].bp_value); } } else { - LOG_DEBUG("ERROR: setting unknown breakpoint type"); + LOG_TARGET_ERROR(target, "setting unknown breakpoint type"); return ERROR_FAIL; } @@ -1632,13 +1630,13 @@ static int arc_unset_breakpoint(struct target *target, int retval = ERROR_OK; if (!breakpoint->is_set) { - LOG_WARNING("breakpoint not set"); + LOG_TARGET_WARNING(target, "breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_SOFT) { /* restore original instruction (kept in target endianness) */ - LOG_DEBUG("bpid: %" PRIu32, breakpoint->unique_id); + LOG_TARGET_DEBUG(target, "bpid: %" PRIu32, breakpoint->unique_id); if (breakpoint->length == 4) { uint32_t current_instr; @@ -1651,7 +1649,7 @@ static int arc_unset_breakpoint(struct target *target, if (retval != ERROR_OK) return retval; } else { - LOG_WARNING("Software breakpoint @0x%" TARGET_PRIxADDR + LOG_TARGET_WARNING(target, "Software breakpoint @0x%" TARGET_PRIxADDR " has been overwritten outside of debugger." "Expected: @0x%x, got: @0x%" PRIx32, breakpoint->address, ARC_SDBBP_32, current_instr); @@ -1667,24 +1665,24 @@ static int arc_unset_breakpoint(struct target *target, if (retval != ERROR_OK) return retval; } else { - LOG_WARNING("Software breakpoint @0x%" TARGET_PRIxADDR + LOG_TARGET_WARNING(target, "Software breakpoint @0x%" TARGET_PRIxADDR " has been overwritten outside of debugger. " "Expected: 0x%04x, got: 0x%04" PRIx16, breakpoint->address, ARC_SDBBP_16, current_instr); } } else { - LOG_ERROR("Invalid breakpoint length: target supports only 2 or 4"); + LOG_TARGET_ERROR(target, "Invalid breakpoint length: target supports only 2 or 4"); return ERROR_COMMAND_ARGUMENT_INVALID; } breakpoint->is_set = false; - } else if (breakpoint->type == BKPT_HARD) { + } else if (breakpoint->type == BKPT_HARD) { struct arc_common *arc = target_to_arc(target); struct arc_actionpoint *ap_list = arc->actionpoints_list; unsigned int bp_num = breakpoint->number; if (bp_num >= arc->actionpoints_num) { - LOG_DEBUG("Invalid actionpoint ID: %u in breakpoint: %" PRIu32, + LOG_TARGET_DEBUG(target, "Invalid actionpoint ID: %u in breakpoint: %" PRIu32, bp_num, breakpoint->unique_id); return ERROR_OK; } @@ -1697,12 +1695,12 @@ static int arc_unset_breakpoint(struct target *target, ap_list[bp_num].used = 0; ap_list[bp_num].bp_value = 0; - LOG_DEBUG("bpid: %" PRIu32 " - released actionpoint ID: %u", + LOG_TARGET_DEBUG(target, "bpid: %" PRIu32 " - released actionpoint ID: %u", breakpoint->unique_id, bp_num); } } else { - LOG_DEBUG("ERROR: unsetting unknown breakpoint type"); - return ERROR_FAIL; + LOG_TARGET_ERROR(target, "unsetting unknown breakpoint type"); + return ERROR_FAIL; } return retval; @@ -1775,7 +1773,7 @@ static void arc_reset_actionpoints(struct target *target) int arc_set_actionpoints_num(struct target *target, uint32_t ap_num) { - LOG_DEBUG("target=%s actionpoints=%" PRIu32, target_name(target), ap_num); + LOG_TARGET_DEBUG(target, "actionpoints=%" PRIu32, ap_num); struct arc_common *arc = target_to_arc(target); /* Make sure that there are no enabled actionpoints in target. */ @@ -1790,7 +1788,7 @@ int arc_set_actionpoints_num(struct target *target, uint32_t ap_num) arc->actionpoints_list = calloc(ap_num, sizeof(struct arc_actionpoint)); if (!arc->actionpoints_list) { - LOG_ERROR("Unable to allocate memory"); + LOG_TARGET_ERROR(target, "Unable to allocate memory"); return ERROR_FAIL; } return ERROR_OK; @@ -1813,7 +1811,7 @@ int arc_add_auxreg_actionpoint(struct target *target, ap_num++; if (ap_num >= arc->actionpoints_num) { - LOG_ERROR("No actionpoint free, maximum amount is %u", + LOG_TARGET_ERROR(target, "No actionpoint free, maximum amount is %u", arc->actionpoints_num); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -1858,7 +1856,7 @@ int arc_remove_auxreg_actionpoint(struct target *target, uint32_t auxreg_addr) ap_list[ap_num].bp_value = 0; } } else { - LOG_ERROR("Register actionpoint not found"); + LOG_TARGET_ERROR(target, "Register actionpoint not found"); } return retval; } @@ -1872,7 +1870,7 @@ static int arc_set_watchpoint(struct target *target, struct arc_actionpoint *ap_list = arc->actionpoints_list; if (watchpoint->is_set) { - LOG_WARNING("watchpoint already set"); + LOG_TARGET_WARNING(target, "watchpoint already set"); return ERROR_OK; } @@ -1882,13 +1880,13 @@ static int arc_set_watchpoint(struct target *target, } if (wp_num >= arc->actionpoints_num) { - LOG_ERROR("No free actionpoints, maximum amount is %u", + LOG_TARGET_ERROR(target, "No free actionpoints, maximum amount is %u", arc->actionpoints_num); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } if (watchpoint->length != 4) { - LOG_ERROR("Only watchpoints of length 4 are supported"); + LOG_TARGET_ERROR(target, "Only watchpoints of length 4 are supported"); return ERROR_TARGET_UNALIGNED_ACCESS; } @@ -1904,7 +1902,7 @@ static int arc_set_watchpoint(struct target *target, enable = AP_AC_TT_READWRITE; break; default: - LOG_ERROR("BUG: watchpoint->rw neither read, write nor access"); + LOG_TARGET_ERROR(target, "BUG: watchpoint->rw neither read, write nor access"); return ERROR_FAIL; } @@ -1917,7 +1915,7 @@ static int arc_set_watchpoint(struct target *target, ap_list[wp_num].bp_value = watchpoint->address; ap_list[wp_num].type = ARC_AP_WATCHPOINT; - LOG_DEBUG("wpid: %" PRIu32 ", wp_num %u wp_value 0x%" PRIx32, + LOG_TARGET_DEBUG(target, "wpid: %" PRIu32 ", wp_num %u wp_value 0x%" PRIx32, watchpoint->unique_id, wp_num, ap_list[wp_num].bp_value); } @@ -1932,13 +1930,13 @@ static int arc_unset_watchpoint(struct target *target, struct arc_actionpoint *ap_list = arc->actionpoints_list; if (!watchpoint->is_set) { - LOG_WARNING("watchpoint not set"); + LOG_TARGET_WARNING(target, "watchpoint not set"); return ERROR_OK; } unsigned int wp_num = watchpoint->number; if (wp_num >= arc->actionpoints_num) { - LOG_DEBUG("Invalid actionpoint ID: %u in watchpoint: %" PRIu32, + LOG_TARGET_DEBUG(target, "Invalid actionpoint ID: %u in watchpoint: %" PRIu32, wp_num, watchpoint->unique_id); return ERROR_OK; } @@ -1951,7 +1949,7 @@ static int arc_unset_watchpoint(struct target *target, ap_list[wp_num].used = 0; ap_list[wp_num].bp_value = 0; - LOG_DEBUG("wpid: %" PRIu32 " - releasing actionpoint ID: %u", + LOG_TARGET_DEBUG(target, "wpid: %" PRIu32 " - releasing actionpoint ID: %u", watchpoint->unique_id, wp_num); } @@ -2009,18 +2007,18 @@ static int arc_hit_watchpoint(struct target *target, struct watchpoint **hit_wat if (actionpoint) { if (!actionpoint->used) - LOG_WARNING("Target halted by unused actionpoint."); + LOG_TARGET_WARNING(target, "Target halted by unused actionpoint"); /* If this check fails - that is some sort of an error in OpenOCD. */ if (actionpoint->type != ARC_AP_WATCHPOINT) - LOG_WARNING("Target halted by breakpoint, but is treated as a watchpoint."); + LOG_TARGET_WARNING(target, "Target halted by breakpoint, but is treated as a watchpoint"); for (struct watchpoint *watchpoint = target->watchpoints; watchpoint; watchpoint = watchpoint->next) { if (actionpoint->bp_value == watchpoint->address) { *hit_watchpoint = watchpoint; - LOG_DEBUG("Hit watchpoint, wpid: %" PRIu32 ", watchpoint num: %u", + LOG_TARGET_DEBUG(target, "Hit watchpoint, wpid: %" PRIu32 ", watchpoint num: %u", watchpoint->unique_id, watchpoint->number); return ERROR_OK; } @@ -2032,7 +2030,7 @@ static int arc_hit_watchpoint(struct target *target, struct watchpoint **hit_wat /* Helper function which switches core to single_step mode by * doing aux r/w operations. */ -static int arc_config_step(struct target *target, int enable_step) +static int arc_config_step(struct target *target, bool enable_step) { uint32_t value; @@ -2045,7 +2043,7 @@ static int arc_config_step(struct target *target, int enable_step) value &= ~SET_CORE_AE_BIT; /* clear the AE bit */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_STATUS32_REG, value)); - LOG_DEBUG(" [status32:0x%08" PRIx32 "]", value); + LOG_TARGET_DEBUG(target, " [status32:0x%08" PRIx32 "]", value); /* Doing read-modify-write, because DEBUG might contain manually set * bits like UB or ED, which should be preserved. */ @@ -2054,7 +2052,7 @@ static int arc_config_step(struct target *target, int enable_step) value |= SET_CORE_SINGLE_INSTR_STEP; /* set the IS bit */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, value)); - LOG_DEBUG("core debug step mode enabled [debug-reg:0x%08" PRIx32 "]", value); + LOG_TARGET_DEBUG(target, "core debug step mode enabled [debug-reg:0x%08" PRIx32 "]", value); } else { /* disable core debug step mode */ CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, @@ -2062,7 +2060,7 @@ static int arc_config_step(struct target *target, int enable_step) value &= ~SET_CORE_SINGLE_INSTR_STEP; /* clear the IS bit */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_DEBUG_REG, value)); - LOG_DEBUG("core debug step mode disabled"); + LOG_TARGET_DEBUG(target, "core debug step mode disabled"); } return ERROR_OK; @@ -2073,10 +2071,10 @@ static int arc_single_step_core(struct target *target) CHECK_RETVAL(arc_debug_entry(target)); /* disable interrupts while stepping */ - CHECK_RETVAL(arc_enable_interrupts(target, 0)); + CHECK_RETVAL(arc_enable_interrupts(target, false)); /* configure single step mode */ - CHECK_RETVAL(arc_config_step(target, 1)); + CHECK_RETVAL(arc_config_step(target, true)); /* exit debug mode */ CHECK_RETVAL(arc_exit_debug(target)); @@ -2084,8 +2082,8 @@ static int arc_single_step_core(struct target *target) return ERROR_OK; } -static int arc_step(struct target *target, int current, target_addr_t address, - int handle_breakpoints) +static int arc_step(struct target *target, bool current, target_addr_t address, + bool handle_breakpoints) { /* get pointers to arch-specific information */ struct arc_common *arc = target_to_arc(target); @@ -2097,14 +2095,14 @@ static int arc_step(struct target *target, int current, target_addr_t address, return ERROR_TARGET_NOT_HALTED; } - /* current = 1: continue on current pc, otherwise continue at <address> */ + /* current = true: continue on current pc, otherwise continue at <address> */ if (!current) { buf_set_u32(pc->value, 0, 32, address); pc->dirty = true; pc->valid = true; } - LOG_DEBUG("Target steps one instruction from PC=0x%" PRIx32, + LOG_TARGET_DEBUG(target, "Target steps one instruction from PC=0x%" PRIx32, buf_get_u32(pc->value, 0, 32)); /* the front-end may request us not to handle breakpoints */ @@ -2122,10 +2120,10 @@ static int arc_step(struct target *target, int current, target_addr_t address, CHECK_RETVAL(target_call_event_callbacks(target, TARGET_EVENT_RESUMED)); /* disable interrupts while stepping */ - CHECK_RETVAL(arc_enable_interrupts(target, 0)); + CHECK_RETVAL(arc_enable_interrupts(target, false)); /* do a single step */ - CHECK_RETVAL(arc_config_step(target, 1)); + CHECK_RETVAL(arc_config_step(target, true)); /* make sure we done our step */ alive_sleep(1); @@ -2136,7 +2134,7 @@ static int arc_step(struct target *target, int current, target_addr_t address, if (breakpoint) CHECK_RETVAL(arc_set_breakpoint(target, breakpoint)); - LOG_DEBUG("target stepped "); + LOG_TARGET_DEBUG(target, "target stepped"); target->state = TARGET_HALTED; @@ -2159,7 +2157,7 @@ static int arc_icache_invalidate(struct target *target) if (!arc->has_icache || arc->icache_invalidated) return ERROR_OK; - LOG_DEBUG("Invalidating I$."); + LOG_TARGET_DEBUG(target, "Invalidating I$"); value = IC_IVIC_INVALIDATE; /* invalidate I$ */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, AUX_IC_IVIC_REG, value)); @@ -2179,7 +2177,7 @@ static int arc_dcache_invalidate(struct target *target) if (!arc->has_dcache || arc->dcache_invalidated) return ERROR_OK; - LOG_DEBUG("Invalidating D$."); + LOG_TARGET_DEBUG(target, "Invalidating D$"); CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_DC_CTRL_REG, &value)); dc_ctrl_value = value; @@ -2208,7 +2206,7 @@ static int arc_l2cache_invalidate(struct target *target) if (!arc->has_l2cache || arc->l2cache_invalidated) return ERROR_OK; - LOG_DEBUG("Invalidating L2$."); + LOG_TARGET_DEBUG(target, "Invalidating L2$"); CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_CTRL, &value)); slc_ctrl_value = value; @@ -2221,7 +2219,7 @@ static int arc_l2cache_invalidate(struct target *target) /* Wait until invalidate operation ends */ do { - LOG_DEBUG("Waiting for invalidation end."); + LOG_TARGET_DEBUG(target, "Waiting for invalidation end"); CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_CTRL, &value)); } while (value & L2_CTRL_BS); @@ -2259,7 +2257,7 @@ static int arc_dcache_flush(struct target *target) if (!arc->has_dcache || arc->dcache_flushed) return ERROR_OK; - LOG_DEBUG("Flushing D$."); + LOG_TARGET_DEBUG(target, "Flushing D$"); /* Store current value of DC_CTRL */ CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, AUX_DC_CTRL_REG, &dc_ctrl_value)); @@ -2295,14 +2293,14 @@ static int arc_l2cache_flush(struct target *target) if (!arc->has_l2cache || arc->l2cache_flushed) return ERROR_OK; - LOG_DEBUG("Flushing L2$."); + LOG_TARGET_DEBUG(target, "Flushing L2$"); /* Flush L2 cache */ CHECK_RETVAL(arc_jtag_write_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_FLUSH, L2_FLUSH_FL)); /* Wait until flush operation ends */ do { - LOG_DEBUG("Waiting for flushing end."); + LOG_TARGET_DEBUG(target, "Waiting for flushing end"); CHECK_RETVAL(arc_jtag_read_aux_reg_one(&arc->jtag_info, SLC_AUX_CACHE_CTRL, &value)); } while (value & L2_CTRL_BS); diff --git a/src/target/arc.h b/src/target/arc.h index a351802..4255840 100644 --- a/src/target/arc.h +++ b/src/target/arc.h @@ -22,6 +22,7 @@ #include "target_request.h" #include "target_type.h" #include "helper/bits.h" +#include "rtt/rtt.h" #include "arc_jtag.h" #include "arc_cmd.h" diff --git a/src/target/arc_cmd.c b/src/target/arc_cmd.c index e7760b0..bf8a8aa 100644 --- a/src/target/arc_cmd.c +++ b/src/target/arc_cmd.c @@ -906,5 +906,8 @@ const struct command_registration arc_monitor_command_handlers[] = { .usage = "", .chain = arc_core_command_handlers, }, + { + .chain = rtt_target_command_handlers, + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/arc_jtag.c b/src/target/arc_jtag.c index a186709..c2bc5aa 100644 --- a/src/target/arc_jtag.c +++ b/src/target/arc_jtag.c @@ -66,7 +66,7 @@ static void arc_jtag_enque_write_ir(struct arc_jtag *jtag_info, uint32_t * @param end_state End state after reading. */ static void arc_jtag_enque_read_dr(struct arc_jtag *jtag_info, uint8_t *data, - tap_state_t end_state) + enum tap_state end_state) { assert(jtag_info); @@ -88,7 +88,7 @@ static void arc_jtag_enque_read_dr(struct arc_jtag *jtag_info, uint8_t *data, * @param end_state End state after writing. */ static void arc_jtag_enque_write_dr(struct arc_jtag *jtag_info, uint32_t data, - tap_state_t end_state) + enum tap_state end_state) { uint8_t out_value[sizeof(uint32_t)] = {0}; @@ -116,7 +116,7 @@ static void arc_jtag_enque_write_dr(struct arc_jtag *jtag_info, uint32_t data, * @param end_state End state after writing. */ static void arc_jtag_enque_set_transaction(struct arc_jtag *jtag_info, - uint32_t new_trans, tap_state_t end_state) + uint32_t new_trans, enum tap_state end_state) { uint8_t out_value[sizeof(uint32_t)] = {0}; diff --git a/src/target/arc_mem.c b/src/target/arc_mem.c index 3264b66..5132aca 100644 --- a/src/target/arc_mem.c +++ b/src/target/arc_mem.c @@ -35,7 +35,7 @@ static int arc_mem_write_block32(struct target *target, uint32_t addr, { struct arc_common *arc = target_to_arc(target); - LOG_DEBUG("Write 4-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32, + LOG_TARGET_DEBUG(target, "Write 4-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32, addr, count); /* Check arguments */ @@ -66,7 +66,7 @@ static int arc_mem_write_block16(struct target *target, uint32_t addr, uint8_t buffer_te[sizeof(uint32_t)]; uint8_t halfword_te[sizeof(uint16_t)]; - LOG_DEBUG("Write 2-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32, + LOG_TARGET_DEBUG(target, "Write 2-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32, addr, count); /* Check arguments */ @@ -124,7 +124,7 @@ static int arc_mem_write_block8(struct target *target, uint32_t addr, uint8_t buffer_te[sizeof(uint32_t)]; - LOG_DEBUG("Write 1-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32, + LOG_TARGET_DEBUG(target, "Write 1-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32, addr, count); /* We will read data from memory, so we need to flush the cache. */ @@ -158,14 +158,9 @@ int arc_mem_write(struct target *target, target_addr_t address, uint32_t size, int retval = ERROR_OK; void *tunnel = NULL; - LOG_DEBUG("address: 0x%08" TARGET_PRIxADDR ", size: %" PRIu32 ", count: %" PRIu32, + LOG_TARGET_DEBUG(target, "address: 0x%08" TARGET_PRIxADDR ", size: %" PRIu32 ", count: %" PRIu32, address, size, count); - if (target->state != TARGET_HALTED) { - LOG_TARGET_ERROR(target, "not halted"); - return ERROR_TARGET_NOT_HALTED; - } - /* sanitize arguments */ if (((size != 4) && (size != 2) && (size != 1)) || !(count) || !(buffer)) return ERROR_COMMAND_SYNTAX_ERROR; @@ -182,7 +177,7 @@ int arc_mem_write(struct target *target, target_addr_t address, uint32_t size, tunnel = calloc(1, count * size * sizeof(uint8_t)); if (!tunnel) { - LOG_ERROR("Unable to allocate memory"); + LOG_TARGET_ERROR(target, "Unable to allocate memory"); return ERROR_FAIL; } @@ -220,7 +215,7 @@ static int arc_mem_read_block(struct target *target, target_addr_t addr, { struct arc_common *arc = target_to_arc(target); - LOG_DEBUG("Read memory: addr=0x%08" TARGET_PRIxADDR ", size=%" PRIu32 + LOG_TARGET_DEBUG(target, "Read memory: addr=0x%08" TARGET_PRIxADDR ", size=%" PRIu32 ", count=%" PRIu32, addr, size, count); assert(!(addr & 3)); assert(size == 4); @@ -243,14 +238,9 @@ int arc_mem_read(struct target *target, target_addr_t address, uint32_t size, uint32_t words_to_read, bytes_to_read; - LOG_DEBUG("Read memory: addr=0x%08" TARGET_PRIxADDR ", size=%" PRIu32 + LOG_TARGET_DEBUG(target, "Read memory: addr=0x%08" TARGET_PRIxADDR ", size=%" PRIu32 ", count=%" PRIu32, address, size, count); - if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; - } - /* Sanitize arguments */ if (((size != 4) && (size != 2) && (size != 1)) || !(count) || !(buffer)) return ERROR_COMMAND_SYNTAX_ERROR; @@ -268,7 +258,7 @@ int arc_mem_read(struct target *target, target_addr_t address, uint32_t size, tunnel_te = calloc(1, bytes_to_read); if (!tunnel_he || !tunnel_te) { - LOG_ERROR("Unable to allocate memory"); + LOG_TARGET_ERROR(target, "Unable to allocate memory"); free(tunnel_he); free(tunnel_te); return ERROR_FAIL; diff --git a/src/target/arm.h b/src/target/arm.h index 486666b..79ec99d 100644 --- a/src/target/arm.h +++ b/src/target/arm.h @@ -58,11 +58,12 @@ enum arm_arch { ARM_ARCH_V8M, }; -/** Known ARM implementor IDs */ -enum arm_implementor { - ARM_IMPLEMENTOR_ARM = 0x41, - ARM_IMPLEMENTOR_INFINEON = 0x49, - ARM_IMPLEMENTOR_REALTEK = 0x72, +/** Known ARM implementer IDs */ +enum arm_implementer { + ARM_IMPLEMENTER_ARM = 0x41, + ARM_IMPLEMENTER_INFINEON = 0x49, + ARM_IMPLEMENTER_ARM_CHINA = 0x63, + ARM_IMPLEMENTER_REALTEK = 0x72, }; /** @@ -142,8 +143,8 @@ enum { ARM_VFP_V3_FPSCR, }; -const char *arm_mode_name(unsigned psr_mode); -bool is_arm_mode(unsigned psr_mode); +const char *arm_mode_name(unsigned int psr_mode); +bool is_arm_mode(unsigned int psr_mode); /** The PSR "T" and "J" bits define the mode of "classic ARM" cores. */ enum arm_state { @@ -324,7 +325,7 @@ int arm_blank_check_memory(struct target *target, struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value); void arm_set_cpsr(struct arm *arm, uint32_t cpsr); -struct reg *arm_reg_current(struct arm *arm, unsigned regnum); -struct reg *armv8_reg_current(struct arm *arm, unsigned regnum); +struct reg *arm_reg_current(struct arm *arm, unsigned int regnum); +struct reg *armv8_reg_current(struct arm *arm, unsigned int regnum); #endif /* OPENOCD_TARGET_ARM_H */ diff --git a/src/target/arm11.c b/src/target/arm11.c index 50aaa86..756b36b 100644 --- a/src/target/arm11.c +++ b/src/target/arm11.c @@ -30,8 +30,8 @@ #endif -static int arm11_step(struct target *target, int current, - target_addr_t address, int handle_breakpoints); +static int arm11_step(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints); /** Check and if necessary take control of the system @@ -43,7 +43,7 @@ static int arm11_check_init(struct arm11_common *arm11) CHECK_RETVAL(arm11_read_dscr(arm11)); if (!(arm11->dscr & DSCR_HALT_DBG_MODE)) { - LOG_DEBUG("DSCR %08x", (unsigned) arm11->dscr); + LOG_DEBUG("DSCR %08" PRIx32, arm11->dscr); LOG_DEBUG("Bringing target into debug mode"); arm11->dscr |= DSCR_HALT_DBG_MODE; @@ -241,8 +241,7 @@ static int arm11_leave_debug_state(struct arm11_common *arm11, bool bpwp) registers hold data that was written by one side (CPU or JTAG) and not read out by the other side. */ - LOG_ERROR("wDTR/rDTR inconsistent (DSCR %08x)", - (unsigned) arm11->dscr); + LOG_ERROR("wDTR/rDTR inconsistent (DSCR %08" PRIx32 ")", arm11->dscr); return ERROR_FAIL; } } @@ -402,7 +401,8 @@ static int arm11_halt(struct target *target) return ERROR_OK; } -static uint32_t arm11_nextpc(struct arm11_common *arm11, int current, uint32_t address) +static uint32_t arm11_nextpc(struct arm11_common *arm11, bool current, + uint32_t address) { void *value = arm11->arm.pc->value; @@ -436,8 +436,8 @@ static uint32_t arm11_nextpc(struct arm11_common *arm11, int current, uint32_t a return address; } -static int arm11_resume(struct target *target, int current, - target_addr_t address, int handle_breakpoints, int debug_execution) +static int arm11_resume(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, bool debug_execution) { /* LOG_DEBUG("current %d address %08x handle_breakpoints %d debug_execution %d", */ /* current, address, handle_breakpoints, debug_execution); */ @@ -470,7 +470,7 @@ static int arm11_resume(struct target *target, int current, for (bp = target->breakpoints; bp; bp = bp->next) { if (bp->address == address) { LOG_DEBUG("must step over %08" TARGET_PRIxADDR "", bp->address); - arm11_step(target, 1, 0, 0); + arm11_step(target, true, 0, false); break; } } @@ -479,7 +479,7 @@ static int arm11_resume(struct target *target, int current, /* activate all breakpoints */ if (true) { struct breakpoint *bp; - unsigned brp_num = 0; + unsigned int brp_num = 0; for (bp = target->breakpoints; bp; bp = bp->next) { struct arm11_sc7_action brp[2]; @@ -516,7 +516,7 @@ static int arm11_resume(struct target *target, int current, while (1) { CHECK_RETVAL(arm11_read_dscr(arm11)); - LOG_DEBUG("DSCR %08x", (unsigned) arm11->dscr); + LOG_DEBUG("DSCR %08" PRIx32, arm11->dscr); if (arm11->dscr & DSCR_CORE_RESTARTED) break; @@ -544,8 +544,8 @@ static int arm11_resume(struct target *target, int current, return ERROR_OK; } -static int arm11_step(struct target *target, int current, - target_addr_t address, int handle_breakpoints) +static int arm11_step(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints) { LOG_DEBUG("target->state: %s", target_state_name(target)); @@ -570,13 +570,13 @@ static int arm11_step(struct target *target, int current, /* skip over BKPT */ if ((next_instruction & 0xFFF00070) == 0xe1200070) { - address = arm11_nextpc(arm11, 0, address + 4); + address = arm11_nextpc(arm11, false, address + 4); LOG_DEBUG("Skipping BKPT %08" TARGET_PRIxADDR, address); } /* skip over Wait for interrupt / Standby * mcr 15, 0, r?, cr7, cr0, {4} */ else if ((next_instruction & 0xFFFF0FFF) == 0xee070f90) { - address = arm11_nextpc(arm11, 0, address + 4); + address = arm11_nextpc(arm11, false, address + 4); LOG_DEBUG("Skipping WFI %08" TARGET_PRIxADDR, address); } /* ignore B to self */ @@ -662,7 +662,7 @@ static int arm11_step(struct target *target, int current, | DSCR_CORE_HALTED; CHECK_RETVAL(arm11_read_dscr(arm11)); - LOG_DEBUG("DSCR %08x e", (unsigned) arm11->dscr); + LOG_DEBUG("DSCR %08" PRIx32 " e", arm11->dscr); if ((arm11->dscr & mask) == mask) break; @@ -1012,10 +1012,8 @@ static int arm11_write_memory_inner(struct target *target, return retval; if (address + size * count != r0) { - LOG_ERROR("Data transfer failed. Expected end " - "address 0x%08x, got 0x%08x", - (unsigned) (address + size * count), - (unsigned) r0); + LOG_ERROR("Data transfer failed. Expected end address 0x%08" PRIx32 ", got 0x%08" PRIx32, + address + size * count, r0); if (burst) LOG_ERROR( diff --git a/src/target/arm11.h b/src/target/arm11.h index 1f56f7b..40a3f90 100644 --- a/src/target/arm11.h +++ b/src/target/arm11.h @@ -39,7 +39,7 @@ struct arm11_common { /** Debug module state. */ struct arm_dpm dpm; struct arm11_sc7_action *bpwp_actions; - unsigned bpwp_n; + unsigned int bpwp_n; size_t brp; /**< Number of Breakpoint Register Pairs from DIDR */ size_t free_brps; /**< Number of breakpoints allocated */ diff --git a/src/target/arm11_dbgtap.c b/src/target/arm11_dbgtap.c index b670bd7..4c72113 100644 --- a/src/target/arm11_dbgtap.c +++ b/src/target/arm11_dbgtap.c @@ -31,13 +31,13 @@ behavior of the FTDI driver IIRC was to go via RTI. Conversely there may be other places in this code where the ARM11 code relies on the driver to hit through RTI when coming from Update-?R. */ -static const tap_state_t arm11_move_pi_to_si_via_ci[] = { +static const enum tap_state arm11_move_pi_to_si_via_ci[] = { TAP_IREXIT2, TAP_IRUPDATE, TAP_DRSELECT, TAP_IRSELECT, TAP_IRCAPTURE, TAP_IRSHIFT }; /* REVISIT no error handling here! */ static void arm11_add_ir_scan_vc(struct jtag_tap *tap, struct scan_field *fields, - tap_state_t state) + enum tap_state state) { if (cmd_queue_cur_state == TAP_IRPAUSE) jtag_add_pathmove(ARRAY_SIZE(arm11_move_pi_to_si_via_ci), @@ -46,13 +46,13 @@ static void arm11_add_ir_scan_vc(struct jtag_tap *tap, struct scan_field *fields jtag_add_ir_scan(tap, fields, state); } -static const tap_state_t arm11_move_pd_to_sd_via_cd[] = { +static const enum tap_state arm11_move_pd_to_sd_via_cd[] = { TAP_DREXIT2, TAP_DRUPDATE, TAP_DRSELECT, TAP_DRCAPTURE, TAP_DRSHIFT }; /* REVISIT no error handling here! */ void arm11_add_dr_scan_vc(struct jtag_tap *tap, int num_fields, struct scan_field *fields, - tap_state_t state) + enum tap_state state) { if (cmd_queue_cur_state == TAP_DRPAUSE) jtag_add_pathmove(ARRAY_SIZE(arm11_move_pd_to_sd_via_cd), @@ -121,7 +121,7 @@ static const char *arm11_ir_to_string(uint8_t ir) * * \remarks This adds to the JTAG command queue but does \em not execute it. */ -void arm11_add_ir(struct arm11_common *arm11, uint8_t instr, tap_state_t state) +void arm11_add_ir(struct arm11_common *arm11, uint8_t instr, enum tap_state state) { struct jtag_tap *tap = arm11->arm.target->tap; @@ -181,7 +181,7 @@ static void arm11_in_handler_scan_n(uint8_t *in_value) */ int arm11_add_debug_scan_n(struct arm11_common *arm11, - uint8_t chain, tap_state_t state) + uint8_t chain, enum tap_state state) { /* Don't needlessly switch the scan chain. * NOTE: the ITRSEL instruction fakes SCREG changing; @@ -240,9 +240,9 @@ int arm11_add_debug_scan_n(struct arm11_common *arm11, * to ensure that the rDTR is ready before that Run-Test/Idle state. */ static void arm11_add_debug_inst(struct arm11_common *arm11, - uint32_t inst, uint8_t *flag, tap_state_t state) + uint32_t inst, uint8_t *flag, enum tap_state state) { - JTAG_DEBUG("INST <= 0x%08x", (unsigned) inst); + JTAG_DEBUG("INST <= 0x%08" PRIx32, inst); struct scan_field itr[2]; @@ -282,9 +282,7 @@ int arm11_read_dscr(struct arm11_common *arm11) CHECK_RETVAL(jtag_execute_queue()); if (arm11->dscr != dscr) - JTAG_DEBUG("DSCR = %08x (OLD %08x)", - (unsigned) dscr, - (unsigned) arm11->dscr); + JTAG_DEBUG("DSCR = %08" PRIx32 " (OLD %08" PRIx32 ")", dscr, arm11->dscr); arm11->dscr = dscr; @@ -317,9 +315,7 @@ int arm11_write_dscr(struct arm11_common *arm11, uint32_t dscr) CHECK_RETVAL(jtag_execute_queue()); - JTAG_DEBUG("DSCR <= %08x (OLD %08x)", - (unsigned) dscr, - (unsigned) arm11->dscr); + JTAG_DEBUG("DSCR <= %08" PRIx32 " (OLD %08" PRIx32 ")", dscr, arm11->dscr); arm11->dscr = dscr; @@ -509,8 +505,8 @@ int arm11_run_instr_data_to_core(struct arm11_common *arm11, CHECK_RETVAL(jtag_execute_queue()); - JTAG_DEBUG("DTR _data %08x ready %d n_retry %d", - (unsigned) _data, ready, n_retry); + JTAG_DEBUG("DTR _data %08" PRIx32 " ready %d n_retry %d", + _data, ready, n_retry); int64_t then = 0; @@ -546,7 +542,7 @@ int arm11_run_instr_data_to_core(struct arm11_common *arm11, * https://lists.berlios.de/pipermail/openocd-development/2009-July/009698.html * https://lists.berlios.de/pipermail/openocd-development/2009-August/009865.html */ -static const tap_state_t arm11_move_drpause_idle_drpause_with_delay[] = { +static const enum tap_state arm11_move_drpause_idle_drpause_with_delay[] = { TAP_DREXIT2, TAP_DRUPDATE, TAP_IDLE, TAP_IDLE, TAP_IDLE, TAP_DRSELECT, TAP_DRCAPTURE, TAP_DRSHIFT }; @@ -571,8 +567,8 @@ static int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap, chain5_fields[2].in_value = NULL; uint8_t *readies; - unsigned readies_num = count; - unsigned bytes = sizeof(*readies)*readies_num; + unsigned int readies_num = count; + unsigned int bytes = sizeof(*readies) * readies_num; readies = malloc(bytes); if (!readies) { @@ -596,7 +592,7 @@ static int arm11_run_instr_data_to_core_noack_inner(struct jtag_tap *tap, int retval = jtag_execute_queue(); if (retval == ERROR_OK) { - unsigned error_count = 0; + unsigned int error_count = 0; for (size_t i = 0; i < readies_num; i++) { if (readies[i] != 1) @@ -754,8 +750,8 @@ int arm11_run_instr_data_from_core(struct arm11_common *arm11, CHECK_RETVAL(jtag_execute_queue()); - JTAG_DEBUG("DTR _data %08x ready %d n_retry %d", - (unsigned) _data, ready, n_retry); + JTAG_DEBUG("DTR _data %08" PRIx32 " ready %d n_retry %d", + _data, ready, n_retry); int64_t then = 0; @@ -878,9 +874,8 @@ int arm11_sc7_run(struct arm11_common *arm11, struct arm11_sc7_action *actions, /* Timeout here so we don't get stuck. */ int i_n = 0; while (1) { - JTAG_DEBUG("SC7 <= c%-3d Data %08x %s", - (unsigned) address_out, - (unsigned) data_out, + JTAG_DEBUG("SC7 <= c%-3" PRIu8 " Data %08" PRIx32 " %s", + address_out, data_out, n_rw ? "write" : "read"); arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE(chain7_fields), @@ -908,7 +903,7 @@ int arm11_sc7_run(struct arm11_common *arm11, struct arm11_sc7_action *actions, } if (!n_rw) - JTAG_DEBUG("SC7 => Data %08x", (unsigned) data_in); + JTAG_DEBUG("SC7 => Data %08" PRIx32, data_in); if (i > 0) { if (actions[i - 1].address != address_in) @@ -1047,7 +1042,7 @@ static int arm11_dpm_instr_read_data_r0(struct arm_dpm *dpm, * and watchpoint operations instead of running them right away. Since we * pre-allocated our vector, we don't need to worry about space. */ -static int arm11_bpwp_enable(struct arm_dpm *dpm, unsigned index_t, +static int arm11_bpwp_enable(struct arm_dpm *dpm, unsigned int index_t, uint32_t addr, uint32_t control) { struct arm11_common *arm11 = dpm_to_arm11(dpm); @@ -1084,7 +1079,7 @@ static int arm11_bpwp_enable(struct arm_dpm *dpm, unsigned index_t, return ERROR_OK; } -static int arm11_bpwp_disable(struct arm_dpm *dpm, unsigned index_t) +static int arm11_bpwp_disable(struct arm_dpm *dpm, unsigned int index_t) { struct arm11_common *arm11 = dpm_to_arm11(dpm); struct arm11_sc7_action *action; diff --git a/src/target/arm11_dbgtap.h b/src/target/arm11_dbgtap.h index eeb174a..74dda6e 100644 --- a/src/target/arm11_dbgtap.h +++ b/src/target/arm11_dbgtap.h @@ -17,9 +17,9 @@ void arm11_setup_field(struct arm11_common *arm11, int num_bits, void *in_data, void *out_data, struct scan_field *field); void arm11_add_ir(struct arm11_common *arm11, - uint8_t instr, tap_state_t state); + uint8_t instr, enum tap_state state); int arm11_add_debug_scan_n(struct arm11_common *arm11, - uint8_t chain, tap_state_t state); + uint8_t chain, enum tap_state state); int arm11_read_dscr(struct arm11_common *arm11); int arm11_write_dscr(struct arm11_common *arm11, uint32_t dscr); @@ -40,7 +40,7 @@ int arm11_run_instr_data_to_core_via_r0(struct arm11_common *arm11, uint32_t opcode, uint32_t data); void arm11_add_dr_scan_vc(struct jtag_tap *tap, int num_fields, struct scan_field *fields, - tap_state_t state); + enum tap_state state); /** * Used with arm11_sc7_run to make a list of read/write commands for diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c index ad814e0..5550fb1 100644 --- a/src/target/arm7_9_common.c +++ b/src/target/arm7_9_common.c @@ -1697,10 +1697,10 @@ static void arm7_9_enable_breakpoints(struct target *target) } int arm7_9_resume(struct target *target, - int current, + bool current, target_addr_t address, - int handle_breakpoints, - int debug_execution) + bool handle_breakpoints, + bool debug_execution) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; @@ -1717,7 +1717,7 @@ int arm7_9_resume(struct target *target, if (!debug_execution) target_free_all_working_areas(target); - /* current = 1: continue on current pc, otherwise continue at <address> */ + /* current = true: continue on current pc, otherwise continue at <address> */ if (!current) buf_set_u32(arm->pc->value, 0, 32, address); @@ -1900,7 +1900,8 @@ void arm7_9_disable_eice_step(struct target *target) embeddedice_store_reg(&arm7_9->eice_cache->reg_list[EICE_W1_CONTROL_VALUE]); } -int arm7_9_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) +int arm7_9_step(struct target *target, bool current, target_addr_t address, + bool handle_breakpoints) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm *arm = &arm7_9->arm; @@ -1912,7 +1913,7 @@ int arm7_9_step(struct target *target, int current, target_addr_t address, int h return ERROR_TARGET_NOT_HALTED; } - /* current = 1: continue on current pc, otherwise continue at <address> */ + /* current = true: continue on current pc, otherwise continue at <address> */ if (!current) buf_set_u32(arm->pc->value, 0, 32, address); diff --git a/src/target/arm7_9_common.h b/src/target/arm7_9_common.h index 92d0fd5..c4a5b08 100644 --- a/src/target/arm7_9_common.h +++ b/src/target/arm7_9_common.h @@ -145,10 +145,10 @@ int arm7_9_early_halt(struct target *target); int arm7_9_soft_reset_halt(struct target *target); int arm7_9_halt(struct target *target); -int arm7_9_resume(struct target *target, int current, target_addr_t address, - int handle_breakpoints, int debug_execution); -int arm7_9_step(struct target *target, int current, target_addr_t address, - int handle_breakpoints); +int arm7_9_resume(struct target *target, bool current, target_addr_t address, + bool handle_breakpoints, bool debug_execution); +int arm7_9_step(struct target *target, bool current, target_addr_t address, + bool handle_breakpoints); int arm7_9_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); int arm7_9_write_memory(struct target *target, target_addr_t address, diff --git a/src/target/arm9tdmi.c b/src/target/arm9tdmi.c index 3bacfae..7e31306 100644 --- a/src/target/arm9tdmi.c +++ b/src/target/arm9tdmi.c @@ -821,9 +821,9 @@ COMMAND_HANDLER(handle_arm9tdmi_catch_vectors_command) else if (strcmp(CMD_ARGV[0], "none") == 0) { /* do nothing */ } else { - for (unsigned i = 0; i < CMD_ARGC; i++) { + for (unsigned int i = 0; i < CMD_ARGC; i++) { /* go through list of vectors */ - unsigned j; + unsigned int j; for (j = 0; arm9tdmi_vectors[j].name; j++) { if (strcmp(CMD_ARGV[i], arm9tdmi_vectors[j].name) == 0) { vector_catch_value |= arm9tdmi_vectors[j].value; @@ -850,7 +850,7 @@ COMMAND_HANDLER(handle_arm9tdmi_catch_vectors_command) } /* output current settings */ - for (unsigned i = 0; arm9tdmi_vectors[i].name; i++) { + for (unsigned int i = 0; arm9tdmi_vectors[i].name; i++) { command_print(CMD, "%s: %s", arm9tdmi_vectors[i].name, (vector_catch_value & arm9tdmi_vectors[i].value) ? "catch" : "don't catch"); diff --git a/src/target/arm_adi_v5.c b/src/target/arm_adi_v5.c index 9129ace..df897b8 100644 --- a/src/target/arm_adi_v5.c +++ b/src/target/arm_adi_v5.c @@ -795,11 +795,12 @@ int dap_dp_init(struct adiv5_dap *dap) dap->dp_ctrl_stat = CDBGPWRUPREQ | CSYSPWRUPREQ; /* - * This write operation clears the sticky error bit in jtag mode only and - * is ignored in swd mode. It also powers-up system and debug domains in - * both jtag and swd modes, if not done before. + * This write operation clears the sticky error and overrun bits in jtag + * mode only and is ignored in swd mode. It also powers-up system and + * debug domains in both jtag and swd modes, if not done before. */ - retval = dap_queue_dp_write(dap, DP_CTRL_STAT, dap->dp_ctrl_stat | SSTICKYERR); + retval = dap_queue_dp_write(dap, DP_CTRL_STAT, + dap->dp_ctrl_stat | SSTICKYERR | SSTICKYORUN); if (retval != ERROR_OK) return retval; @@ -1453,11 +1454,13 @@ static const struct dap_part_nums { { ARM_ID, 0x4af, "Cortex-A15 ROM", "(ROM Table)", }, { ARM_ID, 0x4b5, "Cortex-R5 ROM", "(ROM Table)", }, { ARM_ID, 0x4b8, "Cortex-R52 ROM", "(ROM Table)", }, + { ARM_ID, 0x4bd, "Cortex-R52+ ROM", "(ROM Table)", }, { ARM_ID, 0x4c0, "Cortex-M0+ ROM", "(ROM Table)", }, { ARM_ID, 0x4c3, "Cortex-M3 ROM", "(ROM Table)", }, { ARM_ID, 0x4c4, "Cortex-M4 ROM", "(ROM Table)", }, { ARM_ID, 0x4c7, "Cortex-M7 PPB ROM", "(Private Peripheral Bus ROM Table)", }, { ARM_ID, 0x4c8, "Cortex-M7 ROM", "(ROM Table)", }, + { ARM_ID, 0x4c9, "STAR ROM", "(ROM Table)", }, { ARM_ID, 0x4e0, "Cortex-A35 ROM", "(v7 Memory Map ROM Table)", }, { ARM_ID, 0x4e4, "Cortex-A76 ROM", "(ROM Table)", }, { ARM_ID, 0x906, "CoreSight CTI", "(Cross Trigger)", }, @@ -1499,6 +1502,7 @@ static const struct dap_part_nums { { ARM_ID, 0x9ae, "Cortex-A17 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9af, "Cortex-A15 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9b6, "Cortex-R52 PMU/CTI/ETM", "(Performance Monitor Unit/Cross Trigger/ETM)", }, + { ARM_ID, 0x9bb, "Cortex-R52+ PMU/CTI/ETM", "(Performance Monitor Unit/Cross Trigger/ETM)", }, { ARM_ID, 0x9b7, "Cortex-R7 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9d3, "Cortex-A53 PMU", "(Performance Monitor Unit)", }, { ARM_ID, 0x9d7, "Cortex-A57 PMU", "(Performance Monitor Unit)", }, @@ -1528,11 +1532,16 @@ static const struct dap_part_nums { { ARM_ID, 0xc17, "Cortex-R7 Debug", "(Debug Unit)", }, { ARM_ID, 0xd03, "Cortex-A53 Debug", "(Debug Unit)", }, { ARM_ID, 0xd04, "Cortex-A35 Debug", "(Debug Unit)", }, + { ARM_ID, 0xd05, "Cortex-A55 Debug", "(Debug Unit)", }, { ARM_ID, 0xd07, "Cortex-A57 Debug", "(Debug Unit)", }, { ARM_ID, 0xd08, "Cortex-A72 Debug", "(Debug Unit)", }, { ARM_ID, 0xd0b, "Cortex-A76 Debug", "(Debug Unit)", }, { ARM_ID, 0xd0c, "Neoverse N1", "(Debug Unit)", }, { ARM_ID, 0xd13, "Cortex-R52 Debug", "(Debug Unit)", }, + { ARM_ID, 0xd16, "Cortex-R52+ Debug", "(Debug Unit)", }, + { ARM_ID, 0xd21, "STAR Debug", "(Debug Unit)", }, + { ARM_ID, 0xd22, "Cortex-M55 Debug", "(Debug Unit)", }, + { ARM_ID, 0xd43, "Cortex-A65AE Debug", "(Debug Unit)", }, { ARM_ID, 0xd49, "Neoverse N2", "(Debug Unit)", }, { 0x017, 0x120, "TI SDTI", "(System Debug Trace Interface)", }, /* from OMAP3 memmap */ { 0x017, 0x343, "TI DAPCTL", "", }, /* from OMAP3 memmap */ @@ -1552,6 +1561,9 @@ static const struct dap_part_nums { { 0x1eb, 0x211, "Tegra 210 ROM", "(ROM Table)", }, { 0x1eb, 0x302, "Denver Debug", "(Debug Unit)", }, { 0x1eb, 0x402, "Denver PMU", "(Performance Monitor Unit)", }, + { 0x575, 0x132, "STAR SCS", "(System Control Space)", }, + { 0x575, 0x4d2, "Cortex-M52 ROM", "(ROM Table)", }, + { 0x575, 0xd24, "Cortex-M52 Debug", "(Debug Unit)", }, }; static const struct dap_part_nums *pidr_to_part_num(unsigned int designer_id, unsigned int part_num) @@ -2347,7 +2359,7 @@ static int adiv5_jim_spot_configure(struct jim_getopt_info *goi, switch (n->value) { case CFG_DAP: - if (goi->isconfigure) { + if (goi->is_configure) { Jim_Obj *o_t; struct adiv5_dap *dap; e = jim_getopt_obj(goi, &o_t); @@ -2355,7 +2367,9 @@ static int adiv5_jim_spot_configure(struct jim_getopt_info *goi, return e; dap = dap_instance_by_jim_obj(goi->interp, o_t); if (!dap) { - Jim_SetResultString(goi->interp, "DAP name invalid!", -1); + const char *dap_name = Jim_GetString(o_t, NULL); + Jim_SetResultFormatted(goi->interp, "DAP '%s' not found", + dap_name); return JIM_ERR; } if (*dap_p && *dap_p != dap) { @@ -2376,7 +2390,7 @@ static int adiv5_jim_spot_configure(struct jim_getopt_info *goi, break; case CFG_AP_NUM: - if (goi->isconfigure) { + if (goi->is_configure) { /* jim_wide is a signed 64 bits int, ap_num is unsigned with max 52 bits */ jim_wide ap_num; e = jim_getopt_wide(goi, &ap_num); @@ -2403,7 +2417,7 @@ static int adiv5_jim_spot_configure(struct jim_getopt_info *goi, LOG_WARNING("DEPRECATED! use \'-baseaddr' not \'-ctibase\'"); /* fall through */ case CFG_BASEADDR: - if (goi->isconfigure) { + if (goi->is_configure) { jim_wide base; e = jim_getopt_wide(goi, &base); if (e != JIM_OK) diff --git a/src/target/arm_adi_v5.h b/src/target/arm_adi_v5.h index 92c3dbc..ebd2752 100644 --- a/src/target/arm_adi_v5.h +++ b/src/target/arm_adi_v5.h @@ -454,17 +454,17 @@ struct dap_ops { int (*send_sequence)(struct adiv5_dap *dap, enum swd_special_seq seq); /** DP register read. */ - int (*queue_dp_read)(struct adiv5_dap *dap, unsigned reg, + int (*queue_dp_read)(struct adiv5_dap *dap, unsigned int reg, uint32_t *data); /** DP register write. */ - int (*queue_dp_write)(struct adiv5_dap *dap, unsigned reg, + int (*queue_dp_write)(struct adiv5_dap *dap, unsigned int reg, uint32_t data); /** AP register read. */ - int (*queue_ap_read)(struct adiv5_ap *ap, unsigned reg, + int (*queue_ap_read)(struct adiv5_ap *ap, unsigned int reg, uint32_t *data); /** AP register write. */ - int (*queue_ap_write)(struct adiv5_ap *ap, unsigned reg, + int (*queue_ap_write)(struct adiv5_ap *ap, unsigned int reg, uint32_t data); /** AP operation abort. */ @@ -553,7 +553,7 @@ static inline int dap_send_sequence(struct adiv5_dap *dap, * @return ERROR_OK for success, else a fault code. */ static inline int dap_queue_dp_read(struct adiv5_dap *dap, - unsigned reg, uint32_t *data) + unsigned int reg, uint32_t *data) { assert(dap->ops); return dap->ops->queue_dp_read(dap, reg, data); @@ -571,7 +571,7 @@ static inline int dap_queue_dp_read(struct adiv5_dap *dap, * @return ERROR_OK for success, else a fault code. */ static inline int dap_queue_dp_write(struct adiv5_dap *dap, - unsigned reg, uint32_t data) + unsigned int reg, uint32_t data) { assert(dap->ops); return dap->ops->queue_dp_write(dap, reg, data); @@ -588,7 +588,7 @@ static inline int dap_queue_dp_write(struct adiv5_dap *dap, * @return ERROR_OK for success, else a fault code. */ static inline int dap_queue_ap_read(struct adiv5_ap *ap, - unsigned reg, uint32_t *data) + unsigned int reg, uint32_t *data) { assert(ap->dap->ops); if (ap->refcount == 0) { @@ -608,7 +608,7 @@ static inline int dap_queue_ap_read(struct adiv5_ap *ap, * @return ERROR_OK for success, else a fault code. */ static inline int dap_queue_ap_write(struct adiv5_ap *ap, - unsigned reg, uint32_t data) + unsigned int reg, uint32_t data) { assert(ap->dap->ops); if (ap->refcount == 0) { @@ -659,7 +659,7 @@ static inline int dap_sync(struct adiv5_dap *dap) return ERROR_OK; } -static inline int dap_dp_read_atomic(struct adiv5_dap *dap, unsigned reg, +static inline int dap_dp_read_atomic(struct adiv5_dap *dap, unsigned int reg, uint32_t *value) { int retval; @@ -671,7 +671,7 @@ static inline int dap_dp_read_atomic(struct adiv5_dap *dap, unsigned reg, return dap_run(dap); } -static inline int dap_dp_poll_register(struct adiv5_dap *dap, unsigned reg, +static inline int dap_dp_poll_register(struct adiv5_dap *dap, unsigned int reg, uint32_t mask, uint32_t value, int timeout) { assert(timeout > 0); diff --git a/src/target/arm_cti.c b/src/target/arm_cti.c index 7637ad0..b2f78ee 100644 --- a/src/target/arm_cti.c +++ b/src/target/arm_cti.c @@ -25,7 +25,7 @@ struct arm_cti { struct adiv5_ap *ap; }; -static LIST_HEAD(all_cti); +static OOCD_LIST_HEAD(all_cti); const char *arm_cti_name(struct arm_cti *self) { @@ -157,48 +157,44 @@ int arm_cti_clear_channel(struct arm_cti *self, uint32_t channel) return arm_cti_write_reg(self, CTI_APPCLEAR, CTI_CHNL(channel)); } -static uint32_t cti_regs[28]; - static const struct { uint32_t offset; const char *label; - uint32_t *p_val; } cti_names[] = { - { CTI_CTR, "CTR", &cti_regs[0] }, - { CTI_GATE, "GATE", &cti_regs[1] }, - { CTI_INEN0, "INEN0", &cti_regs[2] }, - { CTI_INEN1, "INEN1", &cti_regs[3] }, - { CTI_INEN2, "INEN2", &cti_regs[4] }, - { CTI_INEN3, "INEN3", &cti_regs[5] }, - { CTI_INEN4, "INEN4", &cti_regs[6] }, - { CTI_INEN5, "INEN5", &cti_regs[7] }, - { CTI_INEN6, "INEN6", &cti_regs[8] }, - { CTI_INEN7, "INEN7", &cti_regs[9] }, - { CTI_INEN8, "INEN8", &cti_regs[10] }, - { CTI_OUTEN0, "OUTEN0", &cti_regs[11] }, - { CTI_OUTEN1, "OUTEN1", &cti_regs[12] }, - { CTI_OUTEN2, "OUTEN2", &cti_regs[13] }, - { CTI_OUTEN3, "OUTEN3", &cti_regs[14] }, - { CTI_OUTEN4, "OUTEN4", &cti_regs[15] }, - { CTI_OUTEN5, "OUTEN5", &cti_regs[16] }, - { CTI_OUTEN6, "OUTEN6", &cti_regs[17] }, - { CTI_OUTEN7, "OUTEN7", &cti_regs[18] }, - { CTI_OUTEN8, "OUTEN8", &cti_regs[19] }, - { CTI_TRIN_STATUS, "TRIN", &cti_regs[20] }, - { CTI_TROUT_STATUS, "TROUT", &cti_regs[21] }, - { CTI_CHIN_STATUS, "CHIN", &cti_regs[22] }, - { CTI_CHOU_STATUS, "CHOUT", &cti_regs[23] }, - { CTI_APPSET, "APPSET", &cti_regs[24] }, - { CTI_APPCLEAR, "APPCLR", &cti_regs[25] }, - { CTI_APPPULSE, "APPPULSE", &cti_regs[26] }, - { CTI_INACK, "INACK", &cti_regs[27] }, + { CTI_CTR, "CTR" }, + { CTI_GATE, "GATE" }, + { CTI_INEN0, "INEN0" }, + { CTI_INEN1, "INEN1" }, + { CTI_INEN2, "INEN2" }, + { CTI_INEN3, "INEN3" }, + { CTI_INEN4, "INEN4" }, + { CTI_INEN5, "INEN5" }, + { CTI_INEN6, "INEN6" }, + { CTI_INEN7, "INEN7" }, + { CTI_INEN8, "INEN8" }, + { CTI_OUTEN0, "OUTEN0" }, + { CTI_OUTEN1, "OUTEN1" }, + { CTI_OUTEN2, "OUTEN2" }, + { CTI_OUTEN3, "OUTEN3" }, + { CTI_OUTEN4, "OUTEN4" }, + { CTI_OUTEN5, "OUTEN5" }, + { CTI_OUTEN6, "OUTEN6" }, + { CTI_OUTEN7, "OUTEN7" }, + { CTI_OUTEN8, "OUTEN8" }, + { CTI_TRIN_STATUS, "TRIN" }, + { CTI_TROUT_STATUS, "TROUT" }, + { CTI_CHIN_STATUS, "CHIN" }, + { CTI_CHOU_STATUS, "CHOUT" }, + { CTI_APPSET, "APPSET" }, + { CTI_APPCLEAR, "APPCLR" }, + { CTI_APPPULSE, "APPPULSE" }, + { CTI_INACK, "INACK" }, + { CTI_DEVCTL, "DEVCTL" }, }; static int cti_find_reg_offset(const char *name) { - unsigned int i; - - for (i = 0; i < ARRAY_SIZE(cti_names); i++) { + for (size_t i = 0; i < ARRAY_SIZE(cti_names); i++) { if (!strcmp(name, cti_names[i].label)) return cti_names[i].offset; } @@ -226,10 +222,11 @@ COMMAND_HANDLER(handle_cti_dump) struct arm_cti *cti = CMD_DATA; struct adiv5_ap *ap = cti->ap; int retval = ERROR_OK; + uint32_t values[ARRAY_SIZE(cti_names)]; - for (int i = 0; (retval == ERROR_OK) && (i < (int)ARRAY_SIZE(cti_names)); i++) + for (size_t i = 0; (retval == ERROR_OK) && (i < ARRAY_SIZE(cti_names)); i++) retval = mem_ap_read_u32(ap, - cti->spot.base + cti_names[i].offset, cti_names[i].p_val); + cti->spot.base + cti_names[i].offset, &values[i]); if (retval == ERROR_OK) retval = dap_run(ap->dap); @@ -237,9 +234,9 @@ COMMAND_HANDLER(handle_cti_dump) if (retval != ERROR_OK) return JIM_ERR; - for (int i = 0; i < (int)ARRAY_SIZE(cti_names); i++) + for (size_t i = 0; i < ARRAY_SIZE(cti_names); i++) command_print(CMD, "%8.8s (0x%04"PRIx32") 0x%08"PRIx32, - cti_names[i].label, cti_names[i].offset, *cti_names[i].p_val); + cti_names[i].label, cti_names[i].offset, values[i]); return JIM_OK; } @@ -323,7 +320,6 @@ COMMAND_HANDLER(handle_cti_ack) int retval = arm_cti_ack_events(cti, 1 << event); - if (retval != ERROR_OK) return retval; @@ -437,6 +433,7 @@ static int cti_configure(struct jim_getopt_info *goi, struct arm_cti *cti) return JIM_OK; } + static int cti_create(struct jim_getopt_info *goi) { struct command_context *cmd_ctx; @@ -471,7 +468,7 @@ static int cti_create(struct jim_getopt_info *goi) adiv5_mem_ap_spot_init(&cti->spot); /* Do the rest as "configure" options */ - goi->isconfigure = 1; + goi->is_configure = true; e = cti_configure(goi, cti); if (e != JIM_OK) { free(cti); @@ -538,7 +535,6 @@ COMMAND_HANDLER(cti_handle_names) return ERROR_OK; } - static const struct command_registration cti_subcommand_handlers[] = { { .name = "create", diff --git a/src/target/arm_cti.h b/src/target/arm_cti.h index cfcde65..1513f02 100644 --- a/src/target/arm_cti.h +++ b/src/target/arm_cti.h @@ -39,6 +39,7 @@ #define CTI_CHIN_STATUS 0x138 #define CTI_CHOU_STATUS 0x13C #define CTI_GATE 0x140 +#define CTI_DEVCTL 0x150 #define CTI_UNLOCK 0xFB0 #define CTI_CHNL(x) (1 << x) diff --git a/src/target/arm_dap.c b/src/target/arm_dap.c index 9f4afae..c5bd6cc 100644 --- a/src/target/arm_dap.c +++ b/src/target/arm_dap.c @@ -18,7 +18,7 @@ #include "transport/transport.h" #include "jtag/interface.h" -static LIST_HEAD(all_dap); +static OOCD_LIST_HEAD(all_dap); extern struct adapter_driver *adapter_driver; diff --git a/src/target/arm_disassembler.c b/src/target/arm_disassembler.c index 749274f..8619f8f 100644 --- a/src/target/arm_disassembler.c +++ b/src/target/arm_disassembler.c @@ -114,7 +114,7 @@ static int evaluate_pld(uint32_t opcode, if ((opcode & 0x0d30f000) == 0x0510f000) { uint8_t rn; uint8_t u; - unsigned offset; + unsigned int offset; instruction->type = ARM_PLD; rn = (opcode & 0xf0000) >> 16; @@ -266,18 +266,18 @@ static int evaluate_srs(uint32_t opcode, case 0x08400000: snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tSRS%s\tSP%s, #%d", + "\tSRS%s\tSP%s, #%" PRIu32, address, opcode, mode, wback, - (unsigned)(opcode & 0x1f)); + opcode & 0x1f); break; case 0x08100000: snprintf(instruction->text, 128, "0x%8.8" PRIx32 "\t0x%8.8" PRIx32 - "\tRFE%s\tr%d%s", + "\tRFE%s\tr%" PRIu32 "%s", address, opcode, mode, - (unsigned)((opcode >> 16) & 0xf), wback); + (opcode >> 16) & 0xf, wback); break; default: return evaluate_unknown(opcode, address, instruction); @@ -701,9 +701,9 @@ static int evaluate_load_store(uint32_t opcode, static int evaluate_extend(uint32_t opcode, uint32_t address, char *cp) { - unsigned rm = (opcode >> 0) & 0xf; - unsigned rd = (opcode >> 12) & 0xf; - unsigned rn = (opcode >> 16) & 0xf; + unsigned int rm = (opcode >> 0) & 0xf; + unsigned int rd = (opcode >> 12) & 0xf; + unsigned int rn = (opcode >> 16) & 0xf; char *type, *rot; switch ((opcode >> 24) & 0x3) { @@ -842,7 +842,7 @@ static int evaluate_media(uint32_t opcode, uint32_t address, /* halfword pack */ if ((opcode & 0x01f00020) == 0x00800000) { char *type, *shift; - unsigned imm = (unsigned) (opcode >> 7) & 0x1f; + unsigned int imm = (opcode >> 7) & 0x1f; if (opcode & (1 << 6)) { type = "TB"; @@ -865,7 +865,7 @@ static int evaluate_media(uint32_t opcode, uint32_t address, /* word saturate */ if ((opcode & 0x01a00020) == 0x00a00000) { char *shift; - unsigned imm = (unsigned) (opcode >> 7) & 0x1f; + unsigned int imm = (opcode >> 7) & 0x1f; if (opcode & (1 << 6)) { shift = "ASR"; @@ -892,7 +892,7 @@ static int evaluate_media(uint32_t opcode, uint32_t address, /* multiplies */ if ((opcode & 0x01f00080) == 0x01000000) { - unsigned rn = (opcode >> 12) & 0xf; + unsigned int rn = (opcode >> 12) & 0xf; if (rn != 0xf) sprintf(cp, "SML%cD%s%s\tr%d, r%d, r%d, r%d", @@ -925,7 +925,7 @@ static int evaluate_media(uint32_t opcode, uint32_t address, return ERROR_OK; } if ((opcode & 0x01f00000) == 0x01500000) { - unsigned rn = (opcode >> 12) & 0xf; + unsigned int rn = (opcode >> 12) & 0xf; switch (opcode & 0xc0) { case 3: @@ -1001,8 +1001,8 @@ static int evaluate_media(uint32_t opcode, uint32_t address, return ERROR_OK; } if (mnemonic) { - unsigned rm = (opcode >> 0) & 0xf; - unsigned rd = (opcode >> 12) & 0xf; + unsigned int rm = (opcode >> 0) & 0xf; + unsigned int rd = (opcode >> 12) & 0xf; sprintf(cp, "%s%s\tr%d, r%d", mnemonic, COND(opcode), rm, rd); return ERROR_OK; @@ -2046,8 +2046,7 @@ int arm_evaluate_opcode(uint32_t opcode, uint32_t address, return evaluate_cdp_mcr_mrc(opcode, address, instruction); } - LOG_ERROR("ARM: should never reach this point (opcode=%08x)", - (unsigned) opcode); + LOG_ERROR("ARM: should never reach this point (opcode=%08" PRIx32 ")", opcode); return -1; } @@ -2748,7 +2747,7 @@ static int evaluate_cond_branch_thumb(uint16_t opcode, static int evaluate_cb_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { - unsigned offset; + unsigned int offset; /* added in Thumb2 */ offset = (opcode >> 3) & 0x1f; @@ -2859,7 +2858,7 @@ static int evaluate_hint_thumb(uint16_t opcode, uint32_t address, static int evaluate_ifthen_thumb(uint16_t opcode, uint32_t address, struct arm_instruction *instruction) { - unsigned cond = (opcode >> 4) & 0x0f; + unsigned int cond = (opcode >> 4) & 0x0f; char *x = "", *y = "", *z = ""; if (opcode & 0x01) diff --git a/src/target/arm_disassembler.h b/src/target/arm_disassembler.h index 1be5674..8317da9 100644 --- a/src/target/arm_disassembler.h +++ b/src/target/arm_disassembler.h @@ -171,7 +171,7 @@ struct arm_instruction { uint32_t opcode; /* return value ... Thumb-2 sizes vary */ - unsigned instruction_size; + unsigned int instruction_size; union { struct arm_b_bl_bx_blx_instr b_bl_bx_blx; diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c index 9f3a444..0b2db77 100644 --- a/src/target/arm_dpm.c +++ b/src/target/arm_dpm.c @@ -59,7 +59,7 @@ static int dpm_mrc(struct target *target, int cpnum, ARMV4_5_MRC(cpnum, op1, 0, crn, crm, op2), value); - /* (void) */ dpm->finish(dpm); + dpm->finish(dpm); return retval; } @@ -82,7 +82,7 @@ static int dpm_mrrc(struct target *target, int cpnum, ARMV5_T_MRRC(cpnum, op, 0, 1, crm), value); - /* (void) */ dpm->finish(dpm); + dpm->finish(dpm); return retval; } @@ -107,7 +107,7 @@ static int dpm_mcr(struct target *target, int cpnum, ARMV4_5_MCR(cpnum, op1, 0, crn, crm, op2), value); - /* (void) */ dpm->finish(dpm); + dpm->finish(dpm); return retval; } @@ -129,7 +129,7 @@ static int dpm_mcrr(struct target *target, int cpnum, retval = dpm->instr_write_data_r0_r1(dpm, ARMV5_T_MCRR(cpnum, op, 0, 1, crm), value); - /* (void) */ dpm->finish(dpm); + dpm->finish(dpm); return retval; } @@ -167,7 +167,7 @@ int arm_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) } /* Read 64bit VFP registers */ -static int dpm_read_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum) +static int dpm_read_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned int regnum) { int retval = ERROR_FAIL; uint32_t value_r0, value_r1; @@ -198,15 +198,14 @@ static int dpm_read_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum) buf_set_u32(r->value + 4, 0, 32, value_r1); r->valid = true; r->dirty = false; - LOG_DEBUG("READ: %s, %8.8x, %8.8x", r->name, - (unsigned) value_r0, (unsigned) value_r1); + LOG_DEBUG("READ: %s, %8.8" PRIx32 ", %8.8" PRIx32, r->name, value_r0, value_r1); } return retval; } /* just read the register -- rely on the core mode being right */ -int arm_dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) +int arm_dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned int regnum) { uint32_t value; int retval; @@ -266,14 +265,14 @@ int arm_dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) buf_set_u32(r->value, 0, 32, value); r->valid = true; r->dirty = false; - LOG_DEBUG("READ: %s, %8.8x", r->name, (unsigned) value); + LOG_DEBUG("READ: %s, %8.8" PRIx32, r->name, value); } return retval; } /* Write 64bit VFP registers */ -static int dpm_write_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum) +static int dpm_write_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned int regnum) { int retval = ERROR_FAIL; uint32_t value_r0 = buf_get_u32(r->value, 0, 32); @@ -302,15 +301,14 @@ static int dpm_write_reg_u64(struct arm_dpm *dpm, struct reg *r, unsigned regnum if (retval == ERROR_OK) { r->dirty = false; - LOG_DEBUG("WRITE: %s, %8.8x, %8.8x", r->name, - (unsigned) value_r0, (unsigned) value_r1); + LOG_DEBUG("WRITE: %s, %8.8" PRIx32 ", %8.8" PRIx32, r->name, value_r0, value_r1); } return retval; } /* just write the register -- rely on the core mode being right */ -static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) +static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned int regnum) { int retval; uint32_t value = buf_get_u32(r->value, 0, 32); @@ -351,7 +349,7 @@ static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) if (retval == ERROR_OK) { r->dirty = false; - LOG_DEBUG("WRITE: %s, %8.8x", r->name, (unsigned) value); + LOG_DEBUG("WRITE: %s, %8.8" PRIx32, r->name, value); } return retval; @@ -388,7 +386,7 @@ int arm_dpm_read_current_registers(struct arm_dpm *dpm) return retval; /* read R0 and R1 first (it's used for scratch), then CPSR */ - for (unsigned i = 0; i < 2; i++) { + for (unsigned int i = 0; i < 2; i++) { r = arm->core_cache->reg_list + i; if (!r->valid) { retval = arm_dpm_read_reg(dpm, r, i); @@ -406,7 +404,7 @@ int arm_dpm_read_current_registers(struct arm_dpm *dpm) arm_set_cpsr(arm, cpsr); /* REVISIT we can probably avoid reading R1..R14, saving time... */ - for (unsigned i = 2; i < 16; i++) { + for (unsigned int i = 2; i < 16; i++) { r = arm_reg_current(arm, i); if (r->valid) continue; @@ -424,7 +422,7 @@ int arm_dpm_read_current_registers(struct arm_dpm *dpm) */ fail: - /* (void) */ dpm->finish(dpm); + dpm->finish(dpm); return retval; } @@ -503,7 +501,7 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) * cope with the hand-crafted breakpoint code. */ if (arm->target->type->add_breakpoint == dpm_add_breakpoint) { - for (unsigned i = 0; i < dpm->nbp; i++) { + for (unsigned int i = 0; i < dpm->nbp; i++) { struct dpm_bp *dbp = dpm->dbp + i; struct breakpoint *bp = dbp->bp; @@ -515,7 +513,7 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) } /* enable/disable watchpoints */ - for (unsigned i = 0; i < dpm->nwp; i++) { + for (unsigned int i = 0; i < dpm->nwp; i++) { struct dpm_wp *dwp = dpm->dwp + i; struct watchpoint *wp = dwp->wp; @@ -540,9 +538,9 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) did_write = false; /* check everything except our scratch registers R0 and R1 */ - for (unsigned i = 2; i < cache->num_regs; i++) { + for (unsigned int i = 2; i < cache->num_regs; i++) { struct arm_reg *r; - unsigned regnum; + unsigned int regnum; /* also skip PC, CPSR, and non-dirty */ if (i == 15) @@ -627,14 +625,14 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) arm->pc->dirty = false; /* flush R0 and R1 (our scratch registers) */ - for (unsigned i = 0; i < 2; i++) { + for (unsigned int i = 0; i < 2; i++) { retval = dpm_write_reg(dpm, &cache->reg_list[i], i); if (retval != ERROR_OK) goto done; cache->reg_list[i].dirty = false; } - /* (void) */ dpm->finish(dpm); + dpm->finish(dpm); done: return retval; } @@ -645,7 +643,7 @@ done: * or MODE_ANY. */ static enum arm_mode dpm_mapmode(struct arm *arm, - unsigned num, enum arm_mode mode) + unsigned int num, enum arm_mode mode) { enum arm_mode amode = arm->core_mode; @@ -721,10 +719,10 @@ static int arm_dpm_read_core_reg(struct target *target, struct reg *r, /* always clean up, regardless of error */ if (mode != ARM_MODE_ANY) - /* (void) */ arm_dpm_modeswitch(dpm, ARM_MODE_ANY); + arm_dpm_modeswitch(dpm, ARM_MODE_ANY); fail: - /* (void) */ dpm->finish(dpm); + dpm->finish(dpm); return retval; } @@ -763,10 +761,10 @@ static int arm_dpm_write_core_reg(struct target *target, struct reg *r, /* always clean up, regardless of error */ if (mode != ARM_MODE_ANY) - /* (void) */ arm_dpm_modeswitch(dpm, ARM_MODE_ANY); + arm_dpm_modeswitch(dpm, ARM_MODE_ANY); fail: - /* (void) */ dpm->finish(dpm); + dpm->finish(dpm); return retval; } @@ -795,7 +793,7 @@ static int arm_dpm_full_context(struct target *target) * Pick some mode with unread registers and read them all. * Repeat until done. */ - for (unsigned i = 0; i < cache->num_regs; i++) { + for (unsigned int i = 0; i < cache->num_regs; i++) { struct arm_reg *r; if (!cache->reg_list[i].exist || cache->reg_list[i].valid) @@ -833,7 +831,7 @@ static int arm_dpm_full_context(struct target *target) } while (did_read); retval = arm_dpm_modeswitch(dpm, ARM_MODE_ANY); - /* (void) */ dpm->finish(dpm); + dpm->finish(dpm); done: return retval; } @@ -923,7 +921,7 @@ static int dpm_add_breakpoint(struct target *target, struct breakpoint *bp) if (bp->type == BKPT_SOFT) LOG_DEBUG("using HW bkpt, not SW..."); - for (unsigned i = 0; i < dpm->nbp; i++) { + for (unsigned int i = 0; i < dpm->nbp; i++) { if (!dpm->dbp[i].bp) { retval = dpm_bpwp_setup(dpm, &dpm->dbp[i].bpwp, bp->address, bp->length); @@ -942,7 +940,7 @@ static int dpm_remove_breakpoint(struct target *target, struct breakpoint *bp) struct arm_dpm *dpm = arm->dpm; int retval = ERROR_COMMAND_SYNTAX_ERROR; - for (unsigned i = 0; i < dpm->nbp; i++) { + for (unsigned int i = 0; i < dpm->nbp; i++) { if (dpm->dbp[i].bp == bp) { dpm->dbp[i].bp = NULL; dpm->dbp[i].bpwp.dirty = true; @@ -956,7 +954,7 @@ static int dpm_remove_breakpoint(struct target *target, struct breakpoint *bp) return retval; } -static int dpm_watchpoint_setup(struct arm_dpm *dpm, unsigned index_t, +static int dpm_watchpoint_setup(struct arm_dpm *dpm, unsigned int index_t, struct watchpoint *wp) { int retval; @@ -999,7 +997,7 @@ static int dpm_add_watchpoint(struct target *target, struct watchpoint *wp) int retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; if (dpm->bpwp_enable) { - for (unsigned i = 0; i < dpm->nwp; i++) { + for (unsigned int i = 0; i < dpm->nwp; i++) { if (!dpm->dwp[i].wp) { retval = dpm_watchpoint_setup(dpm, i, wp); break; @@ -1016,7 +1014,7 @@ static int dpm_remove_watchpoint(struct target *target, struct watchpoint *wp) struct arm_dpm *dpm = arm->dpm; int retval = ERROR_COMMAND_SYNTAX_ERROR; - for (unsigned i = 0; i < dpm->nwp; i++) { + for (unsigned int i = 0; i < dpm->nwp; i++) { if (dpm->dwp[i].wp == wp) { dpm->dwp[i].wp = NULL; dpm->dwp[i].bpwp.dirty = true; @@ -1163,7 +1161,7 @@ int arm_dpm_initialize(struct arm_dpm *dpm) { /* Disable all breakpoints and watchpoints at startup. */ if (dpm->bpwp_disable) { - unsigned i; + unsigned int i; for (i = 0; i < dpm->nbp; i++) { dpm->dbp[i].bpwp.number = i; diff --git a/src/target/arm_dpm.h b/src/target/arm_dpm.h index 2da4631..16c801e 100644 --- a/src/target/arm_dpm.h +++ b/src/target/arm_dpm.h @@ -19,7 +19,7 @@ */ struct dpm_bpwp { - unsigned number; + unsigned int number; uint32_t address; uint32_t control; /* true if hardware state needs flushing */ @@ -109,7 +109,7 @@ struct arm_dpm { uint32_t opcode, uint64_t *data); struct reg *(*arm_reg_current)(struct arm *arm, - unsigned regnum); + unsigned int regnum); /* BREAKPOINT/WATCHPOINT SUPPORT */ @@ -119,7 +119,7 @@ struct arm_dpm { * must currently be disabled. Indices 0..15 are used for * breakpoints; indices 16..31 are for watchpoints. */ - int (*bpwp_enable)(struct arm_dpm *dpm, unsigned index_value, + int (*bpwp_enable)(struct arm_dpm *dpm, unsigned int index_value, uint32_t addr, uint32_t control); /** @@ -127,15 +127,15 @@ struct arm_dpm { * hardware control registers. Indices are the same ones * accepted by bpwp_enable(). */ - int (*bpwp_disable)(struct arm_dpm *dpm, unsigned index_value); + int (*bpwp_disable)(struct arm_dpm *dpm, unsigned int index_value); /* The breakpoint and watchpoint arrays are private to the * DPM infrastructure. There are nbp indices in the dbp * array. There are nwp indices in the dwp array. */ - unsigned nbp; - unsigned nwp; + unsigned int nbp; + unsigned int nwp; struct dpm_bp *dbp; struct dpm_wp *dwp; @@ -158,7 +158,7 @@ struct arm_dpm { int arm_dpm_setup(struct arm_dpm *dpm); int arm_dpm_initialize(struct arm_dpm *dpm); -int arm_dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum); +int arm_dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned int regnum); int arm_dpm_read_current_registers(struct arm_dpm *dpm); int arm_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode); diff --git a/src/target/arm_jtag.c b/src/target/arm_jtag.c index c1ec473..e553ec8 100644 --- a/src/target/arm_jtag.c +++ b/src/target/arm_jtag.c @@ -19,7 +19,7 @@ #endif int arm_jtag_set_instr_inner(struct jtag_tap *tap, - uint32_t new_instr, void *no_verify_capture, tap_state_t end_state) + uint32_t new_instr, void *no_verify_capture, enum tap_state end_state) { struct scan_field field; uint8_t t[4] = { 0 }; @@ -41,7 +41,7 @@ int arm_jtag_set_instr_inner(struct jtag_tap *tap, return ERROR_OK; } -int arm_jtag_scann_inner(struct arm_jtag *jtag_info, uint32_t new_scan_chain, tap_state_t end_state) +int arm_jtag_scann_inner(struct arm_jtag *jtag_info, uint32_t new_scan_chain, enum tap_state end_state) { int retval = ERROR_OK; diff --git a/src/target/arm_jtag.h b/src/target/arm_jtag.h index 11b7c3e..5356bcf 100644 --- a/src/target/arm_jtag.h +++ b/src/target/arm_jtag.h @@ -26,10 +26,10 @@ struct arm_jtag { int arm_jtag_set_instr_inner(struct jtag_tap *tap, uint32_t new_instr, void *no_verify_capture, - tap_state_t end_state); + enum tap_state end_state); static inline int arm_jtag_set_instr(struct jtag_tap *tap, - uint32_t new_instr, void *no_verify_capture, tap_state_t end_state) + uint32_t new_instr, void *no_verify_capture, enum tap_state end_state) { /* inline most common code path */ if (buf_get_u32(tap->cur_instr, 0, tap->ir_length) != (new_instr & (BIT(tap->ir_length) - 1))) @@ -39,8 +39,8 @@ static inline int arm_jtag_set_instr(struct jtag_tap *tap, } -int arm_jtag_scann_inner(struct arm_jtag *jtag_info, uint32_t new_scan_chain, tap_state_t end_state); -static inline int arm_jtag_scann(struct arm_jtag *jtag_info, uint32_t new_scan_chain, tap_state_t end_state) +int arm_jtag_scann_inner(struct arm_jtag *jtag_info, uint32_t new_scan_chain, enum tap_state end_state); +static inline int arm_jtag_scann(struct arm_jtag *jtag_info, uint32_t new_scan_chain, enum tap_state end_state) { /* inline most common code path */ int retval = ERROR_OK; diff --git a/src/target/arm_semihosting.c b/src/target/arm_semihosting.c index b557589..a7c47bf 100644 --- a/src/target/arm_semihosting.c +++ b/src/target/arm_semihosting.c @@ -50,7 +50,7 @@ static int arm_semihosting_resume(struct target *target, int *retval) if (is_armv8(target_to_armv8(target))) { struct armv8_common *armv8 = target_to_armv8(target); if (armv8->last_run_control_op == ARMV8_RUNCONTROL_RESUME) { - *retval = target_resume(target, 1, 0, 0, 0); + *retval = target_resume(target, true, 0, false, false); if (*retval != ERROR_OK) { LOG_ERROR("Failed to resume target"); return 0; @@ -58,7 +58,7 @@ static int arm_semihosting_resume(struct target *target, int *retval) } else if (armv8->last_run_control_op == ARMV8_RUNCONTROL_STEP) target->debug_reason = DBG_REASON_SINGLESTEP; } else { - *retval = target_resume(target, 1, 0, 0, 0); + *retval = target_resume(target, true, 0, false, false); if (*retval != ERROR_OK) { LOG_ERROR("Failed to resume target"); return 0; diff --git a/src/target/arm_tpiu_swo.c b/src/target/arm_tpiu_swo.c index 55a9778..e20cd59 100644 --- a/src/target/arm_tpiu_swo.c +++ b/src/target/arm_tpiu_swo.c @@ -126,7 +126,7 @@ struct arm_tpiu_swo_priv_connection { struct arm_tpiu_swo_object *obj; }; -static LIST_HEAD(all_tpiu_swo); +static OOCD_LIST_HEAD(all_tpiu_swo); #define ARM_TPIU_SWO_TRACE_BUF_SIZE 4096 @@ -358,7 +358,7 @@ static int arm_tpiu_swo_configure(struct jim_getopt_info *goi, struct arm_tpiu_s { assert(obj); - if (goi->isconfigure && obj->enabled) { + if (goi->is_configure && obj->enabled) { Jim_SetResultFormatted(goi->interp, "Cannot configure TPIU/SWO; %s is enabled!", obj->name); return JIM_ERR; } @@ -382,7 +382,7 @@ static int arm_tpiu_swo_configure(struct jim_getopt_info *goi, struct arm_tpiu_s switch (n->value) { case CFG_PORT_WIDTH: - if (goi->isconfigure) { + if (goi->is_configure) { jim_wide port_width; e = jim_getopt_wide(goi, &port_width); if (e != JIM_OK) @@ -399,7 +399,7 @@ static int arm_tpiu_swo_configure(struct jim_getopt_info *goi, struct arm_tpiu_s } break; case CFG_PROTOCOL: - if (goi->isconfigure) { + if (goi->is_configure) { struct jim_nvp *p; e = jim_getopt_nvp(goi, nvp_arm_tpiu_swo_protocol_opts, &p); if (e != JIM_OK) @@ -418,7 +418,7 @@ static int arm_tpiu_swo_configure(struct jim_getopt_info *goi, struct arm_tpiu_s } break; case CFG_FORMATTER: - if (goi->isconfigure) { + if (goi->is_configure) { struct jim_nvp *p; e = jim_getopt_nvp(goi, nvp_arm_tpiu_swo_bool_opts, &p); if (e != JIM_OK) @@ -437,7 +437,7 @@ static int arm_tpiu_swo_configure(struct jim_getopt_info *goi, struct arm_tpiu_s } break; case CFG_TRACECLKIN: - if (goi->isconfigure) { + if (goi->is_configure) { jim_wide clk; e = jim_getopt_wide(goi, &clk); if (e != JIM_OK) @@ -450,7 +450,7 @@ static int arm_tpiu_swo_configure(struct jim_getopt_info *goi, struct arm_tpiu_s } break; case CFG_BITRATE: - if (goi->isconfigure) { + if (goi->is_configure) { jim_wide clk; e = jim_getopt_wide(goi, &clk); if (e != JIM_OK) @@ -463,7 +463,7 @@ static int arm_tpiu_swo_configure(struct jim_getopt_info *goi, struct arm_tpiu_s } break; case CFG_OUTFILE: - if (goi->isconfigure) { + if (goi->is_configure) { const char *s; e = jim_getopt_string(goi, &s, NULL); if (e != JIM_OK) @@ -491,7 +491,7 @@ static int arm_tpiu_swo_configure(struct jim_getopt_info *goi, struct arm_tpiu_s } break; case CFG_EVENT: - if (goi->isconfigure) { + if (goi->is_configure) { if (goi->argc < 2) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ?EVENT-BODY?"); return JIM_ERR; @@ -521,7 +521,7 @@ static int arm_tpiu_swo_configure(struct jim_getopt_info *goi, struct arm_tpiu_s ea = ea->next; } - if (goi->isconfigure) { + if (goi->is_configure) { if (!ea) { ea = calloc(1, sizeof(*ea)); if (!ea) { @@ -560,7 +560,7 @@ static int jim_arm_tpiu_swo_configure(Jim_Interp *interp, int argc, Jim_Obj * co struct jim_getopt_info goi; jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - goi.isconfigure = !strcmp(c->name, "configure"); + goi.is_configure = !strcmp(c->name, "configure"); if (goi.argc < 1) { Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, "missing: -option ..."); @@ -977,7 +977,7 @@ static int jim_arm_tpiu_swo_create(Jim_Interp *interp, int argc, Jim_Obj *const } /* Do the rest as "configure" options */ - goi.isconfigure = 1; + goi.is_configure = true; int e = arm_tpiu_swo_configure(&goi, obj); if (e != JIM_OK) goto err_exit; diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index 1886d5e..597dc89 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -168,9 +168,9 @@ static const struct { }; /** Map PSR mode bits to the name of an ARM processor operating mode. */ -const char *arm_mode_name(unsigned psr_mode) +const char *arm_mode_name(unsigned int psr_mode) { - for (unsigned i = 0; i < ARRAY_SIZE(arm_mode_data); i++) { + for (unsigned int i = 0; i < ARRAY_SIZE(arm_mode_data); i++) { if (arm_mode_data[i].psr == psr_mode) return arm_mode_data[i].name; } @@ -179,9 +179,9 @@ const char *arm_mode_name(unsigned psr_mode) } /** Return true iff the parameter denotes a valid ARM processor mode. */ -bool is_arm_mode(unsigned psr_mode) +bool is_arm_mode(unsigned int psr_mode) { - for (unsigned i = 0; i < ARRAY_SIZE(arm_mode_data); i++) { + for (unsigned int i = 0; i < ARRAY_SIZE(arm_mode_data); i++) { if (arm_mode_data[i].psr == psr_mode) return true; } @@ -248,7 +248,11 @@ enum arm_mode armv4_5_number_to_mode(int number) } static const char *arm_state_strings[] = { - "ARM", "Thumb", "Jazelle", "ThumbEE", + [ARM_STATE_ARM] = "ARM", + [ARM_STATE_THUMB] = "Thumb", + [ARM_STATE_JAZELLE] = "Jazelle", + [ARM_STATE_THUMB_EE] = "ThumbEE", + [ARM_STATE_AARCH64] = "AArch64", }; /* Templates for ARM core registers. @@ -272,8 +276,8 @@ static const struct { * CPSR -or- SPSR depending on whether 'mode' is MODE_ANY. * (Exception modes have both CPSR and SPSR registers ...) */ - unsigned cookie; - unsigned gdb_index; + unsigned int cookie; + unsigned int gdb_index; enum arm_mode mode; } arm_core_regs[] = { /* IMPORTANT: we guarantee that the first eight cached registers @@ -430,6 +434,16 @@ const int armv4_5_core_reg_map[9][17] = { } }; +static const char *arm_core_state_string(struct arm *arm) +{ + if (arm->core_state > ARRAY_SIZE(arm_state_strings)) { + LOG_ERROR("core_state exceeds table size"); + return "Unknown"; + } + + return arm_state_strings[arm->core_state]; +} + /** * Configures host-side ARM records to reflect the specified CPSR. * Later, code can use arm_reg_current() to map register numbers @@ -482,9 +496,9 @@ void arm_set_cpsr(struct arm *arm, uint32_t cpsr) } arm->core_state = state; - LOG_DEBUG("set CPSR %#8.8x: %s mode, %s state", (unsigned) cpsr, + LOG_DEBUG("set CPSR %#8.8" PRIx32 ": %s mode, %s state", cpsr, arm_mode_name(mode), - arm_state_strings[arm->core_state]); + arm_core_state_string(arm)); } /** @@ -499,7 +513,7 @@ void arm_set_cpsr(struct arm *arm, uint32_t cpsr) * However, R8..R14, and SPSR (arm->spsr) *must* be mapped. * CPSR (arm->cpsr) is also not mapped. */ -struct reg *arm_reg_current(struct arm *arm, unsigned regnum) +struct reg *arm_reg_current(struct arm *arm, unsigned int regnum) { struct reg *r; @@ -794,7 +808,7 @@ int arm_arch_state(struct target *target) LOG_USER("target halted in %s state due to %s, current mode: %s\n" "cpsr: 0x%8.8" PRIx32 " pc: 0x%8.8" PRIx32 "%s%s", - arm_state_strings[arm->core_state], + arm_core_state_string(arm), debug_reason_name(target), arm_mode_name(arm->core_mode), buf_get_u32(arm->cpsr->value, 0, 32), @@ -840,7 +854,7 @@ COMMAND_HANDLER(handle_armv4_5_reg_command) regs = arm->core_cache->reg_list; - for (unsigned mode = 0; mode < ARRAY_SIZE(arm_mode_data); mode++) { + for (unsigned int mode = 0; mode < ARRAY_SIZE(arm_mode_data); mode++) { const char *name; char *sep = "\n"; char *shadow = ""; @@ -875,11 +889,11 @@ COMMAND_HANDLER(handle_armv4_5_reg_command) sep, name, shadow); /* display N rows of up to 4 registers each */ - for (unsigned i = 0; i < arm_mode_data[mode].n_indices; ) { + for (unsigned int i = 0; i < arm_mode_data[mode].n_indices; ) { char output[80]; int output_len = 0; - for (unsigned j = 0; j < 4; j++, i++) { + for (unsigned int j = 0; j < 4; j++, i++) { uint32_t value; struct reg *reg = regs; @@ -929,7 +943,7 @@ COMMAND_HANDLER(handle_arm_core_state_command) arm->core_state = ARM_STATE_THUMB; } - command_print(CMD, "core state: %s", arm_state_strings[arm->core_state]); + command_print(CMD, "core state: %s", arm_core_state_string(arm)); return ret; } @@ -1287,11 +1301,11 @@ int arm_get_gdb_reg_list(struct target *target, *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < 16; i++) - (*reg_list)[i] = arm_reg_current(arm, i); + (*reg_list)[i] = arm_reg_current(arm, i); /* For GDB compatibility, take FPA registers size into account and zero-fill it*/ for (i = 16; i < 24; i++) - (*reg_list)[i] = &arm_gdb_dummy_fp_reg; + (*reg_list)[i] = &arm_gdb_dummy_fp_reg; (*reg_list)[24] = &arm_gdb_dummy_fps_reg; (*reg_list)[25] = arm->cpsr; @@ -1316,25 +1330,25 @@ int arm_get_gdb_reg_list(struct target *target, *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < 16; i++) - (*reg_list)[i] = arm_reg_current(arm, i); + (*reg_list)[i] = arm_reg_current(arm, i); for (i = 13; i < ARRAY_SIZE(arm_core_regs); i++) { - int reg_index = arm->core_cache->reg_list[i].number; + int reg_index = arm->core_cache->reg_list[i].number; - if (arm_core_regs[i].mode == ARM_MODE_MON + if (arm_core_regs[i].mode == ARM_MODE_MON && arm->core_type != ARM_CORE_TYPE_SEC_EXT && arm->core_type != ARM_CORE_TYPE_VIRT_EXT) - continue; - if (arm_core_regs[i].mode == ARM_MODE_HYP + continue; + if (arm_core_regs[i].mode == ARM_MODE_HYP && arm->core_type != ARM_CORE_TYPE_VIRT_EXT) - continue; - (*reg_list)[reg_index] = &(arm->core_cache->reg_list[i]); + continue; + (*reg_list)[reg_index] = &arm->core_cache->reg_list[i]; } /* When we supply the target description, there is no need for fake FPA */ for (i = 16; i < 24; i++) { - (*reg_list)[i] = &arm_gdb_dummy_fp_reg; - (*reg_list)[i]->size = 0; + (*reg_list)[i] = &arm_gdb_dummy_fp_reg; + (*reg_list)[i]->size = 0; } (*reg_list)[24] = &arm_gdb_dummy_fps_reg; (*reg_list)[24]->size = 0; @@ -1500,7 +1514,7 @@ int armv4_5_run_algorithm_inner(struct target *target, } } - retval = target_resume(target, 0, entry_point, 1, 1); + retval = target_resume(target, false, entry_point, true, true); if (retval != ERROR_OK) return retval; retval = run_it(target, exit_point, timeout_ms, arch_info); @@ -1750,7 +1764,7 @@ cleanup: static int arm_full_context(struct target *target) { struct arm *arm = target_to_arm(target); - unsigned num_regs = arm->core_cache->num_regs; + unsigned int num_regs = arm->core_cache->num_regs; struct reg *reg = arm->core_cache->reg_list; int retval = ERROR_OK; diff --git a/src/target/armv7a.c b/src/target/armv7a.c index dc3752e..c14155e 100644 --- a/src/target/armv7a.c +++ b/src/target/armv7a.c @@ -74,7 +74,7 @@ static void armv7a_show_fault_registers(struct target *target) ", IFAR: %8.8" PRIx32, ifsr, ifar); done: - /* (void) */ dpm->finish(dpm); + dpm->finish(dpm); } @@ -101,14 +101,14 @@ static int armv7a_read_midr(struct target *target) armv7a->arch = (midr >> 16) & 0xf; armv7a->variant = (midr >> 20) & 0xf; armv7a->implementor = (midr >> 24) & 0xff; - LOG_DEBUG("%s rev %" PRIx32 ", partnum %" PRIx32 ", arch %" PRIx32 - ", variant %" PRIx32 ", implementor %" PRIx32, - target->cmd_name, - armv7a->rev, - armv7a->partnum, - armv7a->arch, - armv7a->variant, - armv7a->implementor); + LOG_TARGET_DEBUG(target, + "rev %" PRIx32 ", partnum %" PRIx32 ", arch %" PRIx32 + ", variant %" PRIx32 ", implementor %" PRIx32, + armv7a->rev, + armv7a->partnum, + armv7a->arch, + armv7a->variant, + armv7a->implementor); done: dpm->finish(dpm); diff --git a/src/target/armv7a_cache_l2x.h b/src/target/armv7a_cache_l2x.h index d5f1a6f..ea726ec 100644 --- a/src/target/armv7a_cache_l2x.h +++ b/src/target/armv7a_cache_l2x.h @@ -122,16 +122,16 @@ struct outer_cache_fns { void (*resume)(void); /* This is an ARM L2C thing */ - void (*write_sec)(unsigned long, unsigned); + void (*write_sec)(unsigned long, unsigned int); void (*configure)(const struct l2x0_regs *); }; struct l2c_init_data { const char *type; - unsigned way_size_0; - unsigned num_lock; + unsigned int way_size_0; + unsigned int num_lock; - void (*enable)(uint32_t, uint32_t, unsigned); + void (*enable)(uint32_t, uint32_t, unsigned int); void (*fixup)(uint32_t, uint32_t, struct outer_cache_fns *); void (*save)(uint32_t); void (*configure)(uint32_t); diff --git a/src/target/armv7a_mmu.c b/src/target/armv7a_mmu.c index c4d294e..43b5dae 100644 --- a/src/target/armv7a_mmu.c +++ b/src/target/armv7a_mmu.c @@ -260,8 +260,7 @@ COMMAND_HANDLER(armv7a_mmu_dump_table) /* skip empty entries in the first level table */ if ((first_lvl_descriptor & 3) == 0) { pt_idx++; - } else - if ((first_lvl_descriptor & 0x40002) == 2) { + } else if ((first_lvl_descriptor & 0x40002) == 2) { /* section descriptor */ uint32_t va_range = 1024*1024-1; /* 1MB range */ uint32_t va_start = pt_idx << 20; @@ -273,8 +272,7 @@ COMMAND_HANDLER(armv7a_mmu_dump_table) LOG_USER("SECT: VA[%8.8"PRIx32" -- %8.8"PRIx32"]: PA[%8.8"PRIx32" -- %8.8"PRIx32"] %s", va_start, va_end, pa_start, pa_end, l1_desc_bits_to_string(first_lvl_descriptor, afe)); pt_idx++; - } else - if ((first_lvl_descriptor & 0x40002) == 0x40002) { + } else if ((first_lvl_descriptor & 0x40002) == 0x40002) { /* supersection descriptor */ uint32_t va_range = 16*1024*1024-1; /* 16MB range */ uint32_t va_start = pt_idx << 20; @@ -310,8 +308,7 @@ COMMAND_HANDLER(armv7a_mmu_dump_table) if ((second_lvl_descriptor & 3) == 0) { /* skip entry */ pt2_idx++; - } else - if ((second_lvl_descriptor & 3) == 1) { + } else if ((second_lvl_descriptor & 3) == 1) { /* large page */ uint32_t va_range = 64*1024-1; /* 64KB range */ uint32_t va_start = (pt_idx << 20) + (pt2_idx << 12); diff --git a/src/target/armv7m.c b/src/target/armv7m.c index d508af7..dc2d84f 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -65,6 +65,28 @@ const int armv7m_msp_reg_map[ARMV7M_NUM_CORE_REGS] = { ARMV7M_XPSR, }; +static struct reg_data_type_bitfield armv8m_vpr_bits[] = { + { 0, 15, REG_TYPE_UINT }, + { 16, 19, REG_TYPE_UINT }, + { 20, 23, REG_TYPE_UINT }, +}; + +static struct reg_data_type_flags_field armv8m_vpr_fields[] = { + { "P0", armv8m_vpr_bits + 0, armv8m_vpr_fields + 1, }, + { "MASK01", armv8m_vpr_bits + 1, armv8m_vpr_fields + 2, }, + { "MASK23", armv8m_vpr_bits + 2, NULL }, +}; + +static struct reg_data_type_flags armv8m_vpr_flags[] = { + { 4, armv8m_vpr_fields }, +}; + +static struct reg_data_type armv8m_flags_vpr[] = { + { REG_TYPE_ARCH_DEFINED, "vpr_reg", REG_TYPE_CLASS_FLAGS, + { .reg_type_flags = armv8m_vpr_flags }, + }, +}; + /* * These registers are not memory-mapped. The ARMv7-M profile includes * memory mapped registers too, such as for the NVIC (interrupt controller) @@ -74,36 +96,37 @@ const int armv7m_msp_reg_map[ARMV7M_NUM_CORE_REGS] = { * doesn't include basepri or faultmask registers. */ static const struct { - unsigned id; + unsigned int id; const char *name; - unsigned bits; + unsigned int bits; enum reg_type type; const char *group; const char *feature; + struct reg_data_type *data_type; } armv7m_regs[] = { - { ARMV7M_R0, "r0", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, - { ARMV7M_R1, "r1", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, - { ARMV7M_R2, "r2", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, - { ARMV7M_R3, "r3", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, - { ARMV7M_R4, "r4", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, - { ARMV7M_R5, "r5", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, - { ARMV7M_R6, "r6", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, - { ARMV7M_R7, "r7", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, - { ARMV7M_R8, "r8", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, - { ARMV7M_R9, "r9", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, - { ARMV7M_R10, "r10", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, - { ARMV7M_R11, "r11", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, - { ARMV7M_R12, "r12", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, - { ARMV7M_R13, "sp", 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.arm.m-profile" }, - { ARMV7M_R14, "lr", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, - { ARMV7M_PC, "pc", 32, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.m-profile" }, - { ARMV7M_XPSR, "xpsr", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile" }, - - { ARMV7M_MSP, "msp", 32, REG_TYPE_DATA_PTR, "system", "org.gnu.gdb.arm.m-system" }, - { ARMV7M_PSP, "psp", 32, REG_TYPE_DATA_PTR, "system", "org.gnu.gdb.arm.m-system" }, + { ARMV7M_R0, "r0", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, }, + { ARMV7M_R1, "r1", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, }, + { ARMV7M_R2, "r2", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, }, + { ARMV7M_R3, "r3", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, }, + { ARMV7M_R4, "r4", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, }, + { ARMV7M_R5, "r5", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, }, + { ARMV7M_R6, "r6", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, }, + { ARMV7M_R7, "r7", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, }, + { ARMV7M_R8, "r8", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, }, + { ARMV7M_R9, "r9", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, }, + { ARMV7M_R10, "r10", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, }, + { ARMV7M_R11, "r11", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, }, + { ARMV7M_R12, "r12", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, }, + { ARMV7M_R13, "sp", 32, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.arm.m-profile", NULL, }, + { ARMV7M_R14, "lr", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, }, + { ARMV7M_PC, "pc", 32, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.m-profile", NULL, }, + { ARMV7M_XPSR, "xpsr", 32, REG_TYPE_INT, "general", "org.gnu.gdb.arm.m-profile", NULL, }, + + { ARMV7M_MSP, "msp", 32, REG_TYPE_DATA_PTR, "system", "org.gnu.gdb.arm.m-system", NULL, }, + { ARMV7M_PSP, "psp", 32, REG_TYPE_DATA_PTR, "system", "org.gnu.gdb.arm.m-system", NULL, }, /* A working register for packing/unpacking special regs, hidden from gdb */ - { ARMV7M_PMSK_BPRI_FLTMSK_CTRL, "pmsk_bpri_fltmsk_ctrl", 32, REG_TYPE_INT, NULL, NULL }, + { ARMV7M_PMSK_BPRI_FLTMSK_CTRL, "pmsk_bpri_fltmsk_ctrl", 32, REG_TYPE_INT, NULL, NULL, NULL }, /* WARNING: If you use armv7m_write_core_reg() on one of 4 following * special registers, the new data go to ARMV7M_PMSK_BPRI_FLTMSK_CTRL @@ -111,52 +134,54 @@ static const struct { * To trigger write to CPU HW register, add * armv7m_write_core_reg(,,ARMV7M_PMSK_BPRI_FLTMSK_CTRL,); */ - { ARMV7M_PRIMASK, "primask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, - { ARMV7M_BASEPRI, "basepri", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, - { ARMV7M_FAULTMASK, "faultmask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, - { ARMV7M_CONTROL, "control", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system" }, + { ARMV7M_PRIMASK, "primask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system", NULL, }, + { ARMV7M_BASEPRI, "basepri", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system", NULL, }, + { ARMV7M_FAULTMASK, "faultmask", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system", NULL, }, + { ARMV7M_CONTROL, "control", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.m-system", NULL, }, /* ARMv8-M security extension (TrustZone) specific registers */ - { ARMV8M_MSP_NS, "msp_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, - { ARMV8M_PSP_NS, "psp_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, - { ARMV8M_MSP_S, "msp_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, - { ARMV8M_PSP_S, "psp_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, - { ARMV8M_MSPLIM_S, "msplim_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, - { ARMV8M_PSPLIM_S, "psplim_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, - { ARMV8M_MSPLIM_NS, "msplim_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, - { ARMV8M_PSPLIM_NS, "psplim_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext" }, - - { ARMV8M_PMSK_BPRI_FLTMSK_CTRL_S, "pmsk_bpri_fltmsk_ctrl_s", 32, REG_TYPE_INT, NULL, NULL }, - { ARMV8M_PRIMASK_S, "primask_s", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, - { ARMV8M_BASEPRI_S, "basepri_s", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, - { ARMV8M_FAULTMASK_S, "faultmask_s", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, - { ARMV8M_CONTROL_S, "control_s", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, - - { ARMV8M_PMSK_BPRI_FLTMSK_CTRL_NS, "pmsk_bpri_fltmsk_ctrl_ns", 32, REG_TYPE_INT, NULL, NULL }, - { ARMV8M_PRIMASK_NS, "primask_ns", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, - { ARMV8M_BASEPRI_NS, "basepri_ns", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, - { ARMV8M_FAULTMASK_NS, "faultmask_ns", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, - { ARMV8M_CONTROL_NS, "control_ns", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext" }, + { ARMV8M_MSP_NS, "msp_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext", NULL, }, + { ARMV8M_PSP_NS, "psp_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext", NULL, }, + { ARMV8M_MSP_S, "msp_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext", NULL, }, + { ARMV8M_PSP_S, "psp_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext", NULL, }, + { ARMV8M_MSPLIM_S, "msplim_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext", NULL, }, + { ARMV8M_PSPLIM_S, "psplim_s", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext", NULL, }, + { ARMV8M_MSPLIM_NS, "msplim_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext", NULL, }, + { ARMV8M_PSPLIM_NS, "psplim_ns", 32, REG_TYPE_DATA_PTR, "stack", "org.gnu.gdb.arm.secext", NULL, }, + + { ARMV8M_PMSK_BPRI_FLTMSK_CTRL_S, "pmsk_bpri_fltmsk_ctrl_s", 32, REG_TYPE_INT, NULL, NULL, NULL, }, + { ARMV8M_PRIMASK_S, "primask_s", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext", NULL, }, + { ARMV8M_BASEPRI_S, "basepri_s", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext", NULL, }, + { ARMV8M_FAULTMASK_S, "faultmask_s", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext", NULL, }, + { ARMV8M_CONTROL_S, "control_s", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext", NULL, }, + + { ARMV8M_PMSK_BPRI_FLTMSK_CTRL_NS, "pmsk_bpri_fltmsk_ctrl_ns", 32, REG_TYPE_INT, NULL, NULL, NULL, }, + { ARMV8M_PRIMASK_NS, "primask_ns", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext", NULL, }, + { ARMV8M_BASEPRI_NS, "basepri_ns", 8, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext", NULL, }, + { ARMV8M_FAULTMASK_NS, "faultmask_ns", 1, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext", NULL, }, + { ARMV8M_CONTROL_NS, "control_ns", 3, REG_TYPE_INT8, "system", "org.gnu.gdb.arm.secext", NULL, }, /* FPU registers */ - { ARMV7M_D0, "d0", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, - { ARMV7M_D1, "d1", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, - { ARMV7M_D2, "d2", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, - { ARMV7M_D3, "d3", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, - { ARMV7M_D4, "d4", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, - { ARMV7M_D5, "d5", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, - { ARMV7M_D6, "d6", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, - { ARMV7M_D7, "d7", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, - { ARMV7M_D8, "d8", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, - { ARMV7M_D9, "d9", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, - { ARMV7M_D10, "d10", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, - { ARMV7M_D11, "d11", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, - { ARMV7M_D12, "d12", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, - { ARMV7M_D13, "d13", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, - { ARMV7M_D14, "d14", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, - { ARMV7M_D15, "d15", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp" }, - - { ARMV7M_FPSCR, "fpscr", 32, REG_TYPE_INT, "float", "org.gnu.gdb.arm.vfp" }, + { ARMV7M_D0, "d0", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, }, + { ARMV7M_D1, "d1", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, }, + { ARMV7M_D2, "d2", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, }, + { ARMV7M_D3, "d3", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, }, + { ARMV7M_D4, "d4", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, }, + { ARMV7M_D5, "d5", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, }, + { ARMV7M_D6, "d6", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, }, + { ARMV7M_D7, "d7", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, }, + { ARMV7M_D8, "d8", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, }, + { ARMV7M_D9, "d9", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, }, + { ARMV7M_D10, "d10", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, }, + { ARMV7M_D11, "d11", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, }, + { ARMV7M_D12, "d12", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, }, + { ARMV7M_D13, "d13", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, }, + { ARMV7M_D14, "d14", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, }, + { ARMV7M_D15, "d15", 64, REG_TYPE_IEEE_DOUBLE, "float", "org.gnu.gdb.arm.vfp", NULL, }, + + { ARMV7M_FPSCR, "fpscr", 32, REG_TYPE_INT, "float", "org.gnu.gdb.arm.vfp", NULL, }, + + { ARMV8M_VPR, "vpr", 32, REG_TYPE_INT, "float", "org.gnu.gdb.arm.m-profile-mve", armv8m_flags_vpr, }, }; #define ARMV7M_NUM_REGS ARRAY_SIZE(armv7m_regs) @@ -171,7 +196,7 @@ int armv7m_restore_context(struct target *target) struct armv7m_common *armv7m = target_to_armv7m(target); struct reg_cache *cache = armv7m->arm.core_cache; - LOG_DEBUG(" "); + LOG_TARGET_DEBUG(target, " "); if (armv7m->pre_restore_context) armv7m->pre_restore_context(target); @@ -272,6 +297,9 @@ uint32_t armv7m_map_id_to_regsel(unsigned int arm_reg_id) case ARMV7M_FPSCR: return ARMV7M_REGSEL_FPSCR; + case ARMV8M_VPR: + return ARMV8M_REGSEL_VPR; + case ARMV7M_D0 ... ARMV7M_D15: return ARMV7M_REGSEL_S0 + 2 * (arm_reg_id - ARMV7M_D0); @@ -366,9 +394,9 @@ static int armv7m_read_core_reg(struct target *target, struct reg *r, buf_set_u32(r->value + 4, 0, 32, reg_value); uint64_t q = buf_get_u64(r->value, 0, 64); - LOG_DEBUG("read %s value 0x%016" PRIx64, r->name, q); + LOG_TARGET_DEBUG(target, "read %s value 0x%016" PRIx64, r->name, q); } else { - LOG_DEBUG("read %s value 0x%08" PRIx32, r->name, reg_value); + LOG_TARGET_DEBUG(target, "read %s value 0x%08" PRIx32, r->name, reg_value); } } @@ -436,9 +464,9 @@ static int armv7m_write_core_reg(struct target *target, struct reg *r, goto out_error; uint64_t q = buf_get_u64(value, 0, 64); - LOG_DEBUG("write %s value 0x%016" PRIx64, r->name, q); + LOG_TARGET_DEBUG(target, "write %s value 0x%016" PRIx64, r->name, q); } else { - LOG_DEBUG("write %s value 0x%08" PRIx32, r->name, t); + LOG_TARGET_DEBUG(target, "write %s value 0x%08" PRIx32, r->name, t); } } @@ -449,7 +477,7 @@ static int armv7m_write_core_reg(struct target *target, struct reg *r, out_error: r->dirty = true; - LOG_ERROR("Error setting register %s", r->name); + LOG_TARGET_ERROR(target, "Error setting register %s", r->name); return retval; } @@ -520,7 +548,7 @@ int armv7m_start_algorithm(struct target *target, * at the exit point */ if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) { - LOG_ERROR("current target isn't an ARMV7M target"); + LOG_TARGET_ERROR(target, "current target isn't an ARMV7M target"); return ERROR_TARGET_INVALID; } @@ -530,7 +558,7 @@ int armv7m_start_algorithm(struct target *target, } /* Store all non-debug execution registers to armv7m_algorithm_info context */ - for (unsigned i = 0; i < armv7m->arm.core_cache->num_regs; i++) { + for (unsigned int i = 0; i < armv7m->arm.core_cache->num_regs; i++) { struct reg *reg = &armv7m->arm.core_cache->reg_list[i]; if (!reg->exist) continue; @@ -563,12 +591,12 @@ int armv7m_start_algorithm(struct target *target, /* uint32_t regvalue; */ if (!reg) { - LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); + LOG_TARGET_ERROR(target, "BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } if (reg->size != reg_params[i].size) { - LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", + LOG_TARGET_ERROR(target, "BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -600,10 +628,11 @@ int armv7m_start_algorithm(struct target *target, /* we cannot set ARM_MODE_HANDLER, so use ARM_MODE_THREAD instead */ if (armv7m_algorithm_info->core_mode == ARM_MODE_HANDLER) { armv7m_algorithm_info->core_mode = ARM_MODE_THREAD; - LOG_INFO("ARM_MODE_HANDLER not currently supported, using ARM_MODE_THREAD instead"); + LOG_TARGET_INFO(target, "ARM_MODE_HANDLER not currently supported, using ARM_MODE_THREAD instead"); } - LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode); + LOG_TARGET_DEBUG(target, "setting core_mode: 0x%2.2x", + armv7m_algorithm_info->core_mode); buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value, 0, 1, armv7m_algorithm_info->core_mode); armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = true; @@ -613,7 +642,7 @@ int armv7m_start_algorithm(struct target *target, /* save previous core mode */ armv7m_algorithm_info->core_mode = core_mode; - retval = target_resume(target, 0, entry_point, 1, 1); + retval = target_resume(target, false, entry_point, true, true); return retval; } @@ -633,7 +662,7 @@ int armv7m_wait_algorithm(struct target *target, * at the exit point */ if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) { - LOG_ERROR("current target isn't an ARMV7M target"); + LOG_TARGET_ERROR(target, "current target isn't an ARMV7M target"); return ERROR_TARGET_INVALID; } @@ -653,7 +682,7 @@ int armv7m_wait_algorithm(struct target *target, /* PC value has been cached in cortex_m_debug_entry() */ uint32_t pc = buf_get_u32(armv7m->arm.pc->value, 0, 32); if (pc != exit_point) { - LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 ", expected 0x%" TARGET_PRIxADDR, + LOG_TARGET_DEBUG(target, "failed algorithm halted at 0x%" PRIx32 ", expected 0x%" TARGET_PRIxADDR, pc, exit_point); return ERROR_TARGET_ALGO_EXIT; } @@ -678,12 +707,13 @@ int armv7m_wait_algorithm(struct target *target, false); if (!reg) { - LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); + LOG_TARGET_ERROR(target, "BUG: register '%s' not found", + reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } if (reg->size != reg_params[i].size) { - LOG_ERROR( + LOG_TARGET_ERROR(target, "BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; @@ -701,7 +731,7 @@ int armv7m_wait_algorithm(struct target *target, uint32_t regvalue; regvalue = buf_get_u32(reg->value, 0, 32); if (regvalue != armv7m_algorithm_info->context[i]) { - LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32, + LOG_TARGET_DEBUG(target, "restoring register %s with value 0x%8.8" PRIx32, reg->name, armv7m_algorithm_info->context[i]); buf_set_u32(reg->value, 0, 32, armv7m_algorithm_info->context[i]); @@ -712,7 +742,7 @@ int armv7m_wait_algorithm(struct target *target, /* restore previous core mode */ if (armv7m_algorithm_info->core_mode != armv7m->arm.core_mode) { - LOG_DEBUG("restoring core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode); + LOG_TARGET_DEBUG(target, "restoring core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode); buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value, 0, 1, armv7m_algorithm_info->core_mode); armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = true; @@ -738,9 +768,8 @@ int armv7m_arch_state(struct target *target) ctrl = buf_get_u32(arm->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 32); sp = buf_get_u32(arm->core_cache->reg_list[ARMV7M_R13].value, 0, 32); - LOG_USER("[%s] halted due to %s, current mode: %s %s\n" + LOG_TARGET_USER(target, "halted due to %s, current mode: %s %s\n" "xPSR: %#8.8" PRIx32 " pc: %#8.8" PRIx32 " %csp: %#8.8" PRIx32 "%s%s", - target_name(target), debug_reason_name(target), arm_mode_name(arm->core_mode), armv7m_exception_string(armv7m->exception_number), @@ -807,13 +836,17 @@ struct reg_cache *armv7m_build_reg_cache(struct target *target) feature->name = armv7m_regs[i].feature; reg_list[i].feature = feature; } else - LOG_ERROR("unable to allocate feature list"); + LOG_TARGET_ERROR(target, "unable to allocate feature list"); reg_list[i].reg_data_type = calloc(1, sizeof(struct reg_data_type)); - if (reg_list[i].reg_data_type) - reg_list[i].reg_data_type->type = armv7m_regs[i].type; - else - LOG_ERROR("unable to allocate reg type list"); + if (reg_list[i].reg_data_type) { + if (armv7m_regs[i].data_type) + *reg_list[i].reg_data_type = *armv7m_regs[i].data_type; + else + reg_list[i].reg_data_type->type = armv7m_regs[i].type; + } else { + LOG_TARGET_ERROR(target, "unable to allocate reg type list"); + } } arm->cpsr = reg_list + ARMV7M_XPSR; @@ -918,7 +951,7 @@ int armv7m_checksum_memory(struct target *target, if (retval == ERROR_OK) *checksum = buf_get_u32(reg_params[0].value, 0, 32); else - LOG_ERROR("error executing cortex_m crc algorithm"); + LOG_TARGET_ERROR(target, "error executing cortex_m crc algorithm"); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); @@ -1003,7 +1036,7 @@ int armv7m_blank_check_memory(struct target *target, uint32_t erased_word = erased_value | (erased_value << 8) | (erased_value << 16) | (erased_value << 24); - LOG_DEBUG("Starting erase check of %d blocks, parameters@" + LOG_TARGET_DEBUG(target, "Starting erase check of %d blocks, parameters@" TARGET_ADDR_FMT, blocks_to_check, erase_check_params->address); armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; @@ -1044,7 +1077,8 @@ int armv7m_blank_check_memory(struct target *target, blocks[i].result = result; } if (i && timed_out) - LOG_INFO("Slow CPU clock: %d blocks checked, %d remain. Continuing...", i, num_blocks-i); + LOG_TARGET_INFO(target, "Slow CPU clock: %d blocks checked, %d remain. Continuing...", + i, num_blocks - i); retval = i; /* return number of blocks really checked */ @@ -1085,7 +1119,7 @@ int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found) r->dirty = true; r->valid = true; result = true; - LOG_DEBUG("Skipping over BKPT instruction"); + LOG_TARGET_DEBUG(target, "Skipping over BKPT instruction"); } } } diff --git a/src/target/armv7m.h b/src/target/armv7m.h index 2878dd1..86c45f7 100644 --- a/src/target/armv7m.h +++ b/src/target/armv7m.h @@ -62,6 +62,7 @@ enum { ARMV7M_REGSEL_PMSK_BPRI_FLTMSK_CTRL = 0x14, ARMV8M_REGSEL_PMSK_BPRI_FLTMSK_CTRL_S = 0x22, ARMV8M_REGSEL_PMSK_BPRI_FLTMSK_CTRL_NS = 0x23, + ARMV8M_REGSEL_VPR = 0x24, ARMV7M_REGSEL_FPSCR = 0x21, /* 32bit Floating-point registers */ @@ -196,12 +197,15 @@ enum { /* Floating-point status register */ ARMV7M_FPSCR, + /* Vector Predication Status and Control Register */ + ARMV8M_VPR, + /* for convenience add registers' block delimiters */ ARMV7M_LAST_REG, ARMV7M_CORE_FIRST_REG = ARMV7M_R0, ARMV7M_CORE_LAST_REG = ARMV7M_XPSR, ARMV7M_FPU_FIRST_REG = ARMV7M_D0, - ARMV7M_FPU_LAST_REG = ARMV7M_FPSCR, + ARMV7M_FPU_LAST_REG = ARMV8M_VPR, ARMV8M_FIRST_REG = ARMV8M_MSP_NS, ARMV8M_LAST_REG = ARMV8M_CONTROL_NS, }; diff --git a/src/target/armv8.c b/src/target/armv8.c index b54ef13..4039073 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -36,7 +36,7 @@ static const char * const armv8_state_strings[] = { static const struct { const char *name; - unsigned psr; + unsigned int psr; } armv8_mode_data[] = { { .name = "USR", @@ -105,9 +105,9 @@ static const struct { }; /** Map PSR mode bits to the name of an ARM processor operating mode. */ -const char *armv8_mode_name(unsigned psr_mode) +const char *armv8_mode_name(unsigned int psr_mode) { - for (unsigned i = 0; i < ARRAY_SIZE(armv8_mode_data); i++) { + for (unsigned int i = 0; i < ARRAY_SIZE(armv8_mode_data); i++) { if (armv8_mode_data[i].psr == psr_mode) return armv8_mode_data[i].name; } @@ -683,7 +683,7 @@ static int armv8_read_reg_simdfp_aarch32(struct armv8_common *armv8, int regnum, struct arm_dpm *dpm = &armv8->dpm; struct reg *reg_r1 = dpm->arm->core_cache->reg_list + ARMV8_R1; uint32_t value_r0 = 0, value_r1 = 0; - unsigned num = (regnum - ARMV8_V0) << 1; + unsigned int num = (regnum - ARMV8_V0) << 1; switch (regnum) { case ARMV8_V0 ... ARMV8_V15: @@ -817,7 +817,7 @@ static int armv8_write_reg_simdfp_aarch32(struct armv8_common *armv8, int regnum struct arm_dpm *dpm = &armv8->dpm; struct reg *reg_r1 = dpm->arm->core_cache->reg_list + ARMV8_R1; uint32_t value_r0 = 0, value_r1 = 0; - unsigned num = (regnum - ARMV8_V0) << 1; + unsigned int num = (regnum - ARMV8_V0) << 1; switch (regnum) { case ARMV8_V0 ... ARMV8_V15: @@ -961,7 +961,7 @@ void armv8_set_cpsr(struct arm *arm, uint32_t cpsr) arm->core_state = state; arm->core_mode = mode; - LOG_DEBUG("set CPSR %#8.8x: %s mode, %s state", (unsigned) cpsr, + LOG_DEBUG("set CPSR %#8.8" PRIx32 ": %s mode, %s state", cpsr, armv8_mode_name(arm->core_mode), armv8_state_strings[arm->core_state]); } @@ -1010,7 +1010,7 @@ static void armv8_show_fault_registers32(struct armv8_common *armv8) ", IFAR: %8.8" PRIx32, ifsr, ifar); done: - /* (void) */ dpm->finish(dpm); + dpm->finish(dpm); } static __attribute__((unused)) void armv8_show_fault_registers(struct target *target) @@ -1021,12 +1021,6 @@ static __attribute__((unused)) void armv8_show_fault_registers(struct target *ta armv8_show_fault_registers32(armv8); } -/* method adapted to cortex A : reused arm v4 v5 method*/ -int armv8_mmu_translate_va(struct target *target, target_addr_t va, target_addr_t *val) -{ - return ERROR_OK; -} - static void armv8_decode_cacheability(int attr) { if (attr == 0) { @@ -1506,9 +1500,9 @@ static struct reg_data_type aarch64_flags_cpsr[] = { }; static const struct { - unsigned id; + unsigned int id; const char *name; - unsigned bits; + unsigned int bits; enum arm_mode mode; enum reg_type type; const char *group; @@ -1611,10 +1605,10 @@ static const struct { }; static const struct { - unsigned id; - unsigned mapping; + unsigned int id; + unsigned int mapping; const char *name; - unsigned bits; + unsigned int bits; enum arm_mode mode; enum reg_type type; const char *group; @@ -1692,12 +1686,12 @@ static int armv8_set_core_reg(struct reg *reg, uint8_t *buf) struct arm_reg *armv8_reg = reg->arch_info; struct target *target = armv8_reg->target; struct arm *arm = target_to_arm(target); - uint64_t value = buf_get_u64(buf, 0, reg->size); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; if (reg->size <= 64) { + uint64_t value = buf_get_u64(buf, 0, reg->size); if (reg == arm->cpsr) armv8_set_cpsr(arm, (uint32_t)value); else { @@ -1705,6 +1699,7 @@ static int armv8_set_core_reg(struct reg *reg, uint8_t *buf) reg->valid = true; } } else if (reg->size <= 128) { + uint64_t value = buf_get_u64(buf, 0, 64); uint64_t hvalue = buf_get_u64(buf + 8, 0, reg->size - 64); buf_set_u64(reg->value, 0, 64, value); @@ -1881,7 +1876,7 @@ struct reg_cache *armv8_build_reg_cache(struct target *target) return cache; } -struct reg *armv8_reg_current(struct arm *arm, unsigned regnum) +struct reg *armv8_reg_current(struct arm *arm, unsigned int regnum) { struct reg *r; @@ -1972,7 +1967,7 @@ int armv8_get_gdb_reg_list(struct target *target, *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < *reg_list_size; i++) - (*reg_list)[i] = armv8_reg_current(arm, i); + (*reg_list)[i] = armv8_reg_current(arm, i); return ERROR_OK; case REG_CLASS_ALL: @@ -1980,7 +1975,7 @@ int armv8_get_gdb_reg_list(struct target *target, *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < *reg_list_size; i++) - (*reg_list)[i] = armv8_reg_current(arm, i); + (*reg_list)[i] = armv8_reg_current(arm, i); return ERROR_OK; diff --git a/src/target/armv8.h b/src/target/armv8.h index f5aa211..dba12f9 100644 --- a/src/target/armv8.h +++ b/src/target/armv8.h @@ -162,6 +162,7 @@ struct armv8_cache_common { /* l2 external unified cache if some */ void *l2_cache; int (*flush_all_data_cache)(struct target *target); + int (*invalidate_all_instruction_cache)(struct target *target); int (*display_cache_info)(struct command_invocation *cmd, struct armv8_cache_common *armv8_cache); }; @@ -213,6 +214,8 @@ struct armv8_common { /* True if OpenOCD provides pointer auth related info to GDB */ bool enable_pauth; + bool sticky_reset; + /* last run-control command issued to this target (resume, halt, step) */ enum run_control_op last_run_control_op; @@ -296,7 +299,6 @@ int armv8_identify_cache(struct armv8_common *armv8); int armv8_init_arch_info(struct target *target, struct armv8_common *armv8); int armv8_mmu_translate_va_pa(struct target *target, target_addr_t va, target_addr_t *val, int meminfo); -int armv8_mmu_translate_va(struct target *target, target_addr_t va, target_addr_t *val); int armv8_handle_cache_info_command(struct command_invocation *cmd, struct armv8_cache_common *armv8_cache); @@ -327,7 +329,7 @@ static inline unsigned int armv8_curel_from_core_mode(enum arm_mode core_mode) } } -const char *armv8_mode_name(unsigned psr_mode); +const char *armv8_mode_name(unsigned int psr_mode); void armv8_select_reg_access(struct armv8_common *armv8, bool is_aarch64); int armv8_set_dbgreg_bits(struct armv8_common *armv8, unsigned int reg, unsigned long mask, unsigned long value); diff --git a/src/target/armv8_cache.c b/src/target/armv8_cache.c index 66d4e00..1c251be 100644 --- a/src/target/armv8_cache.c +++ b/src/target/armv8_cache.c @@ -61,6 +61,7 @@ static int armv8_cache_d_inner_flush_level(struct armv8_common *armv8, struct ar goto done; c_way -= 1; } while (c_way >= 0); + keep_alive(); c_index -= 1; } while (c_index >= 0); @@ -140,6 +141,36 @@ done: return retval; } +static int armv8_cache_i_inner_clean_inval_all(struct armv8_common *armv8) +{ + struct arm_dpm *dpm = armv8->arm.dpm; + int retval; + + retval = armv8_i_cache_sanity_check(armv8); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("flushing cache"); + + retval = dpm->prepare(dpm); + if (retval != ERROR_OK) + goto done; + + retval = dpm->instr_execute(dpm, armv8_opcode(armv8, ARMV8_OPC_ICIALLU)); + if (retval != ERROR_OK) + goto done; + + dpm->finish(dpm); + LOG_DEBUG("flushing cache done"); + return retval; + +done: + LOG_ERROR("i-cache invalidate failed"); + dpm->finish(dpm); + + return retval; +} + int armv8_cache_i_inner_inval_virt(struct armv8_common *armv8, target_addr_t va, size_t size) { struct arm_dpm *dpm = armv8->arm.dpm; @@ -252,6 +283,32 @@ static int armv8_flush_all_data(struct target *target) return retval; } +static int armv8_flush_all_instruction(struct target *target) +{ + int retval = ERROR_FAIL; + /* check that armv8_cache is correctly identify */ + struct armv8_common *armv8 = target_to_armv8(target); + if (armv8->armv8_mmu.armv8_cache.info == -1) { + LOG_ERROR("trying to flush un-identified cache"); + return retval; + } + + if (target->smp) { + /* look if all the other target have been flushed in order to flush icache */ + struct target_list *head; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + if (curr->state == TARGET_HALTED) { + LOG_TARGET_INFO(curr, "Wait flushing instruction l1."); + retval = armv8_cache_i_inner_clean_inval_all(target_to_armv8(curr)); + } + } + } else { + retval = armv8_cache_i_inner_clean_inval_all(armv8); + } + return retval; +} + static int get_cache_info(struct arm_dpm *dpm, int cl, int ct, uint32_t *cache_reg) { struct armv8_common *armv8 = dpm->arm->arch_info; @@ -411,6 +468,12 @@ int armv8_identify_cache(struct armv8_common *armv8) armv8->armv8_mmu.armv8_cache.flush_all_data_cache = armv8_flush_all_data; } + if (!armv8->armv8_mmu.armv8_cache.invalidate_all_instruction_cache) { + armv8->armv8_mmu.armv8_cache.display_cache_info = + armv8_handle_inner_cache_info_command; + armv8->armv8_mmu.armv8_cache.invalidate_all_instruction_cache = + armv8_flush_all_instruction; + } done: armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); diff --git a/src/target/armv8_dpm.c b/src/target/armv8_dpm.c index 271bd91..d1cee8a 100644 --- a/src/target/armv8_dpm.c +++ b/src/target/armv8_dpm.c @@ -417,7 +417,7 @@ static int dpmv8_instr_read_data_r0_64(struct arm_dpm *dpm, } #if 0 -static int dpmv8_bpwp_enable(struct arm_dpm *dpm, unsigned index_t, +static int dpmv8_bpwp_enable(struct arm_dpm *dpm, unsigned int index_t, target_addr_t addr, uint32_t control) { struct armv8_common *armv8 = dpm->arm->arch_info; @@ -441,8 +441,7 @@ static int dpmv8_bpwp_enable(struct arm_dpm *dpm, unsigned index_t, vr += 16 * index_t; cr += 16 * index_t; - LOG_DEBUG("A8: bpwp enable, vr %08x cr %08x", - (unsigned) vr, (unsigned) cr); + LOG_DEBUG("A8: bpwp enable, vr %08" PRIx32 " cr %08" PRIx32, vr, cr); retval = mem_ap_write_atomic_u32(armv8->debug_ap, vr, addr); if (retval != ERROR_OK) @@ -451,7 +450,7 @@ static int dpmv8_bpwp_enable(struct arm_dpm *dpm, unsigned index_t, } #endif -static int dpmv8_bpwp_disable(struct arm_dpm *dpm, unsigned index_t) +static int dpmv8_bpwp_disable(struct arm_dpm *dpm, unsigned int index_t) { struct armv8_common *armv8 = dpm->arm->arch_info; uint32_t cr; @@ -469,7 +468,7 @@ static int dpmv8_bpwp_disable(struct arm_dpm *dpm, unsigned index_t) } cr += 16 * index_t; - LOG_DEBUG("A: bpwp disable, cr %08x", (unsigned) cr); + LOG_DEBUG("A: bpwp disable, cr %08" PRIx32, cr); /* clear control register */ return mem_ap_write_atomic_u32(armv8->debug_ap, cr, 0); @@ -501,7 +500,7 @@ static int dpmv8_mrc(struct target *target, int cpnum, ARMV4_5_MRC(cpnum, op1, 0, crn, crm, op2), value); - /* (void) */ dpm->finish(dpm); + dpm->finish(dpm); return retval; } @@ -526,7 +525,7 @@ static int dpmv8_mcr(struct target *target, int cpnum, ARMV4_5_MCR(cpnum, op1, 0, crn, crm, op2), value); - /* (void) */ dpm->finish(dpm); + dpm->finish(dpm); return retval; } @@ -642,7 +641,7 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode) /* * Common register read, relies on armv8_select_reg_access() having been called. */ -static int dpmv8_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) +static int dpmv8_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned int regnum) { struct armv8_common *armv8 = dpm->arm->arch_info; int retval = ERROR_FAIL; @@ -685,7 +684,7 @@ static int dpmv8_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) /* * Common register write, relies on armv8_select_reg_access() having been called. */ -static int dpmv8_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum) +static int dpmv8_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned int regnum) { struct armv8_common *armv8 = dpm->arm->arch_info; int retval = ERROR_FAIL; @@ -888,7 +887,7 @@ int armv8_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) * cope with the hand-crafted breakpoint code. */ if (arm->target->type->add_breakpoint == dpmv8_add_breakpoint) { - for (unsigned i = 0; i < dpm->nbp; i++) { + for (unsigned int i = 0; i < dpm->nbp; i++) { struct dpm_bp *dbp = dpm->dbp + i; struct breakpoint *bp = dbp->bp; @@ -900,7 +899,7 @@ int armv8_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) } /* enable/disable watchpoints */ - for (unsigned i = 0; i < dpm->nwp; i++) { + for (unsigned int i = 0; i < dpm->nwp; i++) { struct dpm_wp *dwp = dpm->dwp + i; struct watchpoint *wp = dwp->wp; @@ -920,7 +919,7 @@ int armv8_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp) goto done; /* check everything except our scratch register R0 */ - for (unsigned i = 1; i < cache->num_regs; i++) { + for (unsigned int i = 1; i < cache->num_regs; i++) { struct arm_reg *r; /* skip non-existent */ @@ -992,7 +991,7 @@ static int armv8_dpm_read_core_reg(struct target *target, struct reg *r, goto fail; fail: - /* (void) */ dpm->finish(dpm); + dpm->finish(dpm); return retval; } @@ -1048,7 +1047,7 @@ static int armv8_dpm_full_context(struct target *target) * Pick some mode with unread registers and read them all. * Repeat until done. */ - for (unsigned i = 0; i < cache->num_regs; i++) { + for (unsigned int i = 0; i < cache->num_regs; i++) { struct arm_reg *r; if (!cache->reg_list[i].exist || cache->reg_list[i].valid) @@ -1086,7 +1085,7 @@ static int armv8_dpm_full_context(struct target *target) } while (did_read); retval = armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); - /* (void) */ dpm->finish(dpm); + dpm->finish(dpm); done: return retval; } @@ -1176,7 +1175,7 @@ static int dpmv8_add_breakpoint(struct target *target, struct breakpoint *bp) if (bp->type == BKPT_SOFT) LOG_DEBUG("using HW bkpt, not SW..."); - for (unsigned i = 0; i < dpm->nbp; i++) { + for (unsigned int i = 0; i < dpm->nbp; i++) { if (!dpm->dbp[i].bp) { retval = dpmv8_bpwp_setup(dpm, &dpm->dbp[i].bpwp, bp->address, bp->length); @@ -1195,7 +1194,7 @@ static int dpmv8_remove_breakpoint(struct target *target, struct breakpoint *bp) struct arm_dpm *dpm = arm->dpm; int retval = ERROR_COMMAND_SYNTAX_ERROR; - for (unsigned i = 0; i < dpm->nbp; i++) { + for (unsigned int i = 0; i < dpm->nbp; i++) { if (dpm->dbp[i].bp == bp) { dpm->dbp[i].bp = NULL; dpm->dbp[i].bpwp.dirty = true; @@ -1209,7 +1208,7 @@ static int dpmv8_remove_breakpoint(struct target *target, struct breakpoint *bp) return retval; } -static int dpmv8_watchpoint_setup(struct arm_dpm *dpm, unsigned index_t, +static int dpmv8_watchpoint_setup(struct arm_dpm *dpm, unsigned int index_t, struct watchpoint *wp) { int retval; @@ -1252,7 +1251,7 @@ static int dpmv8_add_watchpoint(struct target *target, struct watchpoint *wp) int retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; if (dpm->bpwp_enable) { - for (unsigned i = 0; i < dpm->nwp; i++) { + for (unsigned int i = 0; i < dpm->nwp; i++) { if (!dpm->dwp[i].wp) { retval = dpmv8_watchpoint_setup(dpm, i, wp); break; @@ -1269,7 +1268,7 @@ static int dpmv8_remove_watchpoint(struct target *target, struct watchpoint *wp) struct arm_dpm *dpm = arm->dpm; int retval = ERROR_COMMAND_SYNTAX_ERROR; - for (unsigned i = 0; i < dpm->nwp; i++) { + for (unsigned int i = 0; i < dpm->nwp; i++) { if (dpm->dwp[i].wp == wp) { dpm->dwp[i].wp = NULL; dpm->dwp[i].bpwp.dirty = true; @@ -1485,7 +1484,7 @@ int armv8_dpm_initialize(struct arm_dpm *dpm) { /* Disable all breakpoints and watchpoints at startup. */ if (dpm->bpwp_disable) { - unsigned i; + unsigned int i; for (i = 0; i < dpm->nbp; i++) { dpm->dbp[i].bpwp.number = i; diff --git a/src/target/armv8_opcodes.c b/src/target/armv8_opcodes.c index 2635b3e..0f6c810 100644 --- a/src/target/armv8_opcodes.c +++ b/src/target/armv8_opcodes.c @@ -41,6 +41,7 @@ static const uint32_t a64_opcodes[ARMV8_OPC_NUM] = { [ARMV8_OPC_STRH_IP] = ARMV8_STRH_IP(1, 0), [ARMV8_OPC_STRW_IP] = ARMV8_STRW_IP(1, 0), [ARMV8_OPC_STRD_IP] = ARMV8_STRD_IP(1, 0), + [ARMV8_OPC_ICIALLU] = ARMV8_SYS(SYSTEM_ICIALLU, 0x1F), }; static const uint32_t t32_opcodes[ARMV8_OPC_NUM] = { @@ -68,6 +69,7 @@ static const uint32_t t32_opcodes[ARMV8_OPC_NUM] = { [ARMV8_OPC_STRB_IP] = ARMV8_STRB_IP_T3(1, 0), [ARMV8_OPC_STRH_IP] = ARMV8_STRH_IP_T3(1, 0), [ARMV8_OPC_STRW_IP] = ARMV8_STRW_IP_T3(1, 0), + [ARMV8_OPC_ICIALLU] = ARMV4_5_MCR(15, 0, 0, 7, 5, 0), }; void armv8_select_opcodes(struct armv8_common *armv8, bool state_is_aarch64) diff --git a/src/target/armv8_opcodes.h b/src/target/armv8_opcodes.h index 9200dac..9f18e94 100644 --- a/src/target/armv8_opcodes.h +++ b/src/target/armv8_opcodes.h @@ -72,6 +72,8 @@ #define SYSTEM_DCCISW 0x43F2 #define SYSTEM_DCCSW 0x43D2 #define SYSTEM_ICIVAU 0x5BA9 +/* Attention, SYSTEM_ICIALLU requires rt=0x1f */ +#define SYSTEM_ICIALLU 0x03A8 #define SYSTEM_DCCVAU 0x5BD9 #define SYSTEM_DCCIVAC 0x5BF1 @@ -207,6 +209,7 @@ enum armv8_opcode { ARMV8_OPC_LDRH_IP, ARMV8_OPC_LDRW_IP, ARMV8_OPC_LDRD_IP, + ARMV8_OPC_ICIALLU, ARMV8_OPC_NUM, }; diff --git a/src/target/avr32_ap7k.c b/src/target/avr32_ap7k.c index bbbf236..1b051dc 100644 --- a/src/target/avr32_ap7k.c +++ b/src/target/avr32_ap7k.c @@ -300,8 +300,8 @@ static int avr32_ap7k_deassert_reset(struct target *target) return ERROR_OK; } -static int avr32_ap7k_resume(struct target *target, int current, - target_addr_t address, int handle_breakpoints, int debug_execution) +static int avr32_ap7k_resume(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, bool debug_execution) { struct avr32_ap7k_common *ap7k = target_to_ap7k(target); struct breakpoint *breakpoint = NULL; @@ -321,7 +321,7 @@ static int avr32_ap7k_resume(struct target *target, int current, */ } - /* current = 1: continue on current pc, otherwise continue at <address> */ + /* current = true: continue on current pc, otherwise continue at <address> */ if (!current) { #if 0 if (retval != ERROR_OK) @@ -382,8 +382,8 @@ static int avr32_ap7k_resume(struct target *target, int current, return ERROR_OK; } -static int avr32_ap7k_step(struct target *target, int current, - target_addr_t address, int handle_breakpoints) +static int avr32_ap7k_step(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints) { LOG_ERROR("%s: implement me", __func__); diff --git a/src/target/avrt.c b/src/target/avrt.c index 61bef32..3afe320 100644 --- a/src/target/avrt.c +++ b/src/target/avrt.c @@ -22,19 +22,19 @@ static int avr_init_target(struct command_context *cmd_ctx, struct target *targe static int avr_arch_state(struct target *target); static int avr_poll(struct target *target); static int avr_halt(struct target *target); -static int avr_resume(struct target *target, int current, target_addr_t address, - int handle_breakpoints, int debug_execution); -static int avr_step(struct target *target, int current, target_addr_t address, - int handle_breakpoints); +static int avr_resume(struct target *target, bool current, target_addr_t address, + bool handle_breakpoints, bool debug_execution); +static int avr_step(struct target *target, bool current, target_addr_t address, + bool handle_breakpoints); static int avr_assert_reset(struct target *target); static int avr_deassert_reset(struct target *target); /* IR and DR functions */ -static int mcu_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, int ir_len, int rti); -static int mcu_write_dr(struct jtag_tap *tap, uint8_t *dr_in, uint8_t *dr_out, int dr_len, int rti); -static int mcu_write_ir_u8(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out, int ir_len, int rti); -static int mcu_write_dr_u32(struct jtag_tap *tap, uint32_t *ir_in, uint32_t ir_out, int dr_len, int rti); +static int mcu_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, int ir_len); +static int mcu_write_dr(struct jtag_tap *tap, uint8_t *dr_in, uint8_t *dr_out, int dr_len); +static int mcu_write_ir_u8(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out, int ir_len); +static int mcu_write_dr_u32(struct jtag_tap *tap, uint32_t *ir_in, uint32_t ir_out, int dr_len); struct target_type avr_target = { .name = "avr", @@ -105,14 +105,15 @@ static int avr_halt(struct target *target) return ERROR_OK; } -static int avr_resume(struct target *target, int current, target_addr_t address, - int handle_breakpoints, int debug_execution) +static int avr_resume(struct target *target, bool current, target_addr_t address, + bool handle_breakpoints, bool debug_execution) { LOG_DEBUG("%s", __func__); return ERROR_OK; } -static int avr_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) +static int avr_step(struct target *target, bool current, target_addr_t address, + bool handle_breakpoints) { LOG_DEBUG("%s", __func__); return ERROR_OK; @@ -137,23 +138,23 @@ static int avr_deassert_reset(struct target *target) int avr_jtag_senddat(struct jtag_tap *tap, uint32_t *dr_in, uint32_t dr_out, int len) { - return mcu_write_dr_u32(tap, dr_in, dr_out, len, 1); + return mcu_write_dr_u32(tap, dr_in, dr_out, len); } int avr_jtag_sendinstr(struct jtag_tap *tap, uint8_t *ir_in, uint8_t ir_out) { - return mcu_write_ir_u8(tap, ir_in, ir_out, AVR_JTAG_INS_LEN, 1); + return mcu_write_ir_u8(tap, ir_in, ir_out, AVR_JTAG_INS_LEN); } /* IR and DR functions */ static int mcu_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, - int ir_len, int rti) + int ir_len) { if (!tap) { LOG_ERROR("invalid tap"); return ERROR_FAIL; } - if (ir_len != tap->ir_length) { + if ((unsigned int)ir_len != tap->ir_length) { LOG_ERROR("invalid ir_len"); return ERROR_FAIL; } @@ -166,7 +167,7 @@ static int mcu_write_ir(struct jtag_tap *tap, uint8_t *ir_in, uint8_t *ir_out, } static int mcu_write_dr(struct jtag_tap *tap, uint8_t *dr_in, uint8_t *dr_out, - int dr_len, int rti) + int dr_len) { if (!tap) { LOG_ERROR("invalid tap"); @@ -181,27 +182,27 @@ static int mcu_write_dr(struct jtag_tap *tap, uint8_t *dr_in, uint8_t *dr_out, } static int mcu_write_ir_u8(struct jtag_tap *tap, uint8_t *ir_in, - uint8_t ir_out, int ir_len, int rti) + uint8_t ir_out, int ir_len) { if (ir_len > 8) { LOG_ERROR("ir_len overflow, maximum is 8"); return ERROR_FAIL; } - mcu_write_ir(tap, ir_in, &ir_out, ir_len, rti); + mcu_write_ir(tap, ir_in, &ir_out, ir_len); return ERROR_OK; } static int mcu_write_dr_u32(struct jtag_tap *tap, uint32_t *dr_in, - uint32_t dr_out, int dr_len, int rti) + uint32_t dr_out, int dr_len) { if (dr_len > 32) { LOG_ERROR("dr_len overflow, maximum is 32"); return ERROR_FAIL; } - mcu_write_dr(tap, (uint8_t *)dr_in, (uint8_t *)&dr_out, dr_len, rti); + mcu_write_dr(tap, (uint8_t *)dr_in, (uint8_t *)&dr_out, dr_len); return ERROR_OK; } diff --git a/src/target/breakpoints.c b/src/target/breakpoints.c index 77f7673..0e9ae6e 100644 --- a/src/target/breakpoints.c +++ b/src/target/breakpoints.c @@ -39,7 +39,7 @@ static int bpwp_unique_id; static int breakpoint_add_internal(struct target *target, target_addr_t address, - uint32_t length, + unsigned int length, enum breakpoint_type type) { struct breakpoint *breakpoint = target->breakpoints; @@ -102,7 +102,7 @@ fail: static int context_breakpoint_add_internal(struct target *target, uint32_t asid, - uint32_t length, + unsigned int length, enum breakpoint_type type) { struct breakpoint *breakpoint = target->breakpoints; @@ -115,7 +115,7 @@ static int context_breakpoint_add_internal(struct target *target, * breakpoint" ... check all the parameters before * succeeding. */ - LOG_ERROR("Duplicate Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")", + LOG_TARGET_ERROR(target, "Duplicate Breakpoint asid: 0x%08" PRIx32 " (BP %" PRIu32 ")", asid, breakpoint->unique_id); return ERROR_TARGET_DUPLICATE_BREAKPOINT; } @@ -152,7 +152,7 @@ static int context_breakpoint_add_internal(struct target *target, static int hybrid_breakpoint_add_internal(struct target *target, target_addr_t address, uint32_t asid, - uint32_t length, + unsigned int length, enum breakpoint_type type) { struct breakpoint *breakpoint = target->breakpoints; @@ -208,7 +208,7 @@ static int hybrid_breakpoint_add_internal(struct target *target, int breakpoint_add(struct target *target, target_addr_t address, - uint32_t length, + unsigned int length, enum breakpoint_type type) { if (target->smp && type == BKPT_HARD) { @@ -232,7 +232,7 @@ int breakpoint_add(struct target *target, int context_breakpoint_add(struct target *target, uint32_t asid, - uint32_t length, + unsigned int length, enum breakpoint_type type) { if (target->smp) { @@ -256,7 +256,7 @@ int context_breakpoint_add(struct target *target, int hybrid_breakpoint_add(struct target *target, target_addr_t address, uint32_t asid, - uint32_t length, + unsigned int length, enum breakpoint_type type) { if (target->smp) { @@ -542,7 +542,7 @@ struct breakpoint *breakpoint_find(struct target *target, target_addr_t address) } static int watchpoint_add_internal(struct target *target, target_addr_t address, - uint32_t length, enum watchpoint_rw rw, uint64_t value, uint64_t mask) + unsigned int length, enum watchpoint_rw rw, uint64_t value, uint64_t mask) { struct watchpoint *watchpoint = target->watchpoints; struct watchpoint **watchpoint_p = &target->watchpoints; @@ -598,7 +598,7 @@ bye: } LOG_TARGET_DEBUG(target, "added %s watchpoint at " TARGET_ADDR_FMT - " of length 0x%8.8" PRIx32 " (WPID: %d)", + " of length 0x%8.8x (WPID: %d)", watchpoint_rw_strings[(*watchpoint_p)->rw], (*watchpoint_p)->address, (*watchpoint_p)->length, @@ -608,7 +608,7 @@ bye: } int watchpoint_add(struct target *target, target_addr_t address, - uint32_t length, enum watchpoint_rw rw, uint64_t value, uint64_t mask) + unsigned int length, enum watchpoint_rw rw, uint64_t value, uint64_t mask) { if (target->smp) { struct target_list *head; @@ -687,8 +687,7 @@ int watchpoint_remove(struct target *target, target_addr_t address) int watchpoint_clear_target(struct target *target) { - LOG_DEBUG("Delete all watchpoints for target: %s", - target_name(target)); + LOG_TARGET_DEBUG(target, "Delete all watchpoints"); struct watchpoint *watchpoint = target->watchpoints; int retval = ERROR_OK; diff --git a/src/target/breakpoints.h b/src/target/breakpoints.h index 0ec65de..ac5d701 100644 --- a/src/target/breakpoints.h +++ b/src/target/breakpoints.h @@ -26,7 +26,7 @@ enum watchpoint_rw { struct breakpoint { target_addr_t address; uint32_t asid; - int length; + unsigned int length; enum breakpoint_type type; bool is_set; unsigned int number; @@ -40,7 +40,7 @@ struct breakpoint { struct watchpoint { target_addr_t address; - uint32_t length; + unsigned int length; uint64_t mask; uint64_t value; enum watchpoint_rw rw; @@ -52,11 +52,12 @@ struct watchpoint { int breakpoint_clear_target(struct target *target); int breakpoint_add(struct target *target, - target_addr_t address, uint32_t length, enum breakpoint_type type); + target_addr_t address, unsigned int length, enum breakpoint_type type); int context_breakpoint_add(struct target *target, - uint32_t asid, uint32_t length, enum breakpoint_type type); + uint32_t asid, unsigned int length, enum breakpoint_type type); int hybrid_breakpoint_add(struct target *target, - target_addr_t address, uint32_t asid, uint32_t length, enum breakpoint_type type); + target_addr_t address, uint32_t asid, unsigned int length, + enum breakpoint_type type); int breakpoint_remove(struct target *target, target_addr_t address); int breakpoint_remove_all(struct target *target); @@ -70,7 +71,7 @@ static inline void breakpoint_hw_set(struct breakpoint *breakpoint, unsigned int int watchpoint_clear_target(struct target *target); int watchpoint_add(struct target *target, - target_addr_t address, uint32_t length, + target_addr_t address, unsigned int length, enum watchpoint_rw rw, uint64_t value, uint64_t mask); int watchpoint_remove(struct target *target, target_addr_t address); int watchpoint_remove_all(struct target *target); diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 2de77c9..9c60645 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -571,7 +571,7 @@ static int cortex_a_instr_read_data_r0_r1(struct arm_dpm *dpm, return retval; } -static int cortex_a_bpwp_enable(struct arm_dpm *dpm, unsigned index_t, +static int cortex_a_bpwp_enable(struct arm_dpm *dpm, unsigned int index_t, uint32_t addr, uint32_t control) { struct cortex_a_common *a = dpm_to_a(dpm); @@ -595,8 +595,7 @@ static int cortex_a_bpwp_enable(struct arm_dpm *dpm, unsigned index_t, vr += 4 * index_t; cr += 4 * index_t; - LOG_DEBUG("A: bpwp enable, vr %08x cr %08x", - (unsigned) vr, (unsigned) cr); + LOG_DEBUG("A: bpwp enable, vr %08" PRIx32 " cr %08" PRIx32, vr, cr); retval = mem_ap_write_atomic_u32(a->armv7a_common.debug_ap, vr, addr); @@ -607,7 +606,7 @@ static int cortex_a_bpwp_enable(struct arm_dpm *dpm, unsigned index_t, return retval; } -static int cortex_a_bpwp_disable(struct arm_dpm *dpm, unsigned index_t) +static int cortex_a_bpwp_disable(struct arm_dpm *dpm, unsigned int index_t) { struct cortex_a_common *a = dpm_to_a(dpm); uint32_t cr; @@ -625,7 +624,7 @@ static int cortex_a_bpwp_disable(struct arm_dpm *dpm, unsigned index_t) } cr += 4 * index_t; - LOG_DEBUG("A: bpwp disable, cr %08x", (unsigned) cr); + LOG_DEBUG("A: bpwp disable, cr %08" PRIx32, cr); /* clear control register */ return mem_ap_write_atomic_u32(a->armv7a_common.debug_ap, cr, 0); @@ -818,8 +817,8 @@ static int cortex_a_halt(struct target *target) return ERROR_OK; } -static int cortex_a_internal_restore(struct target *target, int current, - target_addr_t *address, int handle_breakpoints, int debug_execution) +static int cortex_a_internal_restore(struct target *target, bool current, + target_addr_t *address, bool handle_breakpoints, bool debug_execution) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; @@ -850,7 +849,7 @@ static int cortex_a_internal_restore(struct target *target, int current, } #endif - /* current = 1: continue on current pc, otherwise continue at <address> */ + /* current = true: continue on current pc, otherwise continue at <address> */ resume_pc = buf_get_u32(arm->pc->value, 0, 32); if (!current) resume_pc = *address; @@ -966,7 +965,7 @@ static int cortex_a_internal_restart(struct target *target) return ERROR_OK; } -static int cortex_a_restore_smp(struct target *target, int handle_breakpoints) +static int cortex_a_restore_smp(struct target *target, bool handle_breakpoints) { int retval = 0; struct target_list *head; @@ -977,16 +976,16 @@ static int cortex_a_restore_smp(struct target *target, int handle_breakpoints) if ((curr != target) && (curr->state != TARGET_RUNNING) && target_was_examined(curr)) { /* resume current address , not in step mode */ - retval += cortex_a_internal_restore(curr, 1, &address, - handle_breakpoints, 0); + retval += cortex_a_internal_restore(curr, true, &address, + handle_breakpoints, false); retval += cortex_a_internal_restart(curr); } } return retval; } -static int cortex_a_resume(struct target *target, int current, - target_addr_t address, int handle_breakpoints, int debug_execution) +static int cortex_a_resume(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, bool debug_execution) { int retval = 0; /* dummy resume for smp toggle in order to reduce gdb impact */ @@ -998,7 +997,8 @@ static int cortex_a_resume(struct target *target, int current, target_call_event_callbacks(target, TARGET_EVENT_RESUMED); return 0; } - cortex_a_internal_restore(target, current, &address, handle_breakpoints, debug_execution); + cortex_a_internal_restore(target, current, &address, handle_breakpoints, + debug_execution); if (target->smp) { target->gdb_service->core[0] = -1; retval = cortex_a_restore_smp(target, handle_breakpoints); @@ -1169,8 +1169,8 @@ static int cortex_a_set_dscr_bits(struct target *target, return retval; } -static int cortex_a_step(struct target *target, int current, target_addr_t address, - int handle_breakpoints) +static int cortex_a_step(struct target *target, bool current, target_addr_t address, + bool handle_breakpoints) { struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = target_to_armv7a(target); @@ -1185,7 +1185,7 @@ static int cortex_a_step(struct target *target, int current, target_addr_t addre return ERROR_TARGET_NOT_HALTED; } - /* current = 1: continue on current pc, otherwise continue at <address> */ + /* current = true: continue on current pc, otherwise continue at <address> */ r = arm->pc; if (!current) buf_set_u32(r->value, 0, 32, address); @@ -1196,7 +1196,7 @@ static int cortex_a_step(struct target *target, int current, target_addr_t addre * But since Cortex-A uses breakpoint for single step, * we MUST handle breakpoints. */ - handle_breakpoints = 1; + handle_breakpoints = true; if (handle_breakpoints) { breakpoint = breakpoint_find(target, address); if (breakpoint) @@ -1223,7 +1223,7 @@ static int cortex_a_step(struct target *target, int current, target_addr_t addre target->debug_reason = DBG_REASON_SINGLESTEP; - retval = cortex_a_resume(target, 1, address, 0, 0); + retval = cortex_a_resume(target, true, address, false, false); if (retval != ERROR_OK) return retval; @@ -1325,21 +1325,21 @@ static int cortex_a_set_breakpoint(struct target *target, brp_list[brp_i].value); } else if (breakpoint->type == BKPT_SOFT) { uint8_t code[4]; - /* length == 2: Thumb breakpoint */ - if (breakpoint->length == 2) + if (breakpoint->length == 2) { + /* length == 2: Thumb breakpoint */ buf_set_u32(code, 0, 32, ARMV5_T_BKPT(0x11)); - else - /* length == 3: Thumb-2 breakpoint, actual encoding is - * a regular Thumb BKPT instruction but we replace a - * 32bit Thumb-2 instruction, so fix-up the breakpoint - * length - */ - if (breakpoint->length == 3) { + } else if (breakpoint->length == 3) { + /* length == 3: Thumb-2 breakpoint, actual encoding is + * a regular Thumb BKPT instruction but we replace a + * 32bit Thumb-2 instruction, so fix-up the breakpoint + * length + */ buf_set_u32(code, 0, 32, ARMV5_T_BKPT(0x11)); breakpoint->length = 4; - } else + } else { /* length == 4, normal ARM breakpoint */ buf_set_u32(code, 0, 32, ARMV5_BKPT(0x11)); + } retval = target_read_memory(target, breakpoint->address & 0xFFFFFFFE, @@ -1349,8 +1349,7 @@ static int cortex_a_set_breakpoint(struct target *target, return retval; /* make sure data cache is cleaned & invalidated down to PoC */ - armv7a_cache_flush_virt(target, breakpoint->address, - breakpoint->length); + armv7a_cache_flush_virt(target, breakpoint->address, breakpoint->length); retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, @@ -1359,10 +1358,8 @@ static int cortex_a_set_breakpoint(struct target *target, return retval; /* update i-cache at breakpoint location */ - armv7a_l1_d_cache_inval_virt(target, breakpoint->address, - breakpoint->length); - armv7a_l1_i_cache_inval_virt(target, breakpoint->address, - breakpoint->length); + armv7a_l1_d_cache_inval_virt(target, breakpoint->address, breakpoint->length); + armv7a_l1_i_cache_inval_virt(target, breakpoint->address, breakpoint->length); breakpoint->is_set = true; } @@ -2926,14 +2923,12 @@ static int cortex_a_examine_first(struct target *target) armv7a->debug_ap->memaccess_tck = 80; if (!target->dbgbase_set) { - LOG_DEBUG("%s's dbgbase is not set, trying to detect using the ROM table", - target->cmd_name); + LOG_TARGET_DEBUG(target, "dbgbase is not set, trying to detect using the ROM table"); /* Lookup Processor DAP */ retval = dap_lookup_cs_component(armv7a->debug_ap, ARM_CS_C9_DEVTYPE_CORE_DEBUG, &armv7a->debug_base, target->coreid); if (retval != ERROR_OK) { - LOG_ERROR("Can't detect %s's dbgbase from the ROM table; you need to specify it explicitly.", - target->cmd_name); + LOG_TARGET_ERROR(target, "Can't detect dbgbase from the ROM table; you need to specify it explicitly"); return retval; } LOG_DEBUG("Detected core %" PRId32 " dbgbase: " TARGET_ADDR_FMT, @@ -2942,8 +2937,9 @@ static int cortex_a_examine_first(struct target *target) armv7a->debug_base = target->dbgbase; if ((armv7a->debug_base & (1UL<<31)) == 0) - LOG_WARNING("Debug base address for target %s has bit 31 set to 0. Access to debug registers will likely fail!\n" - "Please fix the target configuration.", target_name(target)); + LOG_TARGET_WARNING(target, + "Debug base address has bit 31 set to 0. Access to debug registers will likely fail!\n" + "Please fix the target configuration"); retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DIDR, &didr); diff --git a/src/target/cortex_m.c b/src/target/cortex_m.c index 34c7cd4..e17f23c 100644 --- a/src/target/cortex_m.c +++ b/src/target/cortex_m.c @@ -100,6 +100,12 @@ static const struct cortex_m_part_info cortex_m_parts[] = { .flags = CORTEX_M_F_HAS_FPV5, }, { + .impl_part = CORTEX_M52_PARTNO, + .name = "Cortex-M52", + .arch = ARM_ARCH_V8M, + .flags = CORTEX_M_F_HAS_FPV5, + }, + { .impl_part = CORTEX_M55_PARTNO, .name = "Cortex-M55", .arch = ARM_ARCH_V8M, @@ -273,7 +279,8 @@ static int cortex_m_fast_read_all_regs(struct target *target) /* because the DCB_DCRDR is used for the emulated dcc channel * we have to save/restore the DCB_DCRDR when used */ - if (target->dbg_msg_enabled) { + bool dbg_msg_enabled = target->dbg_msg_enabled; + if (dbg_msg_enabled) { retval = mem_ap_read_u32(armv7m->debug_ap, DCB_DCRDR, &dcrdr); if (retval != ERROR_OK) return retval; @@ -326,7 +333,7 @@ static int cortex_m_fast_read_all_regs(struct target *target) if (retval != ERROR_OK) return retval; - if (target->dbg_msg_enabled) { + if (dbg_msg_enabled) { /* restore DCB_DCRDR - this needs to be in a separate * transaction otherwise the emulated DCC channel breaks */ retval = mem_ap_write_atomic_u32(armv7m->debug_ap, DCB_DCRDR, dcrdr); @@ -797,6 +804,42 @@ static int cortex_m_examine_exception_reason(struct target *target) return retval; } +/* Errata 3092511 workaround + * Cortex-M7 can halt in an incorrect address when breakpoint + * and exception occurs simultaneously */ +static int cortex_m_erratum_check_breakpoint(struct target *target) +{ + struct cortex_m_common *cortex_m = target_to_cm(target); + struct armv7m_common *armv7m = &cortex_m->armv7m; + struct arm *arm = &armv7m->arm; + + uint32_t pc = buf_get_u32(arm->pc->value, 0, 32); + + /* To reduce the workaround processing cost we assume FPB is in sync + * with OpenOCD breakpoints. If the target app writes to FPB + * OpenOCD will resume after the break set by app */ + struct breakpoint *bkpt = breakpoint_find(target, pc); + if (bkpt) { + LOG_TARGET_DEBUG(target, "Erratum 3092511: breakpoint confirmed"); + return ERROR_OK; + } + if (pc >= 0xe0000000u) + /* not executable area, do not read instruction @ pc */ + return ERROR_OK; + + uint16_t insn; + int retval = target_read_u16(target, pc, &insn); + if (retval != ERROR_OK) + return ERROR_OK; /* do not propagate the error, just avoid workaround */ + + if ((insn & 0xff00) == (ARMV5_T_BKPT(0) & 0xff00)) { + LOG_TARGET_DEBUG(target, "Erratum 3092511: breakpoint embedded in code confirmed"); + return ERROR_OK; + } + LOG_TARGET_DEBUG(target, "Erratum 3092511: breakpoint not found, proceed with resume"); + return ERROR_TARGET_HALTED_DO_RESUME; +} + static int cortex_m_debug_entry(struct target *target) { uint32_t xpsr; @@ -855,7 +898,7 @@ static int cortex_m_debug_entry(struct target *target) arm->core_mode = ARM_MODE_HANDLER; arm->map = armv7m_msp_reg_map; } else { - unsigned control = buf_get_u32(arm->core_cache + unsigned int control = buf_get_u32(arm->core_cache ->reg_list[ARMV7M_CONTROL].value, 0, 3); /* is this thread privileged? */ @@ -883,6 +926,17 @@ static int cortex_m_debug_entry(struct target *target) secure_state ? "Secure" : "Non-Secure", target_state_name(target)); + /* Errata 3092511 workaround + * Cortex-M7 can halt in an incorrect address when breakpoint + * and exception occurs simultaneously */ + if (cortex_m->incorrect_halt_erratum + && armv7m->exception_number + && cortex_m->nvic_dfsr == (DFSR_BKPT | DFSR_HALTED)) { + retval = cortex_m_erratum_check_breakpoint(target); + if (retval != ERROR_OK) + return retval; + } + if (armv7m->post_debug_entry) { retval = armv7m->post_debug_entry(target); if (retval != ERROR_OK) @@ -935,6 +989,18 @@ static int cortex_m_poll_one(struct target *target) * and keep it until the next poll to allow its detection */ return ERROR_OK; } + + /* refresh status bits */ + retval = cortex_m_read_dhcsr_atomic_sticky(target); + if (retval != ERROR_OK) + return retval; + + /* If still under reset, quit and re-check at next poll */ + if (cortex_m->dcb_dhcsr_cumulated_sticky & S_RESET_ST) { + cortex_m->dcb_dhcsr_cumulated_sticky &= ~S_RESET_ST; + return ERROR_OK; + } + /* S_RESET_ST was expected (in a reset command). Continue processing * to quickly get out of TARGET_RESET state */ } @@ -960,6 +1026,28 @@ static int cortex_m_poll_one(struct target *target) if ((prev_target_state == TARGET_RUNNING) || (prev_target_state == TARGET_RESET)) { retval = cortex_m_debug_entry(target); + /* Errata 3092511 workaround + * Cortex-M7 can halt in an incorrect address when breakpoint + * and exception occurs simultaneously */ + if (retval == ERROR_TARGET_HALTED_DO_RESUME) { + struct arm *arm = &armv7m->arm; + LOG_TARGET_INFO(target, "Resuming after incorrect halt @ PC 0x%08" PRIx32 + ", ARM Cortex-M7 erratum 3092511", + buf_get_u32(arm->pc->value, 0, 32)); + /* We don't need to restore registers, just restart the core */ + cortex_m_set_maskints_for_run(target); + retval = cortex_m_write_debug_halt_mask(target, 0, C_HALT); + if (retval != ERROR_OK) + return retval; + + target->debug_reason = DBG_REASON_NOTHALTED; + /* registers are now invalid */ + register_cache_invalidate(armv7m->arm.core_cache); + + target->state = TARGET_RUNNING; + return ERROR_OK; + } + /* arm_semihosting needs to know registers, don't run if debug entry returned error */ if (retval == ERROR_OK && arm_semihosting(target, &retval) != 0) return retval; @@ -1271,7 +1359,7 @@ static int cortex_m_restore_one(struct target *target, bool current, r->valid = true; } - /* current = 1: continue on current pc, otherwise continue at <address> */ + /* current = true: continue on current pc, otherwise continue at <address> */ r = armv7m->arm.pc; if (!current) { buf_set_u32(r->value, 0, 32, *address); @@ -1356,7 +1444,7 @@ static int cortex_m_restore_smp(struct target *target, bool handle_breakpoints) continue; int retval = cortex_m_restore_one(curr, true, &address, - handle_breakpoints, false); + handle_breakpoints, false); if (retval != ERROR_OK) return retval; @@ -1369,22 +1457,23 @@ static int cortex_m_restore_smp(struct target *target, bool handle_breakpoints) return ERROR_OK; } -static int cortex_m_resume(struct target *target, int current, - target_addr_t address, int handle_breakpoints, int debug_execution) +static int cortex_m_resume(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, bool debug_execution) { - int retval = cortex_m_restore_one(target, !!current, &address, !!handle_breakpoints, !!debug_execution); + int retval = cortex_m_restore_one(target, current, &address, + handle_breakpoints, debug_execution); if (retval != ERROR_OK) { LOG_TARGET_ERROR(target, "context restore failed, aborting resume"); return retval; } if (target->smp && !debug_execution) { - retval = cortex_m_restore_smp(target, !!handle_breakpoints); + retval = cortex_m_restore_smp(target, handle_breakpoints); if (retval != ERROR_OK) - LOG_WARNING("resume of a SMP target failed, trying to resume current one"); + LOG_TARGET_WARNING(target, "resume of a SMP target failed, trying to resume current one"); } - cortex_m_restart_one(target, !!debug_execution); + cortex_m_restart_one(target, debug_execution); if (retval != ERROR_OK) { LOG_TARGET_ERROR(target, "resume failed"); return retval; @@ -1397,8 +1486,8 @@ static int cortex_m_resume(struct target *target, int current, } /* int irqstepcount = 0; */ -static int cortex_m_step(struct target *target, int current, - target_addr_t address, int handle_breakpoints) +static int cortex_m_step(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints) { struct cortex_m_common *cortex_m = target_to_cm(target); struct armv7m_common *armv7m = &cortex_m->armv7m; @@ -1418,7 +1507,7 @@ static int cortex_m_step(struct target *target, int current, if (target->smp && target->gdb_service) target->gdb_service->target = target; - /* current = 1: continue on current pc, otherwise continue at <address> */ + /* current = true: continue on current pc, otherwise continue at <address> */ if (!current) { buf_set_u32(pc->value, 0, 32, address); pc->dirty = true; @@ -1445,7 +1534,7 @@ static int cortex_m_step(struct target *target, int current, /* if no bkpt instruction is found at pc then we can perform * a normal step, otherwise we have to manually step over the bkpt * instruction - as such simulate a step */ - if (bkpt_inst_found == false) { + if (!bkpt_inst_found) { if (cortex_m->isrmasking_mode != CORTEX_M_ISRMASK_AUTO) { /* Automatic ISR masking mode off: Just step over the next * instruction, with interrupts on or off as appropriate. */ @@ -1582,7 +1671,7 @@ static int cortex_m_step(struct target *target, int current, cortex_m->dcb_dhcsr, cortex_m->nvic_icsr); retval = cortex_m_debug_entry(target); - if (retval != ERROR_OK) + if (retval != ERROR_OK && retval != ERROR_TARGET_HALTED_DO_RESUME) return retval; target_call_event_callbacks(target, TARGET_EVENT_HALTED); @@ -1761,10 +1850,12 @@ static int cortex_m_deassert_reset(struct target *target) target_state_name(target), target_was_examined(target) ? "" : " not"); + enum reset_types jtag_reset_config = jtag_get_reset_config(); + /* deassert reset lines */ - adapter_deassert_reset(); + if (jtag_reset_config & RESET_HAS_SRST) + adapter_deassert_reset(); - enum reset_types jtag_reset_config = jtag_get_reset_config(); if ((jtag_reset_config & RESET_HAS_SRST) && !(jtag_reset_config & RESET_SRST_NO_GATING) && @@ -2005,11 +2096,9 @@ static int cortex_m_set_watchpoint(struct target *target, struct watchpoint *wat target_write_u32(target, comparator->dwt_comparator_address + 8, comparator->function); - LOG_TARGET_DEBUG(target, "Watchpoint (ID %d) DWT%d 0x%08x 0x%x 0x%05x", + LOG_TARGET_DEBUG(target, "Watchpoint (ID %d) DWT%d 0x%08" PRIx32 " 0x%" PRIx32 " 0x%05" PRIx32, watchpoint->unique_id, dwt_num, - (unsigned) comparator->comp, - (unsigned) comparator->mask, - (unsigned) comparator->function); + comparator->comp, comparator->mask, comparator->function); return ERROR_OK; } @@ -2026,9 +2115,9 @@ static int cortex_m_unset_watchpoint(struct target *target, struct watchpoint *w unsigned int dwt_num = watchpoint->number; - LOG_TARGET_DEBUG(target, "Watchpoint (ID %d) DWT%u address: 0x%08x clear", + LOG_TARGET_DEBUG(target, "Watchpoint (ID %d) DWT%u address: " TARGET_ADDR_FMT " clear", watchpoint->unique_id, dwt_num, - (unsigned) watchpoint->address); + watchpoint->address); if (dwt_num >= cortex_m->dwt_num_comp) { LOG_TARGET_DEBUG(target, "Invalid DWT Comparator number in watchpoint"); @@ -2068,7 +2157,7 @@ int cortex_m_add_watchpoint(struct target *target, struct watchpoint *watchpoint } /* hardware allows address masks of up to 32K */ - unsigned mask; + unsigned int mask; for (mask = 0; mask < 16; mask++) { if ((1u << mask) == watchpoint->length) @@ -2228,7 +2317,7 @@ int cortex_m_profiling(struct target *target, uint32_t *samples, /* Make sure the target is running */ target_poll(target); if (target->state == TARGET_HALTED) - retval = target_resume(target, 1, 0, 0, 0); + retval = target_resume(target, true, 0, false, false); if (retval != ERROR_OK) { LOG_TARGET_ERROR(target, "Error while resuming target"); @@ -2304,7 +2393,7 @@ static int cortex_m_dwt_set_reg(struct reg *reg, uint8_t *buf) struct dwt_reg { uint32_t addr; const char *name; - unsigned size; + unsigned int size; }; static const struct dwt_reg dwt_base_regs[] = { @@ -2467,7 +2556,7 @@ static bool cortex_m_has_tz(struct target *target) int retval = target_read_u32(target, DAUTHSTATUS, &dauthstatus); if (retval != ERROR_OK) { - LOG_WARNING("Error reading DAUTHSTATUS register"); + LOG_TARGET_WARNING(target, "Error reading DAUTHSTATUS register"); return false; } return (dauthstatus & DAUTHSTATUS_SID_MASK) != 0; @@ -2516,7 +2605,7 @@ int cortex_m_examine(struct target *target) } else { armv7m->debug_ap = dap_get_ap(swjdp, cortex_m->apsel); if (!armv7m->debug_ap) { - LOG_ERROR("Cannot get AP"); + LOG_TARGET_ERROR(target, "Cannot get AP"); return ERROR_FAIL; } } @@ -2537,8 +2626,8 @@ int cortex_m_examine(struct target *target) if (retval != ERROR_OK) return retval; - /* Inspect implementor/part to look for recognized cores */ - unsigned int impl_part = cpuid & (ARM_CPUID_IMPLEMENTOR_MASK | ARM_CPUID_PARTNO_MASK); + /* Inspect implementer/part to look for recognized cores */ + unsigned int impl_part = cpuid & (ARM_CPUID_IMPLEMENTER_MASK | ARM_CPUID_PARTNO_MASK); for (unsigned int n = 0; n < ARRAY_SIZE(cortex_m_parts); n++) { if (impl_part == cortex_m_parts[n].impl_part) { @@ -2560,14 +2649,22 @@ int cortex_m_examine(struct target *target) (uint8_t)((cpuid >> 0) & 0xf)); cortex_m->maskints_erratum = false; + cortex_m->incorrect_halt_erratum = false; if (impl_part == CORTEX_M7_PARTNO) { uint8_t rev, patch; rev = (cpuid >> 20) & 0xf; patch = (cpuid >> 0) & 0xf; if ((rev == 0) && (patch < 2)) { - LOG_TARGET_WARNING(target, "Silicon bug: single stepping may enter pending exception handler!"); + LOG_TARGET_WARNING(target, "Erratum 702596: single stepping may enter pending exception handler!"); cortex_m->maskints_erratum = true; } + /* TODO: add revision check when a Cortex-M7 revision with fixed 3092511 is out */ + LOG_TARGET_WARNING(target, "Erratum 3092511: Cortex-M7 can halt in an incorrect address when breakpoint and exception occurs simultaneously"); + cortex_m->incorrect_halt_erratum = true; + if (armv7m->is_hla_target) + LOG_TARGET_WARNING(target, "No erratum 3092511 workaround on hla adapter"); + else + LOG_TARGET_INFO(target, "The erratum 3092511 workaround will resume after an incorrect halt"); } LOG_TARGET_DEBUG(target, "cpuid: 0x%8.8" PRIx32 "", cpuid); @@ -2614,6 +2711,10 @@ int cortex_m_examine(struct target *target) for (size_t idx = ARMV7M_FPU_FIRST_REG; idx <= ARMV7M_FPU_LAST_REG; idx++) armv7m->arm.core_cache->reg_list[idx].exist = false; + /* TODO: MVE can be present without floating points. Revisit this test */ + if (armv7m->fp_feature != FPV5_MVE_F && armv7m->fp_feature != FPV5_MVE_I) + armv7m->arm.core_cache->reg_list[ARMV8M_VPR].exist = false; + if (!cortex_m_has_tz(target)) for (size_t idx = ARMV8M_FIRST_REG; idx <= ARMV8M_LAST_REG; idx++) armv7m->arm.core_cache->reg_list[idx].exist = false; @@ -2864,7 +2965,7 @@ COMMAND_HANDLER(handle_cortex_m_vector_catch_command) static const struct { char name[10]; - unsigned mask; + unsigned int mask; } vec_ids[] = { { "hard_err", VC_HARDERR, }, { "int_err", VC_INTERR, }, @@ -2890,7 +2991,7 @@ COMMAND_HANDLER(handle_cortex_m_vector_catch_command) return retval; if (CMD_ARGC > 0) { - unsigned catch = 0; + unsigned int catch = 0; if (CMD_ARGC == 1) { if (strcmp(CMD_ARGV[0], "all") == 0) { @@ -2902,7 +3003,7 @@ COMMAND_HANDLER(handle_cortex_m_vector_catch_command) goto write; } while (CMD_ARGC-- > 0) { - unsigned i; + unsigned int i; for (i = 0; i < ARRAY_SIZE(vec_ids); i++) { if (strcmp(CMD_ARGV[CMD_ARGC], vec_ids[i].name) != 0) continue; @@ -2935,7 +3036,7 @@ write: */ } - for (unsigned i = 0; i < ARRAY_SIZE(vec_ids); i++) { + for (unsigned int i = 0; i < ARRAY_SIZE(vec_ids); i++) { command_print(CMD, "%9s: %s", vec_ids[i].name, (demcr & vec_ids[i].mask) ? "catch" : "ignore"); } diff --git a/src/target/cortex_m.h b/src/target/cortex_m.h index a585b78..144f245 100644 --- a/src/target/cortex_m.h +++ b/src/target/cortex_m.h @@ -31,35 +31,36 @@ #define CPUID 0xE000ED00 -#define ARM_CPUID_IMPLEMENTOR_POS 24 -#define ARM_CPUID_IMPLEMENTOR_MASK (0xFF << ARM_CPUID_IMPLEMENTOR_POS) +#define ARM_CPUID_IMPLEMENTER_POS 24 +#define ARM_CPUID_IMPLEMENTER_MASK (0xFF << ARM_CPUID_IMPLEMENTER_POS) #define ARM_CPUID_PARTNO_POS 4 #define ARM_CPUID_PARTNO_MASK (0xFFF << ARM_CPUID_PARTNO_POS) -#define ARM_MAKE_CPUID(impl, partno) ((((impl) << ARM_CPUID_IMPLEMENTOR_POS) & ARM_CPUID_IMPLEMENTOR_MASK) | \ +#define ARM_MAKE_CPUID(impl, partno) ((((impl) << ARM_CPUID_IMPLEMENTER_POS) & ARM_CPUID_IMPLEMENTER_MASK) | \ (((partno) << ARM_CPUID_PARTNO_POS) & ARM_CPUID_PARTNO_MASK)) /** Known Arm Cortex masked CPU Ids - * This includes the implementor and part number, but _not_ the revision or + * This includes the implementer and part number, but _not_ the revision or * patch fields. */ enum cortex_m_impl_part { CORTEX_M_PARTNO_INVALID, - STAR_MC1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0x132), /* FIXME - confirm implementor! */ - CORTEX_M0_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC20), - CORTEX_M1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC21), - CORTEX_M3_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC23), - CORTEX_M4_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC24), - CORTEX_M7_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC27), - CORTEX_M0P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xC60), - CORTEX_M23_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD20), - CORTEX_M33_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD21), - CORTEX_M35P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD31), - CORTEX_M55_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD22), - CORTEX_M85_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_ARM, 0xD23), - INFINEON_SLX2_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_INFINEON, 0xDB0), - REALTEK_M200_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_REALTEK, 0xd20), - REALTEK_M300_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTOR_REALTEK, 0xd22), + STAR_MC1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM_CHINA, 0x132), + CORTEX_M0_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM, 0xC20), + CORTEX_M1_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM, 0xC21), + CORTEX_M3_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM, 0xC23), + CORTEX_M4_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM, 0xC24), + CORTEX_M7_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM, 0xC27), + CORTEX_M0P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM, 0xC60), + CORTEX_M23_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM, 0xD20), + CORTEX_M33_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM, 0xD21), + CORTEX_M35P_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM, 0xD31), + CORTEX_M52_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM_CHINA, 0xD24), + CORTEX_M55_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM, 0xD22), + CORTEX_M85_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_ARM, 0xD23), + INFINEON_SLX2_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_INFINEON, 0xDB0), + REALTEK_M200_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_REALTEK, 0xd20), + REALTEK_M300_PARTNO = ARM_MAKE_CPUID(ARM_IMPLEMENTER_REALTEK, 0xd22), }; /* Relevant Cortex-M flags, used in struct cortex_m_part_info.flags */ @@ -149,6 +150,7 @@ struct cortex_m_part_info { #define VC_CORERESET BIT(0) /* DCB_DSCSR bit and field definitions */ +#define DSCSR_CDSKEY BIT(17) #define DSCSR_CDS BIT(16) /* NVIC registers */ @@ -256,6 +258,10 @@ struct cortex_m_common { /* Whether this target has the erratum that makes C_MASKINTS not apply to * already pending interrupts */ bool maskints_erratum; + + /* Errata 3092511 Cortex-M7 can halt in an incorrect address when breakpoint + * and exception occurs simultaneously */ + bool incorrect_halt_erratum; }; static inline bool is_cortex_m_or_hla(const struct cortex_m_common *cortex_m) diff --git a/src/target/dsp563xx.c b/src/target/dsp563xx.c index 1e71803..629056f 100644 --- a/src/target/dsp563xx.c +++ b/src/target/dsp563xx.c @@ -220,9 +220,9 @@ enum dsp563xx_reg_idx { }; static const struct { - unsigned id; + unsigned int id; const char *name; - unsigned bits; + unsigned int bits; /* effective addressing mode encoding */ uint8_t eame; uint32_t instr_mask; @@ -1115,10 +1115,10 @@ static int dsp563xx_halt(struct target *target) } static int dsp563xx_resume(struct target *target, - int current, + bool current, target_addr_t address, - int handle_breakpoints, - int debug_execution) + bool handle_breakpoints, + bool debug_execution) { int err; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); @@ -1132,10 +1132,10 @@ static int dsp563xx_resume(struct target *target, if (current && dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_PC].dirty) { dsp563xx_write_core_reg(target, DSP563XX_REG_IDX_PC); address = dsp563xx->core_regs[DSP563XX_REG_IDX_PC]; - current = 0; + current = false; } - LOG_DEBUG("%s %08X %08X", __func__, current, (unsigned) address); + LOG_DEBUG("%s %08X %08" TARGET_PRIXADDR, __func__, current, address); err = dsp563xx_restore_context(target); if (err != ERROR_OK) @@ -1172,9 +1172,9 @@ static int dsp563xx_resume(struct target *target, } static int dsp563xx_step_ex(struct target *target, - int current, + bool current, uint32_t address, - int handle_breakpoints, + bool handle_breakpoints, int steps) { int err; @@ -1196,10 +1196,10 @@ static int dsp563xx_step_ex(struct target *target, if (current && dsp563xx->core_cache->reg_list[DSP563XX_REG_IDX_PC].dirty) { dsp563xx_write_core_reg(target, DSP563XX_REG_IDX_PC); address = dsp563xx->core_regs[DSP563XX_REG_IDX_PC]; - current = 0; + current = false; } - LOG_DEBUG("%s %08X %08X", __func__, current, (unsigned) address); + LOG_DEBUG("%s %08X %08" PRIX32, __func__, current, address); err = dsp563xx_jtag_debug_request(target); if (err != ERROR_OK) @@ -1260,15 +1260,15 @@ static int dsp563xx_step_ex(struct target *target, err = dsp563xx_once_reg_read(target->tap, 1, DSP563XX_ONCE_OPABFR, &dr_in); if (err != ERROR_OK) return err; - LOG_DEBUG("fetch: %08X", (unsigned) dr_in&0x00ffffff); + LOG_DEBUG("fetch: %08" PRIX32, dr_in & 0x00ffffff); err = dsp563xx_once_reg_read(target->tap, 1, DSP563XX_ONCE_OPABDR, &dr_in); if (err != ERROR_OK) return err; - LOG_DEBUG("decode: %08X", (unsigned) dr_in&0x00ffffff); + LOG_DEBUG("decode: %08" PRIX32, dr_in & 0x00ffffff); err = dsp563xx_once_reg_read(target->tap, 1, DSP563XX_ONCE_OPABEX, &dr_in); if (err != ERROR_OK) return err; - LOG_DEBUG("execute: %08X", (unsigned) dr_in&0x00ffffff); + LOG_DEBUG("execute: %08" PRIX32, dr_in & 0x00ffffff); /* reset trace mode */ err = dsp563xx_once_reg_write(target->tap, 1, DSP563XX_ONCE_OSCR, 0x000000); @@ -1288,9 +1288,9 @@ static int dsp563xx_step_ex(struct target *target, } static int dsp563xx_step(struct target *target, - int current, + bool current, target_addr_t address, - int handle_breakpoints) + bool handle_breakpoints) { int err; struct dsp563xx_common *dsp563xx = target_to_dsp563xx(target); @@ -1359,7 +1359,7 @@ static int dsp563xx_deassert_reset(struct target *target) * reset vector and need 2 cycles to fill * the cache (fetch,decode,execute) */ - err = dsp563xx_step_ex(target, 1, 0, 1, 1); + err = dsp563xx_step_ex(target, true, 0, true, 1); if (err != ERROR_OK) return err; } @@ -1419,7 +1419,7 @@ static int dsp563xx_run_algorithm(struct target *target, } /* exec */ - retval = target_resume(target, 0, entry_point, 1, 1); + retval = target_resume(target, false, entry_point, true, true); if (retval != ERROR_OK) return retval; @@ -1972,7 +1972,7 @@ static int dsp563xx_add_custom_watchpoint(struct target *target, uint32_t addres if (err == ERROR_OK && was_running) { /* Resume from current PC */ - err = dsp563xx_resume(target, 1, 0x0, 0, 0); + err = dsp563xx_resume(target, true, 0x0, false, false); } return err; diff --git a/src/target/dsp563xx_once.c b/src/target/dsp563xx_once.c index 866f331..bb41ae8 100644 --- a/src/target/dsp563xx_once.c +++ b/src/target/dsp563xx_once.c @@ -34,6 +34,8 @@ #define JTAG_INSTR_DEBUG_REQUEST 0x07 #define JTAG_INSTR_BYPASS 0x0F +static int dsp563xx_once_reg_read_ex(struct jtag_tap *tap, int flush, uint8_t reg, uint8_t len, uint32_t *data); + /** */ static inline int dsp563xx_write_dr(struct jtag_tap *tap, uint8_t *dr_in, uint8_t *dr_out, int dr_len, int rti) { @@ -185,7 +187,7 @@ int dsp563xx_once_read_register(struct jtag_tap *tap, int flush, struct once_reg } /** once read register with register len */ -int dsp563xx_once_reg_read_ex(struct jtag_tap *tap, int flush, uint8_t reg, uint8_t len, uint32_t *data) +static int dsp563xx_once_reg_read_ex(struct jtag_tap *tap, int flush, uint8_t reg, uint8_t len, uint32_t *data) { int err; diff --git a/src/target/dsp563xx_once.h b/src/target/dsp563xx_once.h index 8715488..4f27e1d 100644 --- a/src/target/dsp563xx_once.h +++ b/src/target/dsp563xx_once.h @@ -65,8 +65,6 @@ int dsp563xx_once_target_status(struct jtag_tap *tap); /** once read registers */ int dsp563xx_once_read_register(struct jtag_tap *tap, int flush, struct once_reg *regs, int len); /** once read register */ -int dsp563xx_once_reg_read_ex(struct jtag_tap *tap, int flush, uint8_t reg, uint8_t len, uint32_t *data); -/** once read register */ int dsp563xx_once_reg_read(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t *data); /** once write register */ int dsp563xx_once_reg_write(struct jtag_tap *tap, int flush, uint8_t reg, uint32_t data); diff --git a/src/target/dsp5680xx.c b/src/target/dsp5680xx.c index c90bca3..3f9a674 100644 --- a/src/target/dsp5680xx.c +++ b/src/target/dsp5680xx.c @@ -44,7 +44,7 @@ static int reset_jtag(void) { int retval; - tap_state_t states[2]; + enum tap_state states[2]; const char *cp = "RESET"; @@ -993,8 +993,8 @@ static int dsp5680xx_poll(struct target *target) return ERROR_OK; } -static int dsp5680xx_resume(struct target *target, int current, - target_addr_t address, int hb, int d) +static int dsp5680xx_resume(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, bool debug_execution) { if (target->state == TARGET_RUNNING) { LOG_USER("Target already running."); @@ -1172,7 +1172,7 @@ static int dsp5680xx_read(struct target *t, target_addr_t a, uint32_t size, dsp5680xx_context.flush = 0; int counter = FLUSH_COUNT_READ_WRITE; - for (unsigned i = 0; i < count; i++) { + for (unsigned int i = 0; i < count; i++) { if (--counter == 0) { dsp5680xx_context.flush = 1; counter = FLUSH_COUNT_READ_WRITE; @@ -2048,7 +2048,7 @@ int dsp5680xx_f_wr(struct target *t, const uint8_t *b, uint32_t a, uint32_t coun retval = core_tx_upper_data(target, tmp, &drscan_data); err_check_propagate(retval); - retval = dsp5680xx_resume(target, 0, ram_addr, 0, 0); + retval = dsp5680xx_resume(target, false, ram_addr, false, false); err_check_propagate(retval); int counter = FLUSH_COUNT_FLASH; @@ -2234,8 +2234,8 @@ int dsp5680xx_f_lock(struct target *target) return retval; } -static int dsp5680xx_step(struct target *target, int current, target_addr_t address, - int handle_breakpoints) +static int dsp5680xx_step(struct target *target, bool current, target_addr_t address, + bool handle_breakpoints) { err_check(ERROR_FAIL, DSP5680XX_ERROR_NOT_IMPLEMENTED_STEP, "Not implemented yet."); diff --git a/src/target/esirisc.c b/src/target/esirisc.c index 0f76b59..da40928 100644 --- a/src/target/esirisc.c +++ b/src/target/esirisc.c @@ -160,11 +160,11 @@ static int esirisc_disable_interrupts(struct target *target) uint32_t etc; int retval; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); retval = esirisc_jtag_read_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, &etc); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read Thread CSR: ETC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to read Thread CSR: ETC"); return retval; } @@ -172,7 +172,7 @@ static int esirisc_disable_interrupts(struct target *target) retval = esirisc_jtag_write_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, etc); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Thread CSR: ETC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Thread CSR: ETC"); return retval; } @@ -187,11 +187,11 @@ static int esirisc_enable_interrupts(struct target *target) uint32_t etc; int retval; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); retval = esirisc_jtag_read_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, &etc); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read Thread CSR: ETC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to read Thread CSR: ETC"); return retval; } @@ -199,7 +199,7 @@ static int esirisc_enable_interrupts(struct target *target) retval = esirisc_jtag_write_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, etc); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Thread CSR: ETC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Thread CSR: ETC"); return retval; } @@ -212,12 +212,12 @@ static int esirisc_save_interrupts(struct target *target) struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); int retval = esirisc_jtag_read_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, &esirisc->etc_save); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read Thread CSR: ETC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to read Thread CSR: ETC"); return retval; } @@ -229,12 +229,12 @@ static int esirisc_restore_interrupts(struct target *target) struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); int retval = esirisc_jtag_write_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETC, esirisc->etc_save); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Thread CSR: ETC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Thread CSR: ETC"); return retval; } @@ -247,12 +247,12 @@ static int esirisc_save_hwdc(struct target *target) struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); int retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_HWDC, &esirisc->hwdc_save); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read Thread CSR: HWDC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to read Thread CSR: HWDC"); return retval; } @@ -265,12 +265,12 @@ static int esirisc_restore_hwdc(struct target *target) struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); int retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_HWDC, esirisc->hwdc_save); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Debug CSR: HWDC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Debug CSR: HWDC"); return retval; } @@ -281,9 +281,9 @@ static int esirisc_save_context(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); - for (unsigned i = 0; i < esirisc->reg_cache->num_regs; ++i) { + for (unsigned int i = 0; i < esirisc->reg_cache->num_regs; ++i) { struct reg *reg = esirisc->reg_cache->reg_list + i; struct esirisc_reg *reg_info = reg->arch_info; @@ -298,9 +298,9 @@ static int esirisc_restore_context(struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); - for (unsigned i = 0; i < esirisc->reg_cache->num_regs; ++i) { + for (unsigned int i = 0; i < esirisc->reg_cache->num_regs; ++i) { struct reg *reg = esirisc->reg_cache->reg_list + i; struct esirisc_reg *reg_info = reg->arch_info; @@ -316,7 +316,7 @@ static int esirisc_flush_caches(struct target *target) struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); if (target->state != TARGET_HALTED) { LOG_TARGET_ERROR(target, "not halted"); @@ -325,7 +325,7 @@ static int esirisc_flush_caches(struct target *target) int retval = esirisc_jtag_flush_caches(jtag_info); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to flush caches", target_name(target)); + LOG_TARGET_ERROR(target, "failed to flush caches"); return retval; } @@ -337,7 +337,7 @@ static int esirisc_wait_debug_active(struct esirisc_common *esirisc, int ms) struct esirisc_jtag *jtag_info = &esirisc->jtag_info; int64_t t; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(esirisc->target, "-"); t = timeval_ms(); for (;;) { @@ -359,7 +359,7 @@ static int esirisc_read_memory(struct target *target, target_addr_t address, struct esirisc_jtag *jtag_info = &esirisc->jtag_info; int retval; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); int num_bits = 8 * size; for (uint32_t i = 0; i < count; ++i) { @@ -383,12 +383,12 @@ static int esirisc_read_memory(struct target *target, target_addr_t address, break; default: - LOG_ERROR("%s: unsupported size: %" PRIu32, target_name(target), size); + LOG_TARGET_ERROR(target, "unsupported size: %" PRIu32, size); return ERROR_FAIL; } if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read address: 0x%" TARGET_PRIxADDR, target_name(target), + LOG_TARGET_ERROR(target, "failed to read address: 0x%" TARGET_PRIxADDR, address); return retval; } @@ -408,7 +408,7 @@ static int esirisc_write_memory(struct target *target, target_addr_t address, struct esirisc_jtag *jtag_info = &esirisc->jtag_info; int retval; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); int num_bits = 8 * size; for (uint32_t i = 0; i < count; ++i) { @@ -431,12 +431,12 @@ static int esirisc_write_memory(struct target *target, target_addr_t address, break; default: - LOG_ERROR("%s: unsupported size: %" PRIu32, target_name(target), size); + LOG_TARGET_ERROR(target, "unsupported size: %" PRIu32, size); return ERROR_FAIL; } if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write address: 0x%" TARGET_PRIxADDR, target_name(target), + LOG_TARGET_ERROR(target, "failed to write address: 0x%" TARGET_PRIxADDR, address); return retval; } @@ -460,7 +460,7 @@ static int esirisc_next_breakpoint(struct target *target) struct breakpoint **breakpoints_p = esirisc->breakpoints_p; struct breakpoint **breakpoints_e = breakpoints_p + esirisc->num_breakpoints; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); for (int bp_index = 0; breakpoints_p < breakpoints_e; ++breakpoints_p, ++bp_index) if (!*breakpoints_p) @@ -477,13 +477,13 @@ static int esirisc_add_breakpoint(struct target *target, struct breakpoint *brea uint32_t ibc; int retval; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); /* * The default linker scripts provided by the eSi-RISC toolchain do * not specify attributes on memory regions, which results in * incorrect application of software breakpoints by GDB. Targets - * must be configured with `gdb_breakpoint_override hard` as + * must be configured with `gdb breakpoint_override hard` as * software breakpoints are not supported. */ if (breakpoint->type != BKPT_HARD) @@ -491,7 +491,7 @@ static int esirisc_add_breakpoint(struct target *target, struct breakpoint *brea bp_index = esirisc_next_breakpoint(target); if (bp_index < 0) { - LOG_ERROR("%s: out of hardware breakpoints", target_name(target)); + LOG_TARGET_ERROR(target, "out of hardware breakpoints"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } @@ -502,14 +502,14 @@ static int esirisc_add_breakpoint(struct target *target, struct breakpoint *brea retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBA_N + bp_index, breakpoint->address); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Debug CSR: IBA", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Debug CSR: IBA"); return retval; } /* enable instruction breakpoint */ retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, &ibc); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read Debug CSR: IBC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to read Debug CSR: IBC"); return retval; } @@ -517,7 +517,7 @@ static int esirisc_add_breakpoint(struct target *target, struct breakpoint *brea retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, ibc); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Debug CSR: IBC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Debug CSR: IBC"); return retval; } @@ -528,7 +528,7 @@ static int esirisc_add_breakpoints(struct target *target) { struct breakpoint *breakpoint = target->breakpoints; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); while (breakpoint) { if (!breakpoint->is_set) @@ -548,12 +548,12 @@ static int esirisc_remove_breakpoint(struct target *target, struct breakpoint *b uint32_t ibc; int retval; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); /* disable instruction breakpoint */ retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, &ibc); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read Debug CSR: IBC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to read Debug CSR: IBC"); return retval; } @@ -561,7 +561,7 @@ static int esirisc_remove_breakpoint(struct target *target, struct breakpoint *b retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, ibc); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Debug CSR: IBC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Debug CSR: IBC"); return retval; } @@ -576,12 +576,12 @@ static int esirisc_remove_breakpoints(struct target *target) struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); /* clear instruction breakpoints */ int retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_IBC, 0); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Debug CSR: IBC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Debug CSR: IBC"); return retval; } @@ -596,7 +596,7 @@ static int esirisc_next_watchpoint(struct target *target) struct watchpoint **watchpoints_p = esirisc->watchpoints_p; struct watchpoint **watchpoints_e = watchpoints_p + esirisc->num_watchpoints; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); for (int wp_index = 0; watchpoints_p < watchpoints_e; ++watchpoints_p, ++wp_index) if (!*watchpoints_p) @@ -613,11 +613,11 @@ static int esirisc_add_watchpoint(struct target *target, struct watchpoint *watc uint32_t dbs, dbc; int retval; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); wp_index = esirisc_next_watchpoint(target); if (wp_index < 0) { - LOG_ERROR("%s: out of hardware watchpoints", target_name(target)); + LOG_TARGET_ERROR(target, "out of hardware watchpoints"); return ERROR_FAIL; } @@ -628,14 +628,14 @@ static int esirisc_add_watchpoint(struct target *target, struct watchpoint *watc retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBA_N + wp_index, watchpoint->address); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Debug CSR: DBA", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Debug CSR: DBA"); return retval; } /* specify data breakpoint size */ retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBS, &dbs); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read Debug CSR: DBS", target_name(target)); + LOG_TARGET_ERROR(target, "failed to read Debug CSR: DBS"); return retval; } @@ -657,7 +657,7 @@ static int esirisc_add_watchpoint(struct target *target, struct watchpoint *watc break; default: - LOG_ERROR("%s: unsupported length: %" PRIu32, target_name(target), + LOG_TARGET_ERROR(target, "unsupported length: %" PRIu32, watchpoint->length); return ERROR_FAIL; } @@ -666,14 +666,14 @@ static int esirisc_add_watchpoint(struct target *target, struct watchpoint *watc retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBS, dbs); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Debug CSR: DBS", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Debug CSR: DBS"); return retval; } /* enable data breakpoint */ retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, &dbc); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read Debug CSR: DBC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to read Debug CSR: DBC"); return retval; } @@ -692,8 +692,7 @@ static int esirisc_add_watchpoint(struct target *target, struct watchpoint *watc break; default: - LOG_ERROR("%s: unsupported rw: %" PRId32, target_name(target), - watchpoint->rw); + LOG_TARGET_ERROR(target, "unsupported rw: %" PRId32, watchpoint->rw); return ERROR_FAIL; } @@ -701,7 +700,7 @@ static int esirisc_add_watchpoint(struct target *target, struct watchpoint *watc retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, dbc); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Debug CSR: DBC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Debug CSR: DBC"); return retval; } @@ -712,7 +711,7 @@ static int esirisc_add_watchpoints(struct target *target) { struct watchpoint *watchpoint = target->watchpoints; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); while (watchpoint) { if (!watchpoint->is_set) @@ -732,12 +731,12 @@ static int esirisc_remove_watchpoint(struct target *target, struct watchpoint *w uint32_t dbc; int retval; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); /* disable data breakpoint */ retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, &dbc); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read Debug CSR: DBC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to read Debug CSR: DBC"); return retval; } @@ -745,7 +744,7 @@ static int esirisc_remove_watchpoint(struct target *target, struct watchpoint *w retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, dbc); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Debug CSR: DBC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Debug CSR: DBC"); return retval; } @@ -760,12 +759,12 @@ static int esirisc_remove_watchpoints(struct target *target) struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); /* clear data breakpoints */ int retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DBC, 0); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Debug CSR: DBC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Debug CSR: DBC"); return retval; } @@ -779,14 +778,14 @@ static int esirisc_halt(struct target *target) struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); if (target->state == TARGET_HALTED) return ERROR_OK; int retval = esirisc_jtag_break(jtag_info); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to halt target", target_name(target)); + LOG_TARGET_ERROR(target, "failed to halt target"); return retval; } @@ -802,11 +801,11 @@ static int esirisc_disable_step(struct target *target) uint32_t dc; int retval; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DC, &dc); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read Debug CSR: DC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to read Debug CSR: DC"); return retval; } @@ -814,7 +813,7 @@ static int esirisc_disable_step(struct target *target) retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DC, dc); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Debug CSR: DC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Debug CSR: DC"); return retval; } @@ -828,11 +827,11 @@ static int esirisc_enable_step(struct target *target) uint32_t dc; int retval; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); retval = esirisc_jtag_read_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DC, &dc); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read Debug CSR: DC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to read Debug CSR: DC"); return retval; } @@ -840,22 +839,23 @@ static int esirisc_enable_step(struct target *target) retval = esirisc_jtag_write_csr(jtag_info, CSR_DEBUG, CSR_DEBUG_DC, dc); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Debug CSR: DC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Debug CSR: DC"); return retval; } return ERROR_OK; } -static int esirisc_resume_or_step(struct target *target, int current, target_addr_t address, - int handle_breakpoints, int debug_execution, bool step) +static int esirisc_resume_or_step(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, bool debug_execution, + bool step) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_jtag *jtag_info = &esirisc->jtag_info; struct breakpoint *breakpoint = NULL; int retval; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); if (target->state != TARGET_HALTED) { LOG_TARGET_ERROR(target, "not halted"); @@ -901,7 +901,7 @@ static int esirisc_resume_or_step(struct target *target, int current, target_add retval = esirisc_jtag_continue(jtag_info); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to resume target", target_name(target)); + LOG_TARGET_ERROR(target, "failed to resume target"); return retval; } @@ -918,22 +918,22 @@ static int esirisc_resume_or_step(struct target *target, int current, target_add return ERROR_OK; } -static int esirisc_resume(struct target *target, int current, target_addr_t address, - int handle_breakpoints, int debug_execution) +static int esirisc_resume(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, bool debug_execution) { - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); return esirisc_resume_or_step(target, current, address, handle_breakpoints, debug_execution, false); } -static int esirisc_step(struct target *target, int current, target_addr_t address, - int handle_breakpoints) +static int esirisc_step(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints) { - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); return esirisc_resume_or_step(target, current, address, - handle_breakpoints, 0, true); + handle_breakpoints, false, true); } static int esirisc_debug_step(struct target *target) @@ -942,20 +942,20 @@ static int esirisc_debug_step(struct target *target) struct esirisc_jtag *jtag_info = &esirisc->jtag_info; int retval; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); esirisc_disable_interrupts(target); esirisc_enable_step(target); retval = esirisc_jtag_continue(jtag_info); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to resume target", target_name(target)); + LOG_TARGET_ERROR(target, "failed to resume target"); return retval; } retval = esirisc_wait_debug_active(esirisc, STEP_TIMEOUT); if (retval != ERROR_OK) { - LOG_ERROR("%s: step timed out", target_name(target)); + LOG_TARGET_ERROR(target, "step timed out"); return retval; } @@ -971,23 +971,23 @@ static int esirisc_debug_reset(struct target *target) struct esirisc_jtag *jtag_info = &esirisc->jtag_info; int retval; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); retval = esirisc_jtag_assert_reset(jtag_info); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to assert reset", target_name(target)); + LOG_TARGET_ERROR(target, "failed to assert reset"); return retval; } retval = esirisc_jtag_deassert_reset(jtag_info); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to deassert reset", target_name(target)); + LOG_TARGET_ERROR(target, "failed to deassert reset"); return retval; } retval = esirisc_wait_debug_active(esirisc, RESET_TIMEOUT); if (retval != ERROR_OK) { - LOG_ERROR("%s: reset timed out", target_name(target)); + LOG_TARGET_ERROR(target, "reset timed out"); return retval; } @@ -1000,11 +1000,11 @@ static int esirisc_debug_enable(struct target *target) struct esirisc_jtag *jtag_info = &esirisc->jtag_info; int retval; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); retval = esirisc_jtag_enable_debug(jtag_info); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to enable debug mode", target_name(target)); + LOG_TARGET_ERROR(target, "failed to enable debug mode"); return retval; } @@ -1015,13 +1015,13 @@ static int esirisc_debug_enable(struct target *target) * targets, which will respond with all ones and appear active. */ if (esirisc_jtag_is_stopped(jtag_info)) { - LOG_INFO("%s: debug clock inactive; attempting debug reset", target_name(target)); + LOG_TARGET_INFO(target, "debug clock inactive; attempting debug reset"); retval = esirisc_debug_reset(target); if (retval != ERROR_OK) return retval; if (esirisc_jtag_is_stopped(jtag_info)) { - LOG_ERROR("%s: target unresponsive; giving up", target_name(target)); + LOG_TARGET_ERROR(target, "target unresponsive; giving up"); return ERROR_FAIL; } } @@ -1034,7 +1034,7 @@ static int esirisc_debug_entry(struct target *target) struct esirisc_common *esirisc = target_to_esirisc(target); struct breakpoint *breakpoint; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); esirisc_save_context(target); @@ -1087,12 +1087,12 @@ static int esirisc_poll(struct target *target) retval = esirisc_jtag_enable_debug(jtag_info); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to poll target", target_name(target)); + LOG_TARGET_ERROR(target, "failed to poll target"); return retval; } if (esirisc_jtag_is_stopped(jtag_info)) { - LOG_ERROR("%s: target has stopped; reset required", target_name(target)); + LOG_TARGET_ERROR(target, "target has stopped; reset required"); target->state = TARGET_UNKNOWN; return ERROR_TARGET_FAILURE; } @@ -1122,7 +1122,7 @@ static int esirisc_assert_reset(struct target *target) struct esirisc_jtag *jtag_info = &esirisc->jtag_info; int retval; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); if (jtag_get_reset_config() & RESET_HAS_SRST) { jtag_add_reset(1, 1); @@ -1134,7 +1134,7 @@ static int esirisc_assert_reset(struct target *target) retval = esirisc_jtag_assert_reset(jtag_info); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to assert reset", target_name(target)); + LOG_TARGET_ERROR(target, "failed to assert reset"); return retval; } } @@ -1153,19 +1153,19 @@ static int esirisc_reset_entry(struct target *target) uint32_t eta, epc; int retval; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); /* read exception table address */ retval = esirisc_jtag_read_csr(jtag_info, CSR_THREAD, CSR_THREAD_ETA, &eta); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read Thread CSR: ETA", target_name(target)); + LOG_TARGET_ERROR(target, "failed to read Thread CSR: ETA"); return retval; } /* read reset entry point */ retval = esirisc_jtag_read_word(jtag_info, eta + ENTRY_RESET, &epc); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read address: 0x%" TARGET_PRIxADDR, target_name(target), + LOG_TARGET_ERROR(target, "failed to read address: 0x%" TARGET_PRIxADDR, (target_addr_t)epc); return retval; } @@ -1173,7 +1173,7 @@ static int esirisc_reset_entry(struct target *target) /* write reset entry point */ retval = esirisc_jtag_write_csr(jtag_info, CSR_THREAD, CSR_THREAD_EPC, epc); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Thread CSR: EPC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Thread CSR: EPC"); return retval; } @@ -1186,7 +1186,7 @@ static int esirisc_deassert_reset(struct target *target) struct esirisc_jtag *jtag_info = &esirisc->jtag_info; int retval; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); if (jtag_get_reset_config() & RESET_HAS_SRST) { jtag_add_reset(0, 0); @@ -1202,14 +1202,14 @@ static int esirisc_deassert_reset(struct target *target) } else { retval = esirisc_jtag_deassert_reset(jtag_info); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to deassert reset", target_name(target)); + LOG_TARGET_ERROR(target, "failed to deassert reset"); return retval; } } retval = esirisc_wait_debug_active(esirisc, RESET_TIMEOUT); if (retval != ERROR_OK) { - LOG_ERROR("%s: reset timed out", target_name(target)); + LOG_TARGET_ERROR(target, "reset timed out"); return retval; } @@ -1225,7 +1225,7 @@ static int esirisc_deassert_reset(struct target *target) if (!target->reset_halt) { retval = esirisc_jtag_continue(jtag_info); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to resume target", target_name(target)); + LOG_TARGET_ERROR(target, "failed to resume target"); return retval; } } @@ -1241,7 +1241,7 @@ static int esirisc_arch_state(struct target *target) uint32_t eid = buf_get_u32(esirisc->eid->value, 0, esirisc->eid->size); uint32_t ed = buf_get_u32(esirisc->ed->value, 0, esirisc->ed->size); - LOG_USER("target halted due to %s, exception: %s\n" + LOG_TARGET_USER(target, "target halted due to %s, exception: %s\n" "EPC: 0x%" PRIx32 ", ECAS: 0x%" PRIx32 ", EID: 0x%" PRIx32 ", ED: 0x%" PRIx32, debug_reason_name(target), esirisc_exception_strings[eid], epc, ecas, eid, ed); @@ -1252,7 +1252,7 @@ static const char *esirisc_get_gdb_arch(const struct target *target) { struct esirisc_common *esirisc = target_to_esirisc(target); - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); /* * Targets with the UNIFIED_ADDRESS_SPACE option disabled employ a @@ -1272,7 +1272,7 @@ static int esirisc_get_gdb_reg_list(struct target *target, struct reg **reg_list { struct esirisc_common *esirisc = target_to_esirisc(target); - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); *reg_list_size = ESIRISC_NUM_REGS; @@ -1302,11 +1302,11 @@ static int esirisc_read_reg(struct reg *reg) struct target *target = esirisc->target; uint32_t data; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); int retval = esirisc_jtag_read_reg(jtag_info, reg->number, &data); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read register: %s", target_name(target), reg->name); + LOG_TARGET_ERROR(target, "failed to read register: %s", reg->name); return retval; } @@ -1325,11 +1325,11 @@ static int esirisc_write_reg(struct reg *reg) struct target *target = esirisc->target; uint32_t data = buf_get_u32(reg->value, 0, reg->size); - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); int retval = esirisc_jtag_write_reg(jtag_info, reg->number, data); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write register: %s", target_name(target), reg->name); + LOG_TARGET_ERROR(target, "failed to write register: %s", reg->name); return retval; } @@ -1347,11 +1347,11 @@ static int esirisc_read_csr(struct reg *reg) struct target *target = esirisc->target; uint32_t data; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); int retval = esirisc_jtag_read_csr(jtag_info, reg_info->bank, reg_info->csr, &data); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read CSR: %s", target_name(target), reg->name); + LOG_TARGET_ERROR(target, "failed to read CSR: %s", reg->name); return retval; } @@ -1370,11 +1370,11 @@ static int esirisc_write_csr(struct reg *reg) struct target *target = esirisc->target; uint32_t data = buf_get_u32(reg->value, 0, reg->size); - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); int retval = esirisc_jtag_write_csr(jtag_info, reg_info->bank, reg_info->csr, data); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write CSR: %s", target_name(target), reg->name); + LOG_TARGET_ERROR(target, "failed to write CSR: %s", reg->name); return retval; } @@ -1390,7 +1390,7 @@ static int esirisc_get_reg(struct reg *reg) struct esirisc_common *esirisc = reg_info->esirisc; struct target *target = esirisc->target; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; @@ -1405,7 +1405,7 @@ static int esirisc_set_reg(struct reg *reg, uint8_t *buf) struct target *target = esirisc->target; uint32_t value = buf_get_u32(buf, 0, reg->size); - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; @@ -1429,7 +1429,7 @@ static struct reg_cache *esirisc_build_reg_cache(struct target *target) struct reg_cache *cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = calloc(ESIRISC_NUM_REGS, sizeof(struct reg)); - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); cache->name = "eSi-RISC registers"; cache->next = NULL; @@ -1519,11 +1519,11 @@ static int esirisc_identify(struct target *target) uint32_t csr; int retval; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_ARCH0, &csr); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read Configuration CSR: ARCH0", target_name(target)); + LOG_TARGET_ERROR(target, "failed to read Configuration CSR: ARCH0"); return retval; } @@ -1532,7 +1532,7 @@ static int esirisc_identify(struct target *target) retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_MEM, &csr); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read Configuration CSR: MEM", target_name(target)); + LOG_TARGET_ERROR(target, "failed to read Configuration CSR: MEM"); return retval; } @@ -1541,7 +1541,7 @@ static int esirisc_identify(struct target *target) retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_IC, &csr); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read Configuration CSR: IC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to read Configuration CSR: IC"); return retval; } @@ -1549,7 +1549,7 @@ static int esirisc_identify(struct target *target) retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_DC, &csr); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read Configuration CSR: DC", target_name(target)); + LOG_TARGET_ERROR(target, "failed to read Configuration CSR: DC"); return retval; } @@ -1557,7 +1557,7 @@ static int esirisc_identify(struct target *target) retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_DBG, &csr); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read Configuration CSR: DBG", target_name(target)); + LOG_TARGET_ERROR(target, "failed to read Configuration CSR: DBG"); return retval; } @@ -1566,7 +1566,7 @@ static int esirisc_identify(struct target *target) retval = esirisc_jtag_read_csr(jtag_info, CSR_CONFIG, CSR_CONFIG_TRACE, &csr); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read Configuration CSR: TRACE", target_name(target)); + LOG_TARGET_ERROR(target, "failed to read Configuration CSR: TRACE"); return retval; } @@ -1584,8 +1584,7 @@ static int esirisc_target_create(struct target *target, Jim_Interp *interp) return ERROR_FAIL; if (tap->ir_length != INSTR_LENGTH) { - LOG_ERROR("%s: invalid IR length; expected %d", target_name(target), - INSTR_LENGTH); + LOG_TARGET_ERROR(target, "invalid IR length; expected %d", INSTR_LENGTH); return ERROR_FAIL; } @@ -1629,7 +1628,7 @@ static int esirisc_examine(struct target *target) struct esirisc_jtag *jtag_info = &esirisc->jtag_info; int retval; - LOG_DEBUG("-"); + LOG_TARGET_DEBUG(target, "-"); if (!target_was_examined(target)) { retval = esirisc_debug_enable(target); @@ -1649,7 +1648,7 @@ static int esirisc_examine(struct target *target) } else { retval = esirisc_jtag_break(jtag_info); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to halt target", target_name(target)); + LOG_TARGET_ERROR(target, "failed to halt target"); return retval; } @@ -1658,7 +1657,7 @@ static int esirisc_examine(struct target *target) retval = esirisc_identify(target); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to identify target", target_name(target)); + LOG_TARGET_ERROR(target, "failed to identify target"); return retval; } @@ -1675,20 +1674,20 @@ static int esirisc_examine(struct target *target) else { retval = esirisc_jtag_continue(jtag_info); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to resume target", target_name(target)); + LOG_TARGET_ERROR(target, "failed to resume target"); return retval; } } target_set_examined(target); - LOG_INFO("%s: %d bit, %d registers, %s%s%s", target_name(target), + LOG_TARGET_INFO(target, "%d bit, %d registers, %s%s%s", esirisc->num_bits, esirisc->num_regs, target_endianness(target), esirisc->has_icache ? ", icache" : "", esirisc->has_dcache ? ", dcache" : ""); - LOG_INFO("%s: hardware has %d breakpoints, %d watchpoints%s", target_name(target), + LOG_TARGET_INFO(target, "hardware has %d breakpoints, %d watchpoints%s", esirisc->num_breakpoints, esirisc->num_watchpoints, esirisc->has_trace ? ", trace" : ""); } @@ -1707,7 +1706,7 @@ COMMAND_HANDLER(handle_esirisc_cache_arch_command) else if (strcmp(*CMD_ARGV, "von_neumann") == 0) esirisc->cache_arch = ESIRISC_CACHE_VON_NEUMANN; else { - LOG_ERROR("invalid cache_arch: %s", *CMD_ARGV); + LOG_TARGET_ERROR(target, "invalid cache_arch: %s", *CMD_ARGV); return ERROR_COMMAND_SYNTAX_ERROR; } } @@ -1724,7 +1723,7 @@ COMMAND_HANDLER(handle_esirisc_flush_caches_command) int retval; if (!esirisc_has_cache(esirisc)) { - LOG_ERROR("target does not support caching"); + LOG_TARGET_ERROR(target, "target does not support caching"); return ERROR_FAIL; } @@ -1770,7 +1769,7 @@ COMMAND_HANDLER(handle_esirisc_hwdc_command) while (CMD_ARGC-- > 0) { int mask = esirisc_find_hwdc_mask(CMD_ARGV[CMD_ARGC]); if (mask < 0) { - LOG_ERROR("invalid mask: %s", CMD_ARGV[CMD_ARGC]); + LOG_TARGET_ERROR(target, "invalid mask: %s", CMD_ARGV[CMD_ARGC]); return ERROR_COMMAND_SYNTAX_ERROR; } esirisc->hwdc_save |= mask; diff --git a/src/target/esirisc_jtag.c b/src/target/esirisc_jtag.c index 1ec1726..ad2bef5 100644 --- a/src/target/esirisc_jtag.c +++ b/src/target/esirisc_jtag.c @@ -19,6 +19,8 @@ #include "esirisc_jtag.h" +static uint8_t esirisc_jtag_get_eid(struct esirisc_jtag *jtag_info); + static void esirisc_jtag_set_instr(struct esirisc_jtag *jtag_info, uint32_t new_instr) { struct jtag_tap *tap = jtag_info->tap; @@ -58,11 +60,12 @@ static int esirisc_jtag_get_padding(void) return padding; } -static int esirisc_jtag_count_bits(int num_fields, struct scan_field *fields) +static int esirisc_jtag_count_bits(unsigned int num_fields, + struct scan_field *fields) { int bit_count = 0; - for (int i = 0; i < num_fields; ++i) + for (unsigned int i = 0; i < num_fields; ++i) bit_count += fields[i].num_bits; return bit_count; @@ -220,7 +223,7 @@ bool esirisc_jtag_is_stopped(struct esirisc_jtag *jtag_info) return !!(jtag_info->status & 1<<6); /* S */ } -uint8_t esirisc_jtag_get_eid(struct esirisc_jtag *jtag_info) +static uint8_t esirisc_jtag_get_eid(struct esirisc_jtag *jtag_info) { return jtag_info->status & 0x3f; /* EID */ } @@ -489,7 +492,7 @@ int esirisc_jtag_enable_debug(struct esirisc_jtag *jtag_info) return esirisc_jtag_send_ctrl(jtag_info, DEBUG_ENABLE_DEBUG); } -int esirisc_jtag_disable_debug(struct esirisc_jtag *jtag_info) +static __attribute__((unused)) int esirisc_jtag_disable_debug(struct esirisc_jtag *jtag_info) { return esirisc_jtag_send_ctrl(jtag_info, DEBUG_DISABLE_DEBUG); } diff --git a/src/target/esirisc_jtag.h b/src/target/esirisc_jtag.h index 98ec8af..d59b75f 100644 --- a/src/target/esirisc_jtag.h +++ b/src/target/esirisc_jtag.h @@ -54,7 +54,6 @@ struct esirisc_jtag { bool esirisc_jtag_is_debug_active(struct esirisc_jtag *jtag_info); bool esirisc_jtag_is_stopped(struct esirisc_jtag *jtag_info); -uint8_t esirisc_jtag_get_eid(struct esirisc_jtag *jtag_info); int esirisc_jtag_read_byte(struct esirisc_jtag *jtag_info, uint32_t address, uint8_t *data); @@ -81,7 +80,6 @@ int esirisc_jtag_write_csr(struct esirisc_jtag *jtag_info, uint8_t bank, uint8_t csr, uint32_t data); int esirisc_jtag_enable_debug(struct esirisc_jtag *jtag_info); -int esirisc_jtag_disable_debug(struct esirisc_jtag *jtag_info); int esirisc_jtag_assert_reset(struct esirisc_jtag *jtag_info); int esirisc_jtag_deassert_reset(struct esirisc_jtag *jtag_info); diff --git a/src/target/esirisc_trace.c b/src/target/esirisc_trace.c index 376ea1d..a1d92d1 100644 --- a/src/target/esirisc_trace.c +++ b/src/target/esirisc_trace.c @@ -85,7 +85,7 @@ static int esirisc_trace_clear_status(struct target *target) retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_STATUS, ~0); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Trace CSR: Status", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Trace CSR: Status"); return retval; } @@ -102,7 +102,7 @@ static int esirisc_trace_get_status(struct target *target, uint32_t *status) int retval = esirisc_jtag_read_csr(jtag_info, CSR_TRACE, CSR_TRACE_STATUS, status); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read Trace CSR: Status", target_name(target)); + LOG_TARGET_ERROR(target, "failed to read Trace CSR: Status"); return retval; } @@ -121,7 +121,7 @@ static int esirisc_trace_start(struct target *target) retval = esirisc_jtag_read_csr(jtag_info, CSR_TRACE, CSR_TRACE_CONTROL, &control); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read Trace CSR: Control", target_name(target)); + LOG_TARGET_ERROR(target, "failed to read Trace CSR: Control"); return retval; } @@ -129,7 +129,7 @@ static int esirisc_trace_start(struct target *target) retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_CONTROL, control); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Trace CSR: Control", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Trace CSR: Control"); return retval; } @@ -148,7 +148,7 @@ static int esirisc_trace_stop(struct target *target) retval = esirisc_jtag_read_csr(jtag_info, CSR_TRACE, CSR_TRACE_CONTROL, &control); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read Trace CSR: Control", target_name(target)); + LOG_TARGET_ERROR(target, "failed to read Trace CSR: Control"); return retval; } @@ -156,7 +156,7 @@ static int esirisc_trace_stop(struct target *target) retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_CONTROL, control); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Trace CSR: Control", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Trace CSR: Control"); return retval; } @@ -195,7 +195,7 @@ static int esirisc_trace_init(struct target *target) retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_CONTROL, control); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Trace CSR: Control", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Trace CSR: Control"); return retval; } @@ -203,14 +203,14 @@ static int esirisc_trace_init(struct target *target) retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_BUFFER_START, trace_info->buffer_start); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Trace CSR: BufferStart", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Trace CSR: BufferStart"); return retval; } retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_BUFFER_END, trace_info->buffer_end); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Trace CSR: BufferEnd", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Trace CSR: BufferEnd"); return retval; } @@ -221,7 +221,7 @@ static int esirisc_trace_init(struct target *target) retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_BUFFER_CUR, trace_info->buffer_start); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Trace CSR: BufferCurrent", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Trace CSR: BufferCurrent"); return retval; } @@ -241,7 +241,7 @@ static int esirisc_trace_init(struct target *target) retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_TRIGGER, trigger); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Trace CSR: Trigger", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Trace CSR: Trigger"); return retval; } @@ -249,14 +249,14 @@ static int esirisc_trace_init(struct target *target) retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_START_DATA, trace_info->start_data); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Trace CSR: StartData", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Trace CSR: StartData"); return retval; } retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_START_MASK, trace_info->start_mask); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Trace CSR: StartMask", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Trace CSR: StartMask"); return retval; } @@ -264,14 +264,14 @@ static int esirisc_trace_init(struct target *target) retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_STOP_DATA, trace_info->stop_data); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Trace CSR: StopData", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Trace CSR: StopData"); return retval; } retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_STOP_MASK, trace_info->stop_mask); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Trace CSR: StopMask", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Trace CSR: StopMask"); return retval; } @@ -279,7 +279,7 @@ static int esirisc_trace_init(struct target *target) retval = esirisc_jtag_write_csr(jtag_info, CSR_TRACE, CSR_TRACE_DELAY, trace_info->delay_cycles); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to write Trace CSR: Delay", target_name(target)); + LOG_TARGET_ERROR(target, "failed to write Trace CSR: Delay"); return retval; } @@ -287,9 +287,9 @@ static int esirisc_trace_init(struct target *target) } static int esirisc_trace_buf_get_u32(uint8_t *buffer, uint32_t size, - unsigned *pos, unsigned count, uint32_t *value) + unsigned int *pos, unsigned int count, uint32_t *value) { - const unsigned num_bits = size * 8; + const unsigned int num_bits = size * 8; if (*pos+count > num_bits) return ERROR_FAIL; @@ -301,7 +301,7 @@ static int esirisc_trace_buf_get_u32(uint8_t *buffer, uint32_t size, } static int esirisc_trace_buf_get_pc(struct target *target, uint8_t *buffer, uint32_t size, - unsigned *pos, uint32_t *value) + unsigned int *pos, uint32_t *value) { struct esirisc_common *esirisc = target_to_esirisc(target); struct esirisc_trace *trace_info = &esirisc->trace_info; @@ -326,7 +326,7 @@ static int esirisc_trace_read_memory(struct target *target, target_addr_t addres retval = target_read_memory(target, address, 1, size, buffer); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read trace data", target_name(target)); + LOG_TARGET_ERROR(target, "failed to read trace data"); return retval; } @@ -346,7 +346,7 @@ static int esirisc_trace_read_buffer(struct target *target, uint8_t *buffer) retval = esirisc_jtag_read_csr(jtag_info, CSR_TRACE, CSR_TRACE_BUFFER_CUR, &buffer_cur); if (retval != ERROR_OK) { - LOG_ERROR("%s: failed to read Trace CSR: BufferCurrent", target_name(target)); + LOG_TARGET_ERROR(target, "failed to read Trace CSR: BufferCurrent"); return retval; } @@ -380,7 +380,7 @@ static int esirisc_trace_analyze_full(struct command_invocation *cmd, uint8_t *b const uint32_t num_bits = size * 8; int retval; - unsigned pos = 0; + unsigned int pos = 0; while (pos < num_bits) { uint32_t id; @@ -484,7 +484,7 @@ static int esirisc_trace_analyze_simple(struct command_invocation *cmd, uint8_t const uint32_t num_bits = size * 8; int retval; - unsigned pos = 0; + unsigned int pos = 0; while (pos < num_bits) { uint32_t pc; diff --git a/src/target/espressif/esp32.c b/src/target/espressif/esp32.c index 324aa39..4deb5e0 100644 --- a/src/target/espressif/esp32.c +++ b/src/target/espressif/esp32.c @@ -175,7 +175,8 @@ static int esp32_soc_reset(struct target *target) LOG_DEBUG("Resuming the target"); xtensa = target_to_xtensa(target); xtensa->suppress_dsr_errors = true; - res = xtensa_resume(target, 0, ESP32_RTC_SLOW_MEM_BASE + 4, 0, 0); + res = xtensa_resume(target, false, ESP32_RTC_SLOW_MEM_BASE + 4, false, + false); xtensa->suppress_dsr_errors = false; if (res != ERROR_OK) { LOG_ERROR("Failed to run stub (%d)!", res); diff --git a/src/target/espressif/esp32_apptrace.c b/src/target/espressif/esp32_apptrace.c index 125f366..3070960 100644 --- a/src/target/espressif/esp32_apptrace.c +++ b/src/target/espressif/esp32_apptrace.c @@ -649,7 +649,7 @@ static int esp32_apptrace_wait4halt(struct esp32_apptrace_cmd_ctx *ctx, struct t if (res != ERROR_OK) return res; if (target->state == TARGET_HALTED) { - LOG_USER("%s: HALTED", target->cmd_name); + LOG_TARGET_USER(target, "HALTED"); break; } alive_sleep(500); @@ -708,7 +708,7 @@ int esp32_apptrace_safe_halt_targets(struct esp32_apptrace_cmd_ctx *ctx, } while (stat) { /* allow this CPU to leave ERI write critical section */ - res = target_resume(ctx->cpus[k], 1, 0, 1, 0); + res = target_resume(ctx->cpus[k], true, 0, true, false); if (res != ERROR_OK) { LOG_ERROR("Failed to resume target (%d)!", res); breakpoint_remove(ctx->cpus[k], bp_addr); @@ -796,7 +796,7 @@ static int esp32_apptrace_connect_targets(struct esp32_apptrace_cmd_ctx *ctx, /* in SMP mode we need to call target_resume for one core only */ continue; } - res = target_resume(ctx->cpus[k], 1, 0, 1, 0); + res = target_resume(ctx->cpus[k], true, 0, true, false); if (res != ERROR_OK) { command_print(ctx->cmd, "Failed to resume target (%d)!", res); return res; @@ -1352,7 +1352,7 @@ static int esp32_sysview_stop(struct esp32_apptrace_cmd_ctx *ctx) /* in SMP mode we need to call target_resume for one core only */ continue; } - res = target_resume(ctx->cpus[k], 1, 0, 1, 0); + res = target_resume(ctx->cpus[k], true, 0, true, false); if (res != ERROR_OK) { LOG_ERROR("sysview: Failed to resume target '%s' (%d)!", target_name(ctx->cpus[k]), res); return res; diff --git a/src/target/espressif/esp32s2.c b/src/target/espressif/esp32s2.c index 2abde47..4f3914f 100644 --- a/src/target/espressif/esp32s2.c +++ b/src/target/espressif/esp32s2.c @@ -370,7 +370,8 @@ static int esp32s2_on_halt(struct target *target) return ret; } -static int esp32s2_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) +static int esp32s2_step(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints) { int ret = xtensa_step(target, current, address, handle_breakpoints); if (ret == ERROR_OK) { @@ -397,7 +398,7 @@ static int esp32s2_poll(struct target *target) if (ret == ERROR_OK && esp_xtensa->semihost.need_resume) { esp_xtensa->semihost.need_resume = false; /* Resume xtensa_resume will handle BREAK instruction. */ - ret = target_resume(target, 1, 0, 1, 0); + ret = target_resume(target, true, 0, true, false); if (ret != ERROR_OK) { LOG_ERROR("Failed to resume target"); return ret; diff --git a/src/target/espressif/esp32s3.c b/src/target/espressif/esp32s3.c index 22e1630..7507c11 100644 --- a/src/target/espressif/esp32s3.c +++ b/src/target/espressif/esp32s3.c @@ -175,7 +175,8 @@ static int esp32s3_soc_reset(struct target *target) LOG_DEBUG("Resuming the target"); xtensa = target_to_xtensa(target); xtensa->suppress_dsr_errors = true; - res = xtensa_resume(target, 0, ESP32_S3_RTC_SLOW_MEM_BASE + 4, 0, 0); + res = xtensa_resume(target, false, ESP32_S3_RTC_SLOW_MEM_BASE + 4, false, + false); xtensa->suppress_dsr_errors = false; if (res != ERROR_OK) { LOG_ERROR("Failed to run stub (%d)!", res); @@ -421,4 +422,5 @@ struct target_type esp32s3_target = { .deinit_target = esp_xtensa_target_deinit, .commands = esp32s3_command_handlers, + .profiling = esp_xtensa_profiling, }; diff --git a/src/target/espressif/esp_algorithm.h b/src/target/espressif/esp_algorithm.h index 11d2757..185234f 100644 --- a/src/target/espressif/esp_algorithm.h +++ b/src/target/espressif/esp_algorithm.h @@ -36,11 +36,13 @@ * Procedure of executing stub on target includes: * 1) User prepares struct esp_algorithm_run_data and calls one of algorithm_run_xxx() functions. * 2) Routine allocates all necessary stub code and data sections. - * 3) If a user specifies an initializer func esp_algorithm_usr_func_init_t it is called just before the stub starts. - * 4) If user specifies stub communication func esp_algorithm_usr_func_t (@see esp_flash_write/read in ESP flash driver) + * 3) If a user specifies an initializer func esp_algorithm_run_data::usr_func_init + * it is called just before the stub starts. + * 4) If user specifies stub communication func esp_algorithm_run_data::usr_func + * (@see esp_flash_write/read in ESP flash driver) * it is called just after the stub starts. When communication with stub is finished this function must return. * 5) OpenOCD waits for the stub to finish (hit exit breakpoint). - * 6) If the user specified arguments cleanup func esp_algorithm_usr_func_done_t, + * 6) If the user specified arguments cleanup func esp_algorithm_run_data::usr_func_done, * it is called just after the stub finishes. * * There are two options to run code on target under OpenOCD control: @@ -190,60 +192,6 @@ struct esp_algorithm_reg_args { struct esp_algorithm_run_data; -/** - * @brief Algorithm run function. - * - * @param target Pointer to target. - * @param run Pointer to algo run data. - * @param arg Function specific argument. - * - * @return ERROR_OK on success, otherwise ERROR_XXX. - */ -typedef int (*esp_algorithm_func_t)(struct target *target, struct esp_algorithm_run_data *run, void *arg); - -/** - * @brief Host part of algorithm. - * This function will be called while stub is running on target. - * It can be used for communication with stub. - * - * @param target Pointer to target. - * @param usr_arg Function specific argument. - * - * @return ERROR_OK on success, otherwise ERROR_XXX. - */ -typedef int (*esp_algorithm_usr_func_t)(struct target *target, void *usr_arg); - -/** - * @brief Algorithm's arguments setup function. - * This function will be called just before stub start. - * It must return when all operations with running stub are completed. - * It can be used to prepare stub memory parameters. - * - * @param target Pointer to target. - * @param run Pointer to algo run data. - * @param usr_arg Function specific argument. The same as for esp_algorithm_usr_func_t. - * - * @return ERROR_OK on success, otherwise ERROR_XXX. - */ -typedef int (*esp_algorithm_usr_func_init_t)(struct target *target, - struct esp_algorithm_run_data *run, - void *usr_arg); - -/** - * @brief Algorithm's arguments cleanup function. - * This function will be called just after stub exit. - * It can be used to cleanup stub memory parameters. - * - * @param target Pointer to target. - * @param run Pointer to algo run data. - * @param usr_arg Function specific argument. The same as for esp_algorithm_usr_func_t. - * - * @return ERROR_OK on success, otherwise ERROR_XXX. - */ -typedef void (*esp_algorithm_usr_func_done_t)(struct target *target, - struct esp_algorithm_run_data *run, - void *usr_arg); - struct esp_algorithm_hw { int (*algo_init)(struct target *target, struct esp_algorithm_run_data *run, uint32_t num_args, va_list ap); int (*algo_cleanup)(struct target *target, struct esp_algorithm_run_data *run); @@ -283,14 +231,61 @@ struct esp_algorithm_run_data { }; /** Host side algorithm function argument. */ void *usr_func_arg; - /** Host side algorithm function. */ - esp_algorithm_usr_func_t usr_func; - /** Host side algorithm function setup routine. */ - esp_algorithm_usr_func_init_t usr_func_init; - /** Host side algorithm function cleanup routine. */ - esp_algorithm_usr_func_done_t usr_func_done; - /** Algorithm run function: see algorithm_run_xxx for example. */ - esp_algorithm_func_t algo_func; + + /** + * @brief Host part of algorithm. + * This function will be called while stub is running on target. + * It can be used for communication with stub. + * + * @param target Pointer to target. + * @param usr_arg Function specific argument. + * + * @return ERROR_OK on success, otherwise ERROR_XXX. + */ + int (*usr_func)(struct target *target, void *usr_arg); + + /** + * @brief Algorithm's arguments setup function. + * This function will be called just before stub start. + * It must return when all operations with running stub are completed. + * It can be used to prepare stub memory parameters. + * + * @param target Pointer to target. + * @param run Pointer to algo run data. + * @param usr_arg Function specific argument. The same as for usr_func. + * + * @return ERROR_OK on success, otherwise ERROR_XXX. + */ + int (*usr_func_init)(struct target *target, + struct esp_algorithm_run_data *run, + void *usr_arg); + + /** + * @brief Algorithm's arguments cleanup function. + * This function will be called just after stub exit. + * It can be used to cleanup stub memory parameters. + * + * @param target Pointer to target. + * @param run Pointer to algo run data. + * @param usr_arg Function specific argument. The same as for usr_func. + * + * @return ERROR_OK on success, otherwise ERROR_XXX. + */ + void (*usr_func_done)(struct target *target, + struct esp_algorithm_run_data *run, + void *usr_arg); + + /** + * @brief Algorithm run function. + * + * @param target Pointer to target. + * @param run Pointer to algo run data. + * @param arg Function specific argument. + * + * @return ERROR_OK on success, otherwise ERROR_XXX. + */ + int (*algo_func)(struct target *target, struct esp_algorithm_run_data *run, void *arg); + /** HW specific API */ const struct esp_algorithm_hw *hw; }; diff --git a/src/target/espressif/esp_xtensa.c b/src/target/espressif/esp_xtensa.c index 11895d2..4cadcb3 100644 --- a/src/target/espressif/esp_xtensa.c +++ b/src/target/espressif/esp_xtensa.c @@ -179,3 +179,75 @@ int esp_xtensa_breakpoint_remove(struct target *target, struct breakpoint *break return xtensa_breakpoint_remove(target, breakpoint); /* flash breakpoints will be handled in another patch */ } + +int esp_xtensa_profiling(struct target *target, uint32_t *samples, + uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds) +{ + struct timeval timeout, now; + struct xtensa *xtensa = target_to_xtensa(target); + int retval = ERROR_OK; + int res; + + /* Vary samples per pass to avoid sampling a periodic function periodically */ + #define MIN_PASS 200 + #define MAX_PASS 1000 + + gettimeofday(&timeout, NULL); + timeval_add_time(&timeout, seconds, 0); + + uint8_t buf[sizeof(uint32_t) * MAX_PASS]; + + /* Capture one sample to verify the register is present and working */ + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DEBUGPC, buf); + res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_TARGET_INFO(target, "Failed to read DEBUGPC, fallback to stop-and-go"); + return target_profiling_default(target, samples, max_num_samples, num_samples, seconds); + } else if (buf[0] == 0 && buf[1] == 0 && buf[2] == 0 && buf[3] == 0) { + LOG_TARGET_INFO(target, "NULL DEBUGPC, fallback to stop-and-go"); + return target_profiling_default(target, samples, max_num_samples, num_samples, seconds); + } + + LOG_TARGET_INFO(target, "Starting XTENSA DEBUGPC profiling. Sampling as fast as we can..."); + + /* Make sure the target is running */ + target_poll(target); + if (target->state == TARGET_HALTED) + retval = target_resume(target, true, 0, false, false); + + if (retval != ERROR_OK) { + LOG_TARGET_ERROR(target, "Error while resuming target"); + return retval; + } + + uint32_t sample_count = 0; + + for (;;) { + uint32_t remaining = max_num_samples - sample_count; + uint32_t this_pass = rand() % (MAX_PASS - MIN_PASS) + MIN_PASS; + this_pass = this_pass > remaining ? remaining : this_pass; + for (uint32_t i = 0; i < this_pass; ++i) + xtensa_queue_dbg_reg_read(xtensa, XDMREG_DEBUGPC, buf + i * sizeof(uint32_t)); + res = xtensa_dm_queue_execute(&xtensa->dbg_mod); + if (res != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to read DEBUGPC!"); + return res; + } + + for (uint32_t i = 0; i < this_pass; ++i) { + uint32_t sample32 = buf_get_u32(buf + i * sizeof(uint32_t), 0, 32); + samples[sample_count++] = sample32; + } + gettimeofday(&now, NULL); + if (sample_count >= max_num_samples || timeval_compare(&now, &timeout) > 0) { + LOG_TARGET_INFO(target, "Profiling completed. %" PRIu32 " samples.", sample_count); + break; + } + } + + *num_samples = sample_count; + return retval; + + #undef MIN_PASS + #undef MAX_PASS +} diff --git a/src/target/espressif/esp_xtensa.h b/src/target/espressif/esp_xtensa.h index 00f67a3..56c903f 100644 --- a/src/target/espressif/esp_xtensa.h +++ b/src/target/espressif/esp_xtensa.h @@ -37,6 +37,9 @@ void esp_xtensa_queue_tdi_idle(struct target *target); int esp_xtensa_breakpoint_add(struct target *target, struct breakpoint *breakpoint); int esp_xtensa_breakpoint_remove(struct target *target, struct breakpoint *breakpoint); int esp_xtensa_poll(struct target *target); +int esp_xtensa_profiling(struct target *target, uint32_t *samples, + uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds); + int esp_xtensa_on_halt(struct target *target); #endif /* OPENOCD_TARGET_ESP_XTENSA_H */ diff --git a/src/target/espressif/esp_xtensa_apptrace.c b/src/target/espressif/esp_xtensa_apptrace.c index 5741ab0..313f6ce 100644 --- a/src/target/espressif/esp_xtensa_apptrace.c +++ b/src/target/espressif/esp_xtensa_apptrace.c @@ -277,7 +277,7 @@ static int esp_xtensa_swdbg_activate(struct target *target, int enab) xtensa_dm_queue_tdi_idle(&xtensa->dbg_mod); int res = xtensa_dm_queue_execute(&xtensa->dbg_mod); if (res != ERROR_OK) { - LOG_ERROR("%s: writing DCR failed!", target->cmd_name); + LOG_TARGET_ERROR(target, "writing DCR failed"); return res; } diff --git a/src/target/espressif/esp_xtensa_smp.c b/src/target/espressif/esp_xtensa_smp.c index c49146d..b9e2156 100644 --- a/src/target/espressif/esp_xtensa_smp.c +++ b/src/target/espressif/esp_xtensa_smp.c @@ -218,7 +218,7 @@ int esp_xtensa_smp_poll(struct target *target) !esp_xtensa_smp->other_core_does_resume) { esp_xtensa->semihost.need_resume = false; /* Resume xtensa_resume will handle BREAK instruction. */ - ret = target_resume(target, 1, 0, 1, 0); + ret = target_resume(target, true, 0, true, false); if (ret != ERROR_OK) { LOG_ERROR("Failed to resume target"); return ret; @@ -229,7 +229,7 @@ int esp_xtensa_smp_poll(struct target *target) /* check whether any core polled by esp_xtensa_smp_update_halt_gdb() requested resume */ if (target->smp && other_core_resume_req) { /* Resume xtensa_resume will handle BREAK instruction. */ - ret = target_resume(target, 1, 0, 1, 0); + ret = target_resume(target, true, 0, true, false); if (ret != ERROR_OK) { LOG_ERROR("Failed to resume target"); return ret; @@ -334,8 +334,7 @@ static inline int esp_xtensa_smp_smpbreak_restore(struct target *target, uint32_ } static int esp_xtensa_smp_resume_cores(struct target *target, - int handle_breakpoints, - int debug_execution) + bool handle_breakpoints, bool debug_execution) { struct target_list *head; struct target *curr; @@ -348,7 +347,7 @@ static int esp_xtensa_smp_resume_cores(struct target *target, if ((curr != target) && (curr->state != TARGET_RUNNING) && target_was_examined(curr)) { /* resume current address, not in SMP mode */ curr->smp = 0; - int res = esp_xtensa_smp_resume(curr, 1, 0, handle_breakpoints, debug_execution); + int res = esp_xtensa_smp_resume(curr, true, 0, handle_breakpoints, debug_execution); curr->smp = 1; if (res != ERROR_OK) return res; @@ -358,10 +357,10 @@ static int esp_xtensa_smp_resume_cores(struct target *target, } int esp_xtensa_smp_resume(struct target *target, - int current, + bool current, target_addr_t address, - int handle_breakpoints, - int debug_execution) + bool handle_breakpoints, + bool debug_execution) { int res; uint32_t smp_break; @@ -420,9 +419,9 @@ int esp_xtensa_smp_resume(struct target *target, } int esp_xtensa_smp_step(struct target *target, - int current, + bool current, target_addr_t address, - int handle_breakpoints) + bool handle_breakpoints) { int res; uint32_t smp_break = 0; diff --git a/src/target/espressif/esp_xtensa_smp.h b/src/target/espressif/esp_xtensa_smp.h index 39afd8a..ec074c1 100644 --- a/src/target/espressif/esp_xtensa_smp.h +++ b/src/target/espressif/esp_xtensa_smp.h @@ -27,14 +27,14 @@ struct esp_xtensa_smp_common { int esp_xtensa_smp_poll(struct target *target); int esp_xtensa_smp_resume(struct target *target, - int current, + bool current, target_addr_t address, - int handle_breakpoints, - int debug_execution); + bool handle_breakpoints, + bool debug_execution); int esp_xtensa_smp_step(struct target *target, - int current, + bool current, target_addr_t address, - int handle_breakpoints); + bool handle_breakpoints); int esp_xtensa_smp_assert_reset(struct target *target); int esp_xtensa_smp_deassert_reset(struct target *target); int esp_xtensa_smp_soft_reset_halt(struct target *target); diff --git a/src/target/etb.c b/src/target/etb.c index 3b9004b..fb3112d 100644 --- a/src/target/etb.c +++ b/src/target/etb.c @@ -454,12 +454,12 @@ static int etb_init(struct etm_context *etm_ctx) return ERROR_OK; } -static trace_status_t etb_status(struct etm_context *etm_ctx) +static enum trace_status etb_status(struct etm_context *etm_ctx) { struct etb *etb = etm_ctx->capture_driver_priv; struct reg *control = &etb->reg_cache->reg_list[ETB_CTRL]; struct reg *status = &etb->reg_cache->reg_list[ETB_STATUS]; - trace_status_t retval = 0; + enum trace_status retval = 0; int etb_timeout = 100; etb->etm_ctx = etm_ctx; diff --git a/src/target/etb.h b/src/target/etb.h index fa75600..1d0c08b 100644 --- a/src/target/etb.h +++ b/src/target/etb.h @@ -32,7 +32,7 @@ struct etb { uint32_t ram_width; /** how much trace buffer to fill after trigger */ - unsigned trigger_percent; + unsigned int trigger_percent; }; struct etb_reg { diff --git a/src/target/etm.c b/src/target/etm.c index d083017..d9a3cdc 100644 --- a/src/target/etm.c +++ b/src/target/etm.c @@ -220,10 +220,10 @@ static const struct reg_arch_type etm_scan6_type = { /* Look up register by ID ... most ETM instances only * support a subset of the possible registers. */ -static struct reg *etm_reg_lookup(struct etm_context *etm_ctx, unsigned id) +static struct reg *etm_reg_lookup(struct etm_context *etm_ctx, unsigned int id) { struct reg_cache *cache = etm_ctx->reg_cache; - unsigned i; + unsigned int i; for (i = 0; i < cache->num_regs; i++) { struct etm_reg *reg = cache->reg_list[i].arch_info; @@ -238,9 +238,9 @@ static struct reg *etm_reg_lookup(struct etm_context *etm_ctx, unsigned id) return NULL; } -static void etm_reg_add(unsigned bcd_vers, struct arm_jtag *jtag_info, +static void etm_reg_add(unsigned int bcd_vers, struct arm_jtag *jtag_info, struct reg_cache *cache, struct etm_reg *ereg, - const struct etm_reg_info *r, unsigned nreg) + const struct etm_reg_info *r, unsigned int nreg) { struct reg *reg = cache->reg_list; @@ -281,7 +281,7 @@ struct reg_cache *etm_build_reg_cache(struct target *target, struct reg_cache *reg_cache = malloc(sizeof(struct reg_cache)); struct reg *reg_list = NULL; struct etm_reg *arch_info = NULL; - unsigned bcd_vers, config; + unsigned int bcd_vers, config; /* the actual registers are kept in two arrays */ reg_list = calloc(128, sizeof(struct reg)); @@ -320,9 +320,8 @@ struct reg_cache *etm_build_reg_cache(struct target *target, etm_reg_add(0x20, jtag_info, reg_cache, arch_info, etm_core + 1, 1); etm_get_reg(reg_list + 1); - etm_ctx->id = buf_get_u32( - arch_info[1].value, 0, 32); - LOG_DEBUG("ETM ID: %08x", (unsigned) etm_ctx->id); + etm_ctx->id = buf_get_u32(arch_info[1].value, 0, 32); + LOG_DEBUG("ETM ID: %08" PRIx32, etm_ctx->id); bcd_vers = 0x10 + (((etm_ctx->id) >> 4) & 0xff); } else { @@ -1495,7 +1494,7 @@ COMMAND_HANDLER(handle_etm_info_command) etm_get_reg(etm_sys_config_reg); config = buf_get_u32(etm_sys_config_reg->value, 0, 32); - LOG_DEBUG("ETM SYS CONFIG %08x", (unsigned) config); + LOG_DEBUG("ETM SYS CONFIG %08" PRIx32, config); max_port_size = config & 0x7; if (etm->bcd_vers >= 0x30) @@ -1568,7 +1567,7 @@ COMMAND_HANDLER(handle_etm_status_command) struct target *target; struct arm *arm; struct etm_context *etm; - trace_status_t trace_status; + enum trace_status trace_status; target = get_current_target(CMD_CTX); arm = target_to_arm(target); @@ -1591,7 +1590,7 @@ COMMAND_HANDLER(handle_etm_status_command) if (!reg) return ERROR_FAIL; if (etm_get_reg(reg) == ERROR_OK) { - unsigned s = buf_get_u32(reg->value, 0, reg->size); + unsigned int s = buf_get_u32(reg->value, 0, reg->size); command_print(CMD, "etm: %s%s%s%s", /* bit(1) == progbit */ diff --git a/src/target/etm.h b/src/target/etm.h index be5f2c7..e18549d 100644 --- a/src/target/etm.h +++ b/src/target/etm.h @@ -126,7 +126,7 @@ struct etm_capture_driver { const char *name; const struct command_registration *commands; int (*init)(struct etm_context *etm_ctx); - trace_status_t (*status)(struct etm_context *etm_ctx); + enum trace_status (*status)(struct etm_context *etm_ctx); int (*read_trace)(struct etm_context *etm_ctx); int (*start_capture)(struct etm_context *etm_ctx); int (*stop_capture)(struct etm_context *etm_ctx); @@ -153,7 +153,7 @@ struct etm_context { struct reg_cache *reg_cache; /* ETM register cache */ struct etm_capture_driver *capture_driver; /* driver used to access ETM data */ void *capture_driver_priv; /* capture driver private data */ - trace_status_t capture_status; /* current state of capture run */ + enum trace_status capture_status; /* current state of capture run */ struct etmv1_trace_data *trace_data; /* trace data */ uint32_t trace_depth; /* number of cycles to be analyzed, 0 if no data available */ uint32_t control; /* shadow of ETM_CTRL */ @@ -175,7 +175,7 @@ struct etm_context { }; /* PIPESTAT values */ -typedef enum { +enum etmv1_pipestat { STAT_IE = 0x0, STAT_ID = 0x1, STAT_IN = 0x2, @@ -184,10 +184,10 @@ typedef enum { STAT_BD = 0x5, STAT_TR = 0x6, STAT_TD = 0x7 -} etmv1_pipestat_t; +}; /* branch reason values */ -typedef enum { +enum etmv1_branch_reason { BR_NORMAL = 0x0, /* Normal PC change : periodic synchro (ETMv1.1) */ BR_ENABLE = 0x1, /* Trace has been enabled */ BR_RESTART = 0x2, /* Trace restarted after a FIFO overflow */ @@ -196,7 +196,7 @@ typedef enum { BR_RSVD5 = 0x5, /* reserved */ BR_RSVD6 = 0x6, /* reserved */ BR_RSVD7 = 0x7, /* reserved */ -} etmv1_branch_reason_t; +}; struct reg_cache *etm_build_reg_cache(struct target *target, struct arm_jtag *jtag_info, struct etm_context *etm_ctx); diff --git a/src/target/etm_dummy.c b/src/target/etm_dummy.c index 8deccf5..2709b6e 100644 --- a/src/target/etm_dummy.c +++ b/src/target/etm_dummy.c @@ -65,7 +65,7 @@ static int etm_dummy_init(struct etm_context *etm_ctx) return ERROR_OK; } -static trace_status_t etm_dummy_status(struct etm_context *etm_ctx) +static enum trace_status etm_dummy_status(struct etm_context *etm_ctx) { return TRACE_IDLE; } diff --git a/src/target/feroceon.c b/src/target/feroceon.c index 1e7eb09..840ca1b 100644 --- a/src/target/feroceon.c +++ b/src/target/feroceon.c @@ -526,7 +526,7 @@ static int feroceon_bulk_write_memory(struct target *target, arm->core_state = ARM_STATE_ARM; embeddedice_write_reg(&arm7_9->eice_cache->reg_list[EICE_COMMS_DATA], 0); - arm7_9_resume(target, 0, arm7_9->dcc_working_area->address, 1, 1); + arm7_9_resume(target, false, arm7_9->dcc_working_area->address, true, true); /* send data over */ x = 0; diff --git a/src/target/hla_target.c b/src/target/hla_target.c index d6f2afb..ef05df2 100644 --- a/src/target/hla_target.c +++ b/src/target/hla_target.c @@ -258,7 +258,7 @@ static int adapter_debug_entry(struct target *target) arm->core_mode = ARM_MODE_HANDLER; arm->map = armv7m_msp_reg_map; } else { - unsigned control = buf_get_u32(arm->core_cache + unsigned int control = buf_get_u32(arm->core_cache ->reg_list[ARMV7M_CONTROL].value, 0, 3); /* is this thread privileged? */ @@ -406,7 +406,8 @@ static int hl_deassert_reset(struct target *target) target->SAVED_DCRDR = 0; /* clear both DCC busy bits on initial resume */ - return target->reset_halt ? ERROR_OK : target_resume(target, 1, 0, 0, 0); + return target->reset_halt ? ERROR_OK : target_resume(target, true, 0, false, + false); } static int adapter_halt(struct target *target) @@ -434,9 +435,9 @@ static int adapter_halt(struct target *target) return ERROR_OK; } -static int adapter_resume(struct target *target, int current, - target_addr_t address, int handle_breakpoints, - int debug_execution) +static int adapter_resume(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, + bool debug_execution) { int res; struct hl_interface *adapter = target_to_adapter(target); @@ -525,8 +526,8 @@ static int adapter_resume(struct target *target, int current, return ERROR_OK; } -static int adapter_step(struct target *target, int current, - target_addr_t address, int handle_breakpoints) +static int adapter_step(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints) { int res; struct hl_interface *adapter = target_to_adapter(target); diff --git a/src/target/image.c b/src/target/image.c index 9175c20..6864e4e 100644 --- a/src/target/image.c +++ b/src/target/image.c @@ -194,7 +194,7 @@ static int image_ihex_buffer_complete_inner(struct image *image, } while (count-- > 0) { - unsigned value; + unsigned int value; sscanf(&lpsz_line[bytes_read], "%2x", &value); ihex->buffer[cooked_bytes] = (uint8_t)value; cal_checksum += (uint8_t)ihex->buffer[cooked_bytes]; @@ -863,7 +863,7 @@ static int image_mot_buffer_complete_inner(struct image *image, } while (count-- > 0) { - unsigned value; + unsigned int value; sscanf(&lpsz_line[bytes_read], "%2x", &value); mot->buffer[cooked_bytes] = (uint8_t)value; cal_checksum += (uint8_t)mot->buffer[cooked_bytes]; diff --git a/src/target/lakemont.c b/src/target/lakemont.c index 6c0964b..39a50c7 100644 --- a/src/target/lakemont.c +++ b/src/target/lakemont.c @@ -67,7 +67,7 @@ static const struct { const char *name; uint64_t op; uint8_t pm_idx; - unsigned bits; + unsigned int bits; enum reg_type type; const char *group; const char *feature; @@ -224,10 +224,10 @@ static int irscan(struct target *t, uint8_t *out, if (ir_len != t->tap->ir_length) { retval = ERROR_FAIL; if (t->tap->enabled) - LOG_ERROR("%s tap enabled but tap irlen=%d", + LOG_ERROR("%s tap enabled but tap irlen=%u", __func__, t->tap->ir_length); else - LOG_ERROR("%s tap not enabled and irlen=%d", + LOG_ERROR("%s tap not enabled and irlen=%u", __func__, t->tap->ir_length); return retval; } @@ -597,7 +597,7 @@ static int read_all_core_hw_regs(struct target *t) { int err; uint32_t regval; - unsigned i; + unsigned int i; struct x86_32_common *x86_32 = target_to_x86_32(t); for (i = 0; i < (x86_32->cache->num_regs); i++) { if (regs[i].pm_idx == NOT_AVAIL_REG) @@ -616,7 +616,7 @@ static int read_all_core_hw_regs(struct target *t) static int write_all_core_hw_regs(struct target *t) { int err; - unsigned i; + unsigned int i; struct x86_32_common *x86_32 = target_to_x86_32(t); for (i = 0; i < (x86_32->cache->num_regs); i++) { if (regs[i].pm_idx == NOT_AVAIL_REG) @@ -988,8 +988,8 @@ int lakemont_halt(struct target *t) } } -int lakemont_resume(struct target *t, int current, target_addr_t address, - int handle_breakpoints, int debug_execution) +int lakemont_resume(struct target *t, bool current, target_addr_t address, + bool handle_breakpoints, bool debug_execution) { struct breakpoint *bp = NULL; struct x86_32_common *x86_32 = target_to_x86_32(t); @@ -1004,7 +1004,7 @@ int lakemont_resume(struct target *t, int current, target_addr_t address, bp = breakpoint_find(t, eip); if (bp /*&& bp->type == BKPT_SOFT*/) { /* the step will step over the breakpoint */ - if (lakemont_step(t, 0, 0, 1) != ERROR_OK) { + if (lakemont_step(t, false, 0, true) != ERROR_OK) { LOG_ERROR("%s stepping over a software breakpoint at 0x%08" PRIx32 " " "failed to resume the target", __func__, eip); return ERROR_FAIL; @@ -1029,8 +1029,8 @@ int lakemont_resume(struct target *t, int current, target_addr_t address, return ERROR_OK; } -int lakemont_step(struct target *t, int current, - target_addr_t address, int handle_breakpoints) +int lakemont_step(struct target *t, bool current, target_addr_t address, + bool handle_breakpoints) { struct x86_32_common *x86_32 = target_to_x86_32(t); uint32_t eflags = buf_get_u32(x86_32->cache->reg_list[EFLAGS].value, 0, 32); diff --git a/src/target/lakemont.h b/src/target/lakemont.h index ca6557f..4c84f74 100644 --- a/src/target/lakemont.h +++ b/src/target/lakemont.h @@ -84,10 +84,10 @@ int lakemont_init_arch_info(struct target *t, struct x86_32_common *x86_32); int lakemont_poll(struct target *t); int lakemont_arch_state(struct target *t); int lakemont_halt(struct target *t); -int lakemont_resume(struct target *t, int current, target_addr_t address, - int handle_breakpoints, int debug_execution); -int lakemont_step(struct target *t, int current, - target_addr_t address, int handle_breakpoints); +int lakemont_resume(struct target *t, bool current, target_addr_t address, + bool handle_breakpoints, bool debug_execution); +int lakemont_step(struct target *t, bool current, + target_addr_t address, bool handle_breakpoints); int lakemont_reset_assert(struct target *t); int lakemont_reset_deassert(struct target *t); int lakemont_update_after_probemode_entry(struct target *t); diff --git a/src/target/ls1_sap.c b/src/target/ls1_sap.c index 9bd00c0..692f4cc 100644 --- a/src/target/ls1_sap.c +++ b/src/target/ls1_sap.c @@ -55,15 +55,15 @@ static int ls1_sap_halt(struct target *target) return ERROR_OK; } -static int ls1_sap_resume(struct target *target, int current, target_addr_t address, - int handle_breakpoints, int debug_execution) +static int ls1_sap_resume(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, bool debug_execution) { LOG_DEBUG("%s", __func__); return ERROR_OK; } -static int ls1_sap_step(struct target *target, int current, target_addr_t address, - int handle_breakpoints) +static int ls1_sap_step(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints) { LOG_DEBUG("%s", __func__); return ERROR_OK; diff --git a/src/target/mem_ap.c b/src/target/mem_ap.c index 61a9475..fdc52c3 100644 --- a/src/target/mem_ap.c +++ b/src/target/mem_ap.c @@ -34,13 +34,13 @@ static int mem_ap_target_create(struct target *target, Jim_Interp *interp) return ERROR_FAIL; if (pc->ap_num == DP_APSEL_INVALID) { - LOG_ERROR("AP number not specified"); + LOG_TARGET_ERROR(target, "AP number not specified"); return ERROR_FAIL; } mem_ap = calloc(1, sizeof(struct mem_ap)); if (!mem_ap) { - LOG_ERROR("Out of memory"); + LOG_TARGET_ERROR(target, "Out of memory"); return ERROR_FAIL; } @@ -58,7 +58,7 @@ static int mem_ap_target_create(struct target *target, Jim_Interp *interp) static int mem_ap_init_target(struct command_context *cmd_ctx, struct target *target) { - LOG_DEBUG("%s", __func__); + LOG_TARGET_DEBUG(target, "%s", __func__); target->state = TARGET_UNKNOWN; target->debug_reason = DBG_REASON_UNDEFINED; return ERROR_OK; @@ -68,19 +68,18 @@ static void mem_ap_deinit_target(struct target *target) { struct mem_ap *mem_ap = target->arch_info; - LOG_DEBUG("%s", __func__); + LOG_TARGET_DEBUG(target, "%s", __func__); if (mem_ap->ap) dap_put_ap(mem_ap->ap); free(target->private_config); free(target->arch_info); - return; } static int mem_ap_arch_state(struct target *target) { - LOG_DEBUG("%s", __func__); + LOG_TARGET_DEBUG(target, "%s", __func__); return ERROR_OK; } @@ -96,26 +95,27 @@ static int mem_ap_poll(struct target *target) static int mem_ap_halt(struct target *target) { - LOG_DEBUG("%s", __func__); + LOG_TARGET_DEBUG(target, "%s", __func__); target->state = TARGET_HALTED; target->debug_reason = DBG_REASON_DBGRQ; target_call_event_callbacks(target, TARGET_EVENT_HALTED); return ERROR_OK; } -static int mem_ap_resume(struct target *target, int current, target_addr_t address, - int handle_breakpoints, int debug_execution) +static int mem_ap_resume(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, + bool debug_execution) { - LOG_DEBUG("%s", __func__); + LOG_TARGET_DEBUG(target, "%s", __func__); target->state = TARGET_RUNNING; target->debug_reason = DBG_REASON_NOTHALTED; return ERROR_OK; } -static int mem_ap_step(struct target *target, int current, target_addr_t address, - int handle_breakpoints) +static int mem_ap_step(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints) { - LOG_DEBUG("%s", __func__); + LOG_TARGET_DEBUG(target, "%s", __func__); target->state = TARGET_HALTED; target->debug_reason = DBG_REASON_DBGRQ; target_call_event_callbacks(target, TARGET_EVENT_HALTED); @@ -127,7 +127,7 @@ static int mem_ap_assert_reset(struct target *target) target->state = TARGET_RESET; target->debug_reason = DBG_REASON_UNDEFINED; - LOG_DEBUG("%s", __func__); + LOG_TARGET_DEBUG(target, "%s", __func__); return ERROR_OK; } @@ -139,7 +139,7 @@ static int mem_ap_examine(struct target *target) if (!mem_ap->ap) { mem_ap->ap = dap_get_ap(mem_ap->dap, mem_ap->ap_num); if (!mem_ap->ap) { - LOG_ERROR("Cannot get AP"); + LOG_TARGET_ERROR(target, "Cannot get AP"); return ERROR_FAIL; } } @@ -163,7 +163,7 @@ static int mem_ap_deassert_reset(struct target *target) target->debug_reason = DBG_REASON_NOTHALTED; } - LOG_DEBUG("%s", __func__); + LOG_TARGET_DEBUG(target, "%s", __func__); return ERROR_OK; } @@ -213,7 +213,7 @@ static int mem_ap_get_gdb_reg_list(struct target *target, struct reg **reg_list[ { struct mem_ap_alloc_reg_list *mem_ap_alloc = calloc(1, sizeof(struct mem_ap_alloc_reg_list)); if (!mem_ap_alloc) { - LOG_ERROR("Out of memory"); + LOG_TARGET_ERROR(target, "Out of memory"); return ERROR_FAIL; } @@ -238,7 +238,7 @@ static int mem_ap_read_memory(struct target *target, target_addr_t address, { struct mem_ap *mem_ap = target->arch_info; - LOG_DEBUG("Reading memory at physical address " TARGET_ADDR_FMT + LOG_TARGET_DEBUG(target, "Reading memory at physical address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32, address, size, count); if (count == 0 || !buffer) @@ -253,7 +253,7 @@ static int mem_ap_write_memory(struct target *target, target_addr_t address, { struct mem_ap *mem_ap = target->arch_info; - LOG_DEBUG("Writing memory at physical address " TARGET_ADDR_FMT + LOG_TARGET_DEBUG(target, "Writing memory at physical address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32, address, size, count); if (count == 0 || !buffer) diff --git a/src/target/mips32.c b/src/target/mips32.c index 81faab7..4527c5f 100644 --- a/src/target/mips32.c +++ b/src/target/mips32.c @@ -31,10 +31,10 @@ static const char *mips_isa_strings[] = { /* * GDB registers - * based on gdb-7.6.2/gdb/features/mips-{fpu,cp0,cpu}.xml + * based on gdb-7.6.2/gdb/features/mips-{fpu,cp0,cpu,dsp}.xml */ static const struct { - unsigned id; + unsigned int id; const char *name; enum reg_type type; const char *group; @@ -156,6 +156,22 @@ static const struct { "org.gnu.gdb.mips.cpu", 0 }, { MIPS32_REGLIST_C0_GUESTCTL1_INDEX, "guestCtl1", REG_TYPE_INT, NULL, "org.gnu.gdb.mips.cp0", 0 }, + + { MIPS32_REGLIST_DSP_INDEX + 0, "hi1", REG_TYPE_INT, NULL, + "org.gnu.gdb.mips.dsp", 0 }, + { MIPS32_REGLIST_DSP_INDEX + 1, "lo1", REG_TYPE_INT, NULL, + "org.gnu.gdb.mips.dsp", 0 }, + { MIPS32_REGLIST_DSP_INDEX + 2, "hi2", REG_TYPE_INT, NULL, + "org.gnu.gdb.mips.dsp", 0 }, + { MIPS32_REGLIST_DSP_INDEX + 3, "lo2", REG_TYPE_INT, NULL, + "org.gnu.gdb.mips.dsp", 0 }, + { MIPS32_REGLIST_DSP_INDEX + 4, "hi3", REG_TYPE_INT, NULL, + "org.gnu.gdb.mips.dsp", 0 }, + { MIPS32_REGLIST_DSP_INDEX + 5, "lo3", REG_TYPE_INT, NULL, + "org.gnu.gdb.mips.dsp", 0 }, + + { MIPS32_REGLIST_DSP_DSPCTL_INDEX, "dspctl", REG_TYPE_INT, NULL, + "org.gnu.gdb.mips.dsp", 0 }, }; #define MIPS32_NUM_REGS ARRAY_SIZE(mips32_regs) @@ -211,13 +227,11 @@ static const struct { static const struct { const char *name; } mips32_dsp_regs[MIPS32NUMDSPREGS] = { - { "hi0"}, { "hi1"}, - { "hi2"}, - { "hi3"}, - { "lo0"}, { "lo1"}, + { "hi2"}, { "lo2"}, + { "hi3"}, { "lo3"}, { "control"}, }; @@ -328,7 +342,12 @@ static int mips32_read_core_reg(struct target *target, unsigned int num) if (num >= MIPS32_NUM_REGS) return ERROR_COMMAND_SYNTAX_ERROR; - if (num >= MIPS32_REGLIST_C0_INDEX) { + if (num >= MIPS32_REGLIST_DSP_INDEX) { + /* DSP */ + cnum = num - MIPS32_REGLIST_DSP_INDEX; + reg_value = mips32->core_regs.dsp[cnum]; + buf_set_u32(mips32->core_cache->reg_list[num].value, 0, 32, reg_value); + } else if (num >= MIPS32_REGLIST_C0_INDEX) { /* CP0 */ cnum = num - MIPS32_REGLIST_C0_INDEX; reg_value = mips32->core_regs.cp0[cnum]; @@ -371,7 +390,12 @@ static int mips32_write_core_reg(struct target *target, unsigned int num) if (num >= MIPS32_NUM_REGS) return ERROR_COMMAND_SYNTAX_ERROR; - if (num >= MIPS32_REGLIST_C0_INDEX) { + if (num >= MIPS32_REGLIST_DSP_INDEX) { + /* DSP */ + cnum = num - MIPS32_REGLIST_DSP_INDEX; + reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32); + mips32->core_regs.dsp[cnum] = (uint32_t)reg_value; + } else if (num >= MIPS32_REGLIST_C0_INDEX) { /* CP0 */ cnum = num - MIPS32_REGLIST_C0_INDEX; reg_value = buf_get_u32(mips32->core_cache->reg_list[num].value, 0, 32); @@ -564,7 +588,7 @@ static int mips32_run_and_wait(struct target *target, target_addr_t entry_point, int retval; /* This code relies on the target specific resume() and poll()->debug_entry() * sequence to write register values to the processor and the read them back */ - retval = target_resume(target, 0, entry_point, 0, 1); + retval = target_resume(target, false, entry_point, false, true); if (retval != ERROR_OK) return retval; @@ -1026,10 +1050,20 @@ int mips32_cpu_probe(struct target *target) /* reads dsp implementation info from CP0 Config3 register {DSPP, DSPREV}*/ static void mips32_read_config_dsp(struct mips32_common *mips32, struct mips_ejtag *ejtag_info) { - uint32_t dsp_present = ((ejtag_info->config[3] & MIPS32_CONFIG3_DSPP_MASK) >> MIPS32_CONFIG3_DSPP_SHIFT); + uint32_t retval, status_value, dsp_present; + bool dsp_enabled; + + retval = mips32_cp0_read(ejtag_info, &status_value, MIPS32_C0_STATUS, 0); + if (retval != ERROR_OK) { + LOG_ERROR("Failed to read cp0 status register"); + return; + } + + dsp_present = ((ejtag_info->config[3] & MIPS32_CONFIG3_DSPP_MASK) >> MIPS32_CONFIG3_DSPP_SHIFT); + dsp_enabled = (status_value & BIT(MIPS32_CP0_STATUS_MX_SHIFT)) != 0; if (dsp_present) { mips32->dsp_imp = ((ejtag_info->config[3] & MIPS32_CONFIG3_DSPREV_MASK) >> MIPS32_CONFIG3_DSPREV_SHIFT) + 1; - LOG_USER("DSP implemented: %s, rev %d", "yes", mips32->dsp_imp); + LOG_USER("DSP implemented: rev %d, %s", mips32->dsp_imp, dsp_enabled ? "enabled" : "disabled"); } else { LOG_USER("DSP implemented: %s", "no"); } @@ -1153,7 +1187,7 @@ int mips32_read_config_regs(struct target *target) mips32->isa_imp = MIPS32_MIPS16; LOG_USER("ISA implemented: %s%s", "MIPS32, MIPS16", buf); } else if (ejtag_info->config_regs >= 4) { /* config3 implemented */ - unsigned isa_imp = (ejtag_info->config[3] & MIPS32_CONFIG3_ISA_MASK) >> MIPS32_CONFIG3_ISA_SHIFT; + unsigned int isa_imp = (ejtag_info->config[3] & MIPS32_CONFIG3_ISA_MASK) >> MIPS32_CONFIG3_ISA_SHIFT; if (isa_imp == 1) { mips32->isa_imp = MMIPS32_ONLY; LOG_USER("ISA implemented: %s%s", "microMIPS32", buf); @@ -1747,13 +1781,11 @@ static int mips32_pracc_read_dsp_reg(struct mips_ejtag *ejtag_info, uint32_t *va }; uint32_t dsp_read_code[] = { - MIPS32_MFHI(isa, t0), /* mfhi t0 ($ac0) - OPCODE - 0x00004010 */ MIPS32_DSP_MFHI(t0, 1), /* mfhi t0,$ac1 - OPCODE - 0x00204010 */ - MIPS32_DSP_MFHI(t0, 2), /* mfhi t0,$ac2 - OPCODE - 0x00404010 */ - MIPS32_DSP_MFHI(t0, 3), /* mfhi t0,$ac3 - OPCODE - 0x00604010*/ - MIPS32_MFLO(isa, t0), /* mflo t0 ($ac0) - OPCODE - 0x00004012 */ MIPS32_DSP_MFLO(t0, 1), /* mflo t0,$ac1 - OPCODE - 0x00204012 */ + MIPS32_DSP_MFHI(t0, 2), /* mfhi t0,$ac2 - OPCODE - 0x00404010 */ MIPS32_DSP_MFLO(t0, 2), /* mflo t0,$ac2 - OPCODE - 0x00404012 */ + MIPS32_DSP_MFHI(t0, 3), /* mfhi t0,$ac3 - OPCODE - 0x00604010*/ MIPS32_DSP_MFLO(t0, 3), /* mflo t0,$ac3 - OPCODE - 0x00604012 */ MIPS32_DSP_RDDSP(t0, 0x3F), /* rddsp t0, 0x3f (DSPCtl) - OPCODE - 0x7c3f44b8 */ }; @@ -1824,13 +1856,11 @@ static int mips32_pracc_write_dsp_reg(struct mips_ejtag *ejtag_info, uint32_t va }; uint32_t dsp_write_code[] = { - MIPS32_MTHI(isa, t0), /* mthi t0 ($ac0) - OPCODE - 0x01000011 */ MIPS32_DSP_MTHI(t0, 1), /* mthi t0, $ac1 - OPCODE - 0x01000811 */ - MIPS32_DSP_MTHI(t0, 2), /* mthi t0, $ac2 - OPCODE - 0x01001011 */ - MIPS32_DSP_MTHI(t0, 3), /* mthi t0, $ac3 - OPCODE - 0x01001811 */ - MIPS32_MTLO(isa, t0), /* mtlo t0 ($ac0) - OPCODE - 0x01000013 */ MIPS32_DSP_MTLO(t0, 1), /* mtlo t0, $ac1 - OPCODE - 0x01000813 */ + MIPS32_DSP_MTHI(t0, 2), /* mthi t0, $ac2 - OPCODE - 0x01001011 */ MIPS32_DSP_MTLO(t0, 2), /* mtlo t0, $ac2 - OPCODE - 0x01001013 */ + MIPS32_DSP_MTHI(t0, 3), /* mthi t0, $ac3 - OPCODE - 0x01001811 */ MIPS32_DSP_MTLO(t0, 3), /* mtlo t0, $ac3 - OPCODE - 0x01001813 */ MIPS32_DSP_WRDSP(t0, 0x1F), /* wrdsp t0, 0x1f (DSPCtl) - OPCODE - 0x7d00fcf8*/ }; @@ -2107,15 +2137,18 @@ static int mips32_dsp_find_register_by_name(const char *reg_name) * * @return ERROR_OK on success; error code on failure. */ -static int mips32_dsp_get_all_regs(struct command_invocation *cmd, struct mips_ejtag *ejtag_info) +static int mips32_dsp_get_all_regs(struct command_invocation *cmd, struct mips32_common *mips32) { uint32_t value = 0; + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; for (int i = 0; i < MIPS32NUMDSPREGS; i++) { int retval = mips32_pracc_read_dsp_reg(ejtag_info, &value, i); if (retval != ERROR_OK) { command_print(CMD, "couldn't access reg %s", mips32_dsp_regs[i].name); return retval; } + mips32->core_regs.dsp[i] = value; + mips32->core_cache->reg_list[MIPS32_REGLIST_DSP_INDEX + i].dirty = 1; command_print(CMD, "%*s: 0x%8.8x", 7, mips32_dsp_regs[i].name, value); } return ERROR_OK; @@ -2132,20 +2165,28 @@ static int mips32_dsp_get_all_regs(struct command_invocation *cmd, struct mips_e * * @return ERROR_OK on success; error code on failure. */ -static int mips32_dsp_get_register(struct command_invocation *cmd, struct mips_ejtag *ejtag_info) +static int mips32_dsp_get_register(struct command_invocation *cmd, struct mips32_common *mips32) { uint32_t value = 0; int index = mips32_dsp_find_register_by_name(CMD_ARGV[0]); + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; if (index == MIPS32NUMDSPREGS) { command_print(CMD, "ERROR: register '%s' not found", CMD_ARGV[0]); return ERROR_COMMAND_SYNTAX_ERROR; } int retval = mips32_pracc_read_dsp_reg(ejtag_info, &value, index); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { command_print(CMD, "ERROR: Could not access dsp register %s", CMD_ARGV[0]); - else - command_print(CMD, "0x%8.8x", value); + return retval; + } + + command_print(CMD, "0x%8.8x", value); + + if (mips32->core_regs.dsp[index] != value) { + mips32->core_regs.dsp[index] = value; + mips32->core_cache->reg_list[MIPS32_REGLIST_DSP_INDEX + index].dirty = 1; + } return retval; } @@ -2162,9 +2203,10 @@ static int mips32_dsp_get_register(struct command_invocation *cmd, struct mips_e * * @return ERROR_OK on success; error code on failure. */ -static int mips32_dsp_set_register(struct command_invocation *cmd, struct mips_ejtag *ejtag_info) +static int mips32_dsp_set_register(struct command_invocation *cmd, struct mips32_common *mips32) { uint32_t value; + struct mips_ejtag *ejtag_info = &mips32->ejtag_info; int index = mips32_dsp_find_register_by_name(CMD_ARGV[0]); if (index == MIPS32NUMDSPREGS) { command_print(CMD, "ERROR: register '%s' not found", CMD_ARGV[0]); @@ -2174,8 +2216,13 @@ static int mips32_dsp_set_register(struct command_invocation *cmd, struct mips_e COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); int retval = mips32_pracc_write_dsp_reg(ejtag_info, value, index); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { command_print(CMD, "Error: could not write to dsp register %s", CMD_ARGV[0]); + return retval; + } + + mips32->core_regs.dsp[index] = value; + mips32->core_cache->reg_list[MIPS32_REGLIST_DSP_INDEX + index].dirty = 1; return retval; } @@ -2193,7 +2240,6 @@ COMMAND_HANDLER(mips32_handle_dsp_command) int retval, tmp; struct target *target = get_current_target(CMD_CTX); struct mips32_common *mips32 = target_to_mips32(target); - struct mips_ejtag *ejtag_info = &mips32->ejtag_info; retval = mips32_verify_pointer(CMD, mips32); if (retval != ERROR_OK) @@ -2217,10 +2263,10 @@ COMMAND_HANDLER(mips32_handle_dsp_command) switch (CMD_ARGC) { case 0: - retval = mips32_dsp_get_all_regs(CMD, ejtag_info); + retval = mips32_dsp_get_all_regs(CMD, mips32); break; case 1: - retval = mips32_dsp_get_register(CMD, ejtag_info); + retval = mips32_dsp_get_register(CMD, mips32); break; case 2: tmp = *CMD_ARGV[0]; @@ -2228,7 +2274,7 @@ COMMAND_HANDLER(mips32_handle_dsp_command) command_print(CMD, "Error: invalid dsp command format"); retval = ERROR_COMMAND_ARGUMENT_INVALID; } else { - retval = mips32_dsp_set_register(CMD, ejtag_info); + retval = mips32_dsp_set_register(CMD, mips32); } break; default: @@ -2311,7 +2357,7 @@ COMMAND_HANDLER(mips32_handle_scan_delay_command) if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], ejtag_info->scan_delay); else if (CMD_ARGC > 1) - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD, "scan delay: %d nsec", ejtag_info->scan_delay); if (ejtag_info->scan_delay >= MIPS32_SCAN_DELAY_LEGACY_MODE) { diff --git a/src/target/mips32.h b/src/target/mips32.h index a557f31..3d919e7 100644 --- a/src/target/mips32.h +++ b/src/target/mips32.h @@ -69,7 +69,7 @@ #define MIPS32_SCAN_DELAY_LEGACY_MODE 2000000 -#define MIPS32NUMDSPREGS 9 +#define MIPS32NUMDSPREGS 7 /* Bit Mask indicating CP0 register supported by this core */ #define MIPS_CP0_MK4 0x0001 @@ -78,6 +78,7 @@ #define MIPS_CP0_IAPTIV 0x0008 /* CP0 Status register fields */ +#define MIPS32_CP0_STATUS_MX_SHIFT 24 #define MIPS32_CP0_STATUS_FR_SHIFT 26 #define MIPS32_CP0_STATUS_CU1_SHIFT 29 @@ -211,6 +212,7 @@ static const struct mips32_cp0 { enum { MIPS32_PC = 37, MIPS32_FIR = 71, + MIPS32_DSPCTL = 78, MIPS32NUMCOREREGS }; @@ -220,11 +222,13 @@ enum { #define MIPS32_REG_FP_COUNT 32 #define MIPS32_REG_FPC_COUNT 2 #define MIPS32_REG_C0_COUNT 5 +#define MIPS32_REG_DSP_COUNT 7 #define MIPS32_REGLIST_GP_INDEX 0 #define MIPS32_REGLIST_FP_INDEX (MIPS32_REGLIST_GP_INDEX + MIPS32_REG_GP_COUNT) #define MIPS32_REGLIST_FPC_INDEX (MIPS32_REGLIST_FP_INDEX + MIPS32_REG_FP_COUNT) #define MIPS32_REGLIST_C0_INDEX (MIPS32_REGLIST_FPC_INDEX + MIPS32_REG_FPC_COUNT) +#define MIPS32_REGLIST_DSP_INDEX (MIPS32_REGLIST_C0_INDEX + MIPS32_REG_C0_COUNT) #define MIPS32_REGLIST_C0_STATUS_INDEX (MIPS32_REGLIST_C0_INDEX + 0) #define MIPS32_REGLIST_C0_BADVADDR_INDEX (MIPS32_REGLIST_C0_INDEX + 1) @@ -238,6 +242,10 @@ enum { #define MIPS32_REG_C0_PC_INDEX 3 #define MIPS32_REG_C0_GUESTCTL1_INDEX 4 +#define MIPS32_REGLIST_DSP_DSPCTL_INDEX (MIPS32_REGLIST_DSP_INDEX + 6) + +#define MIPS32_REG_DSP_DSPCTL_INDEX 6 + enum mips32_isa_mode { MIPS32_ISA_MIPS32 = 0, MIPS32_ISA_MIPS16E = 1, @@ -377,6 +385,7 @@ struct mips32_core_regs { uint64_t fpr[MIPS32_REG_FP_COUNT]; uint32_t fpcr[MIPS32_REG_FPC_COUNT]; uint32_t cp0[MIPS32_REG_C0_COUNT]; + uint32_t dsp[MIPS32_REG_DSP_COUNT]; }; struct mips32_common { diff --git a/src/target/mips32_pracc.c b/src/target/mips32_pracc.c index aaf3875..ea90d6f 100644 --- a/src/target/mips32_pracc.c +++ b/src/target/mips32_pracc.c @@ -212,7 +212,7 @@ static int mips32_pracc_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_i store_pending--; } else { /* read/fetch access */ - if (!final_check) { /* executing function code */ + if (!final_check) { /* executing function code */ /* check address */ if (ejtag_info->pa_addr != (MIPS32_PRACC_TEXT + code_count * 4)) { LOG_DEBUG("reading at unexpected address %" PRIx32 ", expected %x", @@ -243,7 +243,7 @@ static int mips32_pracc_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_i if (code_count == ctx->code_count) /* last instruction, start final check */ final_check = 1; - } else { /* final check after function code shifted out */ + } else { /* final check after function code shifted out */ /* check address */ if (ejtag_info->pa_addr == MIPS32_PRACC_TEXT) { if (!pass) { /* first pass through pracc text */ @@ -275,7 +275,7 @@ static int mips32_pracc_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_i } instr = MIPS32_NOP; /* shift out NOPs instructions */ code_count++; - } + } /* Send instruction out */ mips_ejtag_set_instr(ejtag_info, EJTAG_INST_DATA); @@ -370,7 +370,7 @@ int mips32_pracc_queue_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_in return ERROR_FAIL; } - unsigned num_clocks = + unsigned int num_clocks = ((uint64_t)(ejtag_info->scan_delay) * adapter_get_speed_khz() + 500000) / 1000000; uint32_t ejtag_ctrl = ejtag_info->ejtag_ctrl & ~EJTAG_CTRL_PRACC; @@ -400,7 +400,7 @@ int mips32_pracc_queue_exec(struct mips_ejtag *ejtag_info, struct pracc_queue_in ejtag_ctrl = buf_get_u32(scan_in[scan_count].scan_32.ctrl, 0, 32); uint32_t addr = buf_get_u32(scan_in[scan_count].scan_32.addr, 0, 32); if (!(ejtag_ctrl & EJTAG_CTRL_PRACC)) { - LOG_ERROR("Error: access not pending count: %d", scan_count); + LOG_ERROR("Access not pending, count: %d", scan_count); retval = ERROR_FAIL; goto exit; } @@ -878,6 +878,7 @@ int mips32_pracc_write_regs(struct mips32_common *mips32) uint32_t *c0rs = mips32->core_regs.cp0; bool fpu_in_64bit = ((c0rs[0] & BIT(MIPS32_CP0_STATUS_FR_SHIFT)) != 0); bool fp_enabled = ((c0rs[0] & BIT(MIPS32_CP0_STATUS_CU1_SHIFT)) != 0); + bool dsp_enabled = ((c0rs[0] & BIT(MIPS32_CP0_STATUS_MX_SHIFT)) != 0); uint32_t rel = (ejtag_info->config[0] & MIPS32_CONFIG0_AR_MASK) >> MIPS32_CONFIG0_AR_SHIFT; pracc_queue_init(&ctx); @@ -943,6 +944,34 @@ int mips32_pracc_write_regs(struct mips32_common *mips32) pracc_add(&ctx, 0, MIPS32_EHB(ctx.isa)); } + /* Store DSP Accumulators */ + if (mips32->dsp_imp && dsp_enabled) { + /* Struct of mips32_dsp_regs: {ac{hi, lo}1-3, dspctl} */ + uint32_t *dspr = mips32->core_regs.dsp; + size_t dsp_regs = ARRAY_SIZE(mips32->core_regs.dsp); + + /* Starts from ac1, core_regs.dsp contains dspctl register, therefore - 1 */ + for (size_t index = 0; index != ((dsp_regs - 1) / 2); index++) { + /* Every accumulator have 2 registers, hi and lo, and core_regs.dsp stores ac[1~3] */ + /* reads hi[ac] from core_regs array */ + pracc_add_li32(&ctx, 2, dspr[index * 2], 0); + /* reads lo[ac] from core_regs array */ + pracc_add_li32(&ctx, 3, dspr[(index * 2) + 1], 0); + + /* Write to accumulator 1~3 and index starts from 0, therefore ac = index + 1 */ + size_t ac = index + 1; + pracc_add(&ctx, 0, MIPS32_DSP_MTHI(2, ac)); + pracc_add(&ctx, 0, MIPS32_DSP_MTLO(3, ac)); + } + + /* DSPCTL is the last element of register store */ + pracc_add_li32(&ctx, 2, dspr[6], 0); + pracc_add(&ctx, 0, MIPS32_DSP_WRDSP(2, 0x1F)); + + if (rel > MIPS32_RELEASE_1) + pracc_add(&ctx, 0, MIPS32_EHB(ctx.isa)); + } + /* load registers 2 to 31 with li32, optimize */ for (int i = 2; i < 32; i++) pracc_add_li32(&ctx, i, gprs[i], 1); @@ -1064,14 +1093,16 @@ int mips32_pracc_read_regs(struct mips32_common *mips32) unsigned int offset_cp0 = ((uint8_t *)&core_regs->cp0[0]) - (uint8_t *)core_regs; unsigned int offset_fpr = ((uint8_t *)&core_regs->fpr[0]) - (uint8_t *)core_regs; unsigned int offset_fpcr = ((uint8_t *)&core_regs->fpcr[0]) - (uint8_t *)core_regs; - bool fp_enabled; + unsigned int offset_dsp = ((uint8_t *)&core_regs->dsp[0]) - (uint8_t *)core_regs; + bool fp_enabled, dsp_enabled; /* - * This procedure has to be in 2 distinctive steps, because we can - * only know whether FP is enabled after reading CP0. + * This procedure has to be in 3 distinctive steps, because we can + * only know whether FP and DSP are enabled after reading CP0. * - * Step 1: Read everything except CP1 stuff + * Step 1: Read everything except CP1 and DSP stuff * Step 2: Read CP1 stuff if FP is implemented + * Step 3: Read DSP registers if dsp is implemented */ pracc_queue_init(&ctx); @@ -1149,6 +1180,50 @@ int mips32_pracc_read_regs(struct mips32_common *mips32) pracc_queue_free(&ctx); } + + dsp_enabled = (mips32->core_regs.cp0[MIPS32_REG_C0_STATUS_INDEX] & BIT(MIPS32_CP0_STATUS_MX_SHIFT)) != 0; + if (mips32->dsp_imp && dsp_enabled) { + pracc_queue_init(&ctx); + + mips32_pracc_store_regs_set_base_addr(&ctx); + + /* Struct of mips32_dsp_regs[7]: {ac{hi, lo}1-3, dspctl} */ + size_t dsp_regs = ARRAY_SIZE(mips32->core_regs.dsp); + /* Starts from ac1, core_regs.dsp have dspctl register, therefore - 1 */ + for (size_t index = 0; index != ((dsp_regs - 1) / 2); index++) { + /* Every accumulator have 2 registers, hi&lo, and core_regs.dsp stores ac[1~3] */ + /* Reads offset of hi[ac] from core_regs array */ + size_t offset_hi = offset_dsp + ((index * 2) * sizeof(uint32_t)); + /* Reads offset of lo[ac] from core_regs array */ + size_t offset_lo = offset_dsp + (((index * 2) + 1) * sizeof(uint32_t)); + + /* DSP Ac registers starts from 1 and index starts from 0, therefore ac = index + 1 */ + size_t ac = index + 1; + pracc_add(&ctx, 0, MIPS32_DSP_MFHI(8, ac)); + pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + offset_hi, + MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + offset_hi, 1)); + pracc_add(&ctx, 0, MIPS32_DSP_MFLO(8, ac)); + pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + offset_lo, + MIPS32_SW(ctx.isa, 8, PRACC_OUT_OFFSET + offset_lo, 1)); + } + + /* DSPCTL is the last element of register store */ + pracc_add(&ctx, 0, MIPS32_DSP_RDDSP(8, 0x3F)); + pracc_add(&ctx, MIPS32_PRACC_PARAM_OUT + offset_dsp + ((dsp_regs - 1) * sizeof(uint32_t)), + MIPS32_SW(ctx.isa, 8, + PRACC_OUT_OFFSET + offset_dsp + ((dsp_regs - 1) * sizeof(uint32_t)), 1)); + + mips32_pracc_store_regs_restore(&ctx); + + /* jump to start */ + pracc_add(&ctx, 0, MIPS32_B(ctx.isa, NEG16((ctx.code_count + 1) << ctx.isa))); + /* load $15 in DeSave */ + pracc_add(&ctx, 0, MIPS32_MTC0(ctx.isa, 15, 31, 0)); + + ctx.retval = mips32_pracc_queue_exec(ejtag_info, &ctx, (uint32_t *)&mips32->core_regs, 1); + + pracc_queue_free(&ctx); + } return ctx.retval; } @@ -1287,7 +1362,7 @@ int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_are pracc_swap16_array(ejtag_info, jmp_code, ARRAY_SIZE(jmp_code)); /* execute jump code, with no address check */ - for (unsigned i = 0; i < ARRAY_SIZE(jmp_code); i++) { + for (unsigned int i = 0; i < ARRAY_SIZE(jmp_code); i++) { int retval = wait_for_pracc_rw(ejtag_info); if (retval != ERROR_OK) return retval; @@ -1322,7 +1397,7 @@ int mips32_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_are mips_ejtag_set_instr(ejtag_info, EJTAG_INST_FASTDATA); mips_ejtag_fastdata_scan(ejtag_info, 1, &val); - unsigned num_clocks = 0; /* like in legacy code */ + unsigned int num_clocks = 0; /* like in legacy code */ if (ejtag_info->mode != 0) num_clocks = ((uint64_t)(ejtag_info->scan_delay) * adapter_get_speed_khz() + 500000) / 1000000; diff --git a/src/target/mips32_pracc.h b/src/target/mips32_pracc.h index f78f891..a0244a6 100644 --- a/src/target/mips32_pracc.h +++ b/src/target/mips32_pracc.h @@ -45,7 +45,7 @@ struct pa_list { struct pracc_queue_info { struct mips_ejtag *ejtag_info; - unsigned isa; + unsigned int isa; int retval; int code_count; int store_count; diff --git a/src/target/mips64.c b/src/target/mips64.c index 48f4563..3d193a3 100644 --- a/src/target/mips64.c +++ b/src/target/mips64.c @@ -21,7 +21,7 @@ #include "mips64.h" static const struct { - unsigned id; + unsigned int id; const char *name; enum reg_type type; const char *group; @@ -332,8 +332,8 @@ int mips64_save_context(struct target *target) if (retval != ERROR_OK) return retval; - for (unsigned i = 0; i < MIPS64_NUM_REGS; i++) - retval = mips64->read_core_reg(target, i); + for (unsigned int i = 0; i < MIPS64_NUM_REGS; i++) + retval = mips64->read_core_reg(target, i); return retval; } @@ -343,7 +343,7 @@ int mips64_restore_context(struct target *target) struct mips64_common *mips64 = target->arch_info; struct mips_ejtag *ejtag_info = &mips64->ejtag_info; - for (unsigned i = 0; i < MIPS64_NUM_REGS; i++) { + for (unsigned int i = 0; i < MIPS64_NUM_REGS; i++) { if (mips64->core_cache->reg_list[i].dirty) mips64->write_core_reg(target, i); } @@ -379,7 +379,7 @@ int mips64_build_reg_cache(struct target *target) struct reg_cache **cache_p, *cache; struct mips64_core_reg *arch_info = NULL; struct reg *reg_list = NULL; - unsigned i; + unsigned int i; cache = calloc(1, sizeof(*cache)); if (!cache) { diff --git a/src/target/mips64_pracc.c b/src/target/mips64_pracc.c index b083f5c..11783fe 100644 --- a/src/target/mips64_pracc.c +++ b/src/target/mips64_pracc.c @@ -27,13 +27,13 @@ struct mips64_pracc_context { uint64_t *local_iparam; - unsigned num_iparam; + unsigned int num_iparam; uint64_t *local_oparam; - unsigned num_oparam; + unsigned int num_oparam; const uint32_t *code; - unsigned code_len; + unsigned int code_len; uint64_t stack[STACK_DEPTH]; - unsigned stack_offset; + unsigned int stack_offset; struct mips_ejtag *ejtag_info; }; @@ -65,7 +65,7 @@ static int wait_for_pracc_rw(struct mips_ejtag *ejtag_info, uint32_t *ctrl) static int mips64_pracc_exec_read(struct mips64_pracc_context *ctx, uint64_t address) { struct mips_ejtag *ejtag_info = ctx->ejtag_info; - unsigned offset; + unsigned int offset; uint32_t ejtag_ctrl; uint64_t data; int rc; @@ -76,12 +76,12 @@ static int mips64_pracc_exec_read(struct mips64_pracc_context *ctx, uint64_t add offset = (address - MIPS64_PRACC_PARAM_IN) / MIPS64_PRACC_DATA_STEP; if (offset >= MIPS64_PRACC_PARAM_IN_SIZE) { - LOG_ERROR("Error: iparam size exceeds MIPS64_PRACC_PARAM_IN_SIZE"); + LOG_ERROR("iparam size exceeds MIPS64_PRACC_PARAM_IN_SIZE"); return ERROR_JTAG_DEVICE_ERROR; } if (!ctx->local_iparam) { - LOG_ERROR("Error: unexpected reading of input parameter"); + LOG_ERROR("unexpected reading of input parameter"); return ERROR_JTAG_DEVICE_ERROR; } @@ -93,7 +93,7 @@ static int mips64_pracc_exec_read(struct mips64_pracc_context *ctx, uint64_t add offset = (address - MIPS64_PRACC_PARAM_OUT) / MIPS64_PRACC_DATA_STEP; if (!ctx->local_oparam) { - LOG_ERROR("Error: unexpected reading of output parameter"); + LOG_ERROR("unexpected reading of output parameter"); return ERROR_JTAG_DEVICE_ERROR; } @@ -154,7 +154,7 @@ static int mips64_pracc_exec_write(struct mips64_pracc_context *ctx, uint64_t ad { uint32_t ejtag_ctrl; uint64_t data; - unsigned offset; + unsigned int offset; struct mips_ejtag *ejtag_info = ctx->ejtag_info; int rc; @@ -181,7 +181,7 @@ static int mips64_pracc_exec_write(struct mips64_pracc_context *ctx, uint64_t ad && (address < MIPS64_PRACC_PARAM_IN + ctx->num_iparam * MIPS64_PRACC_DATA_STEP)) { offset = (address - MIPS64_PRACC_PARAM_IN) / MIPS64_PRACC_DATA_STEP; if (!ctx->local_iparam) { - LOG_ERROR("Error: unexpected writing of input parameter"); + LOG_ERROR("unexpected writing of input parameter"); return ERROR_JTAG_DEVICE_ERROR; } ctx->local_iparam[offset] = data; @@ -189,14 +189,14 @@ static int mips64_pracc_exec_write(struct mips64_pracc_context *ctx, uint64_t ad && (address < MIPS64_PRACC_PARAM_OUT + ctx->num_oparam * MIPS64_PRACC_DATA_STEP)) { offset = (address - MIPS64_PRACC_PARAM_OUT) / MIPS64_PRACC_DATA_STEP; if (!ctx->local_oparam) { - LOG_ERROR("Error: unexpected writing of output parameter"); + LOG_ERROR("unexpected writing of output parameter"); return ERROR_JTAG_DEVICE_ERROR; } ctx->local_oparam[offset] = data; } else if (address == MIPS64_PRACC_STACK) { /* save data onto our stack */ if (ctx->stack_offset >= STACK_DEPTH) { - LOG_ERROR("Error: PrAcc stack depth exceeded"); + LOG_ERROR("PrAcc stack depth exceeded"); return ERROR_FAIL; } ctx->stack[ctx->stack_offset++] = data; @@ -209,9 +209,9 @@ static int mips64_pracc_exec_write(struct mips64_pracc_context *ctx, uint64_t ad } int mips64_pracc_exec(struct mips_ejtag *ejtag_info, - unsigned code_len, const uint32_t *code, - unsigned num_param_in, uint64_t *param_in, - unsigned num_param_out, uint64_t *param_out) + unsigned int code_len, const uint32_t *code, + unsigned int num_param_in, uint64_t *param_in, + unsigned int num_param_out, uint64_t *param_out) { uint32_t ejtag_ctrl; uint64_t address = 0, address_prev = 0; @@ -219,7 +219,7 @@ int mips64_pracc_exec(struct mips_ejtag *ejtag_info, int retval; int pass = 0; bool first_time_call = true; - unsigned i; + unsigned int i; for (i = 0; i < code_len; i++) LOG_DEBUG("%08" PRIx32, code[i]); @@ -354,11 +354,11 @@ static int mips64_pracc_read_u64(struct mips_ejtag *ejtag_info, uint64_t addr, } static int mips64_pracc_read_mem64(struct mips_ejtag *ejtag_info, uint64_t addr, - unsigned count, uint64_t *buf) + unsigned int count, uint64_t *buf) { int retval = ERROR_OK; - for (unsigned i = 0; i < count; i++) { + for (unsigned int i = 0; i < count; i++) { retval = mips64_pracc_read_u64(ejtag_info, addr + 8*i, &buf[i]); if (retval != ERROR_OK) return retval; @@ -414,11 +414,11 @@ static int mips64_pracc_read_u32(struct mips_ejtag *ejtag_info, uint64_t addr, } static int mips64_pracc_read_mem32(struct mips_ejtag *ejtag_info, uint64_t addr, - unsigned count, uint32_t *buf) + unsigned int count, uint32_t *buf) { int retval = ERROR_OK; - for (unsigned i = 0; i < count; i++) { + for (unsigned int i = 0; i < count; i++) { retval = mips64_pracc_read_u32(ejtag_info, addr + 4 * i, &buf[i]); if (retval != ERROR_OK) return retval; @@ -474,11 +474,11 @@ static int mips64_pracc_read_u16(struct mips_ejtag *ejtag_info, uint64_t addr, } static int mips64_pracc_read_mem16(struct mips_ejtag *ejtag_info, uint64_t addr, - unsigned count, uint16_t *buf) + unsigned int count, uint16_t *buf) { int retval = ERROR_OK; - for (unsigned i = 0; i < count; i++) { + for (unsigned int i = 0; i < count; i++) { retval = mips64_pracc_read_u16(ejtag_info, addr + 2*i, &buf[i]); if (retval != ERROR_OK) return retval; @@ -534,11 +534,11 @@ static int mips64_pracc_read_u8(struct mips_ejtag *ejtag_info, uint64_t addr, } static int mips64_pracc_read_mem8(struct mips_ejtag *ejtag_info, uint64_t addr, - unsigned count, uint8_t *buf) + unsigned int count, uint8_t *buf) { int retval = ERROR_OK; - for (unsigned i = 0; i < count; i++) { + for (unsigned int i = 0; i < count; i++) { retval = mips64_pracc_read_u8(ejtag_info, addr + i, &buf[i]); if (retval != ERROR_OK) return retval; @@ -547,7 +547,7 @@ static int mips64_pracc_read_mem8(struct mips_ejtag *ejtag_info, uint64_t addr, } int mips64_pracc_read_mem(struct mips_ejtag *ejtag_info, uint64_t addr, - unsigned size, unsigned count, void *buf) + unsigned int size, unsigned int count, void *buf) { switch (size) { case 1: @@ -612,11 +612,11 @@ static int mips64_pracc_write_u64(struct mips_ejtag *ejtag_info, uint64_t addr, } static int mips64_pracc_write_mem64(struct mips_ejtag *ejtag_info, - uint64_t addr, unsigned count, uint64_t *buf) + uint64_t addr, unsigned int count, uint64_t *buf) { int retval = ERROR_OK; - for (unsigned i = 0; i < count; i++) { + for (unsigned int i = 0; i < count; i++) { retval = mips64_pracc_write_u64(ejtag_info, addr + 8 * i, &buf[i]); if (retval != ERROR_OK) return retval; @@ -674,11 +674,11 @@ static int mips64_pracc_write_u32(struct mips_ejtag *ejtag_info, uint64_t addr, } static int mips64_pracc_write_mem32(struct mips_ejtag *ejtag_info, uint64_t addr, - unsigned count, uint32_t *buf) + unsigned int count, uint32_t *buf) { int retval = ERROR_OK; - for (unsigned i = 0; i < count; i++) { + for (unsigned int i = 0; i < count; i++) { retval = mips64_pracc_write_u32(ejtag_info, addr + 4 * i, &buf[i]); if (retval != ERROR_OK) return retval; @@ -734,11 +734,11 @@ static int mips64_pracc_write_u16(struct mips_ejtag *ejtag_info, uint64_t addr, } static int mips64_pracc_write_mem16(struct mips_ejtag *ejtag_info, - uint64_t addr, unsigned count, uint16_t *buf) + uint64_t addr, unsigned int count, uint16_t *buf) { int retval = ERROR_OK; - for (unsigned i = 0; i < count; i++) { + for (unsigned int i = 0; i < count; i++) { retval = mips64_pracc_write_u16(ejtag_info, addr + 2 * i, &buf[i]); if (retval != ERROR_OK) return retval; @@ -795,11 +795,11 @@ static int mips64_pracc_write_u8(struct mips_ejtag *ejtag_info, uint64_t addr, } static int mips64_pracc_write_mem8(struct mips_ejtag *ejtag_info, - uint64_t addr, unsigned count, uint8_t *buf) + uint64_t addr, unsigned int count, uint8_t *buf) { int retval = ERROR_OK; - for (unsigned i = 0; i < count; i++) { + for (unsigned int i = 0; i < count; i++) { retval = mips64_pracc_write_u8(ejtag_info, addr + i, &buf[i]); if (retval != ERROR_OK) return retval; @@ -808,8 +808,8 @@ static int mips64_pracc_write_mem8(struct mips_ejtag *ejtag_info, } int mips64_pracc_write_mem(struct mips_ejtag *ejtag_info, - uint64_t addr, unsigned size, - unsigned count, void *buf) + uint64_t addr, unsigned int size, + unsigned int count, void *buf) { switch (size) { case 1: @@ -1270,7 +1270,7 @@ int mips64_pracc_read_regs(struct mips_ejtag *ejtag_info, uint64_t *regs) int mips64_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_area *source, bool write_t, uint64_t addr, - unsigned count, uint64_t *buf) + unsigned int count, uint64_t *buf) { uint32_t handler_code[] = { /* caution when editing, table is modified below */ @@ -1321,7 +1321,7 @@ int mips64_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, }; int retval; - unsigned i; + unsigned int i; uint32_t ejtag_ctrl, address32; uint64_t address, val; @@ -1385,7 +1385,7 @@ int mips64_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, mips64_ejtag_fastdata_scan(ejtag_info, 1, &val); /* like in legacy code */ - unsigned num_clocks = 0; + unsigned int num_clocks = 0; if (ejtag_info->mode != 0) num_clocks = ((uint64_t)(ejtag_info->scan_delay) * adapter_get_speed_khz() + 500000) / 1000000; LOG_DEBUG("num_clocks=%d", num_clocks); diff --git a/src/target/mips64_pracc.h b/src/target/mips64_pracc.h index 19d1519..2bdc856 100644 --- a/src/target/mips64_pracc.h +++ b/src/target/mips64_pracc.h @@ -40,20 +40,22 @@ #define MIPS64_PRACC_ADDR_STEP 4 #define MIPS64_PRACC_DATA_STEP 8 -int mips64_pracc_read_mem(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned size, unsigned count, void *buf); -int mips64_pracc_write_mem(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned size, unsigned count, void *buf); +int mips64_pracc_read_mem(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned int size, + unsigned int count, void *buf); +int mips64_pracc_write_mem(struct mips_ejtag *ejtag_info, uint64_t addr, unsigned int size, + unsigned int count, void *buf); int mips64_pracc_read_regs(struct mips_ejtag *ejtag_info, uint64_t *regs); int mips64_pracc_write_regs(struct mips_ejtag *ejtag_info, uint64_t *regs); int mips64_pracc_exec(struct mips_ejtag *ejtag_info, - unsigned code_len, const uint32_t *code, - unsigned num_param_in, uint64_t *param_in, - unsigned num_param_out, uint64_t *param_out); + unsigned int code_len, const uint32_t *code, + unsigned int num_param_in, uint64_t *param_in, + unsigned int num_param_out, uint64_t *param_out); int mips64_pracc_fastdata_xfer(struct mips_ejtag *ejtag_info, struct working_area *source, bool write_t, uint64_t addr, - unsigned count, uint64_t *buf); + unsigned int count, uint64_t *buf); #endif /* OPENOCD_TARGET_MIPS64_PRACC_H */ diff --git a/src/target/mips_ejtag.c b/src/target/mips_ejtag.c index 389461c..2ff4aa9 100644 --- a/src/target/mips_ejtag.c +++ b/src/target/mips_ejtag.c @@ -493,7 +493,7 @@ int mips64_ejtag_config_step(struct mips_ejtag *ejtag_info, bool enable_step) MIPS64_NOP, }; const uint32_t *code = enable_step ? code_enable : code_disable; - unsigned code_len = enable_step ? ARRAY_SIZE(code_enable) : + unsigned int code_len = enable_step ? ARRAY_SIZE(code_enable) : ARRAY_SIZE(code_disable); return mips64_pracc_exec(ejtag_info, diff --git a/src/target/mips_ejtag.h b/src/target/mips_ejtag.h index 7376e51..30a4690 100644 --- a/src/target/mips_ejtag.h +++ b/src/target/mips_ejtag.h @@ -214,7 +214,7 @@ struct mips_ejtag { uint32_t reg8; uint32_t reg9; - unsigned scan_delay; + unsigned int scan_delay; int mode; uint32_t pa_ctrl; uint32_t pa_addr; diff --git a/src/target/mips_m4k.c b/src/target/mips_m4k.c index ad98089..dc74501 100644 --- a/src/target/mips_m4k.c +++ b/src/target/mips_m4k.c @@ -30,9 +30,9 @@ static int mips_m4k_set_breakpoint(struct target *target, struct breakpoint *breakpoint); static int mips_m4k_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); -static int mips_m4k_internal_restore(struct target *target, int current, - target_addr_t address, int handle_breakpoints, - int debug_execution); +static int mips_m4k_internal_restore(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, + bool debug_execution); static int mips_m4k_halt(struct target *target); static int mips_m4k_bulk_write_memory(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer); @@ -398,7 +398,8 @@ static int mips_m4k_single_step_core(struct target *target) return ERROR_OK; } -static int mips_m4k_restore_smp(struct target *target, uint32_t address, int handle_breakpoints) +static int mips_m4k_restore_smp(struct target *target, uint32_t address, + bool handle_breakpoints) { int retval = ERROR_OK; struct target_list *head; @@ -408,8 +409,8 @@ static int mips_m4k_restore_smp(struct target *target, uint32_t address, int han struct target *curr = head->target; if ((curr != target) && (curr->state != TARGET_RUNNING)) { /* resume current address , not in step mode */ - ret = mips_m4k_internal_restore(curr, 1, address, - handle_breakpoints, 0); + ret = mips_m4k_internal_restore(curr, true, address, + handle_breakpoints, false); if (ret != ERROR_OK) { LOG_TARGET_ERROR(curr, "failed to resume at address: 0x%" PRIx32, @@ -421,8 +422,9 @@ static int mips_m4k_restore_smp(struct target *target, uint32_t address, int han return retval; } -static int mips_m4k_internal_restore(struct target *target, int current, - target_addr_t address, int handle_breakpoints, int debug_execution) +static int mips_m4k_internal_restore(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, + bool debug_execution) { struct mips32_common *mips32 = target_to_mips32(target); struct mips_ejtag *ejtag_info = &mips32->ejtag_info; @@ -440,7 +442,7 @@ static int mips_m4k_internal_restore(struct target *target, int current, mips_m4k_enable_watchpoints(target); } - /* current = 1: continue on current pc, otherwise continue at <address> */ + /* current = true: continue on current pc, otherwise continue at <address> */ if (!current) { mips_m4k_isa_filter(mips32->isa_imp, &address); buf_set_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32, address); @@ -448,7 +450,7 @@ static int mips_m4k_internal_restore(struct target *target, int current, mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].valid = true; } - if ((mips32->isa_imp > 1) && debug_execution) /* if more than one isa supported */ + if (mips32->isa_imp > 1 && debug_execution) /* if more than one isa supported */ buf_set_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 1, mips32->isa_mode); if (!current) @@ -494,8 +496,8 @@ static int mips_m4k_internal_restore(struct target *target, int current, return ERROR_OK; } -static int mips_m4k_resume(struct target *target, int current, - target_addr_t address, int handle_breakpoints, int debug_execution) +static int mips_m4k_resume(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, bool debug_execution) { int retval = ERROR_OK; @@ -521,8 +523,8 @@ static int mips_m4k_resume(struct target *target, int current, return retval; } -static int mips_m4k_step(struct target *target, int current, - target_addr_t address, int handle_breakpoints) +static int mips_m4k_step(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints) { /* get pointers to arch-specific information */ struct mips32_common *mips32 = target_to_mips32(target); @@ -534,7 +536,7 @@ static int mips_m4k_step(struct target *target, int current, return ERROR_TARGET_NOT_HALTED; } - /* current = 1: continue on current pc, otherwise continue at <address> */ + /* current = true: continue on current pc, otherwise continue at <address> */ if (!current) { mips_m4k_isa_filter(mips32->isa_imp, &address); buf_set_u32(mips32->core_cache->reg_list[MIPS32_REGLIST_C0_PC_INDEX].value, 0, 32, address); @@ -1397,7 +1399,7 @@ COMMAND_HANDLER(mips_m4k_handle_scan_delay_command) if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], ejtag_info->scan_delay); else if (CMD_ARGC > 1) - return ERROR_COMMAND_SYNTAX_ERROR; + return ERROR_COMMAND_SYNTAX_ERROR; command_print(CMD, "scan delay: %d nsec", ejtag_info->scan_delay); if (ejtag_info->scan_delay >= MIPS32_SCAN_DELAY_LEGACY_MODE) { diff --git a/src/target/mips_mips64.c b/src/target/mips_mips64.c index 9921e93..85e3779 100644 --- a/src/target/mips_mips64.c +++ b/src/target/mips_mips64.c @@ -592,9 +592,9 @@ static int mips_mips64_unset_breakpoint(struct target *target, return ERROR_OK; } -static int mips_mips64_resume(struct target *target, int current, - uint64_t address, int handle_breakpoints, - int debug_execution) +static int mips_mips64_resume(struct target *target, bool current, + uint64_t address, bool handle_breakpoints, + bool debug_execution) { struct mips64_common *mips64 = target->arch_info; struct mips_ejtag *ejtag_info = &mips64->ejtag_info; @@ -622,7 +622,7 @@ static int mips_mips64_resume(struct target *target, int current, } pc = &mips64->core_cache->reg_list[MIPS64_PC]; - /* current = 1: continue on current pc, otherwise continue at <address> */ + /* current = true: continue on current pc, otherwise continue at <address> */ if (!current) { buf_set_u64(pc->value, 0, 64, address); pc->dirty = true; @@ -696,8 +696,8 @@ static int mips_mips64_resume(struct target *target, int current, return ERROR_OK; } -static int mips_mips64_step(struct target *target, int current, - uint64_t address, int handle_breakpoints) +static int mips_mips64_step(struct target *target, bool current, + uint64_t address, bool handle_breakpoints) { struct mips64_common *mips64 = target->arch_info; struct mips_ejtag *ejtag_info = &mips64->ejtag_info; @@ -713,7 +713,7 @@ static int mips_mips64_step(struct target *target, int current, if (mips64->mips64mode32) address = mips64_extend_sign(address); - /* current = 1: continue on current pc, otherwise continue at + /* current = true: continue on current pc, otherwise continue at * <address> */ if (!current) { buf_set_u64(pc->value, 0, 64, address); diff --git a/src/target/openrisc/or1k.c b/src/target/openrisc/or1k.c index 8c38610..4b9d3bc 100644 --- a/src/target/openrisc/or1k.c +++ b/src/target/openrisc/or1k.c @@ -27,8 +27,8 @@ #include "or1k.h" #include "or1k_du.h" -LIST_HEAD(tap_list); -LIST_HEAD(du_list); +OOCD_LIST_HEAD(tap_list); +OOCD_LIST_HEAD(du_list); static int or1k_remove_breakpoint(struct target *target, struct breakpoint *breakpoint); @@ -775,9 +775,9 @@ static bool is_any_soft_breakpoint(struct target *target) return false; } -static int or1k_resume_or_step(struct target *target, int current, - uint32_t address, int handle_breakpoints, - int debug_execution, int step) +static int or1k_resume_or_step(struct target *target, bool current, + uint32_t address, bool handle_breakpoints, bool debug_execution, + int step) { struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); @@ -885,9 +885,8 @@ static int or1k_resume_or_step(struct target *target, int current, return ERROR_OK; } -static int or1k_resume(struct target *target, int current, - target_addr_t address, int handle_breakpoints, - int debug_execution) +static int or1k_resume(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, bool debug_execution) { return or1k_resume_or_step(target, current, address, handle_breakpoints, @@ -895,12 +894,12 @@ static int or1k_resume(struct target *target, int current, NO_SINGLE_STEP); } -static int or1k_step(struct target *target, int current, - target_addr_t address, int handle_breakpoints) +static int or1k_step(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints) { return or1k_resume_or_step(target, current, address, handle_breakpoints, - 0, + false, SINGLE_STEP); } @@ -1216,7 +1215,7 @@ static int or1k_profiling(struct target *target, uint32_t *samples, /* Make sure the target is running */ target_poll(target); if (target->state == TARGET_HALTED) - retval = target_resume(target, 1, 0, 0, 0); + retval = target_resume(target, true, 0, false, false); if (retval != ERROR_OK) { LOG_ERROR("Error while resuming target"); diff --git a/src/target/openrisc/or1k_du_adv.c b/src/target/openrisc/or1k_du_adv.c index e4003a2..f401ea9 100644 --- a/src/target/openrisc/or1k_du_adv.c +++ b/src/target/openrisc/or1k_du_adv.c @@ -362,7 +362,7 @@ static int adbg_ctrl_read(struct or1k_jtag *jtag_info, uint32_t regidx, default: LOG_ERROR("Illegal debug chain selected (%i) while doing control read", jtag_info->or1k_jtag_module_selected); - return ERROR_FAIL; + return ERROR_FAIL; } /* Zero MSB = op for module, not top-level debug unit */ diff --git a/src/target/quark_d20xx.c b/src/target/quark_d20xx.c index d63a42a..90cf667 100644 --- a/src/target/quark_d20xx.c +++ b/src/target/quark_d20xx.c @@ -65,7 +65,7 @@ static int quark_d20xx_reset_deassert(struct target *t) } /* resume target if reset mode is run */ if (!t->reset_halt) { - retval = lakemont_resume(t, 1, 0, 0, 0); + retval = lakemont_resume(t, true, 0, false, false); if (retval != ERROR_OK) { LOG_ERROR("%s could not resume target", __func__); return retval; diff --git a/src/target/register.h b/src/target/register.h index 1e4f2e0..b9af401 100644 --- a/src/target/register.h +++ b/src/target/register.h @@ -145,7 +145,7 @@ struct reg_cache { const char *name; struct reg_cache *next; struct reg *reg_list; - unsigned num_regs; + unsigned int num_regs; }; struct reg_arch_type { diff --git a/src/target/riscv/Makefile.am b/src/target/riscv/Makefile.am index aa82f58..189edb3 100644 --- a/src/target/riscv/Makefile.am +++ b/src/target/riscv/Makefile.am @@ -2,15 +2,17 @@ noinst_LTLIBRARIES += %D%/libriscv.la %C%_libriscv_la_SOURCES = \ - %D%/asm.h \ %D%/batch.h \ %D%/debug_defines.h \ %D%/debug_reg_printer.h \ %D%/encoding.h \ + %D%/field_helpers.h \ %D%/gdb_regs.h \ %D%/opcodes.h \ %D%/program.h \ %D%/riscv.h \ + %D%/riscv_reg_impl.h \ + %D%/riscv_reg.h \ %D%/riscv-011.h \ %D%/riscv-011_reg.h \ %D%/riscv-013.h \ @@ -26,3 +28,5 @@ noinst_LTLIBRARIES += %D%/libriscv.la %D%/riscv_semihosting.c \ %D%/debug_defines.c \ %D%/debug_reg_printer.c + +STARTUP_TCL_SRCS += %D%/startup.tcl diff --git a/src/target/riscv/asm.h b/src/target/riscv/asm.h deleted file mode 100644 index 6ceb8c9..0000000 --- a/src/target/riscv/asm.h +++ /dev/null @@ -1,40 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0-or-later */ - -#ifndef TARGET__RISCV__ASM_H -#define TARGET__RISCV__ASM_H - -#include "riscv.h" - -/*** Version-independent functions that we don't want in the main address space. ***/ - -static uint32_t load(const struct target *target, unsigned int rd, - unsigned int base, uint16_t offset) __attribute__ ((unused)); -static uint32_t load(const struct target *target, unsigned int rd, - unsigned int base, uint16_t offset) -{ - switch (riscv_xlen(target)) { - case 32: - return lw(rd, base, offset); - case 64: - return ld(rd, base, offset); - } - assert(0); - return 0; /* Silence -Werror=return-type */ -} - -static uint32_t store(const struct target *target, unsigned int src, - unsigned int base, uint16_t offset) __attribute__ ((unused)); -static uint32_t store(const struct target *target, unsigned int src, - unsigned int base, uint16_t offset) -{ - switch (riscv_xlen(target)) { - case 32: - return sw(src, base, offset); - case 64: - return sd(src, base, offset); - } - assert(0); - return 0; /* Silence -Werror=return-type */ -} - -#endif diff --git a/src/target/riscv/batch.c b/src/target/riscv/batch.c index bb1070a..ec68b37 100644 --- a/src/target/riscv/batch.c +++ b/src/target/riscv/batch.c @@ -6,16 +6,28 @@ #include "batch.h" #include "debug_defines.h" +#include "debug_reg_printer.h" #include "riscv.h" #include "field_helpers.h" +// TODO: DTM_DMI_MAX_ADDRESS_LENGTH should be reduced to 32 (per the debug spec) #define DTM_DMI_MAX_ADDRESS_LENGTH ((1<<DTM_DTMCS_ABITS_LENGTH)-1) #define DMI_SCAN_MAX_BIT_LENGTH (DTM_DMI_MAX_ADDRESS_LENGTH + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH) + #define DMI_SCAN_BUF_SIZE (DIV_ROUND_UP(DMI_SCAN_MAX_BIT_LENGTH, 8)) /* Reserve extra room in the batch (needed for the last NOP operation) */ #define BATCH_RESERVED_SCANS 1 +static unsigned int get_dmi_scan_length(const struct target *target) +{ + const unsigned int abits = riscv_get_dmi_address_bits(target); + assert(abits > 0); + assert(abits <= DTM_DMI_MAX_ADDRESS_LENGTH); + + return abits + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH; +} + struct riscv_batch *riscv_batch_alloc(struct target *target, size_t scans) { scans += BATCH_RESERVED_SCANS; @@ -126,20 +138,141 @@ static void add_idle_before_batch(const struct riscv_batch *batch, size_t start_ const unsigned int idle_change = new_delay - batch->last_scan_delay; LOG_TARGET_DEBUG(batch->target, "Adding %u idle cycles before the batch.", idle_change); - assert(idle_change <= INT_MAX); jtag_add_runtest(idle_change, TAP_IDLE); } -static int get_delay(const struct riscv_batch *batch, size_t scan_idx, - const struct riscv_scan_delays *delays) +static unsigned int get_delay(const struct riscv_batch *batch, size_t scan_idx, + const struct riscv_scan_delays *delays, bool resets_delays, + size_t reset_delays_after) { assert(batch); assert(scan_idx < batch->used_scans); + const bool delays_were_reset = resets_delays + && (scan_idx >= reset_delays_after); const enum riscv_scan_delay_class delay_class = batch->delay_classes[scan_idx]; const unsigned int delay = riscv_scan_get_delay(delays, delay_class); - assert(delay <= INT_MAX); - return delay; + return delays_were_reset ? 0 : delay; +} + +static unsigned int decode_dmi(const struct riscv_batch *batch, char *text, + uint32_t address, uint32_t data) +{ + static const struct { + uint32_t address; + enum riscv_debug_reg_ordinal ordinal; + } description[] = { + {DM_DMCONTROL, DM_DMCONTROL_ORDINAL}, + {DM_DMSTATUS, DM_DMSTATUS_ORDINAL}, + {DM_ABSTRACTCS, DM_ABSTRACTCS_ORDINAL}, + {DM_COMMAND, DM_COMMAND_ORDINAL}, + {DM_SBCS, DM_SBCS_ORDINAL} + }; + + for (unsigned int i = 0; i < ARRAY_SIZE(description); i++) { + if (riscv_get_dmi_address(batch->target, description[i].address) + == address) { + const riscv_debug_reg_ctx_t context = { + .XLEN = { .value = 0, .is_set = false }, + .DXLEN = { .value = 0, .is_set = false }, + .abits = { .value = 0, .is_set = false }, + }; + return riscv_debug_reg_to_s(text, description[i].ordinal, + context, data, RISCV_DEBUG_REG_HIDE_ALL_0); + } + } + if (text) + text[0] = '\0'; + return 0; +} + +static void log_dmi_decoded(const struct riscv_batch *batch, bool write, + uint32_t address, uint32_t data) +{ + const size_t size = decode_dmi(batch, /* text */ NULL, address, data) + 1; + char * const decoded = malloc(size); + if (!decoded) { + LOG_ERROR("Not enough memory to allocate %zu bytes.", size); + return; + } + decode_dmi(batch, decoded, address, data); + LOG_DEBUG("%s: %s", write ? "write" : "read", decoded); + free(decoded); +} + +static void log_batch(const struct riscv_batch *batch, size_t start_idx, + const struct riscv_scan_delays *delays, bool resets_delays, + size_t reset_delays_after) +{ + if (debug_level < LOG_LVL_DEBUG) + return; + + const unsigned int abits = riscv_get_dmi_address_bits(batch->target); + + /* Determine the "op" and "address" of the scan that preceded the first + * executed scan. + * FIXME: The code here assumes that there were no DMI operations between + * the last execution of the batch and the current one. + * Caching the info about the last executed DMI scan in "dm013_info_t" + * would be a more robust solution. + */ + bool last_scan_was_read = false; + uint32_t last_scan_address = (uint32_t)(-1) /* to silence maybe-uninitialized */; + if (start_idx > 0) { + const struct scan_field * const field = &batch->fields[start_idx - 1]; + assert(field->out_value); + last_scan_was_read = buf_get_u32(field->out_value, DTM_DMI_OP_OFFSET, + DTM_DMI_OP_LENGTH) == DTM_DMI_OP_READ; + last_scan_address = buf_get_u32(field->out_value, + DTM_DMI_ADDRESS_OFFSET, abits); + } + + /* Decode and log every executed scan */ + for (size_t i = start_idx; i < batch->used_scans; ++i) { + static const char * const op_string[] = {"-", "r", "w", "?"}; + const unsigned int delay = get_delay(batch, i, delays, resets_delays, + reset_delays_after); + const struct scan_field * const field = &batch->fields[i]; + + assert(field->out_value); + const unsigned int out_op = buf_get_u32(field->out_value, + DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH); + const uint32_t out_data = buf_get_u32(field->out_value, + DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH); + const uint32_t out_address = buf_get_u32(field->out_value, + DTM_DMI_ADDRESS_OFFSET, abits); + if (field->in_value) { + static const char * const status_string[] = { + "+", "?", "F", "b" + }; + const unsigned int in_op = buf_get_u32(field->in_value, + DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH); + const uint32_t in_data = buf_get_u32(field->in_value, + DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH); + const uint32_t in_address = buf_get_u32(field->in_value, + DTM_DMI_ADDRESS_OFFSET, abits); + + LOG_DEBUG("%db %s %08" PRIx32 " @%02" PRIx32 + " -> %s %08" PRIx32 " @%02" PRIx32 "; %ui", + field->num_bits, op_string[out_op], out_data, out_address, + status_string[in_op], in_data, in_address, delay); + + if (last_scan_was_read && in_op == DTM_DMI_OP_SUCCESS) + log_dmi_decoded(batch, /*write*/ false, + last_scan_address, in_data); + } else { + LOG_DEBUG("%db %s %08" PRIx32 " @%02" PRIx32 " -> ?; %ui", + field->num_bits, op_string[out_op], out_data, out_address, + delay); + } + + if (out_op == DTM_DMI_OP_WRITE) + log_dmi_decoded(batch, /*write*/ true, out_address, + out_data); + + last_scan_was_read = out_op == DTM_DMI_OP_READ; + last_scan_address = out_address; + } } int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx, @@ -147,6 +280,7 @@ int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx, size_t reset_delays_after) { assert(batch->used_scans); + assert(start_idx < batch->used_scans); assert(batch->last_scan == RISCV_SCAN_TYPE_NOP); assert(!batch->was_run || riscv_batch_was_scan_busy(batch, start_idx)); assert(start_idx == 0 || !riscv_batch_was_scan_busy(batch, start_idx - 1)); @@ -157,17 +291,17 @@ int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx, LOG_TARGET_DEBUG(batch->target, "Running batch of scans [%zu, %zu)", start_idx, batch->used_scans); + unsigned int delay = 0 /* to silence maybe-uninitialized */; for (size_t i = start_idx; i < batch->used_scans; ++i) { if (bscan_tunnel_ir_width != 0) - riscv_add_bscan_tunneled_scan(batch->target, batch->fields + i, batch->bscan_ctxt + i); + riscv_add_bscan_tunneled_scan(batch->target->tap, batch->fields + i, + batch->bscan_ctxt + i); else jtag_add_dr_scan(batch->target->tap, 1, batch->fields + i, TAP_IDLE); - const bool delays_were_reset = resets_delays - && (i >= reset_delays_after); - const int delay = get_delay(batch, i, delays); - - if (!delays_were_reset) + delay = get_delay(batch, i, delays, resets_delays, + reset_delays_after); + if (delay > 0) jtag_add_runtest(delay, TAP_IDLE); } @@ -188,46 +322,62 @@ int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx, } } - for (size_t i = start_idx; i < batch->used_scans; ++i) { - const int delay = get_delay(batch, i, delays); - riscv_log_dmi_scan(batch->target, delay, batch->fields + i, - /*discard_in*/ false); - } - + log_batch(batch, start_idx, delays, resets_delays, reset_delays_after); batch->was_run = true; - batch->last_scan_delay = get_delay(batch, batch->used_scans - 1, delays); + batch->last_scan_delay = delay; return ERROR_OK; } -void riscv_batch_add_dm_write(struct riscv_batch *batch, uint64_t address, uint32_t data, +void riscv_batch_add_dmi_write(struct riscv_batch *batch, uint32_t address, uint32_t data, bool read_back, enum riscv_scan_delay_class delay_class) { + // TODO: Check that the bit width of "address" is no more than dtmcs.abits, + // otherwise return an error (during batch creation or when the batch is executed). + assert(batch->used_scans < batch->allocated_scans); struct scan_field *field = batch->fields + batch->used_scans; - field->num_bits = riscv_get_dmi_scan_length(batch->target); - field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE); - riscv_fill_dm_write(batch->target, (char *)field->out_value, address, data); + + field->num_bits = get_dmi_scan_length(batch->target); + assert(field->num_bits <= DMI_SCAN_MAX_BIT_LENGTH); + + uint8_t *out_value = batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE; + uint8_t *in_value = batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE; + + field->out_value = out_value; + riscv_fill_dmi_write(batch->target, out_value, address, data); + if (read_back) { - field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE); - riscv_fill_dm_nop(batch->target, (char *)field->in_value); + field->in_value = in_value; + riscv_fill_dm_nop(batch->target, in_value); } else { field->in_value = NULL; } + batch->delay_classes[batch->used_scans] = delay_class; batch->last_scan = RISCV_SCAN_TYPE_WRITE; batch->used_scans++; } -size_t riscv_batch_add_dm_read(struct riscv_batch *batch, uint64_t address, +size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, uint32_t address, enum riscv_scan_delay_class delay_class) { + // TODO: Check that the bit width of "address" is no more than dtmcs.abits, + // otherwise return an error (during batch creation or when the batch is executed). + assert(batch->used_scans < batch->allocated_scans); struct scan_field *field = batch->fields + batch->used_scans; - field->num_bits = riscv_get_dmi_scan_length(batch->target); - field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE); - field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE); - riscv_fill_dm_read(batch->target, (char *)field->out_value, address); - riscv_fill_dm_nop(batch->target, (char *)field->in_value); + + field->num_bits = get_dmi_scan_length(batch->target); + assert(field->num_bits <= DMI_SCAN_MAX_BIT_LENGTH); + + uint8_t *out_value = batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE; + uint8_t *in_value = batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE; + + field->out_value = out_value; + field->in_value = in_value; + riscv_fill_dmi_read(batch->target, out_value, address); + riscv_fill_dm_nop(batch->target, in_value); + batch->delay_classes[batch->used_scans] = delay_class; batch->last_scan = RISCV_SCAN_TYPE_READ; batch->used_scans++; @@ -236,14 +386,14 @@ size_t riscv_batch_add_dm_read(struct riscv_batch *batch, uint64_t address, return batch->read_keys_used++; } -unsigned int riscv_batch_get_dmi_read_op(const struct riscv_batch *batch, size_t key) +uint32_t riscv_batch_get_dmi_read_op(const struct riscv_batch *batch, size_t key) { assert(key < batch->read_keys_used); size_t index = batch->read_keys[key]; assert(index < batch->used_scans); uint8_t *base = batch->data_in + DMI_SCAN_BUF_SIZE * index; /* extract "op" field from the DMI read result */ - return (unsigned int)buf_get_u32(base, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH); + return buf_get_u32(base, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH); } uint32_t riscv_batch_get_dmi_read_data(const struct riscv_batch *batch, size_t key) @@ -260,11 +410,18 @@ void riscv_batch_add_nop(struct riscv_batch *batch) { assert(batch->used_scans < batch->allocated_scans); struct scan_field *field = batch->fields + batch->used_scans; - field->num_bits = riscv_get_dmi_scan_length(batch->target); - field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE); - field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE); - riscv_fill_dm_nop(batch->target, (char *)field->out_value); - riscv_fill_dm_nop(batch->target, (char *)field->in_value); + + field->num_bits = get_dmi_scan_length(batch->target); + assert(field->num_bits <= DMI_SCAN_MAX_BIT_LENGTH); + + uint8_t *out_value = batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE; + uint8_t *in_value = batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE; + + field->out_value = out_value; + field->in_value = in_value; + riscv_fill_dm_nop(batch->target, out_value); + riscv_fill_dm_nop(batch->target, in_value); + /* DMI NOP never triggers any debug module operation, * so the shortest (base) delay can be used. */ batch->delay_classes[batch->used_scans] = RISCV_DELAY_BASE; diff --git a/src/target/riscv/batch.h b/src/target/riscv/batch.h index 327406c..5d8b572 100644 --- a/src/target/riscv/batch.h +++ b/src/target/riscv/batch.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef TARGET__RISCV__SCANS_H -#define TARGET__RISCV__SCANS_H +#ifndef OPENOCD_TARGET_RISCV_BATCH_H +#define OPENOCD_TARGET_RISCV_BATCH_H #include "target/target.h" #include "jtag/jtag.h" @@ -190,15 +190,33 @@ int riscv_batch_run_from(struct riscv_batch *batch, size_t start_idx, size_t riscv_batch_finished_scans(const struct riscv_batch *batch); /* Adds a DM register write to this batch. */ -void riscv_batch_add_dm_write(struct riscv_batch *batch, uint64_t address, uint32_t data, +void riscv_batch_add_dmi_write(struct riscv_batch *batch, uint32_t address, uint32_t data, bool read_back, enum riscv_scan_delay_class delay_class); +static inline void +riscv_batch_add_dm_write(struct riscv_batch *batch, uint32_t address, uint32_t data, + bool read_back, enum riscv_scan_delay_class delay_type) +{ + return riscv_batch_add_dmi_write(batch, + riscv_get_dmi_address(batch->target, address), data, + read_back, delay_type); +} + /* DM register reads must be handled in two parts: the first one schedules a read and * provides a key, the second one actually obtains the result of the read - * status (op) and the actual data. */ -size_t riscv_batch_add_dm_read(struct riscv_batch *batch, uint64_t address, +size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, uint32_t address, enum riscv_scan_delay_class delay_class); -unsigned int riscv_batch_get_dmi_read_op(const struct riscv_batch *batch, size_t key); + +static inline size_t +riscv_batch_add_dm_read(struct riscv_batch *batch, uint32_t address, + enum riscv_scan_delay_class delay_type) +{ + return riscv_batch_add_dmi_read(batch, + riscv_get_dmi_address(batch->target, address), delay_type); +} + +uint32_t riscv_batch_get_dmi_read_op(const struct riscv_batch *batch, size_t key); uint32_t riscv_batch_get_dmi_read_data(const struct riscv_batch *batch, size_t key); /* Scans in a NOP. */ @@ -210,10 +228,4 @@ size_t riscv_batch_available_scans(struct riscv_batch *batch); /* Return true iff the last scan in the batch returned DMI_OP_BUSY. */ bool riscv_batch_was_batch_busy(const struct riscv_batch *batch); -/* TODO: The function is defined in `riscv-013.c`. This is done to reduce the - * diff of the commit. The intention is to move the function definition to - * a separate module (e.g. `riscv013-jtag-dtm.c/h`) in another commit. */ -void riscv_log_dmi_scan(const struct target *target, int idle, const struct scan_field *field, - bool discard_in); - -#endif +#endif /* OPENOCD_TARGET_RISCV_BATCH_H */ diff --git a/src/target/riscv/debug_reg_printer.h b/src/target/riscv/debug_reg_printer.h index 98226b7..5089ff8 100644 --- a/src/target/riscv/debug_reg_printer.h +++ b/src/target/riscv/debug_reg_printer.h @@ -1,5 +1,8 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef OPENOCD_TARGET_RISCV_DEBUG_REG_PRINTER_H +#define OPENOCD_TARGET_RISCV_DEBUG_REG_PRINTER_H + #include "debug_defines.h" enum riscv_debug_reg_show { @@ -33,3 +36,5 @@ enum riscv_debug_reg_show { unsigned int riscv_debug_reg_to_s(char *buf, enum riscv_debug_reg_ordinal reg_ordinal, riscv_debug_reg_ctx_t context, uint64_t value, enum riscv_debug_reg_show show); + +#endif /* OPENOCD_TARGET_RISCV_DEBUG_REG_PRINTER_H */ diff --git a/src/target/riscv/field_helpers.h b/src/target/riscv/field_helpers.h index 16578f1..abf19f6 100644 --- a/src/target/riscv/field_helpers.h +++ b/src/target/riscv/field_helpers.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef FIELD_HELPERS_H -#define FIELD_HELPERS_H +#ifndef OPENOCD_TARGET_RISCV_FIELD_HELPERS_H +#define OPENOCD_TARGET_RISCV_FIELD_HELPERS_H #include <stdint.h> #include <assert.h> @@ -44,4 +44,4 @@ static inline uint32_t field_value32(uint32_t mask, uint32_t val) return set_field32(0, mask, val); } -#endif +#endif /* OPENOCD_TARGET_RISCV_FIELD_HELPERS_H */ diff --git a/src/target/riscv/gdb_regs.h b/src/target/riscv/gdb_regs.h index d606f73..0d03929 100644 --- a/src/target/riscv/gdb_regs.h +++ b/src/target/riscv/gdb_regs.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef TARGET__RISCV__GDB_REGS_H -#define TARGET__RISCV__GDB_REGS_H +#ifndef OPENOCD_TARGET_RISCV_GDB_REGS_H +#define OPENOCD_TARGET_RISCV_GDB_REGS_H #include "encoding.h" @@ -125,4 +125,4 @@ enum gdb_regno { GDB_REGNO_COUNT }; -#endif +#endif /* OPENOCD_TARGET_RISCV_GDB_REGS_H */ diff --git a/src/target/riscv/opcodes.h b/src/target/riscv/opcodes.h index 59c3413..e4efc5b 100644 --- a/src/target/riscv/opcodes.h +++ b/src/target/riscv/opcodes.h @@ -1,15 +1,39 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ +#ifndef OPENOCD_TARGET_RISCV_OPCODES_H +#define OPENOCD_TARGET_RISCV_OPCODES_H + #include "encoding.h" +#include <assert.h> +#include <stdbool.h> +#include <stdint.h> #define ZERO 0 #define T0 5 #define S0 8 #define S1 9 +#define MAX_GPR_NUM 31 +#define MAX_FPR_NUM 31 +#define MAX_VREG_NUM 31 +#define MAX_CSR_NUM 4095 + +#define MIN_INT12 (-0x800) +#define MAX_INT12 0x7ff + +#define MIN_INT13 (-0x1000) +#define MAX_INT13 0xfff + +#define MIN_INT21 (-0x100000) +#define MAX_INT21 0xfffff + +#define MAX_UINT5 0x1f +#define MAX_UINT11 0x7ff +#define MAX_UINT12 0xfff + static uint32_t bits(uint32_t value, unsigned int hi, unsigned int lo) { - return (value >> lo) & ((1 << (hi+1-lo)) - 1); + return (value >> lo) & (((uint32_t)1 << (hi + 1 - lo)) - 1); } static uint32_t bit(uint32_t value, unsigned int b) @@ -65,153 +89,246 @@ 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) +static uint32_t jal(unsigned int rd, int32_t imm) __attribute__ ((unused)); +static uint32_t jal(unsigned int rd, int32_t imm) { - return imm_j(imm) | inst_rd(rd) | MATCH_JAL; + assert(rd <= MAX_GPR_NUM); + assert((imm >= MIN_INT21) && (imm <= MAX_INT21)); + assert((imm & 1) == 0); + + return imm_j((uint32_t)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) +static uint32_t csrsi(unsigned int csr, uint8_t imm) __attribute__ ((unused)); +static uint32_t csrsi(unsigned int csr, uint8_t imm) { + assert(csr <= MAX_CSR_NUM); + assert(imm <= MAX_UINT5); + 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) +static uint32_t sw(unsigned int src, unsigned int base, int16_t offset) __attribute__ ((unused)); +static uint32_t sw(unsigned int src, unsigned int base, int16_t offset) { - return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_SW; + assert(src <= MAX_GPR_NUM); + assert(base <= MAX_GPR_NUM); + assert((offset >= MIN_INT12) && (offset <= MAX_INT12)); + + return imm_s((uint16_t)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) +static uint32_t sd(unsigned int src, unsigned int base, int16_t offset) __attribute__ ((unused)); +static uint32_t sd(unsigned int src, unsigned int base, int16_t offset) { - return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_SD; + assert(src <= MAX_GPR_NUM); + assert(base <= MAX_GPR_NUM); + assert((offset >= MIN_INT12) && (offset <= MAX_INT12)); + + return imm_s((uint16_t)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) +static uint32_t sh(unsigned int src, unsigned int base, int16_t offset) __attribute__ ((unused)); +static uint32_t sh(unsigned int src, unsigned int base, int16_t offset) { - return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_SH; + assert(src <= MAX_GPR_NUM); + assert(base <= MAX_GPR_NUM); + assert((offset >= MIN_INT12) && (offset <= MAX_INT12)); + + return imm_s((uint16_t)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) +static uint32_t sb(unsigned int src, unsigned int base, int16_t offset) __attribute__ ((unused)); +static uint32_t sb(unsigned int src, unsigned int base, int16_t offset) { - return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_SB; + assert(src <= MAX_GPR_NUM); + assert(base <= MAX_GPR_NUM); + assert((offset >= MIN_INT12) && (offset <= MAX_INT12)); + + return imm_s((uint16_t)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) +static uint32_t ld(unsigned int rd, unsigned int base, int16_t offset) __attribute__ ((unused)); +static uint32_t ld(unsigned int rd, unsigned int base, int16_t offset) { - return imm_i(offset) | inst_rs1(base) | inst_rd(rd) | MATCH_LD; + assert(rd <= MAX_GPR_NUM); + assert(base <= MAX_GPR_NUM); + assert((offset >= MIN_INT12) && (offset <= MAX_INT12)); + + return imm_i((uint16_t)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) +static uint32_t lw(unsigned int rd, unsigned int base, int16_t offset) __attribute__ ((unused)); +static uint32_t lw(unsigned int rd, unsigned int base, int16_t offset) { - return imm_i(offset) | inst_rs1(base) | inst_rd(rd) | MATCH_LW; + assert(rd <= MAX_GPR_NUM); + assert(base <= MAX_GPR_NUM); + assert((offset >= MIN_INT12) && (offset <= MAX_INT12)); + + return imm_i((uint16_t)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) +static uint32_t lh(unsigned int rd, unsigned int base, int16_t offset) __attribute__ ((unused)); +static uint32_t lh(unsigned int rd, unsigned int base, int16_t offset) { - return imm_i(offset) | inst_rs1(base) | inst_rd(rd) | MATCH_LH; + assert(rd <= MAX_GPR_NUM); + assert(base <= MAX_GPR_NUM); + assert((offset >= MIN_INT12) && (offset <= MAX_INT12)); + + return imm_i((uint16_t)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) +static uint32_t lb(unsigned int rd, unsigned int base, int16_t offset) __attribute__ ((unused)); +static uint32_t lb(unsigned int rd, unsigned int base, int16_t offset) { - return imm_i(offset) | inst_rs1(base) | inst_rd(rd) | MATCH_LB; + assert(rd <= MAX_GPR_NUM); + assert(base <= MAX_GPR_NUM); + assert((offset >= MIN_INT12) && (offset <= MAX_INT12)); + + return imm_i((uint16_t)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) { + assert(source <= MAX_GPR_NUM); + assert(csr <= MAX_CSR_NUM); + 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) +static uint32_t addi(unsigned int dest, unsigned int src, int16_t imm) __attribute__ ((unused)); +static uint32_t addi(unsigned int dest, unsigned int src, int16_t imm) { - return imm_i(imm) | inst_rs1(src) | inst_rd(dest) | MATCH_ADDI; + assert(dest <= MAX_GPR_NUM); + assert(src <= MAX_GPR_NUM); + assert((imm >= MIN_INT12) && (imm <= MAX_INT12)); + + return imm_i((uint16_t)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) { + assert(rd <= MAX_GPR_NUM); + assert(csr <= MAX_CSR_NUM); + 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) { + assert(rd <= MAX_GPR_NUM); + assert(rs <= MAX_GPR_NUM); + assert(csr <= MAX_CSR_NUM); + 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) { + assert(rd <= MAX_GPR_NUM); + assert(rs <= MAX_GPR_NUM); + assert(csr <= MAX_CSR_NUM); + 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) +static uint32_t csrrci(unsigned int rd, uint8_t zimm, unsigned int csr) __attribute__ ((unused)); +static uint32_t csrrci(unsigned int rd, uint8_t zimm, unsigned int csr) { + assert(rd <= MAX_GPR_NUM); + assert(zimm <= MAX_UINT5); + assert(csr <= MAX_CSR_NUM); + 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) +static uint32_t csrrsi(unsigned int rd, uint8_t zimm, unsigned int csr) __attribute__ ((unused)); +static uint32_t csrrsi(unsigned int rd, uint8_t zimm, unsigned int csr) { + assert(rd <= MAX_GPR_NUM); + assert(zimm <= MAX_UINT5); + assert(csr <= MAX_CSR_NUM); + 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) +static uint32_t fsw(unsigned int src, unsigned int base, int16_t offset) __attribute__ ((unused)); +static uint32_t fsw(unsigned int src, unsigned int base, int16_t offset) { - return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_FSW; + assert(src <= MAX_FPR_NUM); + assert(base <= MAX_GPR_NUM); + assert((offset >= MIN_INT12) && (offset <= MAX_INT12)); + + return imm_s((uint16_t)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) +static uint32_t fsd(unsigned int src, unsigned int base, int16_t offset) __attribute__ ((unused)); +static uint32_t fsd(unsigned int src, unsigned int base, int16_t offset) { - return imm_s(offset) | inst_rs2(src) | inst_rs1(base) | MATCH_FSD; + assert(src <= MAX_FPR_NUM); + assert(base <= MAX_GPR_NUM); + assert((offset >= MIN_INT12) && (offset <= MAX_INT12)); + + return imm_s((uint16_t)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) +static uint32_t flw(unsigned int dest, unsigned int base, int16_t offset) __attribute__ ((unused)); +static uint32_t flw(unsigned int dest, unsigned int base, int16_t offset) { - return imm_i(offset) | inst_rs1(base) | inst_rd(dest) | MATCH_FLW; + assert(dest <= MAX_FPR_NUM); + assert(base <= MAX_GPR_NUM); + assert((offset >= MIN_INT12) && (offset <= MAX_INT12)); + + return imm_i((uint16_t)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) +static uint32_t fld(unsigned int dest, unsigned int base, int16_t offset) __attribute__ ((unused)); +static uint32_t fld(unsigned int dest, unsigned int base, int16_t offset) { - return imm_i(offset) | inst_rs1(base) | inst_rd(dest) | MATCH_FLD; + assert(dest <= MAX_FPR_NUM); + assert(base <= MAX_GPR_NUM); + assert((offset >= MIN_INT12) && (offset <= MAX_INT12)); + + return imm_i((uint16_t)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) +static uint32_t fmv_x_w(unsigned int dest, unsigned int src) __attribute__ ((unused)); +static uint32_t fmv_x_w(unsigned int dest, unsigned int src) { + assert(dest <= MAX_GPR_NUM); + assert(src <= MAX_FPR_NUM); + 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) +static uint32_t fmv_x_d(unsigned int dest, unsigned int src) __attribute__ ((unused)); +static uint32_t fmv_x_d(unsigned int dest, unsigned int src) { + assert(dest <= MAX_GPR_NUM); + assert(src <= MAX_FPR_NUM); + 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) +static uint32_t fmv_w_x(unsigned int dest, unsigned int src) __attribute__ ((unused)); +static uint32_t fmv_w_x(unsigned int dest, unsigned int src) { + assert(dest <= MAX_FPR_NUM); + assert(src <= MAX_GPR_NUM); + 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) +static uint32_t fmv_d_x(unsigned int dest, unsigned int src) __attribute__ ((unused)); +static uint32_t fmv_d_x(unsigned int dest, unsigned int src) { + assert(dest <= MAX_FPR_NUM); + assert(src <= MAX_GPR_NUM); + return inst_rs1(src) | inst_rd(dest) | MATCH_FMV_D_X; } @@ -238,59 +355,29 @@ 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 imm_u(imm) | inst_rd(dest) | MATCH_LUI; -} - -/* -static uint32_t csrci(unsigned int csr, uint16_t imm) __attribute__ ((unused)); -static uint32_t csrci(unsigned int csr, uint16_t imm) -{ - return (csr << 20) | - (bits(imm, 4, 0) << 15) | - MATCH_CSRRCI; -} - -static uint32_t li(unsigned int dest, uint16_t imm) __attribute__ ((unused)); -static uint32_t li(unsigned int dest, uint16_t imm) -{ - return addi(dest, 0, imm); -} - -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; -} + assert(dest <= MAX_GPR_NUM); + assert(bits(imm, 11, 0) == 0); -static uint32_t ori(unsigned int dest, unsigned int src, uint16_t imm) __attribute__ ((unused)); -static uint32_t ori(unsigned int dest, unsigned int src, uint16_t imm) -{ - return (bits(imm, 11, 0) << 20) | - (src << 15) | - (dest << 7) | - MATCH_ORI; + return imm_u(imm) | inst_rd(dest) | MATCH_LUI; } -static uint32_t nop(void) __attribute__ ((unused)); -static uint32_t nop(void) +static uint32_t xori(unsigned int dest, unsigned int src, int16_t imm) __attribute__ ((unused)); +static uint32_t xori(unsigned int dest, unsigned int src, int16_t imm) { - return addi(0, 0, 0); -} -*/ + assert(dest <= MAX_GPR_NUM); + assert(src <= MAX_GPR_NUM); + assert((imm >= MIN_INT12) && (imm <= MAX_INT12)); -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 imm_i(imm) | inst_rs1(src) | inst_rd(dest) | MATCH_XORI; + return imm_i((uint16_t)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) { + assert(dest <= MAX_GPR_NUM); + assert(src <= MAX_GPR_NUM); + assert(shamt <= MAX_UINT5); + return inst_rs2(shamt) | inst_rs1(src) | inst_rd(dest) | MATCH_SRLI; } @@ -304,38 +391,59 @@ static uint32_t fence_rw_rw(void) static uint32_t auipc(unsigned int dest) __attribute__((unused)); static uint32_t auipc(unsigned int dest) { + assert(dest <= MAX_GPR_NUM); + 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) +static uint32_t vsetvli(unsigned int dest, unsigned int src, uint16_t vtypei) __attribute__((unused)); +static uint32_t vsetvli(unsigned int dest, unsigned int src, uint16_t vtypei) { - return (bits(imm, 10, 0) << 20) | inst_rs1(src) | inst_rd(dest) | MATCH_VSETVLI; + assert(dest <= MAX_GPR_NUM); + assert(src <= MAX_GPR_NUM); + assert(vtypei <= MAX_UINT11); + + return (bits(vtypei, 10, 0) << 20) | inst_rs1(src) | inst_rd(dest) | MATCH_VSETVLI; } static uint32_t vsetvl(unsigned int rd, unsigned int rs1, unsigned int rs2) __attribute__((unused)); static uint32_t vsetvl(unsigned int rd, unsigned int rs1, unsigned int rs2) { + assert(rd <= MAX_GPR_NUM); + assert(rs1 <= MAX_GPR_NUM); + assert(rs2 <= MAX_GPR_NUM); + return inst_rd(rd) | inst_rs1(rs1) | inst_rs2(rs2) | MATCH_VSETVL; } 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) { + assert(rd <= MAX_GPR_NUM); + assert(vs2 <= MAX_VREG_NUM); + 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) +static uint32_t vmv_s_x(unsigned int vd, unsigned int rs2) __attribute__((unused)); +static uint32_t vmv_s_x(unsigned int vd, unsigned int rs2) { - return inst_rs1(rs1) | inst_rd(vd) | MATCH_VMV_S_X; + assert(vd <= MAX_VREG_NUM); + assert(rs2 <= MAX_GPR_NUM); + + return inst_rs1(rs2) | inst_rd(vd) | MATCH_VMV_S_X; } static uint32_t vslide1down_vx(unsigned int vd, unsigned int vs2, - unsigned int rs1, unsigned int vm) __attribute__((unused)); + unsigned int rs1, bool vm) __attribute__((unused)); static uint32_t vslide1down_vx(unsigned int vd, unsigned int vs2, - unsigned int rs1, unsigned int vm) + unsigned int rs1, bool vm) { - return ((vm & 1) << 25) | inst_rs2(vs2) | inst_rs1(rs1) | inst_rd(vd) | MATCH_VSLIDE1DOWN_VX; + assert(vd <= MAX_VREG_NUM); + assert(vs2 <= MAX_VREG_NUM); + assert(rs1 <= MAX_GPR_NUM); + + return (vm ? (1u << 25) : 0u) | inst_rs2(vs2) | inst_rs1(rs1) | inst_rd(vd) | MATCH_VSLIDE1DOWN_VX; } +#endif /* OPENOCD_TARGET_RISCV_OPCODES_H */ diff --git a/src/target/riscv/program.c b/src/target/riscv/program.c index c4ffb3f..bf6718f 100644 --- a/src/target/riscv/program.c +++ b/src/target/riscv/program.c @@ -10,7 +10,6 @@ #include "program.h" #include "helper/log.h" -#include "asm.h" #include "debug_defines.h" #include "encoding.h" @@ -21,8 +20,8 @@ int riscv_program_init(struct riscv_program *p, struct target *target) p->target = target; p->instruction_count = 0; - for (size_t i = 0; i < RISCV_MAX_PROGBUF_SIZE; ++i) - p->progbuf[i] = -1; + for (unsigned int i = 0; i < RISCV013_MAX_PROGBUF_SIZE; ++i) + p->progbuf[i] = (uint32_t)(-1); p->execution_result = RISCV_PROGBUF_EXEC_RESULT_NOT_EXECUTED; return ERROR_OK; @@ -30,7 +29,7 @@ int riscv_program_init(struct riscv_program *p, struct target *target) int riscv_program_write(struct riscv_program *program) { - for (unsigned i = 0; i < program->instruction_count; ++i) { + for (unsigned int i = 0; i < program->instruction_count; ++i) { LOG_TARGET_DEBUG(program->target, "progbuf[%02x] = DASM(0x%08x)", i, program->progbuf[i]); if (riscv_write_progbuf(program->target, i, program->progbuf[i]) != ERROR_OK) @@ -48,9 +47,9 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) if (riscv_program_ebreak(p) != ERROR_OK) { LOG_TARGET_ERROR(t, "Unable to insert ebreak into program buffer"); - for (size_t i = 0; i < riscv_progbuf_size(p->target); ++i) - LOG_TARGET_ERROR(t, "ram[%02x]: DASM(0x%08" PRIx32 ") [0x%08" PRIx32 "]", - (int)i, p->progbuf[i], p->progbuf[i]); + for (unsigned int i = 0; i < riscv_progbuf_size(p->target); ++i) + LOG_TARGET_ERROR(t, "progbuf[%02x]: DASM(0x%08" PRIx32 ") [0x%08" PRIx32 "]", + i, p->progbuf[i], p->progbuf[i]); return ERROR_FAIL; } @@ -71,27 +70,27 @@ int riscv_program_exec(struct riscv_program *p, struct target *t) return ERROR_OK; } -int riscv_program_sdr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) +int riscv_program_sdr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int16_t offset) { return riscv_program_insert(p, sd(d, b, offset)); } -int riscv_program_swr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) +int riscv_program_swr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int16_t offset) { return riscv_program_insert(p, sw(d, b, offset)); } -int riscv_program_shr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) +int riscv_program_shr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int16_t offset) { return riscv_program_insert(p, sh(d, b, offset)); } -int riscv_program_sbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) +int riscv_program_sbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int16_t offset) { return riscv_program_insert(p, sb(d, b, offset)); } -int riscv_program_store(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset, +int riscv_program_store(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int16_t offset, unsigned int size) { switch (size) { @@ -108,27 +107,27 @@ int riscv_program_store(struct riscv_program *p, enum gdb_regno d, enum gdb_regn return ERROR_FAIL; } -int riscv_program_ldr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) +int riscv_program_ldr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int16_t offset) { return riscv_program_insert(p, ld(d, b, offset)); } -int riscv_program_lwr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) +int riscv_program_lwr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int16_t offset) { return riscv_program_insert(p, lw(d, b, offset)); } -int riscv_program_lhr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) +int riscv_program_lhr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int16_t offset) { return riscv_program_insert(p, lh(d, b, offset)); } -int riscv_program_lbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset) +int riscv_program_lbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int16_t offset) { return riscv_program_insert(p, lb(d, b, offset)); } -int riscv_program_load(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int offset, +int riscv_program_load(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int16_t offset, unsigned int size) { switch (size) { @@ -145,13 +144,13 @@ int riscv_program_load(struct riscv_program *p, enum gdb_regno d, enum gdb_regno return ERROR_FAIL; } -int riscv_program_csrrsi(struct riscv_program *p, enum gdb_regno d, unsigned int z, enum gdb_regno csr) +int riscv_program_csrrsi(struct riscv_program *p, enum gdb_regno d, uint8_t z, enum gdb_regno csr) { assert(csr >= GDB_REGNO_CSR0 && csr <= GDB_REGNO_CSR4095); return riscv_program_insert(p, csrrsi(d, z, csr - GDB_REGNO_CSR0)); } -int riscv_program_csrrci(struct riscv_program *p, enum gdb_regno d, unsigned int z, enum gdb_regno csr) +int riscv_program_csrrci(struct riscv_program *p, enum gdb_regno d, uint8_t z, enum gdb_regno csr) { assert(csr >= GDB_REGNO_CSR0 && csr <= GDB_REGNO_CSR4095); return riscv_program_insert(p, csrrci(d, z, csr - GDB_REGNO_CSR0)); @@ -165,7 +164,7 @@ int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno int riscv_program_csrw(struct riscv_program *p, enum gdb_regno s, enum gdb_regno csr) { - assert(csr >= GDB_REGNO_CSR0); + assert(csr >= GDB_REGNO_CSR0 && csr <= GDB_REGNO_CSR4095); return riscv_program_insert(p, csrrw(GDB_REGNO_ZERO, s, csr - GDB_REGNO_CSR0)); } @@ -183,8 +182,8 @@ int riscv_program_ebreak(struct riscv_program *p) { struct target *target = p->target; RISCV_INFO(r); - if (p->instruction_count == riscv_progbuf_size(p->target) && - r->impebreak) { + if (p->instruction_count == riscv_progbuf_size(target) && + r->get_impebreak(target)) { return ERROR_OK; } return riscv_program_insert(p, ebreak()); @@ -199,8 +198,8 @@ int riscv_program_insert(struct riscv_program *p, riscv_insn_t i) { if (p->instruction_count >= riscv_progbuf_size(p->target)) { LOG_TARGET_ERROR(p->target, "Unable to insert program into progbuf, " - "capacity would be exceeded (progbufsize=%d).", - (int)riscv_progbuf_size(p->target)); + "capacity would be exceeded (progbufsize=%u).", + riscv_progbuf_size(p->target)); return ERROR_FAIL; } diff --git a/src/target/riscv/program.h b/src/target/riscv/program.h index 93dbdbf..ba44aba 100644 --- a/src/target/riscv/program.h +++ b/src/target/riscv/program.h @@ -1,13 +1,11 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef TARGET__RISCV__PROGRAM_H -#define TARGET__RISCV__PROGRAM_H +#ifndef OPENOCD_TARGET_RISCV_PROGRAM_H +#define OPENOCD_TARGET_RISCV_PROGRAM_H #include "riscv.h" -#define RISCV_MAX_PROGBUF_SIZE 32 -#define RISCV_REGISTER_COUNT 32 -#define RISCV_DSCRATCH_COUNT 2 +#define RISCV013_MAX_PROGBUF_SIZE 16 typedef enum { RISCV_PROGBUF_EXEC_RESULT_NOT_EXECUTED, @@ -23,10 +21,10 @@ typedef enum { struct riscv_program { struct target *target; - uint32_t progbuf[RISCV_MAX_PROGBUF_SIZE]; + uint32_t progbuf[RISCV013_MAX_PROGBUF_SIZE]; /* Number of 32-bit instructions in the program. */ - size_t instruction_count; + unsigned int instruction_count; /* execution result of the program */ /* TODO: remove this field. We should make it a parameter to riscv_program_exec */ @@ -52,22 +50,22 @@ int riscv_program_insert(struct riscv_program *p, riscv_insn_t i); /* 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. */ -int riscv_program_ldr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); -int riscv_program_lwr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); -int riscv_program_lhr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); -int riscv_program_lbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int o); -int riscv_program_load(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int o, +int riscv_program_ldr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int16_t o); +int riscv_program_lwr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int16_t o); +int riscv_program_lhr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int16_t o); +int riscv_program_lbr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno a, int16_t o); +int riscv_program_load(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int16_t o, unsigned int s); -int riscv_program_sdr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); -int riscv_program_swr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); -int riscv_program_shr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); -int riscv_program_sbr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int o); -int riscv_program_store(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int o, +int riscv_program_sdr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int16_t o); +int riscv_program_swr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int16_t o); +int riscv_program_shr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int16_t o); +int riscv_program_sbr(struct riscv_program *p, enum gdb_regno s, enum gdb_regno a, int16_t o); +int riscv_program_store(struct riscv_program *p, enum gdb_regno d, enum gdb_regno b, int16_t o, unsigned int s); -int riscv_program_csrrsi(struct riscv_program *p, enum gdb_regno d, unsigned int z, enum gdb_regno csr); -int riscv_program_csrrci(struct riscv_program *p, enum gdb_regno d, unsigned int z, enum gdb_regno csr); +int riscv_program_csrrsi(struct riscv_program *p, enum gdb_regno d, uint8_t z, enum gdb_regno csr); +int riscv_program_csrrci(struct riscv_program *p, enum gdb_regno d, uint8_t z, enum gdb_regno csr); int riscv_program_csrr(struct riscv_program *p, enum gdb_regno d, enum gdb_regno csr); int riscv_program_csrw(struct riscv_program *p, enum gdb_regno s, enum gdb_regno csr); @@ -77,4 +75,4 @@ int riscv_program_ebreak(struct riscv_program *p); int riscv_program_addi(struct riscv_program *p, enum gdb_regno d, enum gdb_regno s, int16_t i); -#endif +#endif /* OPENOCD_TARGET_RISCV_PROGRAM_H */ diff --git a/src/target/riscv/riscv-011.c b/src/target/riscv/riscv-011.c index 0715de5..54de6a1 100644 --- a/src/target/riscv/riscv-011.c +++ b/src/target/riscv/riscv-011.c @@ -26,7 +26,6 @@ #include "riscv.h" #include "riscv_reg.h" #include "riscv-011_reg.h" -#include "asm.h" #include "gdb_regs.h" #include "field_helpers.h" @@ -251,18 +250,46 @@ static unsigned int slot_offset(const struct target *target, slot_t slot) return 0; /* Silence -Werror=return-type */ } +static uint32_t load(const struct target *target, unsigned int rd, + unsigned int base, int16_t offset) +{ + switch (riscv_xlen(target)) { + case 32: + return lw(rd, base, offset); + case 64: + return ld(rd, base, offset); + } + assert(0); + return 0; /* Silence -Werror=return-type */ +} + +static uint32_t store(const struct target *target, unsigned int src, + unsigned int base, int16_t offset) +{ + switch (riscv_xlen(target)) { + case 32: + return sw(src, base, offset); + case 64: + return sd(src, base, offset); + } + assert(0); + return 0; /* Silence -Werror=return-type */ +} + static uint32_t load_slot(const struct target *target, unsigned int dest, slot_t slot) { unsigned int offset = DEBUG_RAM_START + 4 * slot_offset(target, slot); - return load(target, dest, ZERO, offset); + assert(offset <= MAX_INT12); + return load(target, dest, ZERO, (int16_t)offset); } static uint32_t store_slot(const struct target *target, unsigned int src, slot_t slot) { unsigned int offset = DEBUG_RAM_START + 4 * slot_offset(target, slot); - return store(target, src, ZERO, offset); + assert(offset <= MAX_INT12); + return store(target, src, ZERO, (int16_t)offset); } static uint16_t dram_address(unsigned int index) @@ -273,38 +300,6 @@ static uint16_t dram_address(unsigned int index) return 0x40 + index - 0x10; } -static int dtmcontrol_scan(struct target *target, uint32_t out, uint32_t *in_ptr) -{ - struct scan_field field; - uint8_t in_value[4]; - uint8_t out_value[4] = { 0 }; - - 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 dbus. */ - jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); - - 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("DTMCONTROL: 0x%x -> 0x%x", out, in); - - if (in_ptr) - *in_ptr = in; - return ERROR_OK; -} - static uint32_t idcode_scan(struct target *target) { struct scan_field field; @@ -340,7 +335,7 @@ static void increase_dbus_busy_delay(struct target *target) info->dtmcontrol_idle, info->dbus_busy_delay, info->interrupt_high_delay); - dtmcontrol_scan(target, DTMCONTROL_DBUS_RESET, NULL /* discard value */); + dtmcs_scan(target->tap, DTMCONTROL_DBUS_RESET, NULL /* discard value */); } static void increase_interrupt_high_delay(struct target *target) @@ -408,7 +403,7 @@ static void dump_field(const struct scan_field *field) log_printf_lf(LOG_LVL_DEBUG, __FILE__, __LINE__, "scan", - "%db %s %c%c:%08x @%02x -> %s %c%c:%08x @%02x", + "%ub %s %c%c:%08x @%02x -> %s %c%c:%08x @%02x", field->num_bits, op_string[out_op], out_interrupt, out_haltnot, out_data, out_address, @@ -475,7 +470,7 @@ static uint64_t dbus_read(struct target *target, uint16_t address) * While somewhat nonintuitive, this is an efficient way to get the data. */ - unsigned i = 0; + unsigned int i = 0; do { status = dbus_scan(target, &address_in, &value, DBUS_OP_READ, address, 0); if (status == DBUS_STATUS_BUSY) @@ -496,7 +491,7 @@ static uint64_t dbus_read(struct target *target, uint16_t address) static void dbus_write(struct target *target, uint16_t address, uint64_t value) { dbus_status_t status = DBUS_STATUS_BUSY; - unsigned i = 0; + unsigned int i = 0; while (status == DBUS_STATUS_BUSY && i++ < 256) { status = dbus_scan(target, NULL, NULL, DBUS_OP_WRITE, address, value); if (status == DBUS_STATUS_BUSY) @@ -606,9 +601,9 @@ static void scans_add_write32(scans_t *scans, uint16_t address, uint32_t data, static void scans_add_write_jump(scans_t *scans, uint16_t address, bool set_interrupt) { - scans_add_write32(scans, address, - jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*address))), - set_interrupt); + unsigned int jump_offset = DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4 * address); + assert(jump_offset <= MAX_INT21); + scans_add_write32(scans, address, jal(0, (int32_t)jump_offset), set_interrupt); } /** Add a 32-bit dbus write for an instruction that loads from the indicated @@ -657,13 +652,13 @@ static void scans_add_read(scans_t *scans, slot_t slot, bool set_interrupt) } static uint32_t scans_get_u32(scans_t *scans, unsigned int index, - unsigned first, unsigned num) + unsigned int first, unsigned int num) { return buf_get_u32(scans->in + scans->scan_size * index, first, num); } static uint64_t scans_get_u64(scans_t *scans, unsigned int index, - unsigned first, unsigned num) + unsigned int first, unsigned int num) { return buf_get_u64(scans->in + scans->scan_size * index, first, num); } @@ -695,7 +690,7 @@ static int read_bits(struct target *target, bits_t *result) riscv011_info_t *info = get_info(target); do { - unsigned i = 0; + unsigned int i = 0; do { status = dbus_scan(target, &address_in, &value, DBUS_OP_READ, 0, 0); if (status == DBUS_STATUS_BUSY) { @@ -787,22 +782,25 @@ static void cache_set(struct target *target, slot_t slot, uint64_t data) static void cache_set_jump(struct target *target, unsigned int index) { - cache_set32(target, index, - jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*index)))); + unsigned int jump_offset = DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4 * index); + assert(jump_offset <= MAX_INT21); + cache_set32(target, index, jal(0, (int32_t)jump_offset)); } static void cache_set_load(struct target *target, unsigned int index, unsigned int reg, slot_t slot) { - uint16_t offset = DEBUG_RAM_START + 4 * slot_offset(target, slot); - cache_set32(target, index, load(target, reg, ZERO, offset)); + unsigned int offset = DEBUG_RAM_START + 4 * slot_offset(target, slot); + assert(offset <= MAX_INT12); + cache_set32(target, index, load(target, reg, ZERO, (int16_t)offset)); } static void cache_set_store(struct target *target, unsigned int index, unsigned int reg, slot_t slot) { - uint16_t offset = DEBUG_RAM_START + 4 * slot_offset(target, slot); - cache_set32(target, index, store(target, reg, ZERO, offset)); + unsigned int offset = DEBUG_RAM_START + 4 * slot_offset(target, slot); + assert(offset <= MAX_INT12); + cache_set32(target, index, store(target, reg, ZERO, (int16_t)offset)); } static void dump_debug_ram(struct target *target) @@ -1011,9 +1009,9 @@ static uint64_t cache_get(struct target *target, slot_t slot) static void dram_write_jump(struct target *target, unsigned int index, bool set_interrupt) { - dram_write32(target, index, - jal(0, (uint32_t) (DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4*index))), - set_interrupt); + unsigned int jump_offset = DEBUG_ROM_RESUME - (DEBUG_RAM_START + 4 * index); + assert(jump_offset <= MAX_INT21); + dram_write32(target, index, jal(0, (int32_t)jump_offset), set_interrupt); } static int wait_for_state(struct target *target, enum target_state state) @@ -1106,9 +1104,18 @@ static int maybe_write_tselect(struct target *target) return ERROR_OK; } +static uint64_t set_ebreakx_fields(uint64_t dcsr, const struct target *target) +{ + const struct riscv_private_config * const config = riscv_private_config(target); + dcsr = set_field(dcsr, DCSR_EBREAKM, config->dcsr_ebreak_fields[RISCV_MODE_M]); + dcsr = set_field(dcsr, DCSR_EBREAKS, config->dcsr_ebreak_fields[RISCV_MODE_S]); + dcsr = set_field(dcsr, DCSR_EBREAKU, config->dcsr_ebreak_fields[RISCV_MODE_U]); + dcsr = set_field(dcsr, DCSR_EBREAKH, 1); + return dcsr; +} + static int execute_resume(struct target *target, bool step) { - RISCV_INFO(r); riscv011_info_t *info = get_info(target); LOG_DEBUG("step=%d", step); @@ -1140,10 +1147,7 @@ static int execute_resume(struct target *target, bool step) } } - info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, r->riscv_ebreakm); - info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, r->riscv_ebreaks); - info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, r->riscv_ebreaku); - info->dcsr = set_field(info->dcsr, DCSR_EBREAKH, 1); + info->dcsr = set_ebreakx_fields(info->dcsr, target); info->dcsr &= ~DCSR_HALT; if (step) @@ -1168,7 +1172,7 @@ static int execute_resume(struct target *target, bool step) } target->state = TARGET_RUNNING; - register_cache_invalidate(target->reg_cache); + riscv_reg_cache_invalidate_all(target); return ERROR_OK; } @@ -1289,7 +1293,7 @@ static int register_write(struct target *target, unsigned int number, int result = update_mstatus_actual(target); if (result != ERROR_OK) return result; - unsigned i = 0; + unsigned int i = 0; if ((info->mstatus_actual & MSTATUS_FS) == 0) { info->mstatus_actual = set_field(info->mstatus_actual, MSTATUS_FS, 1); cache_set_load(target, i++, S0, SLOT1); @@ -1350,7 +1354,7 @@ int riscv011_get_register(struct target *target, riscv_reg_t *value, int result = update_mstatus_actual(target); if (result != ERROR_OK) return result; - unsigned i = 0; + unsigned int i = 0; if ((info->mstatus_actual & MSTATUS_FS) == 0) { info->mstatus_actual = set_field(info->mstatus_actual, MSTATUS_FS, 1); cache_set_load(target, i++, S0, SLOT1); @@ -1454,8 +1458,8 @@ static int strict_step(struct target *target, bool announce) return ERROR_OK; } -static int step(struct target *target, int current, target_addr_t address, - int handle_breakpoints) +static int step(struct target *target, bool current, target_addr_t address, + bool handle_breakpoints) { jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); @@ -1484,7 +1488,7 @@ static int examine(struct target *target) { /* Don't need to select dbus, since the first thing we do is read dtmcontrol. */ uint32_t dtmcontrol; - if (dtmcontrol_scan(target, 0, &dtmcontrol) != ERROR_OK || dtmcontrol == 0) { + if (dtmcs_scan(target->tap, 0, &dtmcontrol) != ERROR_OK || dtmcontrol == 0) { LOG_ERROR("Could not scan dtmcontrol. Check JTAG connectivity/board power."); return ERROR_FAIL; } @@ -1554,7 +1558,7 @@ static int examine(struct target *target) /* 0x00000000 0x00000000:00000003 0x00000000:00000003:ffffffff:ffffffff */ cache_set32(target, 4, sw(S1, ZERO, DEBUG_RAM_START + 4)); cache_set_jump(target, 5); - for (unsigned i = 6; i < info->dramsize; i++) + for (unsigned int i = 6; i < info->dramsize; i++) cache_set32(target, i, i * 0x01020304); cache_write(target, 0, false); @@ -1585,7 +1589,7 @@ static int examine(struct target *target) LOG_DEBUG("Discovered XLEN is %d", riscv_xlen(target)); if (read_remote_csr(target, &r->misa, CSR_MISA) != ERROR_OK) { - const unsigned old_csr_misa = 0xf10; + const unsigned int 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, old_csr_misa) != ERROR_OK) { @@ -1664,7 +1668,7 @@ static riscv_error_t handle_halt_routine(struct target *target) unsigned int dbus_busy = 0; unsigned int interrupt_set = 0; - unsigned result = 0; + unsigned int result = 0; uint64_t value = 0; reg_cache_set(target, 0, 0); /* The first scan result is the result from something old we don't care @@ -1885,8 +1889,16 @@ static int handle_halt(struct target *target, bool announce) if (target->debug_reason == DBG_REASON_BREAKPOINT) { int retval; - if (riscv_semihosting(target, &retval) != 0) - return retval; + /* Hotfix: Don't try to handle semihosting before the target is marked as examined. */ + /* TODO: The code should be rearranged so that: + * - Semihosting is not attempted before the target is examined. + * - When the target is already halted on a semihosting magic sequence + * at the time when OpenOCD connects to it, this semihosting attempt + * gets handled right after the examination. + */ + if (target_was_examined(target)) + if (riscv_semihosting(target, &retval) != SEMIHOSTING_NONE) + return retval; } if (announce) @@ -1948,8 +1960,9 @@ static int riscv011_poll(struct target *target) return poll_target(target, true); } -static int riscv011_resume(struct target *target, int current, - target_addr_t address, int handle_breakpoints, int debug_execution) +static int riscv011_resume(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, + bool debug_execution) { RISCV_INFO(r); jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); @@ -1960,7 +1973,6 @@ static int riscv011_resume(struct target *target, int current, static int assert_reset(struct target *target) { - RISCV_INFO(r); riscv011_info_t *info = get_info(target); /* TODO: Maybe what I implemented here is more like soft_reset_halt()? */ @@ -1974,10 +1986,7 @@ static int assert_reset(struct target *target) /* Not sure what we should do when there are multiple cores. * Here just reset the single hart we're talking to. */ - info->dcsr = set_field(info->dcsr, DCSR_EBREAKM, r->riscv_ebreakm); - info->dcsr = set_field(info->dcsr, DCSR_EBREAKS, r->riscv_ebreaks); - info->dcsr = set_field(info->dcsr, DCSR_EBREAKU, r->riscv_ebreaku); - info->dcsr = set_field(info->dcsr, DCSR_EBREAKH, 1); + info->dcsr = set_ebreakx_fields(info->dcsr, target); info->dcsr |= DCSR_HALT; if (target->reset_halt) info->dcsr |= DCSR_NDRESET; @@ -2004,9 +2013,16 @@ static int deassert_reset(struct target *target) return wait_for_state(target, TARGET_RUNNING); } -static int read_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) +static int read_memory(struct target *target, const riscv_mem_access_args_t args) { + assert(riscv_mem_access_is_read(args)); + + const target_addr_t address = args.address; + const uint32_t size = args.size; + const uint32_t count = args.count; + const uint32_t increment = args.increment; + uint8_t * const buffer = args.read_buffer; + if (increment != size) { LOG_ERROR("read_memory with custom increment not implemented"); return ERROR_NOT_IMPLEMENTED; @@ -2036,7 +2052,7 @@ static int read_memory(struct target *target, target_addr_t address, cache_write(target, CACHE_NO_READ, false); riscv011_info_t *info = get_info(target); - const unsigned max_batch_size = 256; + const unsigned int max_batch_size = 256; scans_t *scans = scans_new(target, max_batch_size); if (!scans) return ERROR_FAIL; @@ -2174,9 +2190,20 @@ static int setup_write_memory(struct target *target, uint32_t size) return ERROR_OK; } -static int write_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, const uint8_t *buffer) +static int write_memory(struct target *target, const riscv_mem_access_args_t args) { + assert(riscv_mem_access_is_write(args)); + + if (args.increment != args.size) { + LOG_TARGET_ERROR(target, "Write increment size has to be equal to element size"); + return ERROR_NOT_IMPLEMENTED; + } + + const target_addr_t address = args.address; + const uint32_t size = args.size; + const uint32_t count = args.count; + const uint8_t * const buffer = args.write_buffer; + riscv011_info_t *info = get_info(target); jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); @@ -2194,7 +2221,7 @@ static int write_memory(struct target *target, target_addr_t address, if (setup_write_memory(target, size) != ERROR_OK) return ERROR_FAIL; - const unsigned max_batch_size = 256; + const unsigned int max_batch_size = 256; scans_t *scans = scans_new(target, max_batch_size); if (!scans) return ERROR_FAIL; @@ -2312,6 +2339,15 @@ error: return ERROR_FAIL; } +static int access_memory(struct target *target, const riscv_mem_access_args_t args) +{ + assert(riscv_mem_access_is_valid(args)); + const bool is_write = riscv_mem_access_is_write(args); + if (is_write) + return write_memory(target, args); + return read_memory(target, args); +} + static int arch_state(struct target *target) { return ERROR_OK; @@ -2388,15 +2424,27 @@ static int riscv011_authdata_write(struct target *target, uint32_t value, unsign return ERROR_OK; } +static bool riscv011_get_impebreak(const struct target *target) +{ + return false; +} + +static unsigned int riscv011_get_progbufsize(const struct target *target) +{ + return 0; +} + static int init_target(struct command_context *cmd_ctx, struct target *target) { LOG_DEBUG("init"); RISCV_INFO(generic_info); - generic_info->read_memory = read_memory; + generic_info->access_memory = access_memory; generic_info->authdata_read = &riscv011_authdata_read; generic_info->authdata_write = &riscv011_authdata_write; generic_info->print_info = &riscv011_print_info; + generic_info->get_impebreak = &riscv011_get_impebreak; + generic_info->get_progbufsize = &riscv011_get_progbufsize; generic_info->version_specific = calloc(1, sizeof(riscv011_info_t)); if (!generic_info->version_specific) @@ -2426,7 +2474,5 @@ struct target_type riscv011_target = { .assert_reset = assert_reset, .deassert_reset = deassert_reset, - .write_memory = write_memory, - .arch_state = arch_state, }; diff --git a/src/target/riscv/riscv-011.h b/src/target/riscv/riscv-011.h index 8d1d06a..bbbc194 100644 --- a/src/target/riscv/riscv-011.h +++ b/src/target/riscv/riscv-011.h @@ -12,4 +12,4 @@ int riscv011_get_register(struct target *target, riscv_reg_t *value, int riscv011_set_register(struct target *target, enum gdb_regno regid, riscv_reg_t value); -#endif /*OPENOCD_TARGET_RISCV_RISCV_011_H*/ +#endif /* OPENOCD_TARGET_RISCV_RISCV_011_H */ diff --git a/src/target/riscv/riscv-011_reg.c b/src/target/riscv/riscv-011_reg.c index 7f29064..9b72918 100644 --- a/src/target/riscv/riscv-011_reg.c +++ b/src/target/riscv/riscv-011_reg.c @@ -36,21 +36,46 @@ static const struct reg_arch_type *riscv011_gdb_regno_reg_type(uint32_t regno) return &riscv011_reg_type; } -static int riscv011_init_reg(struct target *target, uint32_t regno) -{ - return riscv_reg_impl_init_one(target, regno, riscv011_gdb_regno_reg_type(regno)); -} int riscv011_reg_init_all(struct target *target) { - if (riscv_reg_impl_init_cache(target) != ERROR_OK) - return ERROR_FAIL; + int res = riscv_reg_impl_init_cache(target); + if (res != ERROR_OK) + return res; init_shared_reg_info(target); - for (uint32_t regno = 0; regno < target->reg_cache->num_regs; ++regno) - if (riscv011_init_reg(target, regno) != ERROR_OK) - return ERROR_FAIL; + RISCV_INFO(r); + assert(!r->vlenb + && "VLENB discovery is not supported on RISC-V 0.11 targets"); + /* Existence of some registers depends on others. + * E.g. the presence of "v0-31" registers is infered from "vlenb" being + * non-zero. + * Currently, discovery of the following registers is not supported on + * RISC-V 0.11 targets. */ + uint32_t non_discoverable_regs[] = { + GDB_REGNO_VLENB, + GDB_REGNO_MTOPI, + GDB_REGNO_MTOPEI + }; + for (unsigned int i = 0; i < ARRAY_SIZE(non_discoverable_regs); ++i) { + const uint32_t regno = non_discoverable_regs[i]; + res = riscv_reg_impl_init_cache_entry(target, regno, + /*exist*/ false, riscv011_gdb_regno_reg_type(regno)); + if (res != ERROR_OK) + return res; + } + + for (uint32_t regno = 0; regno < target->reg_cache->num_regs; ++regno) { + const struct reg * const reg = riscv_reg_impl_cache_entry(target, regno); + if (riscv_reg_impl_is_initialized(reg)) + continue; + res = riscv_reg_impl_init_cache_entry(target, regno, + riscv_reg_impl_gdb_regno_exist(target, regno), + riscv011_gdb_regno_reg_type(regno)); + if (res != ERROR_OK) + return res; + } if (riscv_reg_impl_expose_csrs(target) != ERROR_OK) return ERROR_FAIL; diff --git a/src/target/riscv/riscv-011_reg.h b/src/target/riscv/riscv-011_reg.h index ee00c9b..4f7911a 100644 --- a/src/target/riscv/riscv-011_reg.h +++ b/src/target/riscv/riscv-011_reg.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef OPENOCD_TARGET_RISCV_RISCV_REG_011_H -#define OPENOCD_TARGET_RISCV_RISCV_REG_011_H +#ifndef OPENOCD_TARGET_RISCV_RISCV_011_REG_H +#define OPENOCD_TARGET_RISCV_RISCV_011_REG_H #include "target/target.h" @@ -16,4 +16,4 @@ */ int riscv011_reg_init_all(struct target *target); -#endif /*OPENOCD_TARGET_RISCV_RISCV_REG_011_H*/ +#endif /* OPENOCD_TARGET_RISCV_RISCV_011_REG_H */ diff --git a/src/target/riscv/riscv-013.c b/src/target/riscv/riscv-013.c index 5e06cec..b5c6bfb 100644 --- a/src/target/riscv/riscv-013.c +++ b/src/target/riscv/riscv-013.c @@ -6,6 +6,7 @@ */ #include <assert.h> +#include <stdint.h> #include <stdlib.h> #include <time.h> @@ -16,6 +17,7 @@ #include "target/target.h" #include "target/algorithm.h" #include "target/target_type.h" +#include <helper/align.h> #include <helper/log.h> #include "jtag/jtag.h" #include "target/register.h" @@ -29,7 +31,6 @@ #include "debug_defines.h" #include "rtos/rtos.h" #include "program.h" -#include "asm.h" #include "batch.h" #include "debug_reg_printer.h" #include "field_helpers.h" @@ -54,22 +55,18 @@ static riscv_insn_t riscv013_read_progbuf(struct target *target, unsigned int index); static int riscv013_invalidate_cached_progbuf(struct target *target); static int riscv013_execute_progbuf(struct target *target, uint32_t *cmderr); -static void riscv013_fill_dmi_write(struct target *target, char *buf, uint64_t a, uint32_t d); -static void riscv013_fill_dmi_read(struct target *target, char *buf, uint64_t a); -static void riscv013_fill_dmi_nop(struct target *target, char *buf); -static int riscv013_get_dmi_scan_length(struct target *target); -static void riscv013_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d); -static void riscv013_fill_dm_read(struct target *target, char *buf, uint64_t a); -static void riscv013_fill_dm_nop(struct target *target, char *buf); +static void riscv013_fill_dmi_write(const struct target *target, uint8_t *buf, uint32_t a, uint32_t d); +static void riscv013_fill_dmi_read(const struct target *target, uint8_t *buf, uint32_t a); +static unsigned int riscv013_get_dmi_address_bits(const struct target *target); +static void riscv013_fill_dm_nop(const struct target *target, uint8_t *buf); static unsigned int register_size(struct target *target, enum gdb_regno number); static int register_read_direct(struct target *target, riscv_reg_t *value, enum gdb_regno number); static int register_write_direct(struct target *target, enum gdb_regno number, riscv_reg_t value); -static int read_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment); -static int write_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, const uint8_t *buffer); +static int riscv013_access_memory(struct target *target, const riscv_mem_access_args_t args); +static bool riscv013_get_impebreak(const struct target *target); +static unsigned int riscv013_get_progbufsize(const struct target *target); typedef enum { HALT_GROUP, @@ -115,7 +112,7 @@ typedef enum { typedef struct { struct list_head list; - int abs_chain_position; + unsigned int abs_chain_position; /* The base address to access this DM on DMI */ uint32_t base; /* The number of harts connected to this DM. */ @@ -148,15 +145,77 @@ typedef struct { struct target *target; } target_list_t; +struct ac_cache { + uint32_t *commands; + size_t size; +}; + +static int ac_cache_elem_comparator(const void *p_lhs, const void *p_rhs) +{ + uint32_t lhs = *(const uint32_t *)p_lhs; + uint32_t rhs = *(const uint32_t *)p_rhs; + if (lhs < rhs) + return -1; + if (lhs > rhs) + return 1; + return 0; +} + +static struct ac_cache ac_cache_construct(void) +{ + struct ac_cache cache = { + cache.commands = NULL, + cache.size = 0, + }; + return cache; +} + +static void ac_cache_free(struct ac_cache *cache) +{ + free(cache->commands); + cache->commands = NULL; + cache->size = 0; +} + +static void ac_cache_insert(struct ac_cache *cache, uint32_t command) +{ + assert(cache); + + size_t old_size = cache->size; + size_t new_size = old_size + 1; + size_t entry_size = sizeof(*cache->commands); + + uint32_t *commands = realloc(cache->commands, new_size * entry_size); + if (!commands) { + LOG_ERROR("Reallocation to %zu bytes failed", new_size * entry_size); + return; + } + + commands[old_size] = command; + cache->commands = commands; + cache->size = new_size; + + qsort(cache->commands, cache->size, entry_size, + ac_cache_elem_comparator); +} + +static bool ac_cache_contains(const struct ac_cache *cache, uint32_t command) +{ + return bsearch(&command, cache->commands, cache->size, + sizeof(*cache->commands), ac_cache_elem_comparator); +} + typedef struct { /* The indexed used to address this hart in its DM. */ - unsigned index; + unsigned int index; /* Number of address bits in the dbus register. */ - unsigned abits; + unsigned int abits; /* Number of abstract command data registers. */ - unsigned datacount; + unsigned int datacount; /* Number of words in the Program Buffer. */ - unsigned progbufsize; + unsigned int progbufsize; + /* Hart contains an implicit ebreak at the end of the program buffer. */ + bool impebreak; /* We cache the read-only bits of sbcs here. */ uint32_t sbcs; @@ -176,18 +235,16 @@ typedef struct { */ struct riscv_scan_delays learned_delays; - bool abstract_read_csr_supported; - bool abstract_write_csr_supported; - bool abstract_read_fpr_supported; - bool abstract_write_fpr_supported; - - yes_no_maybe_t has_aampostincrement; + struct ac_cache ac_not_supported_cache; /* Some fields from hartinfo. */ uint8_t datasize; uint8_t dataaccess; int16_t dataaddr; + /* The width of the hartsel field. */ + unsigned int hartsellen; + /* DM that provides access to this target. */ dm013_info_t *dm; @@ -202,7 +259,7 @@ typedef struct { bool haltgroup_supported; } riscv013_info_t; -static LIST_HEAD(dm_list); +static OOCD_LIST_HEAD(dm_list); static riscv013_info_t *get_info(const struct target *target) { @@ -223,7 +280,7 @@ static dm013_info_t *get_dm(struct target *target) if (info->dm) return info->dm; - int abs_chain_position = target->tap->abs_chain_position; + unsigned int abs_chain_position = target->tap->abs_chain_position; dm013_info_t *entry; dm013_info_t *dm = NULL; @@ -347,133 +404,45 @@ static uint32_t set_dmcontrol_hartsel(uint32_t initial, int hart_index) return initial; } -static unsigned int decode_dmi(const struct target *target, char *text, uint32_t address, uint32_t data) -{ - static const struct { - uint32_t address; - enum riscv_debug_reg_ordinal ordinal; - } description[] = { - {DM_DMCONTROL, DM_DMCONTROL_ORDINAL}, - {DM_DMSTATUS, DM_DMSTATUS_ORDINAL}, - {DM_ABSTRACTCS, DM_ABSTRACTCS_ORDINAL}, - {DM_COMMAND, DM_COMMAND_ORDINAL}, - {DM_SBCS, DM_SBCS_ORDINAL} - }; - - for (unsigned i = 0; i < ARRAY_SIZE(description); i++) { - if (riscv_get_dmi_address(target, description[i].address) == address) { - const riscv_debug_reg_ctx_t context = { - .XLEN = { .value = 0, .is_set = false }, - .DXLEN = { .value = 0, .is_set = false }, - .abits = { .value = 0, .is_set = false }, - }; - return riscv_debug_reg_to_s(text, description[i].ordinal, - context, data, RISCV_DEBUG_REG_HIDE_ALL_0); - } - } - if (text) - text[0] = '\0'; - return 0; -} - -void riscv_log_dmi_scan(const struct target *target, int idle, const struct scan_field *field, bool discard_in) -{ - static const char * const op_string[] = {"-", "r", "w", "?"}; - static const char * const status_string[] = {"+", "?", "F", "b"}; - - if (debug_level < LOG_LVL_DEBUG) - return; - - assert(field->out_value); - const uint64_t out = buf_get_u64(field->out_value, 0, field->num_bits); - const unsigned int out_op = get_field(out, DTM_DMI_OP); - const uint32_t out_data = get_field(out, DTM_DMI_DATA); - const uint32_t out_address = out >> DTM_DMI_ADDRESS_OFFSET; - - if (field->in_value) { - const uint64_t in = buf_get_u64(field->in_value, 0, field->num_bits); - const unsigned int in_op = get_field(in, DTM_DMI_OP); - const uint32_t in_data = get_field(in, DTM_DMI_DATA); - const uint32_t in_address = in >> DTM_DMI_ADDRESS_OFFSET; - - LOG_DEBUG("%db %s %08" PRIx32 " @%02" PRIx32 " -> %s %08" PRIx32 " @%02" PRIx32 "; %di", - field->num_bits, op_string[out_op], out_data, out_address, - status_string[in_op], in_data, in_address, idle); - - if (!discard_in && in_op == DTM_DMI_OP_SUCCESS) { - char in_decoded[decode_dmi(target, NULL, in_address, in_data) + 1]; - decode_dmi(target, in_decoded, in_address, in_data); - /* FIXME: The current code assumes that the hardware - * provides the read address in the dmi.address field - * when returning the dmi.data. That is however not - * required by the spec, and therefore not guaranteed. - * See https://github.com/riscv-collab/riscv-openocd/issues/1043 - */ - LOG_DEBUG("read: %s", in_decoded); - } - } else { - LOG_DEBUG("%db %s %08" PRIx32 " @%02" PRIx32 " -> ?; %di", - field->num_bits, op_string[out_op], out_data, out_address, - idle); - } - if (out_op == DTM_DMI_OP_WRITE) { - char out_decoded[decode_dmi(target, NULL, out_address, out_data) + 1]; - decode_dmi(target, out_decoded, out_address, out_data); - LOG_DEBUG("write: %s", out_decoded); - } -} - /*** Utility functions. ***/ -static void select_dmi(struct target *target) +static void select_dmi(struct jtag_tap *tap) { if (bscan_tunnel_ir_width != 0) { - select_dmi_via_bscan(target); + select_dmi_via_bscan(tap); return; } - jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); -} - -static int dtmcontrol_scan(struct target *target, uint32_t out, uint32_t *in_ptr) -{ - struct scan_field field; - uint8_t in_value[4]; - uint8_t out_value[4] = { 0 }; - - if (bscan_tunnel_ir_width != 0) - return dtmcontrol_scan_via_bscan(target, out, in_ptr); - - 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; + if (!tap->enabled) + LOG_ERROR("BUG: Target's TAP '%s' is disabled!", jtag_tap_name(tap)); + + bool need_ir_scan = false; + /* FIXME: make "tap" a const pointer. */ + for (struct jtag_tap *other_tap = jtag_tap_next_enabled(NULL); + other_tap; other_tap = jtag_tap_next_enabled(other_tap)) { + if (other_tap != tap) { + /* Different TAP than ours - check if it is in bypass */ + if (!other_tap->bypass) { + need_ir_scan = true; + break; + } + } else { + /* Our TAP - check if the correct instruction is already loaded */ + if (!buf_eq(tap->cur_instr, select_dbus.out_value, tap->ir_length)) { + need_ir_scan = true; + break; + } + } } - uint32_t in = buf_get_u32(field.in_value, 0, 32); - LOG_DEBUG("DTMCS: 0x%x -> 0x%x", out, in); - - if (in_ptr) - *in_ptr = in; - return ERROR_OK; + if (need_ir_scan) + jtag_add_ir_scan(tap, &select_dbus, TAP_IDLE); } static int increase_dmi_busy_delay(struct target *target) { RISCV013_INFO(info); - int res = dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, + int res = dtmcs_scan(target->tap, DTM_DTMCS_DMIRESET, NULL /* discard result */); if (res != ERROR_OK) return res; @@ -506,220 +475,6 @@ static void decrement_reset_delays_counter(struct target *target, size_t finishe "resetting learned delays (reset_delays_wait counter expired)"); reset_learned_delays(target); } -/** - * 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, uint32_t *address_in, - uint32_t *data_in, dmi_op_t op, uint32_t address_out, uint32_t data_out, - bool exec) -{ - riscv013_info_t *info = get_info(target); - unsigned num_bits = info->abits + DTM_DMI_OP_LENGTH + DTM_DMI_DATA_LENGTH; - size_t num_bytes = (num_bits + 7) / 8; - uint8_t in[num_bytes]; - uint8_t out[num_bytes]; - struct scan_field field = { - .num_bits = num_bits, - .out_value = out, - .in_value = in - }; - riscv_bscan_tunneled_scan_context_t bscan_ctxt; - - decrement_reset_delays_counter(target, 1); - - memset(in, 0, num_bytes); - memset(out, 0, num_bytes); - - if (info->abits == 0) { - LOG_TARGET_ERROR(target, "Can't access DMI because addrbits=0."); - return DMI_STATUS_FAILED; - } - - buf_set_u32(out, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, op); - buf_set_u32(out, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, data_out); - buf_set_u32(out, DTM_DMI_ADDRESS_OFFSET, info->abits, address_out); - - /* I wanted to place this code in a different function, but the way JTAG command - queueing works in the jtag handling functions, the scan fields either have to be - heap allocated, global/static, or else they need to stay on the stack until - the jtag_execute_queue() call. Heap or static fields in this case doesn't seem - the best fit. Declaring stack based field values in a subsidiary function call wouldn't - work. */ - if (bscan_tunnel_ir_width != 0) { - riscv_add_bscan_tunneled_scan(target, &field, &bscan_ctxt); - } else { - /* Assume dbus is already selected. */ - jtag_add_dr_scan(target->tap, 1, &field, TAP_IDLE); - } - - int idle_count = exec - ? riscv_scan_get_delay(&info->learned_delays, RISCV_DELAY_ABSTRACT_COMMAND) - : riscv_scan_get_delay(&info->learned_delays, RISCV_DELAY_BASE); - - 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"); - if (data_in) - *data_in = ~0; - return DMI_STATUS_FAILED; - } - - if (bscan_tunnel_ir_width != 0) { - /* need to right-shift "in" by one bit, because of clock skew between BSCAN TAP and DM TAP */ - buffer_shr(in, num_bytes, 1); - } - - if (data_in) - *data_in = buf_get_u32(in, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH); - - if (address_in) - *address_in = buf_get_u32(in, DTM_DMI_ADDRESS_OFFSET, info->abits); - riscv_log_dmi_scan(target, idle_count, &field, /*discard_in*/ !data_in); - return buf_get_u32(in, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH); -} - -/** - * @param target - * @param data_in The data we received from the target. - * @param dmi_busy_encountered - * If non-NULL, will be updated to reflect whether DMI busy was - * encountered while executing this operation or not. - * @param op The operation to perform (read/write/nop). - * @param address The address argument to that operation. - * @param data_out The data to send to the target. - * @param timeout_sec - * @param exec When true, this scan will execute something, so extra RTI - * cycles may be added. - * @param ensure_success - * Scan a nop after the requested operation, ensuring the - * DMI operation succeeded. - */ -static int dmi_op_timeout(struct target *target, uint32_t *data_in, - bool *dmi_busy_encountered, int op, uint32_t address, - uint32_t data_out, int timeout_sec, bool exec, bool ensure_success) -{ - select_dmi(target); - - dmi_status_t status; - - if (dmi_busy_encountered) - *dmi_busy_encountered = false; - - const char *op_name; - switch (op) { - case DMI_OP_NOP: - op_name = "nop"; - break; - case DMI_OP_READ: - op_name = "read"; - break; - case DMI_OP_WRITE: - op_name = "write"; - break; - default: - LOG_ERROR("Invalid DMI operation: %d", op); - return ERROR_FAIL; - } - - keep_alive(); - - time_t start = time(NULL); - /* This first loop performs the request. Note that if for some reason this - * stays busy, it is actually due to the previous access. */ - while (1) { - status = dmi_scan(target, NULL, NULL, op, address, data_out, - exec); - if (status == DMI_STATUS_BUSY) { - int result = increase_dmi_busy_delay(target); - if (result != ERROR_OK) - return result; - if (dmi_busy_encountered) - *dmi_busy_encountered = true; - } else if (status == DMI_STATUS_SUCCESS) { - break; - } else { - dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, NULL /* discard result */); - break; - } - if (time(NULL) - start > timeout_sec) - return ERROR_TIMEOUT_REACHED; - } - - if (status != DMI_STATUS_SUCCESS) { - LOG_TARGET_ERROR(target, "Failed DMI %s at 0x%x; status=%d", op_name, address, status); - return ERROR_FAIL; - } - - if (ensure_success) { - /* This second loop ensures the request succeeded, and gets back data. - * Note that NOP can result in a 'busy' result as well, but that would be - * noticed on the next DMI access we do. */ - while (1) { - status = dmi_scan(target, NULL, data_in, DMI_OP_NOP, address, 0, - false); - if (status == DMI_STATUS_BUSY) { - int result = increase_dmi_busy_delay(target); - if (result != ERROR_OK) - return result; - if (dmi_busy_encountered) - *dmi_busy_encountered = true; - } else if (status == DMI_STATUS_SUCCESS) { - break; - } else { - if (data_in) { - LOG_TARGET_ERROR(target, - "Failed DMI %s (NOP) at 0x%x; value=0x%x, status=%d", - op_name, address, *data_in, status); - } else { - LOG_TARGET_ERROR(target, - "Failed DMI %s (NOP) at 0x%x; status=%d", op_name, address, - status); - } - dtmcontrol_scan(target, DTM_DTMCS_DMIRESET, NULL /* discard result */); - return ERROR_FAIL; - } - if (time(NULL) - start > timeout_sec) - return ERROR_TIMEOUT_REACHED; - } - } - - return ERROR_OK; -} - -static int dmi_op(struct target *target, uint32_t *data_in, - bool *dmi_busy_encountered, int op, uint32_t address, - uint32_t data_out, bool exec, bool ensure_success) -{ - int result = dmi_op_timeout(target, data_in, dmi_busy_encountered, op, - address, data_out, riscv_get_command_timeout_sec(), exec, ensure_success); - if (result == ERROR_TIMEOUT_REACHED) { - LOG_TARGET_ERROR(target, "DMI operation didn't complete in %d seconds. The target is " - "either really slow or broken. You could increase the " - "timeout with riscv set_command_timeout_sec.", - riscv_get_command_timeout_sec()); - return ERROR_FAIL; - } - return result; -} - -static int dmi_read(struct target *target, uint32_t *value, uint32_t address) -{ - return dmi_op(target, value, NULL, DMI_OP_READ, address, 0, false, true); -} - -static int dmi_read_exec(struct target *target, uint32_t *value, uint32_t address) -{ - return dmi_op(target, value, NULL, DMI_OP_READ, address, 0, true, true); -} - -static int dmi_write(struct target *target, uint32_t address, uint32_t value) -{ - return dmi_op(target, NULL, NULL, DMI_OP_WRITE, address, value, false, true); -} static uint32_t riscv013_get_dmi_address(const struct target *target, uint32_t address) { @@ -731,23 +486,22 @@ static uint32_t riscv013_get_dmi_address(const struct target *target, uint32_t a return address + base; } -static int dm_op(struct target *target, uint32_t *data_in, - bool *dmi_busy_encountered, int op, uint32_t address, - uint32_t data_out, bool exec, bool ensure_success) +static int batch_run_timeout(struct target *target, struct riscv_batch *batch); + +static int dmi_read(struct target *target, uint32_t *value, uint32_t address) { - dm013_info_t *dm = get_dm(target); - if (!dm) - return ERROR_FAIL; - return dmi_op(target, data_in, dmi_busy_encountered, op, address + dm->base, - data_out, exec, ensure_success); + struct riscv_batch *batch = riscv_batch_alloc(target, 1); + riscv_batch_add_dmi_read(batch, address, RISCV_DELAY_BASE); + int res = batch_run_timeout(target, batch); + if (res == ERROR_OK && value) + *value = riscv_batch_get_dmi_read_data(batch, 0); + riscv_batch_free(batch); + return res; } static int dm_read(struct target *target, uint32_t *value, uint32_t address) { - dm013_info_t *dm = get_dm(target); - if (!dm) - return ERROR_FAIL; - return dmi_read(target, value, address + dm->base); + return dmi_read(target, value, riscv013_get_dmi_address(target, address)); } static int dm_read_exec(struct target *target, uint32_t *value, uint32_t address) @@ -755,22 +509,36 @@ static int dm_read_exec(struct target *target, uint32_t *value, uint32_t address dm013_info_t *dm = get_dm(target); if (!dm) return ERROR_FAIL; + struct riscv_batch *batch = riscv_batch_alloc(target, 1); + riscv_batch_add_dm_read(batch, address, RISCV_DELAY_ABSTRACT_COMMAND); dm->abstract_cmd_maybe_busy = true; - return dmi_read_exec(target, value, address + dm->base); + int res = batch_run_timeout(target, batch); + if (res == ERROR_OK && value) + *value = riscv_batch_get_dmi_read_data(batch, 0); + riscv_batch_free(batch); + return res; +} + +static int dmi_write(struct target *target, uint32_t address, uint32_t value) +{ + struct riscv_batch *batch = riscv_batch_alloc(target, 1); + riscv_batch_add_dmi_write(batch, address, value, /*read_back*/ true, + RISCV_DELAY_BASE); + int res = batch_run_timeout(target, batch); + riscv_batch_free(batch); + return res; } static int dm_write(struct target *target, uint32_t address, uint32_t value) { - dm013_info_t *dm = get_dm(target); - if (!dm) - return ERROR_FAIL; - return dmi_write(target, address + dm->base, value); + return dmi_write(target, riscv013_get_dmi_address(target, address), value); } static bool check_dbgbase_exists(struct target *target) { uint32_t next_dm = 0; unsigned int count = 1; + riscv013_info_t *info = get_info(target); LOG_TARGET_DEBUG(target, "Searching for DM with DMI base address (dbgbase) = 0x%x", target->dbgbase); while (1) { @@ -785,6 +553,12 @@ static bool check_dbgbase_exists(struct target *target) LOG_TARGET_ERROR(target, "Reached the end of DM chain (detected %u DMs in total).", count); break; } + if (next_dm >> info->abits) { + LOG_TARGET_ERROR(target, "The address of the next Debug Module does not fit into %u bits, " + "which is the width of the DMI bus address. This is a HW bug", + info->abits); + break; + } /* Safety: Avoid looping forever in case of buggy nextdm values in the hardware. */ if (count++ > RISCV_MAX_DMS) { LOG_TARGET_ERROR(target, "Supporting no more than %d DMs on a DMI bus. Aborting", RISCV_MAX_DMS); @@ -822,7 +596,7 @@ static int increase_ac_busy_delay(struct target *target) RISCV_DELAY_ABSTRACT_COMMAND); } -static uint32_t __attribute__((unused)) abstract_register_size(unsigned width) +static uint32_t __attribute__((unused)) abstract_register_size(unsigned int width) { switch (width) { case 32: @@ -915,6 +689,15 @@ static int abstract_cmd_batch_check_and_clear_cmderr(struct target *target, if (res != ERROR_OK) goto clear_cmderr; } + + dm013_info_t * const dm = get_dm(target); + if (!dm) { + LOG_ERROR("BUG: Target %s is not assigned to any RISC-V debug module", + target_name(target)); + return ERROR_FAIL; + } + dm->abstract_cmd_maybe_busy = false; + *cmderr = get_field32(abstractcs, DM_ABSTRACTCS_CMDERR); if (*cmderr == CMDERR_NONE) return ERROR_OK; @@ -930,9 +713,31 @@ clear_cmderr: return res; } -static int batch_run_timeout(struct target *target, struct riscv_batch *batch); +enum riscv_debug_reg_ordinal get_cmdtype(uint32_t command) +{ + switch (get_field(command, DM_COMMAND_CMDTYPE)) { + case 0: + return AC_ACCESS_REGISTER_ORDINAL; + case 1: + return AC_QUICK_ACCESS_ORDINAL; + case 2: + return AC_ACCESS_MEMORY_ORDINAL; + default: + assert(false && "Unknown command type value"); + return 0; + } +} + +static void mark_command_as_unsupported(struct target *target, uint32_t command) +{ + LOG_TARGET_DEBUG(target, "Caching the abstract " + "command 0x%" PRIx32 " as not supported", command); + log_debug_reg(target, get_cmdtype(command), + command, __FILE__, __LINE__, __func__); + ac_cache_insert(&get_info(target)->ac_not_supported_cache, command); +} -static int execute_abstract_command(struct target *target, uint32_t command, +int riscv013_execute_abstract_command(struct target *target, uint32_t command, uint32_t *cmderr) { assert(cmderr); @@ -965,6 +770,9 @@ static int execute_abstract_command(struct target *target, uint32_t command, res = abstract_cmd_batch_check_and_clear_cmderr(target, batch, abstractcs_read_key, cmderr); + if (res != ERROR_OK && *cmderr == CMDERR_NOT_SUPPORTED) + mark_command_as_unsupported(target, command); + cleanup: riscv_batch_free(batch); return res; @@ -1048,10 +856,10 @@ static void abstract_data_write_fill_batch(struct riscv_batch *batch, } /* TODO: reuse "abstract_data_write_fill_batch()" here*/ -static int write_abstract_arg(struct target *target, unsigned index, - riscv_reg_t value, unsigned size_bits) +static int write_abstract_arg(struct target *target, unsigned int index, + riscv_reg_t value, unsigned int size_bits) { - unsigned offset = index * size_bits / 32; + unsigned int offset = index * size_bits / 32; switch (size_bits) { default: LOG_TARGET_ERROR(target, "Unsupported size: %d bits", size_bits); @@ -1068,8 +876,8 @@ static int write_abstract_arg(struct target *target, unsigned index, /** * @par size in bits */ -static uint32_t access_register_command(struct target *target, uint32_t number, - unsigned size, uint32_t flags) +uint32_t riscv013_access_register_command(struct target *target, uint32_t number, + unsigned int size, uint32_t flags) { uint32_t command = set_field(0, DM_COMMAND_CMDTYPE, 0); switch (size) { @@ -1110,38 +918,35 @@ static uint32_t access_register_command(struct target *target, uint32_t number, return command; } +static bool is_command_unsupported(struct target *target, uint32_t command) +{ + bool unsupported = ac_cache_contains(&get_info(target)->ac_not_supported_cache, command); + if (!unsupported) + return false; + + LOG_TARGET_DEBUG(target, "Abstract command 0x%" + PRIx32 " is cached as not supported", command); + log_debug_reg(target, get_cmdtype(command), + command, __FILE__, __LINE__, __func__); + return true; +} + static int register_read_abstract_with_size(struct target *target, riscv_reg_t *value, enum gdb_regno number, unsigned int size) { - RISCV013_INFO(info); - - if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && - !info->abstract_read_fpr_supported) - return ERROR_FAIL; - if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 && - !info->abstract_read_csr_supported) - return ERROR_FAIL; /* The spec doesn't define abstract register numbers for vector registers. */ if (number >= GDB_REGNO_V0 && number <= GDB_REGNO_V31) return ERROR_FAIL; - uint32_t command = access_register_command(target, number, size, + uint32_t command = riscv013_access_register_command(target, number, size, AC_ACCESS_REGISTER_TRANSFER); + if (is_command_unsupported(target, command)) + return ERROR_FAIL; uint32_t cmderr; - int result = execute_abstract_command(target, command, &cmderr); - if (result != ERROR_OK) { - if (cmderr == CMDERR_NOT_SUPPORTED) { - if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - info->abstract_read_fpr_supported = false; - LOG_TARGET_INFO(target, "Disabling abstract command reads from FPRs."); - } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { - info->abstract_read_csr_supported = false; - LOG_TARGET_INFO(target, "Disabling abstract command reads from CSRs."); - } - } + int result = riscv013_execute_abstract_command(target, command, &cmderr); + if (result != ERROR_OK) return result; - } if (value) return read_abstract_arg(target, value, 0, size); @@ -1160,23 +965,17 @@ static int register_read_abstract(struct target *target, riscv_reg_t *value, static int register_write_abstract(struct target *target, enum gdb_regno number, riscv_reg_t value) { - RISCV013_INFO(info); - dm013_info_t *dm = get_dm(target); if (!dm) return ERROR_FAIL; - if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31 && - !info->abstract_write_fpr_supported) - return ERROR_FAIL; - if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095 && - !info->abstract_write_csr_supported) - return ERROR_FAIL; - const unsigned int size_bits = register_size(target, number); - const uint32_t command = access_register_command(target, number, size_bits, + const uint32_t command = riscv013_access_register_command(target, number, size_bits, AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_WRITE); + if (is_command_unsupported(target, command)) + return ERROR_FAIL; + LOG_DEBUG_REG(target, AC_ACCESS_REGISTER, command); assert(size_bits % 32 == 0); const unsigned int size_in_words = size_bits / 32; @@ -1196,18 +995,9 @@ static int register_write_abstract(struct target *target, enum gdb_regno number, uint32_t cmderr; res = abstract_cmd_batch_check_and_clear_cmderr(target, batch, abstractcs_read_key, &cmderr); + if (res != ERROR_OK && cmderr == CMDERR_NOT_SUPPORTED) + mark_command_as_unsupported(target, command); - if (res != ERROR_OK) { - if (cmderr == CMDERR_NOT_SUPPORTED) { - if (number >= GDB_REGNO_FPR0 && number <= GDB_REGNO_FPR31) { - info->abstract_write_fpr_supported = false; - LOG_TARGET_INFO(target, "Disabling abstract command writes to FPRs."); - } else if (number >= GDB_REGNO_CSR0 && number <= GDB_REGNO_CSR4095) { - info->abstract_write_csr_supported = false; - LOG_TARGET_INFO(target, "Disabling abstract command writes to CSRs."); - } - } - } cleanup: riscv_batch_free(batch); return res; @@ -1217,7 +1007,7 @@ cleanup: * Sets the AAMSIZE field of a memory access abstract command based on * the width (bits). */ -static uint32_t abstract_memory_size(unsigned width) +static uint32_t abstract_memory_size(unsigned int width) { switch (width) { case 8: @@ -1399,7 +1189,7 @@ typedef struct { static int scratch_reserve(struct target *target, scratch_mem_t *scratch, struct riscv_program *program, - unsigned size_bytes) + unsigned int size_bytes) { riscv_addr_t alignment = 1; while (alignment < size_bytes) @@ -1431,7 +1221,7 @@ static int scratch_reserve(struct target *target, return ERROR_FAIL; /* Allow for ebreak at the end of the program. */ - unsigned program_size = (program->instruction_count + 1) * 4; + unsigned int program_size = (program->instruction_count + 1) * 4; scratch->hart_address = (info->progbuf_address + program_size + alignment - 1) & ~(alignment - 1); if ((info->progbuf_writable == YNM_YES) && @@ -1487,16 +1277,17 @@ static int scratch_read64(struct target *target, scratch_mem_t *scratch, case SPACE_DMI_RAM: { uint8_t buffer[8] = {0}; - if (read_memory(target, scratch->debug_address, 4, 2, buffer, 4) != ERROR_OK) + const riscv_mem_access_args_t args = { + .address = scratch->debug_address, + .read_buffer = buffer, + .size = 4, + .count = 2, + .increment = 4, + }; + if (riscv013_access_memory(target, args) != ERROR_OK) return ERROR_FAIL; - *value = buffer[0] | - (((uint64_t) buffer[1]) << 8) | - (((uint64_t) buffer[2]) << 16) | - (((uint64_t) buffer[3]) << 24) | - (((uint64_t) buffer[4]) << 32) | - (((uint64_t) buffer[5]) << 40) | - (((uint64_t) buffer[6]) << 48) | - (((uint64_t) buffer[7]) << 56); + *value = buf_get_u64(buffer, + /* first = */ 0, /* bit_num = */ 64); } break; } @@ -1528,7 +1319,14 @@ static int scratch_write64(struct target *target, scratch_mem_t *scratch, value >> 48, value >> 56 }; - if (write_memory(target, scratch->debug_address, 4, 2, buffer) != ERROR_OK) + const riscv_mem_access_args_t args = { + .address = scratch->debug_address, + .write_buffer = buffer, + .size = 4, + .count = 2, + .increment = 4, + }; + if (riscv013_access_memory(target, args) != ERROR_OK) return ERROR_FAIL; } break; @@ -1547,12 +1345,10 @@ static unsigned int register_size(struct target *target, enum gdb_regno number) return riscv_xlen(target); } -static bool has_sufficient_progbuf(struct target *target, unsigned size) +static bool has_sufficient_progbuf(struct target *target, unsigned int size) { RISCV013_INFO(info); - RISCV_INFO(r); - - return info->progbufsize + r->impebreak >= size; + return info->progbufsize + info->impebreak >= size; } /** @@ -1892,7 +1688,6 @@ static int set_dcsr_ebreak(struct target *target, bool step) if (dm013_select_target(target) != ERROR_OK) return ERROR_FAIL; - RISCV_INFO(r); RISCV013_INFO(info); riscv_reg_t original_dcsr, dcsr; /* We want to twiddle some bits in the debug CSR so debugging works. */ @@ -1900,11 +1695,12 @@ static int set_dcsr_ebreak(struct target *target, bool step) return ERROR_FAIL; original_dcsr = dcsr; dcsr = set_field(dcsr, CSR_DCSR_STEP, step); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, r->riscv_ebreakm); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, r->riscv_ebreaks && riscv_supports_extension(target, 'S')); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, r->riscv_ebreaku && riscv_supports_extension(target, 'U')); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKVS, r->riscv_ebreaku && riscv_supports_extension(target, 'H')); - dcsr = set_field(dcsr, CSR_DCSR_EBREAKVU, r->riscv_ebreaku && riscv_supports_extension(target, 'H')); + const struct riscv_private_config * const config = riscv_private_config(target); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKM, config->dcsr_ebreak_fields[RISCV_MODE_M]); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKS, config->dcsr_ebreak_fields[RISCV_MODE_S]); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKU, config->dcsr_ebreak_fields[RISCV_MODE_U]); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKVS, config->dcsr_ebreak_fields[RISCV_MODE_VS]); + dcsr = set_field(dcsr, CSR_DCSR_EBREAKVU, config->dcsr_ebreak_fields[RISCV_MODE_VU]); if (dcsr != original_dcsr && riscv_reg_set(target, GDB_REGNO_DCSR, dcsr) != ERROR_OK) return ERROR_FAIL; @@ -1984,6 +1780,10 @@ static void deinit_target(struct target *target) if (!info) return; + riscv013_info_t *vsinfo = info->version_specific; + if (vsinfo) + ac_cache_free(&vsinfo->ac_not_supported_cache); + riscv013_dm_free(target); free(info->version_specific); @@ -2202,7 +2002,7 @@ static int examine(struct target *target) LOG_TARGET_DEBUG(target, "dbgbase=0x%x", target->dbgbase); uint32_t dtmcontrol; - if (dtmcontrol_scan(target, 0, &dtmcontrol) != ERROR_OK || dtmcontrol == 0) { + if (dtmcs_scan(target->tap, 0, &dtmcontrol) != ERROR_OK || dtmcontrol == 0) { LOG_TARGET_ERROR(target, "Could not scan dtmcontrol. Check JTAG connectivity/board power."); return ERROR_FAIL; } @@ -2222,6 +2022,34 @@ static int examine(struct target *target) info->abits = get_field(dtmcontrol, DTM_DTMCS_ABITS); info->dtmcs_idle = get_field(dtmcontrol, DTM_DTMCS_IDLE); + if (info->abits > RISCV013_DTMCS_ABITS_MAX) { + /* Max. address width given by the debug specification is exceeded */ + LOG_TARGET_ERROR(target, "The target's debug bus (DMI) address width exceeds " + "the maximum:"); + LOG_TARGET_ERROR(target, " found dtmcs.abits = %d; maximum is abits = %d.", + info->abits, RISCV013_DTMCS_ABITS_MAX); + return ERROR_FAIL; + } + + if (info->abits == 0) { + LOG_TARGET_ERROR(target, + "dtmcs.abits is zero. Check JTAG connectivity/board power"); + return ERROR_FAIL; + } + if (info->abits < RISCV013_DTMCS_ABITS_MIN) { + /* The requirement for minimum DMI address width of 7 bits is part of + * the RISC-V Debug spec since Jan-20-2017 (commit 03df6ee7). However, + * implementations exist that implement narrower DMI address. For example + * Spike as of Q1/2025 uses dmi.abits = 6. + * + * For that reason, warn the user but continue. + */ + LOG_TARGET_WARNING(target, "The target's debug bus (DMI) address width is " + "lower than the minimum:"); + LOG_TARGET_WARNING(target, " found dtmcs.abits = %d; minimum is abits = %d.", + info->abits, RISCV013_DTMCS_ABITS_MIN); + } + if (!check_dbgbase_exists(target)) { LOG_TARGET_ERROR(target, "Could not find debug module with DMI base address (dbgbase) = 0x%x", target->dbgbase); return ERROR_FAIL; @@ -2277,21 +2105,13 @@ static int examine(struct target *target) LOG_TARGET_INFO(target, "datacount=%d progbufsize=%d", info->datacount, info->progbufsize); - RISCV_INFO(r); - r->impebreak = get_field(dmstatus, DM_DMSTATUS_IMPEBREAK); + info->impebreak = get_field(dmstatus, DM_DMSTATUS_IMPEBREAK); if (!has_sufficient_progbuf(target, 2)) { LOG_TARGET_WARNING(target, "We won't be able to execute fence instructions on this " "target. Memory may not always appear consistent. " "(progbufsize=%d, impebreak=%d)", info->progbufsize, - r->impebreak); - } - - if (info->progbufsize < 4 && riscv_enable_virtual) { - LOG_TARGET_ERROR(target, "set_enable_virtual is not available on this target. It " - "requires a program buffer size of at least 4. (progbufsize=%d) " - "Use `riscv set_enable_virtual off` to continue." - , info->progbufsize); + info->impebreak); } /* Don't call any riscv_* functions until after we've counted the number of @@ -2300,6 +2120,8 @@ static int examine(struct target *target) enum riscv_hart_state state_at_examine_start; if (riscv_get_hart_state(target, &state_at_examine_start) != ERROR_OK) return ERROR_FAIL; + + RISCV_INFO(r); const bool hart_halted_at_examine_start = state_at_examine_start == RISCV_STATE_HALTED; if (!hart_halted_at_examine_start) { r->prepped = true; @@ -2313,74 +2135,9 @@ static int examine(struct target *target) target->state = TARGET_HALTED; target->debug_reason = hart_halted_at_examine_start ? DBG_REASON_UNDEFINED : DBG_REASON_DBGRQ; - /* Without knowing anything else we can at least mess with the - * program buffer. */ - r->progbuf_size = info->progbufsize; - - result = register_read_abstract_with_size(target, NULL, GDB_REGNO_S0, 64); - if (result == ERROR_OK) - r->xlen = 64; - else - r->xlen = 32; - - /* Save s0 and s1. The register cache hasn't be initialized yet so we - * need to take care of this manually. */ - uint64_t s0, s1; - if (register_read_abstract(target, &s0, GDB_REGNO_S0) != ERROR_OK) { - LOG_TARGET_ERROR(target, "Fatal: Failed to read s0."); - return ERROR_FAIL; - } - if (register_read_abstract(target, &s1, GDB_REGNO_S1) != ERROR_OK) { - LOG_TARGET_ERROR(target, "Fatal: Failed to read s1."); - return ERROR_FAIL; - } - - if (register_read_direct(target, &r->misa, GDB_REGNO_MISA)) { - LOG_TARGET_ERROR(target, "Fatal: Failed to read MISA."); - return ERROR_FAIL; - } - - uint64_t value; - if (register_read_direct(target, &value, GDB_REGNO_VLENB) != ERROR_OK) { - if (riscv_supports_extension(target, 'V')) - LOG_TARGET_WARNING(target, "Couldn't read vlenb; vector register access won't work."); - r->vlenb = 0; - } else { - r->vlenb = value; - LOG_TARGET_INFO(target, "Vector support with vlenb=%d", r->vlenb); - } - - if (register_read_direct(target, &value, GDB_REGNO_MTOPI) == ERROR_OK) { - r->mtopi_readable = true; - - if (register_read_direct(target, &value, GDB_REGNO_MTOPEI) == ERROR_OK) { - LOG_TARGET_INFO(target, "S?aia detected with IMSIC"); - r->mtopei_readable = true; - } else { - r->mtopei_readable = false; - LOG_TARGET_INFO(target, "S?aia detected without IMSIC"); - } - } else { - r->mtopi_readable = false; - } - - /* Display this as early as possible to help people who are using - * really slow simulators. */ - LOG_TARGET_DEBUG(target, " XLEN=%d, misa=0x%" PRIx64, r->xlen, r->misa); - - /* Restore s0 and s1. */ - if (register_write_direct(target, GDB_REGNO_S0, s0) != ERROR_OK) { - LOG_TARGET_ERROR(target, "Fatal: Failed to write back s0."); - return ERROR_FAIL; - } - if (register_write_direct(target, GDB_REGNO_S1, s1) != ERROR_OK) { - LOG_TARGET_ERROR(target, "Fatal: Failed to write back s1."); - return ERROR_FAIL; - } - - /* Now init registers based on what we discovered. */ - if (riscv013_reg_init_all(target) != ERROR_OK) - return ERROR_FAIL; + result = riscv013_reg_examine_all(target); + if (result != ERROR_OK) + return result; if (set_dcsr_ebreak(target, false) != ERROR_OK) return ERROR_FAIL; @@ -2461,13 +2218,13 @@ static int riscv013_authdata_write(struct target *target, uint32_t value, unsign } /* Try to find out the widest memory access size depending on the selected memory access methods. */ -static unsigned riscv013_data_bits(struct target *target) +static unsigned int riscv013_data_bits(struct target *target) { RISCV013_INFO(info); RISCV_INFO(r); - for (unsigned int i = 0; i < RISCV_NUM_MEM_ACCESS_METHODS; i++) { - int method = r->mem_access_methods[i]; + for (unsigned int i = 0; i < r->num_enabled_mem_access_methods; i++) { + riscv_mem_access_method_t method = r->mem_access_methods[i]; if (method == RISCV_MEM_ACCESS_PROGBUF) { if (has_sufficient_progbuf(target, 3)) @@ -2488,9 +2245,9 @@ static unsigned riscv013_data_bits(struct target *target) * take those into account as well. For now we assume abstract commands * support XLEN-wide accesses. */ return riscv_xlen(target); - } else if (method == RISCV_MEM_ACCESS_UNSPECIFIED) - /* No further mem access method to try. */ - break; + } else { + assert(false); + } } LOG_TARGET_ERROR(target, "Unable to determine supported data bits on this target. Assuming 32 bits."); return 32; @@ -2716,38 +2473,63 @@ static uint32_t sb_sbaccess(unsigned int size_bytes) return 0; } -static int sb_write_address(struct target *target, target_addr_t address, - bool ensure_success) +static unsigned int get_sbaadress_reg_count(const struct target *target) { RISCV013_INFO(info); - unsigned int sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); + const unsigned int sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); + return DIV_ROUND_UP(sbasize, 32); +} + +static void batch_fill_sb_write_address(const struct target *target, + struct riscv_batch *batch, target_addr_t address, + enum riscv_scan_delay_class sbaddr0_delay) +{ /* There currently is no support for >64-bit addresses in OpenOCD. */ - if (sbasize > 96) - dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS3, 0, false, false); - if (sbasize > 64) - dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS2, 0, false, false); - if (sbasize > 32) - dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS1, - (uint32_t)(address >> 32), false, false); - return dm_op(target, NULL, NULL, DMI_OP_WRITE, DM_SBADDRESS0, - (uint32_t)address, false, ensure_success); + assert(sizeof(target_addr_t) == sizeof(uint64_t)); + const uint32_t addresses[] = {DM_SBADDRESS0, DM_SBADDRESS1, DM_SBADDRESS2, DM_SBADDRESS3}; + const uint32_t values[] = {(uint32_t)address, (uint32_t)(address >> 32), 0, 0}; + const unsigned int reg_count = get_sbaadress_reg_count(target); + assert(reg_count > 0); + assert(reg_count <= ARRAY_SIZE(addresses)); + assert(ARRAY_SIZE(addresses) == ARRAY_SIZE(values)); + + for (unsigned int i = reg_count - 1; i > 0; --i) + riscv_batch_add_dm_write(batch, addresses[i], values[i], /* read back */ true, + RISCV_DELAY_BASE); + riscv_batch_add_dm_write(batch, addresses[0], values[0], /* read back */ true, + sbaddr0_delay); +} + +static int sb_write_address(struct target *target, target_addr_t address, + enum riscv_scan_delay_class sbaddr0_delay) +{ + struct riscv_batch *batch = riscv_batch_alloc(target, + get_sbaadress_reg_count(target)); + batch_fill_sb_write_address(target, batch, address, sbaddr0_delay); + const int res = batch_run_timeout(target, batch); + riscv_batch_free(batch); + return res; } static int batch_run(struct target *target, struct riscv_batch *batch) { RISCV_INFO(r); RISCV013_INFO(info); - select_dmi(target); + select_dmi(target->tap); riscv_batch_add_nop(batch); const int result = riscv_batch_run_from(batch, 0, &info->learned_delays, /*resets_delays*/ r->reset_delays_wait >= 0, r->reset_delays_wait); + if (result != ERROR_OK) + return result; /* TODO: To use `riscv_batch_finished_scans()` here, it is needed for * all scans to not discard input, meaning * "riscv_batch_add_dm_write(..., false)" should not be used. */ const size_t finished_scans = batch->used_scans; decrement_reset_delays_counter(target, finished_scans); - return result; + if (riscv_batch_was_batch_busy(batch)) + return increase_dmi_busy_delay(target); + return ERROR_OK; } /* It is expected that during creation of the batch @@ -2756,7 +2538,7 @@ static int batch_run(struct target *target, struct riscv_batch *batch) static int batch_run_timeout(struct target *target, struct riscv_batch *batch) { RISCV013_INFO(info); - select_dmi(target); + select_dmi(target->tap); riscv_batch_add_nop(batch); size_t finished_scans = 0; @@ -2770,12 +2552,12 @@ static int batch_run_timeout(struct target *target, struct riscv_batch *batch) &info->learned_delays, /*resets_delays*/ r->reset_delays_wait >= 0, r->reset_delays_wait); + if (result != ERROR_OK) + return result; const size_t new_finished_scans = riscv_batch_finished_scans(batch); assert(new_finished_scans >= finished_scans); decrement_reset_delays_counter(target, new_finished_scans - finished_scans); finished_scans = new_finished_scans; - if (result != ERROR_OK) - return result; if (!riscv_batch_was_batch_busy(batch)) { assert(finished_scans == batch->used_scans); return ERROR_OK; @@ -2930,7 +2712,7 @@ static int sample_memory_bus_v1(struct target *target, /* Discard the batch when we encounter a busy state on the DMI level. * It's too much hassle to try to recover partial data. We'll try again * with a larger DMI delay. */ - unsigned int sbcs_read_op = riscv_batch_get_dmi_read_op(batch, sbcs_read_index); + const uint32_t sbcs_read_op = riscv_batch_get_dmi_read_op(batch, sbcs_read_index); if (sbcs_read_op == DTM_DMI_OP_BUSY) { result = increase_dmi_busy_delay(target); if (result != ERROR_OK) { @@ -3048,6 +2830,13 @@ static int handle_became_unavailable(struct target *target, enum riscv_hart_state previous_riscv_state) { RISCV013_INFO(info); + + if (riscv_reg_cache_any_dirty(target, LOG_LVL_WARNING)) + LOG_TARGET_WARNING(target, "Discarding values of dirty registers " + "(due to target becoming unavailable)."); + + riscv_reg_cache_invalidate_all(target); + info->dcsr_ebreak_is_set = false; return ERROR_OK; } @@ -3081,18 +2870,20 @@ static int init_target(struct command_context *cmd_ctx, generic_info->write_progbuf = &riscv013_write_progbuf; generic_info->execute_progbuf = &riscv013_execute_progbuf; generic_info->invalidate_cached_progbuf = &riscv013_invalidate_cached_progbuf; - generic_info->fill_dm_write = &riscv013_fill_dm_write; - generic_info->fill_dm_read = &riscv013_fill_dm_read; + generic_info->fill_dmi_write = &riscv013_fill_dmi_write; + generic_info->fill_dmi_read = &riscv013_fill_dmi_read; generic_info->fill_dm_nop = &riscv013_fill_dm_nop; - generic_info->get_dmi_scan_length = &riscv013_get_dmi_scan_length; + generic_info->get_dmi_address_bits = &riscv013_get_dmi_address_bits; generic_info->authdata_read = &riscv013_authdata_read; generic_info->authdata_write = &riscv013_authdata_write; generic_info->dmi_read = &dmi_read; generic_info->dmi_write = &dmi_write; generic_info->get_dmi_address = &riscv013_get_dmi_address; - generic_info->read_memory = read_memory; + generic_info->access_memory = &riscv013_access_memory; generic_info->data_bits = &riscv013_data_bits; generic_info->print_info = &riscv013_print_info; + generic_info->get_impebreak = &riscv013_get_impebreak; + generic_info->get_progbufsize = &riscv013_get_progbufsize; generic_info->handle_became_unavailable = &handle_became_unavailable; generic_info->tick = &tick; @@ -3108,17 +2899,7 @@ static int init_target(struct command_context *cmd_ctx, info->progbufsize = -1; reset_learned_delays(target); - /* Assume all these abstract commands are supported until we learn - * otherwise. - * TODO: The spec allows eg. one CSR to be able to be accessed abstractly - * while another one isn't. We don't track that this closely here, but in - * the future we probably should. */ - info->abstract_read_csr_supported = true; - info->abstract_write_csr_supported = true; - info->abstract_read_fpr_supported = true; - info->abstract_write_fpr_supported = true; - - info->has_aampostincrement = YNM_MAYBE; + info->ac_not_supported_cache = ac_cache_construct(); return ERROR_OK; } @@ -3128,7 +2909,7 @@ static int assert_reset(struct target *target) RISCV013_INFO(info); int result; - select_dmi(target); + select_dmi(target->tap); if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) { /* Run the user-supplied script if there is one. */ @@ -3165,6 +2946,15 @@ static int assert_reset(struct target *target) return riscv013_invalidate_cached_progbuf(target); } +static bool dcsr_ebreak_config_equals_reset_value(const struct target *target) +{ + const struct riscv_private_config * const config = riscv_private_config(target); + for (int i = 0; i < N_RISCV_MODE; ++i) + if (config->dcsr_ebreak_fields[i]) + return false; + return true; +} + static int deassert_reset(struct target *target) { RISCV013_INFO(info); @@ -3173,7 +2963,7 @@ static int deassert_reset(struct target *target) return ERROR_FAIL; int result; - select_dmi(target); + select_dmi(target->tap); /* Clear the reset, but make sure haltreq is still set */ uint32_t control = 0; control = set_field(control, DM_DMCONTROL_DMACTIVE, 1); @@ -3224,6 +3014,15 @@ static int deassert_reset(struct target *target) riscv_scan_set_delay(&info->learned_delays, RISCV_DELAY_BASE, orig_base_delay); + /* Ack reset and clear DM_DMCONTROL_HALTREQ if previously set */ + control = 0; + control = set_field(control, DM_DMCONTROL_DMACTIVE, 1); + control = set_field(control, DM_DMCONTROL_ACKHAVERESET, 1); + control = set_dmcontrol_hartsel(control, info->index); + result = dm_write(target, DM_DMCONTROL, control); + if (result != ERROR_OK) + return result; + if (target->reset_halt) { target->state = TARGET_HALTED; target->debug_reason = DBG_REASON_DBGRQ; @@ -3231,21 +3030,19 @@ static int deassert_reset(struct target *target) target->state = TARGET_RUNNING; target->debug_reason = DBG_REASON_NOTHALTED; } - info->dcsr_ebreak_is_set = false; - - /* Ack reset and clear DM_DMCONTROL_HALTREQ if previously set */ - control = 0; - control = set_field(control, DM_DMCONTROL_DMACTIVE, 1); - control = set_field(control, DM_DMCONTROL_ACKHAVERESET, 1); - control = set_dmcontrol_hartsel(control, info->index); - return dm_write(target, DM_DMCONTROL, control); + info->dcsr_ebreak_is_set = dcsr_ebreak_config_equals_reset_value(target); + return ERROR_OK; } -static int execute_fence(struct target *target) +static int execute_autofence(struct target *target) { if (dm013_select_target(target) != ERROR_OK) return ERROR_FAIL; + RISCV_INFO(r); + if (!r->autofence) + return ERROR_OK; + /* FIXME: For non-coherent systems we need to flush the caches right * here, but there's no ISA-defined way of doing that. */ struct riscv_program program; @@ -3267,8 +3064,9 @@ static int execute_fence(struct target *target) LOG_TARGET_ERROR(target, "Unexpected error during fence execution"); return ERROR_FAIL; } - LOG_TARGET_DEBUG(target, "Unable to execute fence"); + LOG_TARGET_DEBUG(target, "Unable to execute fence.i and fence rw, rw"); } + LOG_TARGET_DEBUG(target, "Successfully executed fence.i and fence rw, rw"); return ERROR_OK; } @@ -3282,6 +3080,7 @@ static int execute_fence(struct target *target) } LOG_TARGET_DEBUG(target, "Unable to execute fence.i"); } + LOG_TARGET_DEBUG(target, "Successfully executed fence.i"); riscv_program_init(&program, target); riscv_program_fence_rw_rw(&program); @@ -3292,6 +3091,7 @@ static int execute_fence(struct target *target) } LOG_TARGET_DEBUG(target, "Unable to execute fence rw, rw"); } + LOG_TARGET_DEBUG(target, "Successfully executed fence rw, rw"); return ERROR_OK; } @@ -3371,7 +3171,7 @@ static int read_memory_bus_word(struct target *target, target_addr_t address, static target_addr_t sb_read_address(struct target *target) { RISCV013_INFO(info); - unsigned sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); + unsigned int sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); target_addr_t address = 0; uint32_t v; if (sbasize > 32) { @@ -3401,50 +3201,86 @@ static int read_sbcs_nonbusy(struct target *target, uint32_t *sbcs) } } -static int modify_privilege(struct target *target, uint64_t *mstatus, uint64_t *mstatus_old) +/* TODO: return struct mem_access_result */ +static int modify_privilege_for_virt2phys_mode(struct target *target, riscv_reg_t *mstatus, riscv_reg_t *mstatus_old, + riscv_reg_t *dcsr, riscv_reg_t *dcsr_old) { - if (riscv_enable_virtual && has_sufficient_progbuf(target, 5)) { - /* Read DCSR */ - uint64_t dcsr; - if (register_read_direct(target, &dcsr, GDB_REGNO_DCSR) != ERROR_OK) - return ERROR_FAIL; + assert(mstatus); + assert(mstatus_old); + assert(dcsr); + assert(dcsr_old); + if (!riscv_virt2phys_mode_is_hw(target)) + return ERROR_OK; - /* Read and save MSTATUS */ - if (register_read_direct(target, mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) - return ERROR_FAIL; - *mstatus_old = *mstatus; + /* Read and save DCSR */ + if (riscv_reg_get(target, dcsr, GDB_REGNO_DCSR) != ERROR_OK) + return ERROR_FAIL; + *dcsr_old = *dcsr; - /* If we come from m-mode with mprv set, we want to keep mpp */ - if (get_field(dcsr, CSR_DCSR_PRV) < 3) { - /* MPP = PRIV */ - *mstatus = set_field(*mstatus, MSTATUS_MPP, get_field(dcsr, CSR_DCSR_PRV)); + /* Read and save MSTATUS */ + if (riscv_reg_get(target, mstatus, GDB_REGNO_MSTATUS) != ERROR_OK) + return ERROR_FAIL; + *mstatus_old = *mstatus; - /* MPRV = 1 */ - *mstatus = set_field(*mstatus, MSTATUS_MPRV, 1); + /* If we come from m-mode with mprv set, we want to keep mpp */ + if (get_field(*dcsr, CSR_DCSR_PRV) == PRV_M) + return ERROR_OK; - /* Write MSTATUS */ - if (*mstatus != *mstatus_old) - if (register_write_direct(target, GDB_REGNO_MSTATUS, *mstatus) != ERROR_OK) - return ERROR_FAIL; - } - } + /* mstatus.mpp <- dcsr.prv */ + *mstatus = set_field(*mstatus, MSTATUS_MPP, get_field(*dcsr, CSR_DCSR_PRV)); + + /* mstatus.mprv <- 1 */ + *mstatus = set_field(*mstatus, MSTATUS_MPRV, 1); + + /* Write MSTATUS */ + if (*mstatus != *mstatus_old && + riscv_reg_set(target, GDB_REGNO_MSTATUS, *mstatus) != ERROR_OK) + return ERROR_FAIL; + + /* dcsr.mprven <- 1 */ + *dcsr = set_field(*dcsr, CSR_DCSR_MPRVEN, CSR_DCSR_MPRVEN_ENABLED); + + /* Write DCSR */ + if (*dcsr != *dcsr_old && + riscv_reg_set(target, GDB_REGNO_DCSR, *dcsr) != ERROR_OK) + return ERROR_FAIL; return ERROR_OK; } -static int read_memory_bus_v0(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) +static int restore_privilege_from_virt2phys_mode(struct target *target, riscv_reg_t mstatus, riscv_reg_t mstatus_old, + riscv_reg_t dcsr, riscv_reg_t dcsr_old) { - if (size != increment) { + if (!riscv_virt2phys_mode_is_hw(target)) + return ERROR_OK; + + /* Restore MSTATUS */ + if (mstatus != mstatus_old && + riscv_reg_set(target, GDB_REGNO_MSTATUS, mstatus_old) != ERROR_OK) + return ERROR_FAIL; + + /* Restore DCSR */ + if (dcsr != dcsr_old && + riscv_reg_set(target, GDB_REGNO_DCSR, dcsr_old) != ERROR_OK) + return ERROR_FAIL; + + return ERROR_OK; +} + +static int read_memory_bus_v0(struct target *target, const riscv_mem_access_args_t args) +{ + assert(riscv_mem_access_is_read(args)); + + if (args.size != args.increment) { LOG_TARGET_ERROR(target, "sba v0 reads only support size==increment"); return ERROR_NOT_IMPLEMENTED; } LOG_TARGET_DEBUG(target, "System Bus Access: size: %d\tcount:%d\tstart address: 0x%08" - TARGET_PRIxADDR, size, count, address); - uint8_t *t_buffer = buffer; - riscv_addr_t cur_addr = address; - riscv_addr_t fin_addr = address + (count * size); + TARGET_PRIxADDR, args.size, args.count, args.address); + uint8_t *t_buffer = args.read_buffer; + riscv_addr_t cur_addr = args.address; + riscv_addr_t fin_addr = args.address + (args.count * args.size); uint32_t access = 0; const int DM_SBCS_SBSINGLEREAD_OFFSET = 20; @@ -3454,13 +3290,13 @@ static int read_memory_bus_v0(struct target *target, target_addr_t address, const uint32_t DM_SBCS_SBAUTOREAD = (0x1U << DM_SBCS_SBAUTOREAD_OFFSET); /* ww favorise one off reading if there is an issue */ - if (count == 1) { - for (uint32_t i = 0; i < count; i++) { + if (args.count == 1) { + for (uint32_t i = 0; i < args.count; i++) { if (dm_read(target, &access, DM_SBCS) != ERROR_OK) return ERROR_FAIL; dm_write(target, DM_SBADDRESS0, cur_addr); - /* size/2 matching the bit access of the spec 0.13 */ - access = set_field(access, DM_SBCS_SBACCESS, size/2); + /* size/2 matching the bit sbaccess of the spec 0.13 */ + access = set_field(access, DM_SBCS_SBACCESS, args.size / 2); access = set_field(access, DM_SBCS_SBSINGLEREAD, 1); LOG_TARGET_DEBUG(target, "read_memory: sab: access: 0x%08x", access); dm_write(target, DM_SBCS, access); @@ -3469,9 +3305,9 @@ static int read_memory_bus_v0(struct target *target, target_addr_t address, if (dm_read(target, &value, DM_SBDATA0) != ERROR_OK) return ERROR_FAIL; LOG_TARGET_DEBUG(target, "read_memory: sab: value: 0x%08x", value); - buf_set_u32(t_buffer, 0, 8 * size, value); - t_buffer += size; - cur_addr += size; + buf_set_u32(t_buffer, 0, 8 * args.size, value); + t_buffer += args.size; + cur_addr += args.size; } return ERROR_OK; } @@ -3484,7 +3320,7 @@ static int read_memory_bus_v0(struct target *target, target_addr_t address, dm_write(target, DM_SBADDRESS0, cur_addr); /* 2) write sbaccess=2, sbsingleread,sbautoread,sbautoincrement * size/2 matching the bit access of the spec 0.13 */ - access = set_field(access, DM_SBCS_SBACCESS, size/2); + access = set_field(access, DM_SBCS_SBACCESS, args.size / 2); access = set_field(access, DM_SBCS_SBAUTOREAD, 1); access = set_field(access, DM_SBCS_SBSINGLEREAD, 1); access = set_field(access, DM_SBCS_SBAUTOINCREMENT, 1); @@ -3493,21 +3329,21 @@ static int read_memory_bus_v0(struct target *target, target_addr_t address, while (cur_addr < fin_addr) { LOG_TARGET_DEBUG(target, "sab:autoincrement:\r\n\tsize: %d\tcount:%d\taddress: 0x%08" - PRIx64, size, count, cur_addr); + PRIx64, args.size, args.count, cur_addr); /* read */ uint32_t value; if (dm_read(target, &value, DM_SBDATA0) != ERROR_OK) return ERROR_FAIL; - buf_set_u32(t_buffer, 0, 8 * size, value); - cur_addr += size; - t_buffer += size; + buf_set_u32(t_buffer, 0, 8 * args.size, value); + cur_addr += args.size; + t_buffer += args.size; /* if we are reaching last address, we must clear autoread */ - if (cur_addr == fin_addr && count != 1) { + if (cur_addr == fin_addr && args.count != 1) { dm_write(target, DM_SBCS, 0); if (dm_read(target, &value, DM_SBDATA0) != ERROR_OK) return ERROR_FAIL; - buf_set_u32(t_buffer, 0, 8 * size, value); + buf_set_u32(t_buffer, 0, 8 * args.size, value); } } @@ -3521,14 +3357,24 @@ static int read_memory_bus_v0(struct target *target, target_addr_t address, /** * Read the requested memory using the system bus interface. */ -static int read_memory_bus_v1(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) +static int read_memory_bus_v1(struct target *target, const riscv_mem_access_args_t args) { + assert(riscv_mem_access_is_read(args)); + + const target_addr_t address = args.address; + const uint32_t increment = args.increment; + const uint32_t count = args.count; + const uint32_t size = args.size; + uint8_t *buffer = args.read_buffer; + if (increment != size && increment != 0) { LOG_TARGET_ERROR(target, "sba v1 reads only support increment of size or 0"); return ERROR_NOT_IMPLEMENTED; } + assert(size <= 16); + assert(IS_PWR_OF_2(size)); + dm013_info_t *dm = get_dm(target); if (!dm) return ERROR_FAIL; @@ -3551,21 +3397,9 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, return ERROR_FAIL; /* This address write will trigger the first read. */ - if (sb_write_address(target, next_address, true) != ERROR_OK) + if (sb_write_address(target, next_address, RISCV_DELAY_SYSBUS_READ) != ERROR_OK) return ERROR_FAIL; - unsigned int bus_master_read_delay = riscv_scan_get_delay(&info->learned_delays, - RISCV_DELAY_SYSBUS_READ); - if (bus_master_read_delay) { - LOG_TARGET_DEBUG(target, "Waiting %d cycles for bus master read delay", - bus_master_read_delay); - jtag_add_runtest(bus_master_read_delay, TAP_IDLE); - if (jtag_execute_queue() != ERROR_OK) { - LOG_TARGET_ERROR(target, "Failed to scan idle sequence"); - return ERROR_FAIL; - } - } - /* First read has been started. Optimistically assume that it has * completed. */ @@ -3576,7 +3410,6 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, * be unnecessary. */ uint32_t sbvalue[4] = {0}; - assert(size <= 16); for (uint32_t i = (next_address - address) / size; i < count - 1; i++) { const uint32_t size_in_words = DIV_ROUND_UP(size, 4); struct riscv_batch *batch = riscv_batch_alloc(target, size_in_words); @@ -3597,10 +3430,10 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, const size_t last_key = batch->read_keys_used - 1; for (size_t k = 0; k <= last_key; ++k) { - sbvalue[k] = riscv_batch_get_dmi_read_data(batch, - last_key - k); - buf_set_u32(buffer + i * size + k * 4, 0, 8 * size, sbvalue[k]); + sbvalue[k] = riscv_batch_get_dmi_read_data(batch, last_key - k); + buf_set_u32(buffer + i * size + k * 4, 0, MIN(32, 8 * size), sbvalue[k]); } + riscv_batch_free(batch); const target_addr_t read_addr = address + i * increment; log_memory_access(read_addr, sbvalue, size, true); @@ -3655,7 +3488,7 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, continue; } - unsigned error = get_field(sbcs_read, DM_SBCS_SBERROR); + unsigned int error = get_field(sbcs_read, DM_SBCS_SBERROR); if (error == DM_SBCS_SBERROR_NONE) { next_address = end_address; } else { @@ -3670,7 +3503,7 @@ static int read_memory_bus_v1(struct target *target, target_addr_t address, return ERROR_OK; } -static void log_mem_access_result(struct target *target, bool success, int method, bool is_read) +static void log_mem_access_result(struct target *target, bool success, riscv_mem_access_method_t method, bool is_read) { RISCV_INFO(r); bool warn = false; @@ -3685,18 +3518,8 @@ static void log_mem_access_result(struct target *target, bool success, int metho /* Determine the log message severity. Show warnings only once. */ if (!success) { - if (method == RISCV_MEM_ACCESS_PROGBUF) { - warn = r->mem_access_progbuf_warn; - r->mem_access_progbuf_warn = false; - } - if (method == RISCV_MEM_ACCESS_SYSBUS) { - warn = r->mem_access_sysbus_warn; - r->mem_access_sysbus_warn = false; - } - if (method == RISCV_MEM_ACCESS_ABSTRACT) { - warn = r->mem_access_abstract_warn; - r->mem_access_abstract_warn = false; - } + warn = r->mem_access_warn[method]; + r->mem_access_warn[method] = false; } if (warn) @@ -3705,101 +3528,255 @@ static void log_mem_access_result(struct target *target, bool success, int metho LOG_TARGET_DEBUG(target, "%s", msg); } -static bool mem_should_skip_progbuf(struct target *target, target_addr_t address, - uint32_t size, bool is_read, char **skip_reason) +enum mem_access_result_type { + MEM_ACCESS_RESULT_TYPE_OK, + MEM_ACCESS_RESULT_TYPE_DISABLED, + MEM_ACCESS_RESULT_TYPE_SKIPPED, + MEM_ACCESS_RESULT_TYPE_FAILED, + MEM_ACCESS_RESULT_TYPE_ENUM_SIZE, +}; + +#define LIST_OF_MEM_ACCESS_RESULTS \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_OK, OK, "ok") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_DISABLED, DISABLED, "disabled") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED, SKIPPED, "skipped") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_ABSTRACT_ACCESS_CMDERR, \ + SKIPPED, "skipped (abstract access cmderr)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_PROGBUF_NOT_PRESENT, \ + SKIPPED, "skipped (progbuf not present)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_PROGBUF_INSUFFICIENT, \ + SKIPPED, "skipped (insufficient progbuf)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_UNSUPPORTED_ACCESS_SIZE, \ + SKIPPED, "skipped (unsupported access size)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_XLEN_TOO_SHORT, \ + SKIPPED, "skipped (xlen too short)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_TARGET_NOT_HALTED, \ + SKIPPED, "skipped (target not halted)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_TOO_LARGE_ADDRESS, \ + SKIPPED, "skipped (address too large)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_UNSUPPORTED_INCREMENT_SIZE, \ + SKIPPED, "skipped (increment size not supported)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_TARGET_SELECT_FAILED, \ + SKIPPED, "skipped (dm target select failed)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_FENCE_EXEC_FAILED, \ + SKIPPED, "skipped (fence execution failed)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_SYSBUS_ACCESS_FAILED, \ + SKIPPED, "skipped (sysbus access failed)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_REG_SAVE_FAILED, \ + SKIPPED, "skipped (register save failed)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_UNKNOWN_SYSBUS_VERSION, \ + SKIPPED, "skipped (unknown sysbus version)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_PROGRAM_WRITE_FAILED, \ + SKIPPED, "skipped (program write failed)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_PROGBUF_FILL_FAILED, \ + SKIPPED, "skipped (progbuf fill failed)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_WRITE_ABSTRACT_ARG_FAILED, \ + SKIPPED, "skipped (abstract command argument write failed)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_SKIPPED_PRIV_MOD_FAILED, \ + SKIPPED, "skipped (privilege modification failed)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_FAILED, FAILED, "failed") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_FAILED_DM_ACCESS_FAILED, \ + FAILED, "failed (DM register access failed)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_FAILED_PRIV_MOD_FAILED, \ + FAILED, "failed (privilege modification failed)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_FAILED_REG_READ_FAILED, \ + FAILED, "failed (register read failed)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_FAILED_PROGBUF_STARTUP_FAILED, \ + FAILED, "failed (progbuf startup failed)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_FAILED_PROGBUF_INNER_FAILED, \ + FAILED, "failed (progbuf inner failed)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_FAILED_PROGBUF_TEARDOWN_FAILED, \ + FAILED, "failed (progbuf teardown failed)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_FAILED_EXECUTE_ABSTRACT_FAILED, \ + FAILED, "failed (execute abstract failed)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_FAILED_NO_FORWARD_PROGRESS, \ + FAILED, "failed (no forward progress)") \ + MEM_ACCESS_RESULT_HANDLER(MEM_ACCESS_FAILED_FENCE_EXEC_FAILED, \ + FAILED, "failed (fence execution failed)") \ + + +#define MEM_ACCESS_RESULT_HANDLER(name, kind, msg) name, +enum mem_access_result_enum { + LIST_OF_MEM_ACCESS_RESULTS +}; +#undef MEM_ACCESS_RESULT_HANDLER + +/* Structure is intentionally used to contain the memory access result, + for type safety - to avoid implicit conversions to integers. */ +struct mem_access_result { + enum mem_access_result_enum value; +}; + +bool is_mem_access_ok(struct mem_access_result status) +{ + #define MEM_ACCESS_RESULT_HANDLER(name, kind, msg) \ + case name: return MEM_ACCESS_RESULT_TYPE_##kind \ + == MEM_ACCESS_RESULT_TYPE_OK; + + switch (status.value) { + LIST_OF_MEM_ACCESS_RESULTS + } + #undef MEM_ACCESS_RESULT_HANDLER + + LOG_ERROR("Unknown memory access status: %d", status.value); + assert(false && "Unknown memory access status"); + return false; +} + +bool is_mem_access_failed(struct mem_access_result status) +{ + #define MEM_ACCESS_RESULT_HANDLER(name, kind, msg) \ + case name: return MEM_ACCESS_RESULT_TYPE_##kind \ + == MEM_ACCESS_RESULT_TYPE_FAILED; + + switch (status.value) { + LIST_OF_MEM_ACCESS_RESULTS + } + #undef MEM_ACCESS_RESULT_HANDLER + + LOG_ERROR("Unknown memory access status: %d", status.value); + assert(false && "Unknown memory access status"); + return true; +} + +bool is_mem_access_skipped(struct mem_access_result status) { - assert(skip_reason); + #define MEM_ACCESS_RESULT_HANDLER(name, kind, msg) \ + case name: return MEM_ACCESS_RESULT_TYPE_##kind \ + == MEM_ACCESS_RESULT_TYPE_SKIPPED; + switch (status.value) { + LIST_OF_MEM_ACCESS_RESULTS + } + #undef MEM_ACCESS_RESULT_HANDLER + LOG_ERROR("Unknown memory access status: %d", status.value); + assert(false && "Unknown memory access status"); + return true; +} + +const char *mem_access_result_to_str(struct mem_access_result status) +{ + #define MEM_ACCESS_RESULT_HANDLER(name, kind, msg) \ + [name] = msg, + static const char * const table[] = { + LIST_OF_MEM_ACCESS_RESULTS + }; + #undef MEM_ACCESS_RESULT_HANDLER + + assert(status.value < ARRAY_SIZE(table)); + return table[status.value]; +} + +static struct mem_access_result mem_access_result(enum mem_access_result_enum value) +{ + struct mem_access_result result = {.value = value}; + return result; +} + +static struct mem_access_result mem_should_skip_progbuf(struct target *target, + const riscv_mem_access_args_t args) +{ + assert(riscv_mem_access_is_valid(args)); + const char *const access_type = + riscv_mem_access_is_read(args) ? "read" : "write"; + + if (!has_sufficient_progbuf(target, 1)) { + LOG_TARGET_DEBUG(target, "Skipping mem %s via progbuf " + "- progbuf not present", access_type); + return mem_access_result(MEM_ACCESS_SKIPPED_PROGBUF_NOT_PRESENT); + } if (!has_sufficient_progbuf(target, 3)) { - LOG_TARGET_DEBUG(target, "Skipping mem %s via progbuf - insufficient progbuf size.", - is_read ? "read" : "write"); - *skip_reason = "skipped (insufficient progbuf)"; - return true; + LOG_TARGET_DEBUG(target, "Skipping mem %s via progbuf - " + "insufficient progbuf size.", access_type); + return mem_access_result(MEM_ACCESS_SKIPPED_PROGBUF_INSUFFICIENT); } if (target->state != TARGET_HALTED) { - LOG_TARGET_DEBUG(target, "Skipping mem %s via progbuf - target not halted.", - is_read ? "read" : "write"); - *skip_reason = "skipped (target not halted)"; - return true; - } - if (riscv_xlen(target) < size * 8) { - LOG_TARGET_DEBUG(target, "Skipping mem %s via progbuf - XLEN (%d) is too short for %d-bit memory access.", - is_read ? "read" : "write", riscv_xlen(target), size * 8); - *skip_reason = "skipped (XLEN too short)"; - return true; - } - if (size > 8) { - LOG_TARGET_DEBUG(target, "Skipping mem %s via progbuf - unsupported size.", - is_read ? "read" : "write"); - *skip_reason = "skipped (unsupported size)"; - return true; - } - if ((sizeof(address) * 8 > riscv_xlen(target)) && (address >> riscv_xlen(target))) { - LOG_TARGET_DEBUG(target, "Skipping mem %s via progbuf - progbuf only supports %u-bit address.", - is_read ? "read" : "write", riscv_xlen(target)); - *skip_reason = "skipped (too large address)"; - return true; + LOG_TARGET_DEBUG(target, "Skipping mem %s via progbuf - " + "target not halted.", access_type); + return mem_access_result(MEM_ACCESS_SKIPPED_TARGET_NOT_HALTED); + } + if (riscv_xlen(target) < args.size * 8) { + LOG_TARGET_DEBUG(target, "Skipping mem %s via progbuf - " + "XLEN (%d) is too short for %d-bit memory args.", + access_type, riscv_xlen(target), args.size * 8); + return mem_access_result(MEM_ACCESS_SKIPPED_XLEN_TOO_SHORT); + } + if (args.size > 8) { + LOG_TARGET_DEBUG(target, "Skipping mem %s via progbuf - " + "unsupported size.", access_type); + return mem_access_result(MEM_ACCESS_SKIPPED_UNSUPPORTED_ACCESS_SIZE); + } + if ((sizeof(args.address) * 8 > riscv_xlen(target)) + && (args.address >> riscv_xlen(target))) { + LOG_TARGET_DEBUG(target, "Skipping mem %s via progbuf - " + "progbuf only supports %u-bit address.", access_type, riscv_xlen(target)); + return mem_access_result(MEM_ACCESS_SKIPPED_TOO_LARGE_ADDRESS); } - return false; + return mem_access_result(MEM_ACCESS_OK); } -static bool mem_should_skip_sysbus(struct target *target, target_addr_t address, - uint32_t size, uint32_t increment, bool is_read, char **skip_reason) +static struct mem_access_result +mem_should_skip_sysbus(struct target *target, const riscv_mem_access_args_t args) { - assert(skip_reason); + assert(riscv_mem_access_is_valid(args)); RISCV013_INFO(info); - if (!sba_supports_access(target, size)) { - LOG_TARGET_DEBUG(target, "Skipping mem %s via system bus - unsupported size.", - is_read ? "read" : "write"); - *skip_reason = "skipped (unsupported size)"; - return true; + const bool is_read = riscv_mem_access_is_read(args); + const char *const access_type = is_read ? "read" : "write"; + + if (!sba_supports_access(target, args.size)) { + LOG_TARGET_DEBUG(target, "Skipping mem %s via system bus - " + "unsupported size.", access_type); + return mem_access_result(MEM_ACCESS_SKIPPED_UNSUPPORTED_ACCESS_SIZE); } unsigned int sbasize = get_field(info->sbcs, DM_SBCS_SBASIZE); - if ((sizeof(address) * 8 > sbasize) && (address >> sbasize)) { - LOG_TARGET_DEBUG(target, "Skipping mem %s via system bus - sba only supports %u-bit address.", - is_read ? "read" : "write", sbasize); - *skip_reason = "skipped (too large address)"; - return true; + if ((sizeof(args.address) * 8 > sbasize) + && (args.address >> sbasize)) { + LOG_TARGET_DEBUG(target, "Skipping mem %s via system bus - " + "sba only supports %u-bit address.", access_type, sbasize); + return mem_access_result(MEM_ACCESS_SKIPPED_TOO_LARGE_ADDRESS); } - if (is_read && increment != size && (get_field(info->sbcs, DM_SBCS_SBVERSION) == 0 || increment != 0)) { - LOG_TARGET_DEBUG(target, "Skipping mem read via system bus - " - "sba reads only support size==increment or also size==0 for sba v1."); - *skip_reason = "skipped (unsupported increment)"; - return true; + if (is_read && args.increment != args.size + && (get_field(info->sbcs, DM_SBCS_SBVERSION) == 0 + || args.increment != 0)) { + LOG_TARGET_DEBUG(target, "Skipping mem %s via system bus - " + "sba %ss only support (size == increment) or also " + "size==0 for sba v1.", access_type, access_type); + return mem_access_result(MEM_ACCESS_SKIPPED_UNSUPPORTED_INCREMENT_SIZE); } - return false; + return mem_access_result(MEM_ACCESS_OK); } -static bool mem_should_skip_abstract(struct target *target, target_addr_t address, - uint32_t size, uint32_t increment, bool is_read, char **skip_reason) +static struct mem_access_result +mem_should_skip_abstract(struct target *target, const riscv_mem_access_args_t args) { - assert(skip_reason); + assert(riscv_mem_access_is_valid(args)); - if (size > 8) { + const bool is_read = riscv_mem_access_is_read(args); + const char *const access_type = is_read ? "read" : "write"; + if (args.size > 8) { /* TODO: Add 128b support if it's ever used. Involves modifying read/write_abstract_arg() to work on two 64b values. */ - LOG_TARGET_DEBUG(target, "Skipping mem %s via abstract access - unsupported size: %d bits", - is_read ? "read" : "write", size * 8); - *skip_reason = "skipped (unsupported size)"; - return true; + LOG_TARGET_DEBUG(target, "Skipping mem %s via abstract access - " + "unsupported size: %d bits", access_type, args.size * 8); + return mem_access_result(MEM_ACCESS_SKIPPED_UNSUPPORTED_ACCESS_SIZE); } - if ((sizeof(address) * 8 > riscv_xlen(target)) && (address >> riscv_xlen(target))) { - LOG_TARGET_DEBUG(target, "Skipping mem %s via abstract access - abstract access only supports %u-bit address.", - is_read ? "read" : "write", riscv_xlen(target)); - *skip_reason = "skipped (too large address)"; - return true; + if ((sizeof(args.address) * 8 > riscv_xlen(target)) + && (args.address >> riscv_xlen(target))) { + LOG_TARGET_DEBUG(target, "Skipping mem %s via abstract access - " + "abstract access only supports %u-bit address.", + access_type, riscv_xlen(target)); + return mem_access_result(MEM_ACCESS_SKIPPED_TOO_LARGE_ADDRESS); } - if (is_read && size != increment) { - LOG_TARGET_ERROR(target, "Skipping mem read via abstract access - " - "abstract command reads only support size==increment."); - *skip_reason = "skipped (unsupported increment)"; - return true; + if (is_read && args.size != args.increment) { + LOG_TARGET_ERROR(target, "Skipping mem %s via abstract access - " + "abstract command %ss only support (size == increment).", + access_type, access_type); + return mem_access_result(MEM_ACCESS_SKIPPED_UNSUPPORTED_INCREMENT_SIZE); } - - return false; + return mem_access_result(MEM_ACCESS_OK); } /* @@ -3807,88 +3784,76 @@ static bool mem_should_skip_abstract(struct target *target, target_addr_t addres * supported are 1, 2, and 4 bytes despite the spec's support of 8 and 16 byte * aamsize fields in the memory access abstract command. */ -static int read_memory_abstract(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) +static struct mem_access_result +read_memory_abstract(struct target *target, const riscv_mem_access_args_t args) { - RISCV013_INFO(info); - - int result = ERROR_OK; - bool use_aampostincrement = info->has_aampostincrement != YNM_NO; - - LOG_TARGET_DEBUG(target, "Reading %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, - size, address); + assert(riscv_mem_access_is_read(args)); - memset(buffer, 0, count * size); + memset(args.read_buffer, 0, args.count * args.size); /* Convert the size (bytes) to width (bits) */ - unsigned width = size << 3; - - /* Create the command (physical address, postincrement, read) */ - uint32_t command = access_memory_command(target, false, width, use_aampostincrement, false); + unsigned int width = args.size << 3; + + uint32_t command = access_memory_command(target, /* virtual = */ false, + width, /* postincrement = */ true, /* is_write = */ false); + bool use_aampostincrement = !is_command_unsupported(target, command); + if (!use_aampostincrement) + /* It is already known that this abstract memory + * access with aampostincrement=1 is not supported. + * So try aampostincrement=0 right away. + * + * TODO: check if new command is supported */ + command = access_memory_command(target, /* virtual = */ false, + width, /* postincrement = */ false, /* is_write = */ false); /* Execute the reads */ - uint8_t *p = buffer; + uint8_t *p = args.read_buffer; + int result = ERROR_OK; bool updateaddr = true; - unsigned int width32 = (width < 32) ? 32 : width; - for (uint32_t c = 0; c < count; c++) { + unsigned int width32 = MAX(width, 32); + for (uint32_t c = 0; c < args.count; c++) { /* Update the address if it is the first time or aampostincrement is not supported by the target. */ if (updateaddr) { /* Set arg1 to the address: address + c * size */ - result = write_abstract_arg(target, 1, address + c * size, riscv_xlen(target)); + result = write_abstract_arg(target, 1, args.address + c * args.size, riscv_xlen(target)); if (result != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to write arg1."); - return result; + return mem_access_result(MEM_ACCESS_FAILED_DM_ACCESS_FAILED); } } /* Execute the command */ uint32_t cmderr; - result = execute_abstract_command(target, command, &cmderr); - - /* TODO: we need to modify error handling here. */ - /* NOTE: in case of timeout cmderr is set to CMDERR_NONE */ - if (info->has_aampostincrement == YNM_MAYBE) { - if (result == ERROR_OK) { - /* Safety: double-check that the address was really auto-incremented */ - riscv_reg_t new_address; - result = read_abstract_arg(target, &new_address, 1, riscv_xlen(target)); - if (result != ERROR_OK) - return result; - - if (new_address == address + size) { - LOG_TARGET_DEBUG(target, "aampostincrement is supported on this target."); - info->has_aampostincrement = YNM_YES; - } else { - LOG_TARGET_WARNING(target, "Buggy aampostincrement! Address not incremented correctly."); - info->has_aampostincrement = YNM_NO; - } - } else { - /* Try the same access but with postincrement disabled. */ - command = access_memory_command(target, false, width, false, false); - result = execute_abstract_command(target, command, &cmderr); - if (result == ERROR_OK) { - LOG_TARGET_DEBUG(target, "aampostincrement is not supported on this target."); - info->has_aampostincrement = YNM_NO; - } - } + result = riscv013_execute_abstract_command(target, command, &cmderr); + if (use_aampostincrement && result != ERROR_OK && + cmderr == CMDERR_NOT_SUPPORTED) { + LOG_TARGET_DEBUG(target, "Trying the same abstract memory " + "read command, but without aampostincrement"); + use_aampostincrement = false; + command = access_memory_command(target, /* virtual = */ false, + width, /* postincrement = */ false, /* is_write = */ false); + result = riscv013_execute_abstract_command(target, command, &cmderr); } + /* TODO: + * (1) Only the 1st access can result in a 'skip' + * (2) Analyze cmderr value */ if (result != ERROR_OK) - return result; + return mem_access_result(MEM_ACCESS_SKIPPED_ABSTRACT_ACCESS_CMDERR); /* Copy arg0 to buffer (rounded width up to nearest 32) */ riscv_reg_t value; result = read_abstract_arg(target, &value, 0, width32); if (result != ERROR_OK) - return result; - buf_set_u64(p, 0, 8 * size, value); + return mem_access_result(MEM_ACCESS_FAILED_DM_ACCESS_FAILED); + buf_set_u64(p, 0, 8 * args.size, value); - if (info->has_aampostincrement == YNM_YES) + if (use_aampostincrement) updateaddr = false; - p += size; + p += args.size; } - return result; + return mem_access_result(MEM_ACCESS_OK); } /* @@ -3896,85 +3861,75 @@ static int read_memory_abstract(struct target *target, target_addr_t address, * sizes supported are 1, 2, and 4 bytes despite the spec's support of 8 and 16 * byte aamsize fields in the memory access abstract command. */ -static int write_memory_abstract(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, const uint8_t *buffer) +static struct mem_access_result +write_memory_abstract(struct target *target, const riscv_mem_access_args_t args) { - RISCV013_INFO(info); - int result = ERROR_OK; - bool use_aampostincrement = info->has_aampostincrement != YNM_NO; + assert(riscv_mem_access_is_write(args)); - LOG_TARGET_DEBUG(target, "writing %d words of %d bytes from 0x%" TARGET_PRIxADDR, count, - size, address); + int result = ERROR_OK; /* Convert the size (bytes) to width (bits) */ - unsigned width = size << 3; - - /* Create the command (physical address, postincrement, write) */ - uint32_t command = access_memory_command(target, false, width, use_aampostincrement, true); + unsigned int width = args.size << 3; + + uint32_t command = access_memory_command(target, /* virtual = */ false, + width, /* postincrement = */ true, /* is_write = */ true); + bool use_aampostincrement = !is_command_unsupported(target, command); + if (!use_aampostincrement) + /* It is already known that this abstract memory + * access with aampostincrement=1 is not supported. + * So try aampostincrement=0 right away. + * + * TODO: check if new command is supported */ + command = access_memory_command(target, /* virtual = */ false, + width, /* postincrement = */ false, /* is_write = */ true); /* Execute the writes */ - const uint8_t *p = buffer; + const uint8_t *p = args.write_buffer; bool updateaddr = true; - for (uint32_t c = 0; c < count; c++) { + for (uint32_t c = 0; c < args.count; c++) { /* Move data to arg0 */ - riscv_reg_t value = buf_get_u64(p, 0, 8 * size); + riscv_reg_t value = buf_get_u64(p, 0, 8 * args.size); result = write_abstract_arg(target, 0, value, riscv_xlen(target)); if (result != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to write arg0."); - return result; + return mem_access_result(MEM_ACCESS_FAILED_DM_ACCESS_FAILED); } /* Update the address if it is the first time or aampostincrement is not supported by the target. */ if (updateaddr) { /* Set arg1 to the address: address + c * size */ - result = write_abstract_arg(target, 1, address + c * size, riscv_xlen(target)); + result = write_abstract_arg(target, 1, args.address + c * args.size, riscv_xlen(target)); if (result != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to write arg1."); - return result; + return mem_access_result(MEM_ACCESS_FAILED_DM_ACCESS_FAILED); } } /* Execute the command */ uint32_t cmderr; - result = execute_abstract_command(target, command, &cmderr); - - /* TODO: we need to modify error handling here. */ - /* NOTE: in case of timeout cmderr is set to CMDERR_NONE */ - if (info->has_aampostincrement == YNM_MAYBE) { - if (result == ERROR_OK) { - /* Safety: double-check that the address was really auto-incremented */ - riscv_reg_t new_address; - result = read_abstract_arg(target, &new_address, 1, riscv_xlen(target)); - if (result != ERROR_OK) - return result; - - if (new_address == address + size) { - LOG_TARGET_DEBUG(target, "aampostincrement is supported on this target."); - info->has_aampostincrement = YNM_YES; - } else { - LOG_TARGET_WARNING(target, "Buggy aampostincrement! Address not incremented correctly."); - info->has_aampostincrement = YNM_NO; - } - } else { - /* Try the same access but with postincrement disabled. */ - command = access_memory_command(target, false, width, false, true); - result = execute_abstract_command(target, command, &cmderr); - if (result == ERROR_OK) { - LOG_TARGET_DEBUG(target, "aampostincrement is not supported on this target."); - info->has_aampostincrement = YNM_NO; - } - } + result = riscv013_execute_abstract_command(target, command, &cmderr); + if (use_aampostincrement && result != ERROR_OK && + cmderr == CMDERR_NOT_SUPPORTED) { + LOG_TARGET_DEBUG(target, "Trying the same abstract memory " + "write command, but without aampostincrement"); + use_aampostincrement = false; + command = access_memory_command(target, /* virtual = */ false, + width, /* postincrement = */ false, /* is_write = */ true); + result = riscv013_execute_abstract_command(target, command, &cmderr); } + /* TODO: + * (1) Only the 1st access can result in a 'skip' + * (2) Analyze cmderr value */ if (result != ERROR_OK) - return result; + return mem_access_result(MEM_ACCESS_SKIPPED_ABSTRACT_ACCESS_CMDERR); - if (info->has_aampostincrement == YNM_YES) + if (use_aampostincrement) updateaddr = false; - p += size; + p += args.size; } - return result; + return mem_access_result(MEM_ACCESS_OK); } /** @@ -4004,11 +3959,11 @@ static int read_memory_progbuf_inner_startup(struct target *target, /* AC_ACCESS_REGISTER_POSTEXEC is used to trigger first stage of the * pipeline (memory -> s1) whenever this command is executed. */ - const uint32_t startup_command = access_register_command(target, + const uint32_t startup_command = riscv013_access_register_command(target, GDB_REGNO_S1, riscv_xlen(target), AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC); uint32_t cmderr; - if (execute_abstract_command(target, startup_command, &cmderr) != ERROR_OK) + if (riscv013_execute_abstract_command(target, startup_command, &cmderr) != ERROR_OK) return ERROR_FAIL; /* TODO: we need to modify error handling here. */ /* NOTE: in case of timeout cmderr is set to CMDERR_NONE */ @@ -4048,13 +4003,6 @@ clear_abstractauto_and_fail: return ERROR_FAIL; } -struct memory_access_info { - uint8_t *buffer_address; - target_addr_t target_address; - uint32_t element_size; - uint32_t increment; -}; - /** * This function attempts to restore the pipeline after a busy on abstract * access. @@ -4065,8 +4013,10 @@ struct memory_access_info { */ static int read_memory_progbuf_inner_on_ac_busy(struct target *target, uint32_t start_index, uint32_t *elements_read, - struct memory_access_info access) + const riscv_mem_access_args_t args) { + assert(riscv_mem_access_is_read(args)); + int res = riscv013_clear_abstract_error(target); if (res != ERROR_OK) return res; @@ -4080,7 +4030,7 @@ static int read_memory_progbuf_inner_on_ac_busy(struct target *target, /* See how far we got by reading s0/a0 */ uint32_t index_on_target; - if (/*is_repeated_read*/ access.increment == 0) { + if (/*is_repeated_read*/ args.increment == 0) { /* s0 is constant, a0 is incremented by one each execution */ riscv_reg_t counter; @@ -4092,8 +4042,8 @@ static int read_memory_progbuf_inner_on_ac_busy(struct target *target, if (register_read_direct(target, &address_on_target, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; - index_on_target = (address_on_target - access.target_address) / - access.increment; + index_on_target = (address_on_target - args.address) / + args.increment; } /* According to the spec, if an abstract command fails, one can't make any @@ -4111,10 +4061,10 @@ static int read_memory_progbuf_inner_on_ac_busy(struct target *target, *elements_read = next_index - start_index; LOG_TARGET_WARNING(target, "Re-reading memory from addresses 0x%" TARGET_PRIxADDR " and 0x%" TARGET_PRIxADDR ".", - access.target_address + access.increment * next_index, - access.target_address + access.increment * (next_index + 1)); - return read_memory_progbuf_inner_startup(target, access.target_address, - access.increment, next_index); + args.address + args.increment * next_index, + args.address + args.increment * (next_index + 1)); + return read_memory_progbuf_inner_startup(target, args.address, + args.increment, next_index); } /** @@ -4122,8 +4072,10 @@ static int read_memory_progbuf_inner_on_ac_busy(struct target *target, */ static int read_memory_progbuf_inner_on_dmi_busy(struct target *target, uint32_t start_index, uint32_t next_start_index, - struct memory_access_info access) + const riscv_mem_access_args_t args) { + assert(riscv_mem_access_is_read(args)); + LOG_TARGET_DEBUG(target, "DMI_STATUS_BUSY encountered in batch. Memory read [%" PRIu32 ", %" PRIu32 ")", start_index, next_start_index); if (start_index == next_start_index) @@ -4131,8 +4083,8 @@ static int read_memory_progbuf_inner_on_dmi_busy(struct target *target, if (dm_write(target, DM_ABSTRACTAUTO, 0) != ERROR_OK) return ERROR_FAIL; - return read_memory_progbuf_inner_startup(target, access.target_address, - access.increment, next_start_index); + return read_memory_progbuf_inner_startup(target, args.address, + args.increment, next_start_index); } /** @@ -4141,9 +4093,11 @@ static int read_memory_progbuf_inner_on_dmi_busy(struct target *target, static int read_memory_progbuf_inner_extract_batch_data(struct target *target, const struct riscv_batch *batch, uint32_t start_index, uint32_t elements_to_read, uint32_t *elements_read, - struct memory_access_info access) + const riscv_mem_access_args_t args) { - const bool two_reads_per_element = access.element_size > 4; + assert(riscv_mem_access_is_read(args)); + + const bool two_reads_per_element = args.size > 4; const uint32_t reads_per_element = (two_reads_per_element ? 2 : 1); assert(!two_reads_per_element || riscv_xlen(target) == 64); assert(elements_to_read <= UINT32_MAX / reads_per_element); @@ -4153,7 +4107,7 @@ static int read_memory_progbuf_inner_extract_batch_data(struct target *target, case DMI_STATUS_BUSY: *elements_read = curr_idx - start_index; return read_memory_progbuf_inner_on_dmi_busy(target, start_index, curr_idx - , access); + , args); case DMI_STATUS_FAILED: LOG_TARGET_DEBUG(target, "Batch memory read encountered DMI_STATUS_FAILED on read %" @@ -4165,11 +4119,11 @@ static int read_memory_progbuf_inner_extract_batch_data(struct target *target, assert(0); } const uint32_t value = riscv_batch_get_dmi_read_data(batch, read); - uint8_t * const curr_buff = access.buffer_address + - curr_idx * access.element_size; - const target_addr_t curr_addr = access.target_address + - curr_idx * access.increment; - const uint32_t size = access.element_size; + uint8_t * const curr_buff = args.read_buffer + + curr_idx * args.size; + const target_addr_t curr_addr = args.address + + curr_idx * args.increment; + const uint32_t size = args.size; assert(size <= 8); const bool is_odd_read = read % 2; @@ -4196,9 +4150,11 @@ static int read_memory_progbuf_inner_extract_batch_data(struct target *target, * - DM_ABSTRACTAUTO_AUTOEXECDATA is set. */ static int read_memory_progbuf_inner_run_and_process_batch(struct target *target, - struct riscv_batch *batch, struct memory_access_info access, + struct riscv_batch *batch, const riscv_mem_access_args_t args, uint32_t start_index, uint32_t elements_to_read, uint32_t *elements_read) { + assert(riscv_mem_access_is_read(args)); + dm013_info_t *dm = get_dm(target); if (!dm) return ERROR_FAIL; @@ -4224,7 +4180,7 @@ static int read_memory_progbuf_inner_run_and_process_batch(struct target *target case CMDERR_BUSY: LOG_TARGET_DEBUG(target, "memory read resulted in busy response"); if (read_memory_progbuf_inner_on_ac_busy(target, start_index, - &elements_to_extract_from_batch, access) + &elements_to_extract_from_batch, args) != ERROR_OK) return ERROR_FAIL; break; @@ -4235,7 +4191,7 @@ static int read_memory_progbuf_inner_run_and_process_batch(struct target *target } if (read_memory_progbuf_inner_extract_batch_data(target, batch, start_index, - elements_to_extract_from_batch, elements_read, access) != ERROR_OK) + elements_to_extract_from_batch, elements_read, args) != ERROR_OK) return ERROR_FAIL; return ERROR_OK; @@ -4265,18 +4221,20 @@ static uint32_t read_memory_progbuf_inner_fill_batch(struct riscv_batch *batch, } static int read_memory_progbuf_inner_try_to_read(struct target *target, - struct memory_access_info access, uint32_t *elements_read, + const riscv_mem_access_args_t args, uint32_t *elements_read, uint32_t index, uint32_t loop_count) { + assert(riscv_mem_access_is_read(args)); + struct riscv_batch *batch = riscv_batch_alloc(target, RISCV_BATCH_ALLOC_SIZE); if (!batch) return ERROR_FAIL; const uint32_t elements_to_read = read_memory_progbuf_inner_fill_batch(batch, - loop_count - index, access.element_size); + loop_count - index, args.size); int result = read_memory_progbuf_inner_run_and_process_batch(target, batch, - access, index, elements_to_read, elements_read); + args, index, elements_to_read, elements_read); riscv_batch_free(batch); return result; } @@ -4286,20 +4244,22 @@ static int read_memory_progbuf_inner_try_to_read(struct target *target, * with the address argument equal to curr_target_address. */ static int read_memory_progbuf_inner_ensure_forward_progress(struct target *target, - struct memory_access_info access, uint32_t start_index) + const riscv_mem_access_args_t args, uint32_t start_index) { + assert(riscv_mem_access_is_read(args)); + LOG_TARGET_DEBUG(target, "Executing one loop iteration to ensure forward progress (index=%" PRIu32 ")", start_index); - const target_addr_t curr_target_address = access.target_address + - start_index * access.increment; - uint8_t * const curr_buffer_address = access.buffer_address + - start_index * access.element_size; - const struct memory_access_info curr_access = { - .buffer_address = curr_buffer_address, - .target_address = curr_target_address, - .element_size = access.element_size, - .increment = access.increment, + const target_addr_t curr_target_address = args.address + + start_index * args.increment; + uint8_t * const curr_buffer_address = args.read_buffer + + start_index * args.size; + const riscv_mem_access_args_t curr_access = { + .read_buffer = curr_buffer_address, + .address = curr_target_address, + .size = args.size, + .increment = args.increment, }; uint32_t elements_read; if (read_memory_progbuf_inner_try_to_read(target, curr_access, &elements_read, @@ -4317,13 +4277,15 @@ static int read_memory_progbuf_inner_ensure_forward_progress(struct target *targ return ERROR_OK; } -static void set_buffer_and_log_read(struct memory_access_info access, +static void set_buffer_and_log_read(const riscv_mem_access_args_t args, uint32_t index, uint64_t value) { - uint8_t * const buffer = access.buffer_address; - const uint32_t size = access.element_size; - const uint32_t increment = access.increment; - const target_addr_t address = access.target_address; + assert(riscv_mem_access_is_read(args)); + + uint8_t * const buffer = args.read_buffer; + const uint32_t size = args.size; + const uint32_t increment = args.increment; + const target_addr_t address = args.address; assert(size <= 8); buf_set_u64(buffer + index * size, 0, 8 * size, value); @@ -4332,47 +4294,32 @@ static void set_buffer_and_log_read(struct memory_access_info access, } static int read_word_from_dm_data_regs(struct target *target, - struct memory_access_info access, uint32_t index) + const riscv_mem_access_args_t args, uint32_t index) { - assert(access.element_size <= 8); + assert(args.size <= 8); uint64_t value; int result = read_abstract_arg(target, &value, /*index*/ 0, - access.element_size > 4 ? 64 : 32); + args.size > 4 ? 64 : 32); if (result == ERROR_OK) - set_buffer_and_log_read(access, index, value); + set_buffer_and_log_read(args, index, value); return result; } -static int read_word_from_s1(struct target *target, - struct memory_access_info access, uint32_t index) +static struct mem_access_result read_word_from_s1(struct target *target, + const riscv_mem_access_args_t args, uint32_t index) { + assert(riscv_mem_access_is_read(args)); + uint64_t value; if (register_read_direct(target, &value, GDB_REGNO_S1) != ERROR_OK) - return ERROR_FAIL; - set_buffer_and_log_read(access, index, value); - return ERROR_OK; -} - -static int riscv_program_load_mprv(struct riscv_program *p, enum gdb_regno d, - enum gdb_regno b, int offset, unsigned int size, bool mprven) -{ - if (mprven && riscv_program_csrrsi(p, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, - GDB_REGNO_DCSR) != ERROR_OK) - return ERROR_FAIL; - - if (riscv_program_load(p, d, b, offset, size) != ERROR_OK) - return ERROR_FAIL; - - if (mprven && riscv_program_csrrci(p, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, - GDB_REGNO_DCSR) != ERROR_OK) - return ERROR_FAIL; - - return ERROR_OK; + return mem_access_result(MEM_ACCESS_FAILED_REG_READ_FAILED); + set_buffer_and_log_read(args, index, value); + return mem_access_result(MEM_ACCESS_OK); } static int read_memory_progbuf_inner_fill_progbuf(struct target *target, - uint32_t increment, uint32_t size, bool mprven) + uint32_t increment, uint32_t size) { const bool is_repeated_read = increment == 0; @@ -4386,8 +4333,7 @@ static int read_memory_progbuf_inner_fill_progbuf(struct target *target, struct riscv_program program; riscv_program_init(&program, target); - if (riscv_program_load_mprv(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0, size, - mprven) != ERROR_OK) + if (riscv_program_load(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0, size) != ERROR_OK) return ERROR_FAIL; if (is_repeated_read) { if (riscv_program_addi(&program, GDB_REGNO_A0, GDB_REGNO_A0, 1) @@ -4412,19 +4358,19 @@ static int read_memory_progbuf_inner_fill_progbuf(struct target *target, * re-read the data only if `abstract command busy` or `DMI busy` * is encountered in the process. */ -static int read_memory_progbuf_inner(struct target *target, - struct memory_access_info access, uint32_t count, bool mprven) +static struct mem_access_result +read_memory_progbuf_inner(struct target *target, const riscv_mem_access_args_t args) { - assert(count > 1 && "If count == 1, read_memory_progbuf_inner_one must be called"); + assert(riscv_mem_access_is_read(args)); + assert(args.count > 1 && "If count == 1, read_memory_progbuf_inner_one must be called"); - if (read_memory_progbuf_inner_fill_progbuf(target, access.increment, - access.element_size, mprven) != ERROR_OK) - return ERROR_FAIL; + if (read_memory_progbuf_inner_fill_progbuf(target, + args.increment, args.size) != ERROR_OK) + return mem_access_result(MEM_ACCESS_SKIPPED_PROGBUF_FILL_FAILED); - if (read_memory_progbuf_inner_startup(target, access.target_address, - access.increment, /*index*/ 0) - != ERROR_OK) - return ERROR_FAIL; + if (read_memory_progbuf_inner_startup(target, args.address, + args.increment, /*index*/ 0) != ERROR_OK) + return mem_access_result(MEM_ACCESS_FAILED_PROGBUF_STARTUP_FAILED); /* The program in program buffer is executed twice during * read_memory_progbuf_inner_startup(). * Here: @@ -4435,20 +4381,20 @@ static int read_memory_progbuf_inner(struct target *target, * No need to execute the program any more, since S1 will already contain * M[address + increment * (count - 1)] and we can read it directly. */ - const uint32_t loop_count = count - 2; + const uint32_t loop_count = args.count - 2; for (uint32_t index = 0; index < loop_count;) { uint32_t elements_read; - if (read_memory_progbuf_inner_try_to_read(target, access, &elements_read, + if (read_memory_progbuf_inner_try_to_read(target, args, &elements_read, index, loop_count) != ERROR_OK) { dm_write(target, DM_ABSTRACTAUTO, 0); - return ERROR_FAIL; + return mem_access_result(MEM_ACCESS_FAILED_PROGBUF_INNER_FAILED); } if (elements_read == 0) { - if (read_memory_progbuf_inner_ensure_forward_progress(target, access, + if (read_memory_progbuf_inner_ensure_forward_progress(target, args, index) != ERROR_OK) { dm_write(target, DM_ABSTRACTAUTO, 0); - return ERROR_FAIL; + return mem_access_result(MEM_ACCESS_FAILED_NO_FORWARD_PROGRESS); } elements_read = 1; } @@ -4456,182 +4402,243 @@ static int read_memory_progbuf_inner(struct target *target, assert(index <= loop_count); } if (dm_write(target, DM_ABSTRACTAUTO, 0) != ERROR_OK) - return ERROR_FAIL; + return mem_access_result(MEM_ACCESS_FAILED_DM_ACCESS_FAILED); /* Read the penultimate word. */ - if (read_word_from_dm_data_regs(target, access, count - 2) - != ERROR_OK) - return ERROR_FAIL; + if (read_word_from_dm_data_regs(target, + args, args.count - 2) != ERROR_OK) + return mem_access_result(MEM_ACCESS_FAILED_DM_ACCESS_FAILED); /* Read the last word. */ - return read_word_from_s1(target, access, count - 1); + return read_word_from_s1(target, args, args.count - 1); } /** * Only need to save/restore one GPR to read a single word, and the progbuf * program doesn't need to increment. */ -static int read_memory_progbuf_inner_one(struct target *target, - struct memory_access_info access, bool mprven) +static struct mem_access_result +read_memory_progbuf_inner_one(struct target *target, const riscv_mem_access_args_t args) { + assert(riscv_mem_access_is_read(args)); + if (riscv013_reg_save(target, GDB_REGNO_S1) != ERROR_OK) - return ERROR_FAIL; + return mem_access_result(MEM_ACCESS_SKIPPED_REG_SAVE_FAILED); struct riscv_program program; riscv_program_init(&program, target); - if (riscv_program_load_mprv(&program, GDB_REGNO_S1, GDB_REGNO_S1, 0, - access.element_size, mprven) != ERROR_OK) - return ERROR_FAIL; - if (riscv_program_ebreak(&program) != ERROR_OK) - return ERROR_FAIL; + if (riscv_program_load(&program, GDB_REGNO_S1, GDB_REGNO_S1, + /* offset = */ 0, args.size) != ERROR_OK + || riscv_program_ebreak(&program) != ERROR_OK) + return mem_access_result(MEM_ACCESS_SKIPPED_PROGBUF_FILL_FAILED); + if (riscv_program_write(&program) != ERROR_OK) - return ERROR_FAIL; + return mem_access_result(MEM_ACCESS_SKIPPED_PROGRAM_WRITE_FAILED); /* Write address to S1, and execute buffer. */ - if (write_abstract_arg(target, 0, access.target_address, riscv_xlen(target)) - != ERROR_OK) - return ERROR_FAIL; - uint32_t command = access_register_command(target, GDB_REGNO_S1, + if (write_abstract_arg(target, /* index = */ 0, + args.address, riscv_xlen(target)) != ERROR_OK) + return mem_access_result(MEM_ACCESS_SKIPPED_WRITE_ABSTRACT_ARG_FAILED); + uint32_t command = riscv013_access_register_command(target, GDB_REGNO_S1, riscv_xlen(target), AC_ACCESS_REGISTER_WRITE | AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_POSTEXEC); uint32_t cmderr; - if (execute_abstract_command(target, command, &cmderr) != ERROR_OK) - return ERROR_FAIL; + if (riscv013_execute_abstract_command(target, command, &cmderr) != ERROR_OK) + return mem_access_result(MEM_ACCESS_FAILED_EXECUTE_ABSTRACT_FAILED); - return read_word_from_s1(target, access, 0); + return read_word_from_s1(target, args, 0); } /** * Read the requested memory, silently handling memory access errors. */ -static int read_memory_progbuf(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) +static struct mem_access_result +read_memory_progbuf(struct target *target, const riscv_mem_access_args_t args) { - if (riscv_xlen(target) < size * 8) { - LOG_TARGET_ERROR(target, "XLEN (%d) is too short for %" - PRIu32 "-bit memory read.", riscv_xlen(target), size * 8); - return ERROR_FAIL; - } + assert(riscv_mem_access_is_read(args)); - LOG_TARGET_DEBUG(target, "reading %" PRIu32 " elements of %" PRIu32 - " bytes from 0x%" TARGET_PRIxADDR, count, size, address); + select_dmi(target->tap); + memset(args.read_buffer, 0, args.count * args.size); - if (dm013_select_target(target) != ERROR_OK) - return ERROR_FAIL; + if (execute_autofence(target) != ERROR_OK) + return mem_access_result(MEM_ACCESS_SKIPPED_FENCE_EXEC_FAILED); - select_dmi(target); + return (args.count == 1) ? + read_memory_progbuf_inner_one(target, args) : + read_memory_progbuf_inner(target, args); +} - memset(buffer, 0, count*size); +static struct mem_access_result +write_memory_progbuf(struct target *target, const riscv_mem_access_args_t args); - if (execute_fence(target) != ERROR_OK) - return ERROR_FAIL; +static struct mem_access_result +access_memory_progbuf(struct target *target, const riscv_mem_access_args_t args) +{ + struct mem_access_result skip_reason = mem_should_skip_progbuf(target, args); + if (!is_mem_access_ok(skip_reason)) + return skip_reason; - uint64_t mstatus = 0; - uint64_t mstatus_old = 0; - if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK) - return ERROR_FAIL; + const bool is_read = riscv_mem_access_is_read(args); + const char *const access_type = is_read ? "reading" : "writing"; + LOG_TARGET_DEBUG(target, "%s %" PRIu32 " words of %" PRIu32 + " bytes at 0x%" TARGET_PRIxADDR, access_type, args.count, + args.size, args.address); - const bool mprven = riscv_enable_virtual && get_field(mstatus, MSTATUS_MPRV); - const struct memory_access_info access = { - .target_address = address, - .increment = increment, - .buffer_address = buffer, - .element_size = size, - }; - int result = (count == 1) ? - read_memory_progbuf_inner_one(target, access, mprven) : - read_memory_progbuf_inner(target, access, count, mprven); + if (dm013_select_target(target) != ERROR_OK) + return mem_access_result(MEM_ACCESS_SKIPPED_TARGET_SELECT_FAILED); - if (mstatus != mstatus_old && - register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old) != ERROR_OK) - return ERROR_FAIL; + riscv_reg_t mstatus = 0; + riscv_reg_t mstatus_old = 0; + riscv_reg_t dcsr = 0; + riscv_reg_t dcsr_old = 0; + if (modify_privilege_for_virt2phys_mode(target, + &mstatus, &mstatus_old, &dcsr, &dcsr_old) != ERROR_OK) + return mem_access_result(MEM_ACCESS_SKIPPED_PRIV_MOD_FAILED); + + struct mem_access_result result = is_read ? + read_memory_progbuf(target, args) : + write_memory_progbuf(target, args); + + if (restore_privilege_from_virt2phys_mode(target, + mstatus, mstatus_old, dcsr, dcsr_old) != ERROR_OK) + return mem_access_result(MEM_ACCESS_FAILED_PRIV_MOD_FAILED); return result; } -static int read_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer, uint32_t increment) +static int +write_memory_bus_v0(struct target *target, const riscv_mem_access_args_t args); +static int +write_memory_bus_v1(struct target *target, const riscv_mem_access_args_t args); + +static struct mem_access_result +access_memory_sysbus(struct target *target, const riscv_mem_access_args_t args) { - if (count == 0) - return ERROR_OK; + assert(riscv_mem_access_is_valid(args)); - if (size != 1 && size != 2 && size != 4 && size != 8 && size != 16) { - LOG_TARGET_ERROR(target, "BUG: Unsupported size for memory read: %d", size); - return ERROR_FAIL; - } + struct mem_access_result skip_reason = mem_should_skip_sysbus(target, args); + if (!is_mem_access_ok(skip_reason)) + return skip_reason; - int ret = ERROR_FAIL; - RISCV_INFO(r); RISCV013_INFO(info); + int ret = ERROR_FAIL; + const bool is_read = riscv_mem_access_is_read(args); + const uint64_t sbver = get_field(info->sbcs, DM_SBCS_SBVERSION); + if (sbver == 0) { + ret = is_read ? read_memory_bus_v0(target, args) : + write_memory_bus_v0(target, args); + } else if (sbver == 1) { + ret = is_read ? read_memory_bus_v1(target, args) : + write_memory_bus_v1(target, args); + } else { + LOG_TARGET_ERROR(target, "Unknown system bus version: %" PRIu64, sbver); + return mem_access_result(MEM_ACCESS_SKIPPED_UNKNOWN_SYSBUS_VERSION); + } - char *progbuf_result = "disabled"; - char *sysbus_result = "disabled"; - char *abstract_result = "disabled"; + return mem_access_result(ret == ERROR_OK ? + MEM_ACCESS_OK : MEM_ACCESS_SKIPPED_SYSBUS_ACCESS_FAILED); +} - for (unsigned int i = 0; i < RISCV_NUM_MEM_ACCESS_METHODS; i++) { - int method = r->mem_access_methods[i]; +static struct mem_access_result +access_memory_abstract(struct target *target, const riscv_mem_access_args_t args) +{ + assert(riscv_mem_access_is_valid(args)); - if (method == RISCV_MEM_ACCESS_PROGBUF) { - if (mem_should_skip_progbuf(target, address, size, true, &progbuf_result)) - continue; + struct mem_access_result skip_reason = mem_should_skip_abstract(target, args); + if (!is_mem_access_ok(skip_reason)) + return skip_reason; - ret = read_memory_progbuf(target, address, size, count, buffer, increment); + const bool is_read = riscv_mem_access_is_read(args); + const char *const access_type = is_read ? "reading" : "writing"; + LOG_TARGET_DEBUG(target, "%s %d words of %d bytes at 0x%" + TARGET_PRIxADDR, access_type, args.count, + args.size, args.address); - if (ret != ERROR_OK) - progbuf_result = "failed"; - } else if (method == RISCV_MEM_ACCESS_SYSBUS) { - if (mem_should_skip_sysbus(target, address, size, increment, true, &sysbus_result)) - continue; + return is_read ? read_memory_abstract(target, args) : + write_memory_abstract(target, args); +} - if (get_field(info->sbcs, DM_SBCS_SBVERSION) == 0) - ret = read_memory_bus_v0(target, address, size, count, buffer, increment); - else if (get_field(info->sbcs, DM_SBCS_SBVERSION) == 1) - ret = read_memory_bus_v1(target, address, size, count, buffer, increment); +static int +riscv013_access_memory(struct target *target, const riscv_mem_access_args_t args) +{ + assert(riscv_mem_access_is_valid(args)); - if (ret != ERROR_OK) - sysbus_result = "failed"; - } else if (method == RISCV_MEM_ACCESS_ABSTRACT) { - if (mem_should_skip_abstract(target, address, size, increment, true, &abstract_result)) - continue; + const bool is_read = riscv_mem_access_is_read(args); + const char *const access_type = is_read ? "read" : "write"; + if (!is_read && args.increment != args.size) { + LOG_TARGET_ERROR(target, "Write increment size has to be equal to element size"); + return ERROR_NOT_IMPLEMENTED; + } - ret = read_memory_abstract(target, address, size, count, buffer, increment); + if (!IS_PWR_OF_2(args.size) || args.size < 1 || args.size > 16) { + LOG_TARGET_ERROR(target, "BUG: Unsupported size for " + "memory %s: %d", access_type, args.size); + return ERROR_FAIL; + } - if (ret != ERROR_OK) - abstract_result = "failed"; - } else if (method == RISCV_MEM_ACCESS_UNSPECIFIED) - /* No further mem access method to try. */ - break; + struct mem_access_result skip_reason[] = { + [RISCV_MEM_ACCESS_PROGBUF] = mem_access_result(MEM_ACCESS_DISABLED), + [RISCV_MEM_ACCESS_SYSBUS] = mem_access_result(MEM_ACCESS_DISABLED), + [RISCV_MEM_ACCESS_ABSTRACT] = mem_access_result(MEM_ACCESS_DISABLED), + }; + + RISCV_INFO(r); + for (unsigned int i = 0; i < r->num_enabled_mem_access_methods; ++i) { + riscv_mem_access_method_t method = r->mem_access_methods[i]; + switch (method) { + case RISCV_MEM_ACCESS_PROGBUF: + skip_reason[method] = access_memory_progbuf(target, args); + break; + case RISCV_MEM_ACCESS_SYSBUS: + skip_reason[method] = access_memory_sysbus(target, args); + break; + case RISCV_MEM_ACCESS_ABSTRACT: + skip_reason[method] = access_memory_abstract(target, args); + break; + default: + LOG_TARGET_ERROR(target, "Unknown memory access method: %d", method); + assert(false && "Unknown memory access method"); + goto failure; + } - log_mem_access_result(target, ret == ERROR_OK, method, true); + if (is_mem_access_failed(skip_reason[method])) + goto failure; - if (ret == ERROR_OK) - return ret; + const bool success = is_mem_access_ok(skip_reason[method]); + log_mem_access_result(target, success, method, is_read); + if (success) + return ERROR_OK; } - LOG_TARGET_ERROR(target, "Failed to read memory (addr=0x%" PRIx64 ")", address); - LOG_TARGET_ERROR(target, " progbuf=%s, sysbus=%s, abstract=%s", progbuf_result, sysbus_result, abstract_result); - return ret; +failure: + LOG_TARGET_ERROR(target, "Failed to %s memory (addr=0x%" PRIx64 ")\n" + " progbuf=%s, sysbus=%s, abstract=%s", access_type, args.address, + mem_access_result_to_str(skip_reason[RISCV_MEM_ACCESS_PROGBUF]), + mem_access_result_to_str(skip_reason[RISCV_MEM_ACCESS_SYSBUS]), + mem_access_result_to_str(skip_reason[RISCV_MEM_ACCESS_ABSTRACT])); + return ERROR_FAIL; } -static int write_memory_bus_v0(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, const uint8_t *buffer) +static int write_memory_bus_v0(struct target *target, const riscv_mem_access_args_t args) { + assert(riscv_mem_access_is_write(args)); + /*1) write sbaddress: for singlewrite and autoincrement, we need to write the address once*/ LOG_TARGET_DEBUG(target, "System Bus Access: size: %d\tcount:%d\tstart address: 0x%08" - TARGET_PRIxADDR, size, count, address); - dm_write(target, DM_SBADDRESS0, address); + TARGET_PRIxADDR, args.size, args.count, args.address); + dm_write(target, DM_SBADDRESS0, args.address); int64_t value = 0; int64_t access = 0; riscv_addr_t offset = 0; riscv_addr_t t_addr = 0; - const uint8_t *t_buffer = buffer + offset; + const uint8_t *t_buffer = args.write_buffer + offset; /* B.8 Writing Memory, single write check if we write in one go */ - if (count == 1) { /* count is in bytes here */ - value = buf_get_u64(t_buffer, 0, 8 * size); + if (args.count == 1) { /* count is in bytes here */ + value = buf_get_u64(t_buffer, 0, 8 * args.size); access = 0; - access = set_field(access, DM_SBCS_SBACCESS, size/2); + access = set_field(access, DM_SBCS_SBACCESS, args.size / 2); dm_write(target, DM_SBCS, access); LOG_TARGET_DEBUG(target, " access: 0x%08" PRIx64, access); LOG_TARGET_DEBUG(target, " write_memory:SAB: ONE OFF: value 0x%08" PRIx64, value); @@ -4642,19 +4649,19 @@ static int write_memory_bus_v0(struct target *target, target_addr_t address, /*B.8 Writing Memory, using autoincrement*/ access = 0; - access = set_field(access, DM_SBCS_SBACCESS, size/2); + access = set_field(access, DM_SBCS_SBACCESS, args.size / 2); access = set_field(access, DM_SBCS_SBAUTOINCREMENT, 1); LOG_TARGET_DEBUG(target, " access: 0x%08" PRIx64, access); dm_write(target, DM_SBCS, access); /*2)set the value according to the size required and write*/ - for (riscv_addr_t i = 0; i < count; ++i) { - offset = size*i; + for (riscv_addr_t i = 0; i < args.count; ++i) { + offset = args.size * i; /* for monitoring only */ - t_addr = address + offset; - t_buffer = buffer + offset; + t_addr = args.address + offset; + t_buffer = args.write_buffer + offset; - value = buf_get_u64(t_buffer, 0, 8 * size); + value = buf_get_u64(t_buffer, 0, 8 * args.size); LOG_TARGET_DEBUG(target, "SAB:autoincrement: expected address: 0x%08x value: 0x%08x" PRIx64, (uint32_t)t_addr, (uint32_t)value); dm_write(target, DM_SBDATA0, value); @@ -4666,20 +4673,22 @@ static int write_memory_bus_v0(struct target *target, target_addr_t address, return ERROR_OK; } -static int write_memory_bus_v1(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, const uint8_t *buffer) +static int write_memory_bus_v1(struct target *target, const riscv_mem_access_args_t args) { + assert(riscv_mem_access_is_write(args)); + RISCV013_INFO(info); - uint32_t sbcs = sb_sbaccess(size); + uint32_t sbcs = sb_sbaccess(args.size); sbcs = set_field(sbcs, DM_SBCS_SBAUTOINCREMENT, 1); dm_write(target, DM_SBCS, sbcs); - target_addr_t next_address = address; - target_addr_t end_address = address + count * size; + target_addr_t next_address = args.address; + target_addr_t end_address = args.address + args.count * args.size; - int result; + int result = sb_write_address(target, next_address, RISCV_DELAY_BASE); + if (result != ERROR_OK) + return result; - sb_write_address(target, next_address, true); while (next_address < end_address) { LOG_TARGET_DEBUG(target, "Transferring burst starting at address 0x%" TARGET_PRIxADDR, next_address); @@ -4688,53 +4697,47 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address, if (!batch) return ERROR_FAIL; - for (uint32_t i = (next_address - address) / size; i < count; i++) { - const uint8_t *p = buffer + i * size; + for (uint32_t i = (next_address - args.address) / args.size; i < args.count; i++) { + const uint8_t *p = args.write_buffer + i * args.size; - if (riscv_batch_available_scans(batch) < (size + 3) / 4) + if (riscv_batch_available_scans(batch) < (args.size + 3) / 4) break; uint32_t sbvalue[4] = { 0 }; - if (size > 12) { - sbvalue[3] = ((uint32_t)p[12]) | - (((uint32_t)p[13]) << 8) | - (((uint32_t)p[14]) << 16) | - (((uint32_t)p[15]) << 24); + if (args.size > 12) { + sbvalue[3] = buf_get_u32(&p[12], + /* first = */ 0, /* bit_num = */ 32); riscv_batch_add_dm_write(batch, DM_SBDATA3, sbvalue[3], false, RISCV_DELAY_BASE); } - if (size > 8) { - sbvalue[2] = ((uint32_t)p[8]) | - (((uint32_t)p[9]) << 8) | - (((uint32_t)p[10]) << 16) | - (((uint32_t)p[11]) << 24); + if (args.size > 8) { + sbvalue[2] = buf_get_u32(&p[8], + /* first = */ 0, /* bit_num = */ 32); riscv_batch_add_dm_write(batch, DM_SBDATA2, sbvalue[2], false, RISCV_DELAY_BASE); } - if (size > 4) { - sbvalue[1] = ((uint32_t)p[4]) | - (((uint32_t)p[5]) << 8) | - (((uint32_t)p[6]) << 16) | - (((uint32_t)p[7]) << 24); + if (args.size > 4) { + sbvalue[1] = buf_get_u32(&p[4], + /* first = */ 0, /* bit_num = */ 32); riscv_batch_add_dm_write(batch, DM_SBDATA1, sbvalue[1], false, RISCV_DELAY_BASE); } sbvalue[0] = p[0]; - if (size > 2) { + if (args.size > 2) { sbvalue[0] |= ((uint32_t)p[2]) << 16; sbvalue[0] |= ((uint32_t)p[3]) << 24; } - if (size > 1) + if (args.size > 1) sbvalue[0] |= ((uint32_t)p[1]) << 8; riscv_batch_add_dm_write(batch, DM_SBDATA0, sbvalue[0], false, RISCV_DELAY_SYSBUS_WRITE); - log_memory_access(address + i * size, sbvalue, size, false); + log_memory_access(args.address + i * args.size, sbvalue, args.size, false); - next_address += size; + next_address += args.size; } /* Execute the batch of writes */ @@ -4769,7 +4772,7 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address, /* Recover from the case when the write commands were issued too fast. * Determine the address from which to resume writing. */ next_address = sb_read_address(target); - if (next_address < address) { + if (next_address < args.address) { /* This should never happen, probably buggy hardware. */ LOG_TARGET_DEBUG(target, "unexpected sbaddress=0x%" TARGET_PRIxADDR " - buggy sbautoincrement in hw?", next_address); @@ -4789,7 +4792,7 @@ static int write_memory_bus_v1(struct target *target, target_addr_t address, target_addr_t sbaddress = sb_read_address(target); LOG_TARGET_DEBUG(target, "System bus access failed with sberror=%u (sbaddress=0x%" TARGET_PRIxADDR ")", sberror, sbaddress); - if (sbaddress < address) { + if (sbaddress < args.address) { /* This should never happen, probably buggy hardware. * Make a note to the user not to trust the sbaddress value. */ LOG_TARGET_DEBUG(target, "unexpected sbaddress=0x%" TARGET_PRIxADDR @@ -4833,14 +4836,14 @@ static int write_memory_progbuf_startup(struct target *target, target_addr_t *ad /* Write and execute command that moves the value from data0 [, data1] * into S1 and executes program buffer. */ - uint32_t command = access_register_command(target, + uint32_t command = riscv013_access_register_command(target, GDB_REGNO_S1, riscv_xlen(target), AC_ACCESS_REGISTER_POSTEXEC | AC_ACCESS_REGISTER_TRANSFER | AC_ACCESS_REGISTER_WRITE); uint32_t cmderr; - if (execute_abstract_command(target, command, &cmderr) != ERROR_OK) + if (riscv013_execute_abstract_command(target, command, &cmderr) != ERROR_OK) return ERROR_FAIL; log_memory_access64(*address_p, value, size, /*is_read*/ false); @@ -4991,25 +4994,7 @@ static int write_memory_progbuf_try_to_write(struct target *target, return result; } -static int riscv_program_store_mprv(struct riscv_program *p, enum gdb_regno d, - enum gdb_regno b, int offset, unsigned int size, bool mprven) -{ - if (mprven && riscv_program_csrrsi(p, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, - GDB_REGNO_DCSR) != ERROR_OK) - return ERROR_FAIL; - - if (riscv_program_store(p, d, b, offset, size) != ERROR_OK) - return ERROR_FAIL; - - if (mprven && riscv_program_csrrci(p, GDB_REGNO_ZERO, CSR_DCSR_MPRVEN, - GDB_REGNO_DCSR) != ERROR_OK) - return ERROR_FAIL; - - return ERROR_OK; -} - -static int write_memory_progbuf_fill_progbuf(struct target *target, - uint32_t size, bool mprven) +static int write_memory_progbuf_fill_progbuf(struct target *target, uint32_t size) { if (riscv013_reg_save(target, GDB_REGNO_S0) != ERROR_OK) return ERROR_FAIL; @@ -5019,11 +5004,10 @@ static int write_memory_progbuf_fill_progbuf(struct target *target, struct riscv_program program; riscv_program_init(&program, target); - if (riscv_program_store_mprv(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0, size, - mprven) != ERROR_OK) + if (riscv_program_store(&program, GDB_REGNO_S1, GDB_REGNO_S0, 0, size) != ERROR_OK) return ERROR_FAIL; - if (riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, size) != ERROR_OK) + if (riscv_program_addi(&program, GDB_REGNO_S0, GDB_REGNO_S0, (int16_t)size) != ERROR_OK) return ERROR_FAIL; if (riscv_program_ebreak(&program) != ERROR_OK) @@ -5032,131 +5016,65 @@ static int write_memory_progbuf_fill_progbuf(struct target *target, return riscv_program_write(&program); } -static int write_memory_progbuf_inner(struct target *target, target_addr_t start_addr, - uint32_t size, uint32_t count, const uint8_t *buffer, bool mprven) +static struct mem_access_result +write_memory_progbuf_inner(struct target *target, + const riscv_mem_access_args_t args) { - if (write_memory_progbuf_fill_progbuf(target, size, - mprven) != ERROR_OK) - return ERROR_FAIL; + assert(riscv_mem_access_is_write(args)); - target_addr_t addr_on_target = start_addr; - if (write_memory_progbuf_startup(target, &addr_on_target, buffer, size) != ERROR_OK) - return ERROR_FAIL; + if (write_memory_progbuf_fill_progbuf(target, args.size) != ERROR_OK) + return mem_access_result(MEM_ACCESS_SKIPPED_PROGBUF_FILL_FAILED); + + target_addr_t addr_on_target = args.address; + if (write_memory_progbuf_startup(target, &addr_on_target, + args.write_buffer, args.size) != ERROR_OK) + return mem_access_result(MEM_ACCESS_FAILED_PROGBUF_STARTUP_FAILED); - const target_addr_t end_addr = start_addr + (target_addr_t)size * count; + const target_addr_t end_addr = args.address + (target_addr_t)args.size * args.count; for (target_addr_t next_addr_on_target = addr_on_target; addr_on_target != end_addr; addr_on_target = next_addr_on_target) { - const uint8_t * const curr_buff = buffer + (addr_on_target - start_addr); + const uint8_t * const curr_buff = args.write_buffer + (addr_on_target - args.address); if (write_memory_progbuf_try_to_write(target, &next_addr_on_target, - end_addr, size, curr_buff) != ERROR_OK) { + end_addr, args.size, curr_buff) != ERROR_OK) { write_memory_progbuf_teardown(target); - return ERROR_FAIL; + return mem_access_result(MEM_ACCESS_FAILED_PROGBUF_INNER_FAILED); } /* write_memory_progbuf_try_to_write() ensures that at least one item * gets successfully written even when busy condition is encountered. * These assertions shuld hold when next_address_on_target overflows. */ assert(next_addr_on_target - addr_on_target > 0); - assert(next_addr_on_target - start_addr <= (target_addr_t)size * count); + assert(next_addr_on_target - args.address <= (target_addr_t)args.size * args.count); } - return write_memory_progbuf_teardown(target); + return write_memory_progbuf_teardown(target) == ERROR_OK ? + mem_access_result(MEM_ACCESS_OK) : + mem_access_result(MEM_ACCESS_FAILED_PROGBUF_TEARDOWN_FAILED); } -static int write_memory_progbuf(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, const uint8_t *buffer) +static struct mem_access_result +write_memory_progbuf(struct target *target, const riscv_mem_access_args_t args) { - if (riscv_xlen(target) < size * 8) { - LOG_TARGET_ERROR(target, "XLEN (%u) is too short for %" PRIu32 "-bit memory write.", - riscv_xlen(target), size * 8); - return ERROR_FAIL; - } + assert(riscv_mem_access_is_write(args)); - LOG_TARGET_DEBUG(target, "writing %" PRIu32 " words of %" PRIu32 - " bytes to 0x%" TARGET_PRIxADDR, count, size, address); + struct mem_access_result result = write_memory_progbuf_inner(target, args); - if (dm013_select_target(target) != ERROR_OK) - return ERROR_FAIL; - - uint64_t mstatus = 0; - uint64_t mstatus_old = 0; - if (modify_privilege(target, &mstatus, &mstatus_old) != ERROR_OK) - return ERROR_FAIL; - - const bool mprven = riscv_enable_virtual && get_field(mstatus, MSTATUS_MPRV); - - int result = write_memory_progbuf_inner(target, address, size, count, buffer, mprven); - - /* Restore MSTATUS */ - if (mstatus != mstatus_old) - if (register_write_direct(target, GDB_REGNO_MSTATUS, mstatus_old)) - return ERROR_FAIL; - - if (execute_fence(target) != ERROR_OK) - return ERROR_FAIL; + if (execute_autofence(target) != ERROR_OK) + return mem_access_result(MEM_ACCESS_FAILED_FENCE_EXEC_FAILED); return result; } -static int write_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, const uint8_t *buffer) +static bool riscv013_get_impebreak(const struct target *target) { - if (size != 1 && size != 2 && size != 4 && size != 8 && size != 16) { - LOG_TARGET_ERROR(target, "BUG: Unsupported size for memory write: %d", size); - return ERROR_FAIL; - } - - int ret = ERROR_FAIL; - RISCV_INFO(r); - RISCV013_INFO(info); - - char *progbuf_result = "disabled"; - char *sysbus_result = "disabled"; - char *abstract_result = "disabled"; - - for (unsigned int i = 0; i < RISCV_NUM_MEM_ACCESS_METHODS; i++) { - int method = r->mem_access_methods[i]; - - if (method == RISCV_MEM_ACCESS_PROGBUF) { - if (mem_should_skip_progbuf(target, address, size, false, &progbuf_result)) - continue; - - ret = write_memory_progbuf(target, address, size, count, buffer); - - if (ret != ERROR_OK) - progbuf_result = "failed"; - } else if (method == RISCV_MEM_ACCESS_SYSBUS) { - if (mem_should_skip_sysbus(target, address, size, 0, false, &sysbus_result)) - continue; - - if (get_field(info->sbcs, DM_SBCS_SBVERSION) == 0) - ret = write_memory_bus_v0(target, address, size, count, buffer); - else if (get_field(info->sbcs, DM_SBCS_SBVERSION) == 1) - ret = write_memory_bus_v1(target, address, size, count, buffer); - - if (ret != ERROR_OK) - sysbus_result = "failed"; - } else if (method == RISCV_MEM_ACCESS_ABSTRACT) { - if (mem_should_skip_abstract(target, address, size, 0, false, &abstract_result)) - continue; - - ret = write_memory_abstract(target, address, size, count, buffer); - - if (ret != ERROR_OK) - abstract_result = "failed"; - } else if (method == RISCV_MEM_ACCESS_UNSPECIFIED) - /* No further mem access method to try. */ - break; - - log_mem_access_result(target, ret == ERROR_OK, method, false); - - if (ret == ERROR_OK) - return ret; - } + RISCV013_INFO(r); + return r->impebreak; +} - LOG_TARGET_ERROR(target, "Target %s: Failed to write memory (addr=0x%" PRIx64 ")", target_name(target), address); - LOG_TARGET_ERROR(target, " progbuf=%s, sysbus=%s, abstract=%s", progbuf_result, sysbus_result, abstract_result); - return ret; +static unsigned int riscv013_get_progbufsize(const struct target *target) +{ + RISCV013_INFO(r); + return r->progbufsize; } static int arch_state(struct target *target) @@ -5178,8 +5096,6 @@ struct target_type riscv013_target = { .assert_reset = assert_reset, .deassert_reset = deassert_reset, - .write_memory = write_memory, - .arch_state = arch_state }; @@ -5263,13 +5179,13 @@ static int select_prepped_harts(struct target *target) } assert(dm->hart_count); - unsigned hawindow_count = (dm->hart_count + 31) / 32; + unsigned int hawindow_count = (dm->hart_count + 31) / 32; uint32_t *hawindow = calloc(hawindow_count, sizeof(uint32_t)); if (!hawindow) return ERROR_FAIL; target_list_t *entry; - unsigned total_selected = 0; + unsigned int total_selected = 0; unsigned int selected_index = 0; list_for_each_entry(entry, &dm->target_list, list) { struct target *t = entry->target; @@ -5301,7 +5217,7 @@ static int select_prepped_harts(struct target *target) return ERROR_FAIL; } - for (unsigned i = 0; i < hawindow_count; i++) { + for (unsigned int i = 0; i < hawindow_count; i++) { if (dm_write(target, DM_HAWINDOWSEL, i) != ERROR_OK) { free(hawindow); return ERROR_FAIL; @@ -5467,9 +5383,12 @@ static enum riscv_halt_reason riscv013_halt_reason(struct target *target) static int riscv013_write_progbuf(struct target *target, unsigned int index, riscv_insn_t data) { + assert(index < RISCV013_MAX_PROGBUF_SIZE); + dm013_info_t *dm = get_dm(target); if (!dm) return ERROR_FAIL; + if (dm->progbuf_cache[index] != data) { if (dm_write(target, DM_PROGBUF0 + index, data) != ERROR_OK) return ERROR_FAIL; @@ -5498,8 +5417,7 @@ static int riscv013_invalidate_cached_progbuf(struct target *target) } LOG_TARGET_DEBUG(target, "Invalidating progbuf cache"); - for (unsigned int i = 0; i < 15; i++) - dm->progbuf_cache[i] = 0; + memset(dm->progbuf_cache, 0, sizeof(dm->progbuf_cache)); return ERROR_OK; } @@ -5511,72 +5429,45 @@ static int riscv013_execute_progbuf(struct target *target, uint32_t *cmderr) run_program = set_field(run_program, AC_ACCESS_REGISTER_TRANSFER, 0); run_program = set_field(run_program, AC_ACCESS_REGISTER_REGNO, 0x1000); - return execute_abstract_command(target, run_program, cmderr); + return riscv013_execute_abstract_command(target, run_program, cmderr); } -static void riscv013_fill_dmi_write(struct target *target, char *buf, uint64_t a, uint32_t d) +static void riscv013_fill_dmi_write(const struct target *target, uint8_t *buf, uint32_t a, uint32_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); + buf_set_u32(buf, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, DMI_OP_WRITE); + buf_set_u32(buf, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, d); + buf_set_u32(buf, DTM_DMI_ADDRESS_OFFSET, info->abits, a); } -static void riscv013_fill_dmi_read(struct target *target, char *buf, uint64_t a) +static void riscv013_fill_dmi_read(const struct target *target, uint8_t *buf, uint32_t 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); + buf_set_u32(buf, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, DMI_OP_READ); + buf_set_u32(buf, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, 0); + buf_set_u32(buf, DTM_DMI_ADDRESS_OFFSET, info->abits, a); } -static void riscv013_fill_dmi_nop(struct target *target, char *buf) +static void riscv013_fill_dm_nop(const struct target *target, uint8_t *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); + buf_set_u32(buf, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH, DMI_OP_NOP); + buf_set_u32(buf, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH, 0); + buf_set_u32(buf, DTM_DMI_ADDRESS_OFFSET, info->abits, 0); } -static int riscv013_get_dmi_scan_length(struct target *target) +static unsigned int riscv013_get_dmi_address_bits(const struct target *target) { RISCV013_INFO(info); - return info->abits + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH; -} - -void riscv013_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d) -{ - dm013_info_t *dm = get_dm(target); - if (!dm) - return; - riscv013_fill_dmi_write(target, buf, a + dm->base, d); -} - -void riscv013_fill_dm_read(struct target *target, char *buf, uint64_t a) -{ - dm013_info_t *dm = get_dm(target); - if (!dm) - return; - riscv013_fill_dmi_read(target, buf, a + dm->base); -} - -void riscv013_fill_dm_nop(struct target *target, char *buf) -{ - riscv013_fill_dmi_nop(target, buf); -} - -static int maybe_execute_fence_i(struct target *target) -{ - if (has_sufficient_progbuf(target, 2)) - return execute_fence(target); - return ERROR_OK; + return info->abits; } /* Helper Functions. */ static int riscv013_on_step_or_resume(struct target *target, bool step) { - if (maybe_execute_fence_i(target) != ERROR_OK) - return ERROR_FAIL; + if (has_sufficient_progbuf(target, 2)) + if (execute_autofence(target) != ERROR_OK) + return ERROR_FAIL; if (set_dcsr_ebreak(target, step) != ERROR_OK) return ERROR_FAIL; @@ -5593,11 +5484,15 @@ static int riscv013_step_or_resume_current_hart(struct target *target, LOG_TARGET_ERROR(target, "Hart is not halted!"); return ERROR_FAIL; } - LOG_TARGET_DEBUG(target, "resuming (for step?=%d)", step); + + LOG_TARGET_DEBUG(target, "resuming (operation=%s)", + step ? "single-step" : "resume"); if (riscv_reg_flush_all(target) != ERROR_OK) return ERROR_FAIL; + riscv_reg_cache_invalidate_all(target); + dm013_info_t *dm = get_dm(target); /* Issue the resume command, and then wait for the current hart to resume. */ uint32_t dmcontrol = DM_DMCONTROL_DMACTIVE | DM_DMCONTROL_RESUMEREQ; @@ -5626,16 +5521,26 @@ static int riscv013_step_or_resume_current_hart(struct target *target, return ERROR_OK; } + LOG_TARGET_ERROR(target, "Failed to %s. dmstatus=0x%08x", + step ? "single-step" : "resume", dmstatus); + dm_write(target, DM_DMCONTROL, dmcontrol); + LOG_TARGET_ERROR(target, + " cancelling the resume request (dmcontrol.resumereq <- 0)"); - LOG_TARGET_ERROR(target, "unable to resume"); if (dmstatus_read(target, &dmstatus, true) != ERROR_OK) return ERROR_FAIL; - LOG_TARGET_ERROR(target, " dmstatus=0x%08x", dmstatus); + + LOG_TARGET_ERROR(target, " dmstatus after cancellation=0x%08x", dmstatus); if (step) { - LOG_TARGET_ERROR(target, " was stepping, halting"); - riscv_halt(target); + LOG_TARGET_ERROR(target, + " trying to recover from a failed single-step, by requesting halt"); + if (riscv_halt(target) == ERROR_OK) + LOG_TARGET_ERROR(target, " halt completed after failed single-step"); + else + LOG_TARGET_ERROR(target, " could not halt, something is wrong with the taget"); + // TODO: returning ERROR_OK is questionable, this code needs to be revised return ERROR_OK; } diff --git a/src/target/riscv/riscv-013.h b/src/target/riscv/riscv-013.h index be508f7..ca2d4ae 100644 --- a/src/target/riscv/riscv-013.h +++ b/src/target/riscv/riscv-013.h @@ -19,5 +19,9 @@ int riscv013_set_register(struct target *target, enum gdb_regno rid, riscv_reg_t value); int riscv013_set_register_buf(struct target *target, enum gdb_regno regno, const uint8_t *value); +uint32_t riscv013_access_register_command(struct target *target, uint32_t number, + unsigned int size, uint32_t flags); +int riscv013_execute_abstract_command(struct target *target, uint32_t command, + uint32_t *cmderr); -#endif /*OPENOCD_TARGET_RISCV_RISCV_013_H*/ +#endif /* OPENOCD_TARGET_RISCV_RISCV_013_H */ diff --git a/src/target/riscv/riscv-013_reg.c b/src/target/riscv/riscv-013_reg.c index a71a01c..b2b1a92 100644 --- a/src/target/riscv/riscv-013_reg.c +++ b/src/target/riscv/riscv-013_reg.c @@ -5,10 +5,12 @@ #endif #include "riscv-013_reg.h" +#include "field_helpers.h" #include "riscv_reg.h" #include "riscv_reg_impl.h" #include "riscv-013.h" +#include "debug_defines.h" #include <helper/time_support.h> static int riscv013_reg_get(struct reg *reg) @@ -44,7 +46,6 @@ static int riscv013_reg_get(struct reg *reg) static int riscv013_reg_set(struct reg *reg, uint8_t *buf) { struct target *target = riscv_reg_impl_get_target(reg); - RISCV_INFO(r); char *str = buf_to_hex_str(buf, reg->size); LOG_TARGET_DEBUG(target, "Write 0x%s to %s (valid=%d).", str, reg->name, @@ -57,17 +58,6 @@ static int riscv013_reg_set(struct reg *reg, uint8_t *buf) buf_get_u64(buf, 0, reg->size) == 0) return ERROR_OK; - if (reg->number == GDB_REGNO_TDATA1 || - reg->number == GDB_REGNO_TDATA2) { - r->manual_hwbp_set = true; - /* When enumerating triggers, we clear any triggers with DMODE set, - * assuming they were left over from a previous debug session. So make - * sure that is done before a user might be setting their own triggers. - */ - if (riscv_enumerate_triggers(target) != ERROR_OK) - return ERROR_FAIL; - } - if (reg->number >= GDB_REGNO_V0 && reg->number <= GDB_REGNO_V31) { if (riscv013_set_register_buf(target, reg->number, buf) != ERROR_OK) return ERROR_FAIL; @@ -85,33 +75,270 @@ static int riscv013_reg_set(struct reg *reg, uint8_t *buf) static const struct reg_arch_type *riscv013_gdb_regno_reg_type(uint32_t regno) { - static const struct reg_arch_type riscv011_reg_type = { + static const struct reg_arch_type riscv013_reg_type = { .get = riscv013_reg_get, .set = riscv013_reg_set }; - return &riscv011_reg_type; + return &riscv013_reg_type; +} + +static int init_cache_entry(struct target *target, uint32_t regno) +{ + struct reg * const reg = riscv_reg_impl_cache_entry(target, regno); + if (riscv_reg_impl_is_initialized(reg)) + return ERROR_OK; + return riscv_reg_impl_init_cache_entry(target, regno, + riscv_reg_impl_gdb_regno_exist(target, regno), + riscv013_gdb_regno_reg_type(regno)); +} + +/** + * Some registers are optional (e.g. "misa"). For such registers it is first + * assumed they exist (via "assume_reg_exist()"), then the read is attempted + * (via the usual "riscv_reg_get()") and if the read fails, the register is + * marked as non-existing (via "riscv_reg_impl_set_exist()"). + */ +static int assume_reg_exist(struct target *target, uint32_t regno) +{ + return riscv_reg_impl_init_cache_entry(target, regno, + /* exist */ true, riscv013_gdb_regno_reg_type(regno)); +} + +static int examine_xlen(struct target *target) +{ + RISCV_INFO(r); + unsigned int cmderr; + + const uint32_t command = riscv013_access_register_command(target, + GDB_REGNO_S0, /* size */ 64, AC_ACCESS_REGISTER_TRANSFER); + int res = riscv013_execute_abstract_command(target, command, &cmderr); + if (res == ERROR_OK) { + r->xlen = 64; + return ERROR_OK; + } + if (res == ERROR_TIMEOUT_REACHED) + return ERROR_FAIL; + r->xlen = 32; + + return ERROR_OK; } -static int riscv013_init_reg(struct target *target, uint32_t regno) +static int examine_vlenb(struct target *target) { - return riscv_reg_impl_init_one(target, regno, riscv013_gdb_regno_reg_type(regno)); + RISCV_INFO(r); + + /* Reading "vlenb" requires "mstatus.vs" to be set, so "mstatus" should + * be accessible.*/ + int res = init_cache_entry(target, GDB_REGNO_MSTATUS); + if (res != ERROR_OK) + return res; + + res = assume_reg_exist(target, GDB_REGNO_VLENB); + if (res != ERROR_OK) + return res; + + riscv_reg_t vlenb_val; + if (riscv_reg_get(target, &vlenb_val, GDB_REGNO_VLENB) != ERROR_OK) { + if (riscv_supports_extension(target, 'V')) + LOG_TARGET_WARNING(target, "Couldn't read vlenb; vector register access won't work."); + r->vlenb = 0; + return riscv_reg_impl_set_exist(target, GDB_REGNO_VLENB, false); + } + /* As defined by RISC-V V extension specification: + * https://github.com/riscv/riscv-v-spec/blob/2f68ef7256d6ec53e4d2bd7cb12862f406d64e34/v-spec.adoc?plain=1#L67-L72 */ + const unsigned int vlen_max = 65536; + const unsigned int vlenb_max = vlen_max / 8; + if (vlenb_val > vlenb_max) { + LOG_TARGET_WARNING(target, "'vlenb == %" PRIu64 + "' is greater than maximum allowed by specification (%u); vector register access won't work.", + vlenb_val, vlenb_max); + r->vlenb = 0; + return ERROR_OK; + } + assert(vlenb_max <= UINT_MAX); + r->vlenb = (unsigned int)vlenb_val; + + LOG_TARGET_INFO(target, "Vector support with vlenb=%u", r->vlenb); + return ERROR_OK; +} + +enum misa_mxl { + MISA_MXL_INVALID = 0, + MISA_MXL_32 = 1, + MISA_MXL_64 = 2, + MISA_MXL_128 = 3 +}; + +unsigned int mxl_to_xlen(enum misa_mxl mxl) +{ + switch (mxl) { + case MISA_MXL_32: + return 32; + case MISA_MXL_64: + return 64; + case MISA_MXL_128: + return 128; + case MISA_MXL_INVALID: + assert(0); + } + return 0; } -int riscv013_reg_init_all(struct target *target) +static int check_misa_mxl(const struct target *target) { - if (riscv_reg_impl_init_cache(target) != ERROR_OK) + RISCV_INFO(r); + + if (r->misa == 0) { + LOG_TARGET_WARNING(target, "'misa' register is read as zero." + "OpenOCD will not be able to determine some hart's capabilities."); + return ERROR_OK; + } + const unsigned int dxlen = riscv_xlen(target); + assert(dxlen <= sizeof(riscv_reg_t) * CHAR_BIT); + assert(dxlen >= 2); + const riscv_reg_t misa_mxl_mask = (riscv_reg_t)0x3 << (dxlen - 2); + const unsigned int mxl = get_field(r->misa, misa_mxl_mask); + if (mxl == MISA_MXL_INVALID) { + /* This is not an error! + * Imagine the platform that: + * - Has no abstract access to CSRs, so that CSRs are read + * through Program Buffer via "csrr" instruction. + * - Complies to v1.10 of the Priveleged Spec, so that misa.mxl + * is WARL and MXLEN may be chainged. + * https://github.com/riscv/riscv-isa-manual/commit/9a7dd2fe29011587954560b5dcf1875477b27ad8 + * - DXLEN == MXLEN on reset == 64. + * In a following scenario: + * - misa.mxl was written, so that MXLEN is 32. + * - Debugger connects to the target. + * - Debugger observes DXLEN == 64. + * - Debugger reads misa: + * - Abstract access fails with "cmderr == not supported". + * - Access via Program Buffer involves reading "misa" to an + * "xreg" via "csrr", so that the "xreg" is filled with + * zero-extended value of "misa" (since "misa" is + * MXLEN-wide). + * - Debugger derives "misa.mxl" assumig "misa" is DXLEN-bit + * wide (64) while MXLEN is 32 and therefore erroneously + * assumes "misa.mxl" to be zero (invalid). + */ + LOG_TARGET_WARNING(target, "Detected DXLEN (%u) does not match " + "MXLEN: misa.mxl == 0, misa == 0x%" PRIx64 ".", + dxlen, r->misa); + return ERROR_OK; + } + const unsigned int mxlen = mxl_to_xlen(mxl); + if (dxlen < mxlen) { + LOG_TARGET_ERROR(target, + "MXLEN (%u) reported in misa.mxl field exceeds " + "the detected DXLEN (%u)", + mxlen, dxlen); return ERROR_FAIL; + } + /* NOTE: + * The value of "misa.mxl" may stil not coincide with "xlen". + * "misa[26:XLEN-3]" bits are marked as WIRI in at least version 1.10 + * of RISC-V Priveleged Spec. Therefore, if "xlen" is erroneously + * assumed to be 32 when it actually is 64, "mxl" will be read from + * this WIRI field and may be equal to "MISA_MXL_32" by coincidence. + * This is not an issue though from the version 1.11 onward, since + * "misa[26:XLEN-3]" became WARL and equal to 0. + */ + + /* Display this as early as possible to help people who are using + * really slow simulators. */ + LOG_TARGET_DEBUG(target, " XLEN=%d, misa=0x%" PRIx64, riscv_xlen(target), r->misa); + return ERROR_OK; +} + +static int examine_misa(struct target *target) +{ + RISCV_INFO(r); + + int res = init_cache_entry(target, GDB_REGNO_MISA); + if (res != ERROR_OK) + return res; + + res = riscv_reg_get(target, &r->misa, GDB_REGNO_MISA); + if (res != ERROR_OK) + return res; + return check_misa_mxl(target); +} + +static int examine_mtopi(struct target *target) +{ + /* Assume the registers exist */ + int res = assume_reg_exist(target, GDB_REGNO_MTOPI); + if (res != ERROR_OK) + return res; + res = assume_reg_exist(target, GDB_REGNO_MTOPEI); + if (res != ERROR_OK) + return res; + + riscv_reg_t value; + if (riscv_reg_get(target, &value, GDB_REGNO_MTOPI) != ERROR_OK) { + res = riscv_reg_impl_set_exist(target, GDB_REGNO_MTOPI, false); + if (res != ERROR_OK) + return res; + return riscv_reg_impl_set_exist(target, GDB_REGNO_MTOPEI, false); + } + if (riscv_reg_get(target, &value, GDB_REGNO_MTOPEI) != ERROR_OK) { + LOG_TARGET_INFO(target, "S?aia detected without IMSIC"); + return riscv_reg_impl_set_exist(target, GDB_REGNO_MTOPEI, false); + } + LOG_TARGET_INFO(target, "S?aia detected with IMSIC"); + return ERROR_OK; +} + +/** + * This function assumes target's DM to be initialized (target is able to + * access DMs registers, execute program buffer, etc.) + */ +int riscv013_reg_examine_all(struct target *target) +{ + int res = riscv_reg_impl_init_cache(target); + if (res != ERROR_OK) + return res; init_shared_reg_info(target); + assert(target->state == TARGET_HALTED); + + res = examine_xlen(target); + if (res != ERROR_OK) + return res; + + /* Reading CSRs may clobber "s0", "s1", so it should be possible to + * save them in cache. */ + res = init_cache_entry(target, GDB_REGNO_S0); + if (res != ERROR_OK) + return res; + res = init_cache_entry(target, GDB_REGNO_S1); + if (res != ERROR_OK) + return res; + + res = examine_misa(target); + if (res != ERROR_OK) + return res; + + res = examine_vlenb(target); + if (res != ERROR_OK) + return res; + riscv_reg_impl_init_vector_reg_type(target); - for (uint32_t regno = 0; regno < target->reg_cache->num_regs; ++regno) - if (riscv013_init_reg(target, regno) != ERROR_OK) - return ERROR_FAIL; + res = examine_mtopi(target); + if (res != ERROR_OK) + return res; - if (riscv_reg_impl_expose_csrs(target) != ERROR_OK) - return ERROR_FAIL; + for (uint32_t regno = 0; regno < target->reg_cache->num_regs; ++regno) { + res = init_cache_entry(target, regno); + if (res != ERROR_OK) + return res; + } + + res = riscv_reg_impl_expose_csrs(target); + if (res != ERROR_OK) + return res; riscv_reg_impl_hide_csrs(target); diff --git a/src/target/riscv/riscv-013_reg.h b/src/target/riscv/riscv-013_reg.h index 2bdaaa0..e542a35 100644 --- a/src/target/riscv/riscv-013_reg.h +++ b/src/target/riscv/riscv-013_reg.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef OPENOCD_TARGET_RISCV_RISCV_REG_013_H -#define OPENOCD_TARGET_RISCV_RISCV_REG_013_H +#ifndef OPENOCD_TARGET_RISCV_RISCV_013_REG_H +#define OPENOCD_TARGET_RISCV_RISCV_013_REG_H #include "target/target.h" #include "gdb_regs.h" @@ -13,10 +13,11 @@ */ /** - * Init initialize register cache. After this function all registers can be - * safely accessed via functions described here and in `riscv_reg.h`. + * This function assumes target is halted. + * After this function all registers can be safely accessed via functions + * described here and in `riscv_reg.h`. */ -int riscv013_reg_init_all(struct target *target); +int riscv013_reg_examine_all(struct target *target); /** * This function is used to save the value of a register in cache. The register @@ -28,4 +29,4 @@ int riscv013_reg_init_all(struct target *target); */ int riscv013_reg_save(struct target *target, enum gdb_regno regid); -#endif /*OPENOCD_TARGET_RISCV_RISCV_REG_013_H*/ +#endif /* OPENOCD_TARGET_RISCV_RISCV_013_REG_H */ diff --git a/src/target/riscv/riscv.c b/src/target/riscv/riscv.c index a57c709..aae5eb3 100644 --- a/src/target/riscv/riscv.c +++ b/src/target/riscv/riscv.c @@ -37,6 +37,8 @@ #define RISCV_TRIGGER_HIT_NOT_FOUND ((int64_t)-1) +#define RISCV_HALT_GROUP_REPOLL_LIMIT 5 + static uint8_t ir_dtmcontrol[4] = {DTMCONTROL}; struct scan_field select_dtmcontrol = { .in_value = NULL, @@ -54,7 +56,8 @@ struct scan_field select_idcode = { }; static bscan_tunnel_type_t bscan_tunnel_type; -int bscan_tunnel_ir_width; /* if zero, then tunneling is not present/active */ +#define BSCAN_TUNNEL_IR_WIDTH_NBITS 7 +uint8_t bscan_tunnel_ir_width; /* if zero, then tunneling is not present/active */ static int bscan_tunnel_ir_id; /* IR ID of the JTAG TAP to access the tunnel. Valid when not 0 */ static const uint8_t bscan_zero[4] = {0}; @@ -67,7 +70,6 @@ static struct scan_field select_user4 = { }; -static uint8_t bscan_tunneled_ir_width[4] = {5}; /* overridden by assignment in riscv_init_target */ static struct scan_field _bscan_tunnel_data_register_select_dmi[] = { { .num_bits = 3, @@ -80,8 +82,8 @@ static struct scan_field _bscan_tunnel_data_register_select_dmi[] = { .in_value = NULL, }, { - .num_bits = 7, - .out_value = bscan_tunneled_ir_width, + .num_bits = BSCAN_TUNNEL_IR_WIDTH_NBITS, + .out_value = &bscan_tunnel_ir_width, .in_value = NULL, }, { @@ -98,8 +100,8 @@ static struct scan_field _bscan_tunnel_nested_tap_select_dmi[] = { .in_value = NULL, }, { - .num_bits = 7, - .out_value = bscan_tunneled_ir_width, + .num_bits = BSCAN_TUNNEL_IR_WIDTH_NBITS, + .out_value = &bscan_tunnel_ir_width, .in_value = NULL, }, { @@ -139,6 +141,35 @@ struct tdata1_cache { struct list_head elem_tdata1; }; +bool riscv_virt2phys_mode_is_hw(const struct target *target) +{ + assert(target); + RISCV_INFO(r); + return r->virt2phys_mode == RISCV_VIRT2PHYS_MODE_HW; +} + +bool riscv_virt2phys_mode_is_sw(const struct target *target) +{ + assert(target); + RISCV_INFO(r); + return r->virt2phys_mode == RISCV_VIRT2PHYS_MODE_SW; +} + +const char *riscv_virt2phys_mode_to_str(riscv_virt2phys_mode_t mode) +{ + assert(mode == RISCV_VIRT2PHYS_MODE_OFF + || mode == RISCV_VIRT2PHYS_MODE_SW + || mode == RISCV_VIRT2PHYS_MODE_HW); + + static const char *const names[] = { + [RISCV_VIRT2PHYS_MODE_HW] = "hw", + [RISCV_VIRT2PHYS_MODE_SW] = "sw", + [RISCV_VIRT2PHYS_MODE_OFF] = "off", + }; + + return names[mode]; +} + /* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/ static int riscv_command_timeout_sec_value = DEFAULT_COMMAND_TIMEOUT_SEC; @@ -150,10 +181,6 @@ int riscv_get_command_timeout_sec(void) return MAX(riscv_command_timeout_sec_value, riscv_reset_timeout_sec); } -static bool riscv_enable_virt2phys = true; - -bool riscv_enable_virtual; - static enum { RO_NORMAL, RO_REVERSED @@ -265,9 +292,12 @@ static const virt2phys_info_t sv57x4 = { static enum riscv_halt_reason riscv_halt_reason(struct target *target); static void riscv_info_init(struct target *target, struct riscv_info *r); -static void riscv_invalidate_register_cache(struct target *target); static int riscv_step_rtos_hart(struct target *target); +static const riscv_reg_t mstatus_ie_mask = MSTATUS_MIE | MSTATUS_HIE | MSTATUS_SIE | MSTATUS_UIE; +static int riscv_interrupts_disable(struct target *target, riscv_reg_t *old_mstatus); +static int riscv_interrupts_restore(struct target *target, riscv_reg_t old_mstatus); + static void riscv_sample_buf_maybe_add_timestamp(struct target *target, bool before) { RISCV_INFO(r); @@ -286,21 +316,20 @@ static void riscv_sample_buf_maybe_add_timestamp(struct target *target, bool bef static int riscv_resume_go_all_harts(struct target *target); -void select_dmi_via_bscan(struct target *target) +void select_dmi_via_bscan(struct jtag_tap *tap) { - jtag_add_ir_scan(target->tap, &select_user4, TAP_IDLE); + jtag_add_ir_scan(tap, &select_user4, TAP_IDLE); if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) - jtag_add_dr_scan(target->tap, bscan_tunnel_data_register_select_dmi_num_fields, + jtag_add_dr_scan(tap, bscan_tunnel_data_register_select_dmi_num_fields, bscan_tunnel_data_register_select_dmi, TAP_IDLE); else /* BSCAN_TUNNEL_NESTED_TAP */ - jtag_add_dr_scan(target->tap, bscan_tunnel_nested_tap_select_dmi_num_fields, + jtag_add_dr_scan(tap, bscan_tunnel_nested_tap_select_dmi_num_fields, bscan_tunnel_nested_tap_select_dmi, TAP_IDLE); } -int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_ptr) +static int dtmcs_scan_via_bscan(struct jtag_tap *tap, uint32_t out, uint32_t *in_ptr) { /* On BSCAN TAP: Select IR=USER4, issue tunneled IR scan via BSCAN TAP's DR */ - uint8_t tunneled_ir_width[4] = {bscan_tunnel_ir_width}; uint8_t tunneled_dr_width[4] = {32}; uint8_t out_value[5] = {0}; uint8_t in_value[5] = {0}; @@ -316,8 +345,8 @@ int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_ tunneled_ir[1].num_bits = bscan_tunnel_ir_width; tunneled_ir[1].out_value = ir_dtmcontrol; tunneled_ir[1].in_value = NULL; - tunneled_ir[2].num_bits = 7; - tunneled_ir[2].out_value = tunneled_ir_width; + tunneled_ir[2].num_bits = BSCAN_TUNNEL_IR_WIDTH_NBITS; + tunneled_ir[2].out_value = &bscan_tunnel_ir_width; tunneled_ir[2].in_value = NULL; tunneled_ir[3].num_bits = 1; tunneled_ir[3].out_value = bscan_zero; @@ -329,7 +358,7 @@ int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_ tunneled_dr[1].num_bits = 32 + 1; tunneled_dr[1].out_value = out_value; tunneled_dr[1].in_value = in_value; - tunneled_dr[2].num_bits = 7; + tunneled_dr[2].num_bits = BSCAN_TUNNEL_IR_WIDTH_NBITS; tunneled_dr[2].out_value = tunneled_dr_width; tunneled_dr[2].in_value = NULL; tunneled_dr[3].num_bits = 1; @@ -343,8 +372,8 @@ int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_ tunneled_ir[2].num_bits = bscan_tunnel_ir_width; tunneled_ir[2].out_value = ir_dtmcontrol; tunneled_ir[1].in_value = NULL; - tunneled_ir[1].num_bits = 7; - tunneled_ir[1].out_value = tunneled_ir_width; + tunneled_ir[1].num_bits = BSCAN_TUNNEL_IR_WIDTH_NBITS; + tunneled_ir[1].out_value = &bscan_tunnel_ir_width; tunneled_ir[2].in_value = NULL; tunneled_ir[0].num_bits = 1; tunneled_ir[0].out_value = bscan_zero; @@ -363,10 +392,10 @@ int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_ tunneled_dr[0].out_value = bscan_one; tunneled_dr[0].in_value = NULL; } - jtag_add_ir_scan(target->tap, &select_user4, TAP_IDLE); - jtag_add_dr_scan(target->tap, ARRAY_SIZE(tunneled_ir), tunneled_ir, TAP_IDLE); - jtag_add_dr_scan(target->tap, ARRAY_SIZE(tunneled_dr), tunneled_dr, TAP_IDLE); - select_dmi_via_bscan(target); + jtag_add_ir_scan(tap, &select_user4, TAP_IDLE); + jtag_add_dr_scan(tap, ARRAY_SIZE(tunneled_ir), tunneled_ir, TAP_IDLE); + jtag_add_dr_scan(tap, ARRAY_SIZE(tunneled_dr), tunneled_dr, TAP_IDLE); + select_dmi_via_bscan(tap); int retval = jtag_execute_queue(); if (retval != ERROR_OK) { @@ -383,38 +412,44 @@ int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_ return ERROR_OK; } -static int dtmcontrol_scan(struct target *target, uint32_t out, uint32_t *in_ptr) +/* TODO: rename "dtmcontrol"-> "dtmcs" */ +int dtmcs_scan(struct jtag_tap *tap, uint32_t out, uint32_t *in_ptr) { - struct scan_field field; - uint8_t in_value[4]; - uint8_t out_value[4] = { 0 }; + uint8_t value[4]; if (bscan_tunnel_ir_width != 0) - return dtmcontrol_scan_via_bscan(target, out, in_ptr); + return dtmcs_scan_via_bscan(tap, out, in_ptr); - buf_set_u32(out_value, 0, 32, out); + buf_set_u32(value, 0, 32, out); - jtag_add_ir_scan(target->tap, &select_dtmcontrol, TAP_IDLE); + jtag_add_ir_scan(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); + struct scan_field field = { + .num_bits = 32, + .out_value = value, + .in_value = in_ptr ? value : NULL + }; + jtag_add_dr_scan(tap, 1, &field, TAP_IDLE); /* Always return to dbus. */ - jtag_add_ir_scan(target->tap, &select_dbus, TAP_IDLE); + jtag_add_ir_scan(tap, &select_dbus, TAP_IDLE); int retval = jtag_execute_queue(); if (retval != ERROR_OK) { - LOG_TARGET_ERROR(target, "dtmcontrol scan failed, error code = %d", retval); + LOG_ERROR("'dtmcs' scan failed on TAP %s, error code = %d", + jtag_tap_name(tap), retval); return retval; } - uint32_t in = buf_get_u32(field.in_value, 0, 32); - LOG_DEBUG("DTMCONTROL: 0x%x -> 0x%x", out, in); - - if (in_ptr) + if (in_ptr) { + assert(field.in_value); + uint32_t in = buf_get_u32(field.in_value, 0, 32); + LOG_DEBUG("TAP %s: DTMCS: 0x%" PRIx32 " -> 0x%" PRIx32, + jtag_tap_name(tap), out, in); *in_ptr = in; + } else { + LOG_DEBUG("TAP %s: DTMCS: 0x%" PRIx32 " -> ?", jtag_tap_name(tap), out); + } return ERROR_OK; } @@ -440,9 +475,30 @@ static struct target_type *get_target_type(struct target *target) } } +static struct riscv_private_config *alloc_default_riscv_private_config(void) +{ + struct riscv_private_config * const config = malloc(sizeof(*config)); + if (!config) { + LOG_ERROR("Out of memory!"); + return NULL; + } + + for (unsigned int i = 0; i < ARRAY_SIZE(config->dcsr_ebreak_fields); ++i) + config->dcsr_ebreak_fields[i] = true; + + return config; +} + static int riscv_create_target(struct target *target, Jim_Interp *interp) { LOG_TARGET_DEBUG(target, "riscv_create_target()"); + struct riscv_private_config *config = target->private_config; + if (!config) { + config = alloc_default_riscv_private_config(); + if (!config) + return ERROR_FAIL; + target->private_config = config; + } target->arch_info = calloc(1, sizeof(struct riscv_info)); if (!target->arch_info) { LOG_TARGET_ERROR(target, "Failed to allocate RISC-V target structure."); @@ -452,6 +508,158 @@ static int riscv_create_target(struct target *target, Jim_Interp *interp) return ERROR_OK; } +static struct jim_nvp nvp_ebreak_config_opts[] = { + { .name = "m", .value = RISCV_MODE_M }, + { .name = "s", .value = RISCV_MODE_S }, + { .name = "u", .value = RISCV_MODE_U }, + { .name = "vs", .value = RISCV_MODE_VS }, + { .name = "vu", .value = RISCV_MODE_VU }, + { .name = NULL, .value = N_RISCV_MODE } +}; + +#define RISCV_EBREAK_MODE_INVALID -1 + +static struct jim_nvp nvp_ebreak_mode_opts[] = { + { .name = "exception", .value = false }, + { .name = "halt", .value = true }, + { .name = NULL, .value = RISCV_EBREAK_MODE_INVALID } +}; + +static int jim_configure_ebreak(struct riscv_private_config *config, struct jim_getopt_info *goi) +{ + if (goi->argc == 0) { + Jim_WrongNumArgs(goi->interp, 1, goi->argv - 1, + "[?execution_mode?] ?ebreak_action?"); + return JIM_ERR; + } + struct jim_nvp *common_mode_nvp; + if (jim_nvp_name2value_obj(goi->interp, nvp_ebreak_mode_opts, goi->argv[0], + &common_mode_nvp) == JIM_OK) { + /* Here a common "ebreak" action is processed, e.g: + * "riscv.cpu configure -ebreak halt" + */ + int res = jim_getopt_obj(goi, NULL); + if (res != JIM_OK) + return res; + for (int ebreak_ctl_i = 0; ebreak_ctl_i < N_RISCV_MODE; ++ebreak_ctl_i) + config->dcsr_ebreak_fields[ebreak_ctl_i] = common_mode_nvp->value; + return JIM_OK; + } + + /* Here a "ebreak" action for a specific execution mode is processed, e.g: + * "riscv.cpu configure -ebreak m halt" + */ + if (goi->argc < 2) { + Jim_WrongNumArgs(goi->interp, 2, goi->argv - 2, + "?ebreak_action?"); + return JIM_ERR; + } + struct jim_nvp *ctrl_nvp; + if (jim_getopt_nvp(goi, nvp_ebreak_config_opts, &ctrl_nvp) != JIM_OK) { + jim_getopt_nvp_unknown(goi, nvp_ebreak_config_opts, /*hadprefix*/ true); + return JIM_ERR; + } + struct jim_nvp *mode_nvp; + if (jim_getopt_nvp(goi, nvp_ebreak_mode_opts, &mode_nvp) != JIM_OK) { + jim_getopt_nvp_unknown(goi, nvp_ebreak_mode_opts, /*hadprefix*/ true); + return JIM_ERR; + } + config->dcsr_ebreak_fields[ctrl_nvp->value] = mode_nvp->value; + return JIM_OK; +} + +/** + * Obtain dcsr.ebreak* configuration as a Tcl dictionary. + * Print the resulting string to the "buffer" and return the string length. + * The "buffer" can be NULL, in which case only the length is computed but + * nothing is written. + */ +static int ebreak_config_to_tcl_dict(const struct riscv_private_config *config, + char *buffer) +{ + int len = 0; + const char *separator = ""; + for (int ebreak_ctl_i = 0; ebreak_ctl_i < N_RISCV_MODE; + ++ebreak_ctl_i) { + const char * const format = "%s%s %s"; + const char * const priv_mode = + jim_nvp_value2name_simple(nvp_ebreak_config_opts, ebreak_ctl_i)->name; + const char * const mode = jim_nvp_value2name_simple(nvp_ebreak_mode_opts, + config->dcsr_ebreak_fields[ebreak_ctl_i])->name; + if (!buffer) + len += snprintf(NULL, 0, format, separator, priv_mode, mode); + else + len += sprintf(buffer + len, format, separator, priv_mode, mode); + + separator = "\n"; + } + return len; +} + +static int jim_report_ebreak_config(const struct riscv_private_config *config, + Jim_Interp *interp) +{ + const int len = ebreak_config_to_tcl_dict(config, NULL); + char *str = malloc(len + 1); + if (!str) { + LOG_ERROR("Unable to allocate a string of %d bytes.", len + 1); + return JIM_ERR; + } + ebreak_config_to_tcl_dict(config, str); + Jim_SetResultString(interp, str, len); + free(str); + return JIM_OK; +} + +enum riscv_cfg_opts { + RISCV_CFG_EBREAK, + RISCV_CFG_INVALID = -1 +}; + +static struct jim_nvp nvp_config_opts[] = { + { .name = "-ebreak", .value = RISCV_CFG_EBREAK }, + { .name = NULL, .value = RISCV_CFG_INVALID } +}; + +static int riscv_jim_configure(struct target *target, + struct jim_getopt_info *goi) +{ + struct riscv_private_config *config = target->private_config; + if (!config) { + config = alloc_default_riscv_private_config(); + if (!config) + return JIM_ERR; + target->private_config = config; + } + if (!goi->argc) + return JIM_OK; + + struct jim_nvp *n; + int e = jim_nvp_name2value_obj(goi->interp, nvp_config_opts, + goi->argv[0], &n); + if (e != JIM_OK) + return JIM_CONTINUE; + + e = jim_getopt_obj(goi, NULL); + if (e != JIM_OK) + return e; + + if (!goi->is_configure && goi->argc > 0) { + /* Expecting no arguments */ + Jim_WrongNumArgs(goi->interp, 2, goi->argv - 2, ""); + return JIM_ERR; + } + switch (n->value) { + case RISCV_CFG_EBREAK: + return goi->is_configure + ? jim_configure_ebreak(config, goi) + : jim_report_ebreak_config(config, goi->interp); + default: + assert(false && "'jim_getopt_nvp' should have returned an error."); + } + return JIM_ERR; +} + static int riscv_init_target(struct command_context *cmd_ctx, struct target *target) { @@ -473,7 +681,6 @@ static int riscv_init_target(struct command_context *cmd_ctx, } h_u32_to_le(ir_user4, ir_user4_raw); select_user4.num_bits = target->tap->ir_length; - bscan_tunneled_ir_width[0] = bscan_tunnel_ir_width; if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) bscan_tunnel_data_register_select_dmi[1].num_bits = bscan_tunnel_ir_width; else /* BSCAN_TUNNEL_NESTED_TAP */ @@ -510,6 +717,8 @@ static void riscv_deinit_target(struct target *target) { LOG_TARGET_DEBUG(target, "riscv_deinit_target()"); + free(target->private_config); + struct riscv_info *info = target->arch_info; struct target_type *tt = get_target_type(target); if (!tt) @@ -527,6 +736,8 @@ static void riscv_deinit_target(struct target *target) if (!info) return; + free(info->reserved_triggers); + range_list_t *entry, *tmp; list_for_each_entry_safe(entry, tmp, &info->hide_csr, list) { free(entry->name); @@ -617,9 +828,27 @@ static int find_first_trigger_by_id(struct target *target, int unique_id) return -1; } -static int set_trigger(struct target *target, unsigned int idx, riscv_reg_t tdata1, riscv_reg_t tdata2, - riscv_reg_t tdata1_ignore_mask) +static unsigned int count_trailing_ones(riscv_reg_t reg) { + const unsigned int riscv_reg_bits = sizeof(riscv_reg_t) * CHAR_BIT; + for (unsigned int i = 0; i < riscv_reg_bits; i++) { + if ((1 & (reg >> i)) == 0) + return i; + } + return riscv_reg_bits; +} + +static int set_trigger(struct target *target, unsigned int idx, riscv_reg_t tdata1, riscv_reg_t tdata2) +{ + RISCV_INFO(r); + assert(r->reserved_triggers); + assert(idx < r->trigger_count); + if (r->reserved_triggers[idx]) { + LOG_TARGET_DEBUG(target, + "Trigger %u is reserved by 'reserve_trigger' command.", idx); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + riscv_reg_t tdata1_rb, tdata2_rb; // Select which trigger to use if (riscv_reg_set(target, GDB_REGNO_TSELECT, idx) != ERROR_OK) @@ -642,20 +871,51 @@ static int set_trigger(struct target *target, unsigned int idx, riscv_reg_t tdat return ERROR_FAIL; if (riscv_reg_get(target, &tdata2_rb, GDB_REGNO_TDATA2) != ERROR_OK) return ERROR_FAIL; - bool tdata1_config_denied = (tdata1 & ~tdata1_ignore_mask) != (tdata1_rb & ~tdata1_ignore_mask); - bool tdata2_config_denied = tdata2 != tdata2_rb; - if (tdata1_config_denied || tdata2_config_denied) { + + const uint32_t type = get_field(tdata1, CSR_TDATA1_TYPE(riscv_xlen(target))); + const bool is_mcontrol = type == CSR_TDATA1_TYPE_MCONTROL; + + /* Determine if tdata1 supports what we need. + * For mcontrol triggers, we don't care about + * the value in the read-only "maskmax" field. + */ + const riscv_reg_t tdata1_ignore_mask = is_mcontrol ? CSR_MCONTROL_MASKMAX(riscv_xlen(target)) : 0; + const bool tdata1_config_denied = (tdata1 & ~tdata1_ignore_mask) != (tdata1_rb & ~tdata1_ignore_mask); + + /* Determine if tdata1.maxmask is sufficient + * (only relevant for mcontrol triggers and NAPOT match type) + */ + bool unsupported_napot_range = false; + riscv_reg_t maskmax_value = 0; + if (!tdata1_config_denied) { + const bool is_napot_match = get_field(tdata1_rb, CSR_MCONTROL_MATCH) == CSR_MCONTROL_MATCH_NAPOT; + if (is_mcontrol && is_napot_match) { + maskmax_value = get_field(tdata1_rb, CSR_MCONTROL_MASKMAX(riscv_xlen(target))); + const unsigned int napot_size = count_trailing_ones(tdata2) + 1; + if (maskmax_value < napot_size) + unsupported_napot_range = true; + } + } + + const bool tdata2_config_denied = tdata2 != tdata2_rb; + if (tdata1_config_denied || tdata2_config_denied || unsupported_napot_range) { LOG_TARGET_DEBUG(target, "Trigger %u doesn't support what we need.", idx); if (tdata1_config_denied) LOG_TARGET_DEBUG(target, - "After writing 0x%" PRIx64 " to tdata1 it contains 0x%" PRIx64 "; tdata1_ignore_mask=0x%" PRIx64, - tdata1, tdata1_rb, tdata1_ignore_mask); + "After writing 0x%" PRIx64 " to tdata1 it contains 0x%" PRIx64, + tdata1, tdata1_rb); if (tdata2_config_denied) LOG_TARGET_DEBUG(target, - "wrote 0x%" PRIx64 " to tdata2 but read back 0x%" PRIx64, + "After writing 0x%" PRIx64 " to tdata2 it contains 0x%" PRIx64, tdata2, tdata2_rb); + + if (unsupported_napot_range) + LOG_TARGET_DEBUG(target, + "The requested NAPOT match range (tdata2=0x%" PRIx64 ") exceeds maskmax_value=0x%" PRIx64, + tdata2, maskmax_value); + if (riscv_reg_set(target, GDB_REGNO_TDATA1, 0) != ERROR_OK) return ERROR_FAIL; return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; @@ -704,7 +964,7 @@ static int maybe_add_trigger_t1(struct target *target, struct trigger *trigger) tdata1 = set_field(tdata1, bpcontrol_bpaction, 0); /* cause bp exception */ tdata1 = set_field(tdata1, bpcontrol_bpmatch, 0); /* exact match */ tdata2 = trigger->address; - ret = set_trigger(target, idx, tdata1, tdata2, 0); + ret = set_trigger(target, idx, tdata1, tdata2); if (ret != ERROR_OK) return ret; r->trigger_unique_id[idx] = trigger->unique_id; @@ -714,13 +974,11 @@ static int maybe_add_trigger_t1(struct target *target, struct trigger *trigger) struct trigger_request_info { riscv_reg_t tdata1; riscv_reg_t tdata2; - riscv_reg_t tdata1_ignore_mask; }; static void log_trigger_request_info(struct trigger_request_info trig_info) { - LOG_DEBUG("tdata1=%" PRIx64 ", tdata2=%" PRIx64 ", tdata1_ignore_mask=%" PRIx64, - trig_info.tdata1, trig_info.tdata2, trig_info.tdata1_ignore_mask); + LOG_DEBUG("tdata1=%" PRIx64 ", tdata2=%" PRIx64, trig_info.tdata1, trig_info.tdata2); }; static struct tdata1_cache *tdata1_cache_alloc(struct list_head *tdata1_cache_head, riscv_reg_t tdata1) @@ -803,12 +1061,12 @@ static bool wp_triggers_cache_search(struct target *target, unsigned int idx, } static int try_use_trigger_and_cache_result(struct target *target, unsigned int idx, riscv_reg_t tdata1, - riscv_reg_t tdata2, riscv_reg_t tdata1_ignore_mask) + riscv_reg_t tdata2) { if (wp_triggers_cache_search(target, idx, tdata1, tdata2)) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - int ret = set_trigger(target, idx, tdata1, tdata2, tdata1_ignore_mask); + int ret = set_trigger(target, idx, tdata1, tdata2); /* Add these values to the cache to remember that they are not supported. */ if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) @@ -831,8 +1089,7 @@ static int try_setup_single_match_trigger(struct target *target, for (unsigned int idx = 0; find_next_free_trigger(target, trigger_type, false, &idx) == ERROR_OK; ++idx) { - ret = try_use_trigger_and_cache_result(target, idx, trig_info.tdata1, trig_info.tdata2, - trig_info.tdata1_ignore_mask); + ret = try_use_trigger_and_cache_result(target, idx, trig_info.tdata1, trig_info.tdata2); if (ret == ERROR_OK) { r->trigger_unique_id[idx] = trigger->unique_id; @@ -860,16 +1117,14 @@ static int try_setup_chained_match_triggers(struct target *target, for (unsigned int idx = 0; find_next_free_trigger(target, trigger_type, true, &idx) == ERROR_OK; ++idx) { - ret = try_use_trigger_and_cache_result(target, idx, t1.tdata1, t1.tdata2, - t1.tdata1_ignore_mask); + ret = try_use_trigger_and_cache_result(target, idx, t1.tdata1, t1.tdata2); if (ret == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) continue; else if (ret != ERROR_OK) return ret; - ret = try_use_trigger_and_cache_result(target, idx + 1, t2.tdata1, t2.tdata2, - t2.tdata1_ignore_mask); + ret = try_use_trigger_and_cache_result(target, idx + 1, t2.tdata1, t2.tdata2); if (ret == ERROR_OK) { r->trigger_unique_id[idx] = trigger->unique_id; @@ -877,7 +1132,7 @@ static int try_setup_chained_match_triggers(struct target *target, return ERROR_OK; } /* Undo the setting of the previous trigger */ - int ret_undo = set_trigger(target, idx, 0, 0, 0); + int ret_undo = set_trigger(target, idx, 0, 0); if (ret_undo != ERROR_OK) return ret_undo; @@ -905,7 +1160,6 @@ struct match_triggers_tdata1_fields { riscv_reg_t ge; riscv_reg_t eq; } match; - riscv_reg_t tdata1_ignore_mask; }; static struct match_triggers_tdata1_fields fill_match_triggers_tdata1_fields_t2(struct target *target, @@ -938,8 +1192,7 @@ static struct match_triggers_tdata1_fields fill_match_triggers_tdata1_fields_t2( .lt = field_value(CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_LT), .ge = field_value(CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_GE), .eq = field_value(CSR_MCONTROL_MATCH, CSR_MCONTROL_MATCH_EQUAL) - }, - .tdata1_ignore_mask = CSR_MCONTROL_MASKMAX(riscv_xlen(target)) + } }; return result; } @@ -976,8 +1229,7 @@ static struct match_triggers_tdata1_fields fill_match_triggers_tdata1_fields_t6( .lt = field_value(CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_LT), .ge = field_value(CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_GE), .eq = field_value(CSR_MCONTROL6_MATCH, CSR_MCONTROL6_MATCH_EQUAL) - }, - .tdata1_ignore_mask = 0 + } }; return result; } @@ -996,8 +1248,7 @@ static int maybe_add_trigger_t2_t6_for_wp(struct target *target, struct trigger_request_info napot = { .tdata1 = fields.common | fields.size.any | fields.chain.disable | fields.match.napot, - .tdata2 = trigger->address | ((trigger->length - 1) >> 1), - .tdata1_ignore_mask = fields.tdata1_ignore_mask + .tdata2 = trigger->address | ((trigger->length - 1) >> 1) }; ret = try_setup_single_match_trigger(target, trigger, napot); if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE) @@ -1013,14 +1264,12 @@ static int maybe_add_trigger_t2_t6_for_wp(struct target *target, struct trigger_request_info ge_1 = { .tdata1 = fields.common | fields.size.any | fields.chain.enable | fields.match.ge, - .tdata2 = trigger->address, - .tdata1_ignore_mask = fields.tdata1_ignore_mask + .tdata2 = trigger->address }; struct trigger_request_info lt_2 = { .tdata1 = fields.common | fields.size.any | fields.chain.disable | fields.match.lt, - .tdata2 = trigger->address + trigger->length, - .tdata1_ignore_mask = fields.tdata1_ignore_mask + .tdata2 = trigger->address + trigger->length }; ret = try_setup_chained_match_triggers(target, trigger, ge_1, lt_2); if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE) @@ -1030,14 +1279,12 @@ static int maybe_add_trigger_t2_t6_for_wp(struct target *target, struct trigger_request_info lt_1 = { .tdata1 = fields.common | fields.size.any | fields.chain.enable | fields.match.lt, - .tdata2 = trigger->address + trigger->length, - .tdata1_ignore_mask = fields.tdata1_ignore_mask + .tdata2 = trigger->address + trigger->length }; struct trigger_request_info ge_2 = { .tdata1 = fields.common | fields.size.any | fields.chain.disable | fields.match.ge, - .tdata2 = trigger->address, - .tdata1_ignore_mask = fields.tdata1_ignore_mask + .tdata2 = trigger->address }; ret = try_setup_chained_match_triggers(target, trigger, lt_1, ge_2); if (ret != ERROR_TARGET_RESOURCE_NOT_AVAILABLE) @@ -1053,8 +1300,7 @@ static int maybe_add_trigger_t2_t6_for_wp(struct target *target, struct trigger_request_info eq = { .tdata1 = fields.common | fields.size.any | fields.chain.disable | fields.match.eq, - .tdata2 = trigger->address, - .tdata1_ignore_mask = fields.tdata1_ignore_mask + .tdata2 = trigger->address }; ret = try_setup_single_match_trigger(target, trigger, eq); if (ret != ERROR_OK) @@ -1091,8 +1337,7 @@ static int maybe_add_trigger_t2_t6_for_bp(struct target *target, struct trigger_request_info eq = { .tdata1 = fields.common | fields.size.any | fields.chain.disable | fields.match.eq, - .tdata2 = trigger->address, - .tdata1_ignore_mask = fields.tdata1_ignore_mask + .tdata2 = trigger->address }; return try_setup_single_match_trigger(target, trigger, eq); @@ -1135,7 +1380,7 @@ static int maybe_add_trigger_t3(struct target *target, bool vs, bool vu, ret = find_next_free_trigger(target, CSR_TDATA1_TYPE_ICOUNT, false, &idx); if (ret != ERROR_OK) return ret; - ret = set_trigger(target, idx, tdata1, 0, 0); + ret = set_trigger(target, idx, tdata1, 0); if (ret != ERROR_OK) return ret; r->trigger_unique_id[idx] = unique_id; @@ -1168,7 +1413,7 @@ static int maybe_add_trigger_t4(struct target *target, bool vs, bool vu, ret = find_next_free_trigger(target, CSR_TDATA1_TYPE_ITRIGGER, false, &idx); if (ret != ERROR_OK) return ret; - ret = set_trigger(target, idx, tdata1, tdata2, 0); + ret = set_trigger(target, idx, tdata1, tdata2); if (ret != ERROR_OK) return ret; r->trigger_unique_id[idx] = unique_id; @@ -1200,7 +1445,7 @@ static int maybe_add_trigger_t5(struct target *target, bool vs, bool vu, ret = find_next_free_trigger(target, CSR_TDATA1_TYPE_ETRIGGER, false, &idx); if (ret != ERROR_OK) return ret; - ret = set_trigger(target, idx, tdata1, tdata2, 0); + ret = set_trigger(target, idx, tdata1, tdata2); if (ret != ERROR_OK) return ret; r->trigger_unique_id[idx] = unique_id; @@ -1523,21 +1768,75 @@ int riscv_remove_watchpoint(struct target *target, return ERROR_OK; } +typedef enum { + M6_HIT_ERROR, + M6_HIT_NOT_SUPPORTED, + M6_NOT_HIT, + M6_HIT_BEFORE, + M6_HIT_AFTER, + M6_HIT_IMM_AFTER +} mctrl6hitstatus; + +static mctrl6hitstatus check_mcontrol6_hit_status(struct target *target, + riscv_reg_t tdata1, uint64_t hit_mask) +{ + const uint32_t hit0 = get_field(tdata1, CSR_MCONTROL6_HIT0); + const uint32_t hit1 = get_field(tdata1, CSR_MCONTROL6_HIT1); + const uint32_t hit_info = (hit1 << 1) | hit0; + if (hit_info == CSR_MCONTROL6_HIT0_BEFORE) + return M6_HIT_BEFORE; + + if (hit_info == CSR_MCONTROL6_HIT0_AFTER) + return M6_HIT_AFTER; + + if (hit_info == CSR_MCONTROL6_HIT0_IMMEDIATELY_AFTER) + return M6_HIT_IMM_AFTER; + + if (hit_info == CSR_MCONTROL6_HIT0_FALSE) { + /* hit[1..0] equals 0, which can mean one of the following: + * - "hit" bits are supported and this trigger has not fired + * - "hit" bits are not supported on this trigger + * To distinguish these two cases, try writing all non-zero bit + * patterns to hit[1..0] to determine if the "hit" bits are supported: + */ + riscv_reg_t tdata1_tests[] = { + set_field(tdata1, CSR_MCONTROL6_HIT0, 1), + set_field(tdata1, CSR_MCONTROL6_HIT1, 1), + set_field(tdata1, CSR_MCONTROL6_HIT0, 1) | field_value(CSR_MCONTROL6_HIT1, 1) + }; + riscv_reg_t tdata1_test_rb; + for (uint64_t i = 0; i < ARRAY_SIZE(tdata1_tests); ++i) { + if (riscv_reg_set(target, GDB_REGNO_TDATA1, tdata1_tests[i]) != ERROR_OK) + return M6_HIT_ERROR; + if (riscv_reg_get(target, &tdata1_test_rb, GDB_REGNO_TDATA1) != ERROR_OK) + return M6_HIT_ERROR; + if (tdata1_test_rb == tdata1_tests[i]) { + if (riscv_reg_set(target, GDB_REGNO_TDATA1, tdata1_test_rb & ~hit_mask) != ERROR_OK) + return M6_HIT_ERROR; + return M6_NOT_HIT; + } + } + } + return M6_HIT_NOT_SUPPORTED; +} + /** * Look at the trigger hit bits to find out which trigger is the reason we're * halted. Sets *unique_id to the unique ID of that trigger. If *unique_id is * RISCV_TRIGGER_HIT_NOT_FOUND, no match was found. */ -static int riscv_trigger_detect_hit_bits(struct target *target, int64_t *unique_id) +static int riscv_trigger_detect_hit_bits(struct target *target, int64_t *unique_id, + bool *need_single_step) { /* FIXME: this function assumes that we have only one trigger that can * have hit bit set. Debug spec allows hit bit to bit set if a trigger has * matched but did not fire. Such targets will receive erroneous results. */ - // FIXME: Add hit bits support detection and caching RISCV_INFO(r); + assert(need_single_step); + *need_single_step = false; riscv_reg_t tselect; if (riscv_reg_get(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK) @@ -1563,9 +1862,21 @@ static int riscv_trigger_detect_hit_bits(struct target *target, int64_t *unique_ break; case CSR_TDATA1_TYPE_MCONTROL: hit_mask = CSR_MCONTROL_HIT; + *need_single_step = true; break; case CSR_TDATA1_TYPE_MCONTROL6: hit_mask = CSR_MCONTROL6_HIT0 | CSR_MCONTROL6_HIT1; + if (r->tinfo_version == CSR_TINFO_VERSION_0) { + *need_single_step = true; + } else if (r->tinfo_version == RISCV_TINFO_VERSION_UNKNOWN + || r->tinfo_version == CSR_TINFO_VERSION_1) { + mctrl6hitstatus hits_status = check_mcontrol6_hit_status(target, + tdata1, hit_mask); + if (hits_status == M6_HIT_ERROR) + return ERROR_FAIL; + if (hits_status == M6_HIT_BEFORE || hits_status == M6_HIT_NOT_SUPPORTED) + *need_single_step = true; + } break; case CSR_TDATA1_TYPE_ICOUNT: hit_mask = CSR_ICOUNT_HIT; @@ -1584,8 +1895,9 @@ static int riscv_trigger_detect_hit_bits(struct target *target, int64_t *unique_ /* FIXME: this logic needs to be changed to ignore triggers that are not * the last one in the chain. */ if (tdata1 & hit_mask) { - LOG_TARGET_DEBUG(target, "Trigger %u (unique_id=%" PRIi64 ") has hit bit set.", - i, r->trigger_unique_id[i]); + LOG_TARGET_DEBUG(target, "Trigger %u (unique_id=%" PRIi64 + ") has hit bit set. (need_single_step=%s)", + i, r->trigger_unique_id[i], (*need_single_step) ? "yes" : "no"); if (riscv_reg_set(target, GDB_REGNO_TDATA1, tdata1 & ~hit_mask) != ERROR_OK) return ERROR_FAIL; @@ -2125,8 +2437,8 @@ static int riscv_hit_watchpoint(struct target *target, struct watchpoint **hit_w return ERROR_FAIL; } -static int oldriscv_step(struct target *target, int current, uint32_t address, - int handle_breakpoints) +static int oldriscv_step(struct target *target, bool current, uint32_t address, + bool handle_breakpoints) { struct target_type *tt = get_target_type(target); if (!tt) @@ -2134,14 +2446,15 @@ static int oldriscv_step(struct target *target, int current, uint32_t address, return tt->step(target, current, address, handle_breakpoints); } -static int riscv_openocd_step_impl(struct target *target, int current, - target_addr_t address, int handle_breakpoints, int handle_callbacks); +static int riscv_openocd_step_impl(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, int handle_callbacks); -static int old_or_new_riscv_step_impl(struct target *target, int current, - target_addr_t address, int handle_breakpoints, int handle_callbacks) +static int old_or_new_riscv_step_impl(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, int handle_callbacks) { RISCV_INFO(r); - LOG_TARGET_DEBUG(target, "handle_breakpoints=%d", handle_breakpoints); + LOG_TARGET_DEBUG(target, "handle_breakpoints=%s", + handle_breakpoints ? "true" : "false"); if (!r->get_hart_state) return oldriscv_step(target, current, address, handle_breakpoints); else @@ -2149,8 +2462,8 @@ static int old_or_new_riscv_step_impl(struct target *target, int current, handle_callbacks); } -static int old_or_new_riscv_step(struct target *target, int current, - target_addr_t address, int handle_breakpoints) +static int old_or_new_riscv_step(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints) { return old_or_new_riscv_step_impl(target, current, address, handle_breakpoints, true /* handle callbacks*/); @@ -2168,7 +2481,7 @@ static int riscv_examine(struct target *target) RISCV_INFO(info); uint32_t dtmcontrol; - if (dtmcontrol_scan(target, 0, &dtmcontrol) != ERROR_OK || dtmcontrol == 0) { + if (dtmcs_scan(target->tap, 0, &dtmcontrol) != ERROR_OK || dtmcontrol == 0) { LOG_TARGET_ERROR(target, "Could not read dtmcontrol. Check JTAG connectivity/board power."); return ERROR_FAIL; } @@ -2247,13 +2560,15 @@ static int set_debug_reason(struct target *target, enum riscv_halt_reason halt_r { RISCV_INFO(r); r->trigger_hit = -1; + r->need_single_step = false; switch (halt_reason) { case RISCV_HALT_EBREAK: target->debug_reason = DBG_REASON_BREAKPOINT; break; case RISCV_HALT_TRIGGER: target->debug_reason = DBG_REASON_UNDEFINED; - if (riscv_trigger_detect_hit_bits(target, &r->trigger_hit) != ERROR_OK) + if (riscv_trigger_detect_hit_bits(target, &r->trigger_hit, + &r->need_single_step) != ERROR_OK) return ERROR_FAIL; // FIXME: handle multiple hit bits if (r->trigger_hit != RISCV_TRIGGER_HIT_NOT_FOUND) { @@ -2353,10 +2668,15 @@ static int riscv_halt_go_all_harts(struct target *target) return ERROR_FAIL; } } else { + // Safety check: + if (riscv_reg_cache_any_dirty(target, LOG_LVL_ERROR)) + LOG_TARGET_INFO(target, "BUG: Registers should not be dirty while " + "the target is not halted!"); + + riscv_reg_cache_invalidate_all(target); + if (r->halt_go(target) != ERROR_OK) return ERROR_FAIL; - - riscv_invalidate_register_cache(target); } return ERROR_OK; @@ -2440,7 +2760,11 @@ static int riscv_assert_reset(struct target *target) struct target_type *tt = get_target_type(target); if (!tt) return ERROR_FAIL; - riscv_invalidate_register_cache(target); + + if (riscv_reg_cache_any_dirty(target, LOG_LVL_INFO)) + LOG_TARGET_INFO(target, "Discarding values of dirty registers."); + + riscv_reg_cache_invalidate_all(target); return tt->assert_reset(target); } @@ -2453,87 +2777,48 @@ static int riscv_deassert_reset(struct target *target) return tt->deassert_reset(target); } -/* state must be riscv_reg_t state[RISCV_MAX_HWBPS] = {0}; */ -static int disable_triggers(struct target *target, riscv_reg_t *state) +/* "wp_is_set" array must have at least "r->trigger_count" items. */ +static int disable_watchpoints(struct target *target, bool *wp_is_set) { RISCV_INFO(r); - LOG_TARGET_DEBUG(target, "Disabling triggers."); - if (riscv_enumerate_triggers(target) != ERROR_OK) - return ERROR_FAIL; - - if (r->manual_hwbp_set) { - /* Look at every trigger that may have been set. */ - riscv_reg_t tselect; - if (riscv_reg_get(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK) - return ERROR_FAIL; - for (unsigned int t = 0; t < r->trigger_count; t++) { - if (riscv_reg_set(target, GDB_REGNO_TSELECT, t) != ERROR_OK) - return ERROR_FAIL; - riscv_reg_t tdata1; - if (riscv_reg_get(target, &tdata1, GDB_REGNO_TDATA1) != ERROR_OK) + /* TODO: The algorithm is flawed and may result in a situation described in + * https://github.com/riscv-collab/riscv-openocd/issues/1108 + */ + memset(wp_is_set, false, r->trigger_count); + struct watchpoint *watchpoint = target->watchpoints; + int i = 0; + while (watchpoint) { + LOG_TARGET_DEBUG(target, "Watchpoint %" PRIu32 ": set=%s", + watchpoint->unique_id, + wp_is_set[i] ? "true" : "false"); + wp_is_set[i] = watchpoint->is_set; + if (watchpoint->is_set) { + if (riscv_remove_watchpoint(target, watchpoint) != ERROR_OK) return ERROR_FAIL; - if (tdata1 & CSR_TDATA1_DMODE(riscv_xlen(target))) { - state[t] = tdata1; - if (riscv_reg_set(target, GDB_REGNO_TDATA1, 0) != ERROR_OK) - return ERROR_FAIL; - } - } - if (riscv_reg_set(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK) - return ERROR_FAIL; - - } else { - /* Just go through the triggers we manage. */ - struct watchpoint *watchpoint = target->watchpoints; - int i = 0; - while (watchpoint) { - LOG_TARGET_DEBUG(target, "Watchpoint %d: set=%d", i, watchpoint->is_set); - state[i] = watchpoint->is_set; - if (watchpoint->is_set) { - if (riscv_remove_watchpoint(target, watchpoint) != ERROR_OK) - return ERROR_FAIL; - } - watchpoint = watchpoint->next; - i++; } + watchpoint = watchpoint->next; + i++; } return ERROR_OK; } -static int enable_triggers(struct target *target, riscv_reg_t *state) +static int enable_watchpoints(struct target *target, bool *wp_is_set) { - RISCV_INFO(r); - - if (r->manual_hwbp_set) { - /* Look at every trigger that may have been set. */ - riscv_reg_t tselect; - if (riscv_reg_get(target, &tselect, GDB_REGNO_TSELECT) != ERROR_OK) - return ERROR_FAIL; - for (unsigned int t = 0; t < r->trigger_count; t++) { - if (state[t] != 0) { - if (riscv_reg_set(target, GDB_REGNO_TSELECT, t) != ERROR_OK) - return ERROR_FAIL; - if (riscv_reg_set(target, GDB_REGNO_TDATA1, state[t]) != ERROR_OK) - return ERROR_FAIL; - } - } - if (riscv_reg_set(target, GDB_REGNO_TSELECT, tselect) != ERROR_OK) - return ERROR_FAIL; - - } else { - struct watchpoint *watchpoint = target->watchpoints; - int i = 0; - while (watchpoint) { - LOG_TARGET_DEBUG(target, "Watchpoint %d: cleared=%" PRId64, i, state[i]); - if (state[i]) { - if (riscv_add_watchpoint(target, watchpoint) != ERROR_OK) - return ERROR_FAIL; - } - watchpoint = watchpoint->next; - i++; + struct watchpoint *watchpoint = target->watchpoints; + int i = 0; + while (watchpoint) { + LOG_TARGET_DEBUG(target, "Watchpoint %" PRIu32 + ": %s to be re-enabled.", watchpoint->unique_id, + wp_is_set[i] ? "needs " : "does not need"); + if (wp_is_set[i]) { + if (riscv_add_watchpoint(target, watchpoint) != ERROR_OK) + return ERROR_FAIL; } + watchpoint = watchpoint->next; + i++; } return ERROR_OK; @@ -2542,8 +2827,8 @@ static int enable_triggers(struct target *target, riscv_reg_t *state) /** * Get everything ready to resume. */ -static int resume_prep(struct target *target, int current, - target_addr_t address, int handle_breakpoints, int debug_execution) +static int resume_prep(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, bool debug_execution) { assert(target->state == TARGET_HALTED); RISCV_INFO(r); @@ -2554,10 +2839,19 @@ static int resume_prep(struct target *target, int current, if (handle_breakpoints) { /* To be able to run off a trigger, we perform a step operation and then * resume. If handle_breakpoints is true then step temporarily disables - * pending breakpoints so we can safely perform the step. */ - if (old_or_new_riscv_step_impl(target, current, address, handle_breakpoints, - false /* callbacks are not called */) != ERROR_OK) - return ERROR_FAIL; + * pending breakpoints so we can safely perform the step. + * + * Two cases where single step is needed before resuming: + * 1. ebreak used in software breakpoint; + * 2. a trigger that is taken just before the instruction that triggered it is retired. + */ + if (target->debug_reason == DBG_REASON_BREAKPOINT + || (target->debug_reason == DBG_REASON_WATCHPOINT + && r->need_single_step)) { + if (old_or_new_riscv_step_impl(target, current, address, handle_breakpoints, + false /* callbacks are not called */) != ERROR_OK) + return ERROR_FAIL; + } } if (r->get_hart_state) { @@ -2575,8 +2869,8 @@ static int resume_prep(struct target *target, int current, * Resume all the harts that have been prepped, as close to instantaneous as * possible. */ -static int resume_go(struct target *target, int current, - target_addr_t address, int handle_breakpoints, int debug_execution) +static int resume_go(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, bool debug_execution) { assert(target->state == TARGET_HALTED); RISCV_INFO(r); @@ -2594,10 +2888,18 @@ static int resume_go(struct target *target, int current, return result; } -static int resume_finish(struct target *target, int debug_execution) +static int resume_finish(struct target *target, bool debug_execution) { assert(target->state == TARGET_HALTED); - register_cache_invalidate(target->reg_cache); + if (riscv_reg_cache_any_dirty(target, LOG_LVL_ERROR)) { + /* If this happens, it means there is a bug in the previous + * register-flushing algorithm: not all registers were flushed + * back to the target in preparation for the resume.*/ + LOG_TARGET_ERROR(target, + "BUG: registers should have been flushed by this point."); + } + + riscv_reg_cache_invalidate_all(target); target->state = debug_execution ? TARGET_DEBUG_RUNNING : TARGET_RUNNING; target->debug_reason = DBG_REASON_NOTHALTED; @@ -2611,17 +2913,17 @@ static int resume_finish(struct target *target, int debug_execution) */ static int riscv_resume( struct target *target, - int current, + bool current, target_addr_t address, - int handle_breakpoints, - int debug_execution, + bool handle_breakpoints, + bool debug_execution, bool single_hart) { int result = ERROR_OK; struct list_head *targets; - LIST_HEAD(single_target_list); + OOCD_LIST_HEAD(single_target_list); struct target_list single_target_entry = { .lh = {NULL, NULL}, .target = target @@ -2675,8 +2977,8 @@ static int riscv_resume( return result; } -static int riscv_target_resume(struct target *target, int current, - target_addr_t address, int handle_breakpoints, int debug_execution) +static int riscv_target_resume(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, bool debug_execution) { if (target->state != TARGET_HALTED) { LOG_TARGET_ERROR(target, "Not halted."); @@ -2715,7 +3017,7 @@ static int riscv_mmu(struct target *target, int *enabled) { *enabled = 0; - if (!riscv_enable_virt2phys) + if (!riscv_virt2phys_mode_is_sw(target)) return ERROR_OK; /* Don't use MMU in explicit or effective M (machine) mode */ @@ -2843,8 +3145,14 @@ static int riscv_address_translate(struct target *target, uint8_t buffer[8]; assert(info->pte_shift <= 3); - int retval = r->read_memory(target, pte_address, - 4, (1 << info->pte_shift) / 4, buffer, 4); + const riscv_mem_access_args_t args = { + .address = pte_address, + .read_buffer = buffer, + .size = 4, + .increment = 4, + .count = (1 << info->pte_shift) / 4, + }; + int retval = r->access_memory(target, args); if (retval != ERROR_OK) return ERROR_FAIL; @@ -3062,60 +3370,136 @@ static int riscv_virt2phys(struct target *target, target_addr_t virtual, target_ virtual, physical); } +static int check_virt_memory_access(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, bool is_write) +{ + const bool is_misaligned = address % size != 0; + // TODO: This assumes that size of each page is 4 KiB, which is not necessarily the case. + const bool crosses_page_boundary = RISCV_PGBASE(address + size * count - 1) != RISCV_PGBASE(address); + if (is_misaligned && crosses_page_boundary) { + LOG_TARGET_ERROR(target, "Mis-aligned memory %s (address=0x%" TARGET_PRIxADDR ", size=%d, count=%d)" + " would access an element across page boundary. This is not supported.", + is_write ? "write" : "read", address, size, count); + return ERROR_FAIL; + } + return ERROR_OK; +} + static int riscv_read_phys_memory(struct target *target, target_addr_t phys_address, uint32_t size, uint32_t count, uint8_t *buffer) { + const riscv_mem_access_args_t args = { + .address = phys_address, + .read_buffer = buffer, + .size = size, + .count = count, + .increment = size, + }; RISCV_INFO(r); - return r->read_memory(target, phys_address, size, count, buffer, size); + return r->access_memory(target, args); } -static int riscv_read_memory(struct target *target, target_addr_t address, - uint32_t size, uint32_t count, uint8_t *buffer) +static int riscv_write_phys_memory(struct target *target, target_addr_t phys_address, + uint32_t size, uint32_t count, const uint8_t *buffer) +{ + const riscv_mem_access_args_t args = { + .address = phys_address, + .write_buffer = buffer, + .size = size, + .count = count, + .increment = size, + }; + + RISCV_INFO(r); + return r->access_memory(target, args); +} + +static int riscv_rw_memory(struct target *target, const riscv_mem_access_args_t args) { - if (count == 0) { - LOG_TARGET_WARNING(target, "0-length read from 0x%" TARGET_PRIxADDR, address); + assert(riscv_mem_access_is_valid(args)); + + const bool is_write = riscv_mem_access_is_write(args); + if (args.count == 0) { + LOG_TARGET_WARNING(target, "0-length %s 0x%" TARGET_PRIxADDR, + is_write ? "write to" : "read from", args.address); return ERROR_OK; } - target_addr_t physical_addr; - int result = target->type->virt2phys(target, address, &physical_addr); - if (result != ERROR_OK) { - LOG_TARGET_ERROR(target, "Address translation failed."); + int mmu_enabled; + int result = riscv_mmu(target, &mmu_enabled); + if (result != ERROR_OK) return result; - } RISCV_INFO(r); - return r->read_memory(target, physical_addr, size, count, buffer, size); + if (!mmu_enabled) + return r->access_memory(target, args); + + result = check_virt_memory_access(target, args.address, + args.size, args.count, is_write); + if (result != ERROR_OK) + return result; + + uint32_t current_count = 0; + target_addr_t current_address = args.address; + while (current_count < args.count) { + target_addr_t physical_addr; + result = target->type->virt2phys(target, current_address, &physical_addr); + if (result != ERROR_OK) { + LOG_TARGET_ERROR(target, "Address translation failed."); + return result; + } + + /* TODO: For simplicity, this algorithm assumes the worst case - the smallest possible page size, + * which is 4 KiB. The algorithm can be improved to detect the real page size, and allow to use larger + * memory transfers and avoid extra unnecessary virt2phys address translations. */ + uint32_t chunk_count = MIN(args.count - current_count, + (RISCV_PGSIZE - RISCV_PGOFFSET(current_address)) + / args.size); + + riscv_mem_access_args_t current_access = args; + current_access.address = physical_addr; + current_access.count = chunk_count; + if (is_write) + current_access.write_buffer += current_count * args.size; + else + current_access.read_buffer += current_count * args.size; + + result = r->access_memory(target, current_access); + if (result != ERROR_OK) + return result; + + current_count += chunk_count; + current_address += chunk_count * args.size; + } + return ERROR_OK; } -static int riscv_write_phys_memory(struct target *target, target_addr_t phys_address, - uint32_t size, uint32_t count, const uint8_t *buffer) +static int riscv_read_memory(struct target *target, target_addr_t address, + uint32_t size, uint32_t count, uint8_t *buffer) { - struct target_type *tt = get_target_type(target); - if (!tt) - return ERROR_FAIL; - return tt->write_memory(target, phys_address, size, count, buffer); + const riscv_mem_access_args_t args = { + .address = address, + .read_buffer = buffer, + .size = size, + .count = count, + .increment = size, + }; + + return riscv_rw_memory(target, args); } static int riscv_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { - if (count == 0) { - LOG_TARGET_WARNING(target, "0-length write to 0x%" TARGET_PRIxADDR, address); - return ERROR_OK; - } - - target_addr_t physical_addr; - int result = target->type->virt2phys(target, address, &physical_addr); - if (result != ERROR_OK) { - LOG_TARGET_ERROR(target, "Address translation failed."); - return result; - } + const riscv_mem_access_args_t args = { + .address = address, + .write_buffer = buffer, + .size = size, + .count = count, + .increment = size, + }; - struct target_type *tt = get_target_type(target); - if (!tt) - return ERROR_FAIL; - return tt->write_memory(target, physical_addr, size, count, buffer); + return riscv_rw_memory(target, args); } static const char *riscv_get_gdb_arch(const struct target *target) @@ -3269,14 +3653,13 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, } /* Disable Interrupts before attempting to run the algorithm. */ - uint64_t current_mstatus; - uint64_t irq_disabled_mask = MSTATUS_MIE | MSTATUS_HIE | MSTATUS_SIE | MSTATUS_UIE; - if (riscv_interrupts_disable(target, irq_disabled_mask, ¤t_mstatus) != ERROR_OK) + riscv_reg_t current_mstatus; + if (riscv_interrupts_disable(target, ¤t_mstatus) != ERROR_OK) return ERROR_FAIL; /* Run algorithm */ - LOG_TARGET_DEBUG(target, "Resume at 0x%" TARGET_PRIxADDR, entry_point); - if (riscv_resume(target, 0, entry_point, 0, 1, true) != ERROR_OK) + LOG_TARGET_DEBUG(target, "resume at 0x%" TARGET_PRIxADDR, entry_point); + if (riscv_resume(target, false, entry_point, false, true, true) != ERROR_OK) return ERROR_FAIL; int64_t start = timeval_ms(); @@ -3299,7 +3682,7 @@ static int riscv_run_algorithm(struct target *target, int num_mem_params, GDB_REGNO_PC, GDB_REGNO_MSTATUS, GDB_REGNO_MEPC, GDB_REGNO_MCAUSE, }; - for (unsigned i = 0; i < ARRAY_SIZE(regnums); i++) { + for (unsigned int i = 0; i < ARRAY_SIZE(regnums); i++) { enum gdb_regno regno = regnums[i]; riscv_reg_t reg_value; if (riscv_reg_get(target, ®_value, regno) != ERROR_OK) @@ -3394,8 +3777,8 @@ static int riscv_checksum_memory(struct target *target, static const uint8_t *crc_code; - unsigned xlen = riscv_xlen(target); - unsigned crc_code_size; + unsigned int xlen = riscv_xlen(target); + unsigned int crc_code_size; if (xlen == 32) { crc_code = riscv32_crc_code; crc_code_size = sizeof(riscv32_crc_code); @@ -3651,9 +4034,11 @@ int riscv_openocd_poll(struct target *target) { LOG_TARGET_DEBUG(target, "Polling all harts."); + struct riscv_info *i = riscv_info(target); + struct list_head *targets; - LIST_HEAD(single_target_list); + OOCD_LIST_HEAD(single_target_list); struct target_list single_target_entry = { .lh = {NULL, NULL}, .target = target @@ -3672,6 +4057,7 @@ int riscv_openocd_poll(struct target *target) unsigned int should_resume = 0; unsigned int halted = 0; unsigned int running = 0; + unsigned int cause_groups = 0; struct target_list *entry; foreach_smp_target(entry, targets) { struct target *t = entry->target; @@ -3719,6 +4105,59 @@ int riscv_openocd_poll(struct target *target) LOG_TARGET_DEBUG(target, "resume all"); riscv_resume(target, true, 0, 0, 0, false); } else if (halted && running) { + LOG_TARGET_DEBUG(target, "SMP group is in inconsistent state: %u halted, %u running", + halted, running); + + /* The SMP group is in an inconsistent state - some harts in the group have halted + * whereas others are running. The reasons for that (and corresponding + * OpenOCD actions) could be: + * 1) The targets are in the process of halting due to halt groups + * but not all of them halted --> poll again so that the halt reason of every + * hart can be accurately determined (e.g. semihosting). + * 2) The targets do not support halt groups --> OpenOCD must halt + * the remaining harts by a standard halt request. + * 3) The hart states got out of sync for some other unknown reason (problem?). --> + * Same as previous - try to halt the harts by a standard halt request + * to get them back in sync. */ + + /* Detect if the harts are just in the process of halting due to a halt group */ + foreach_smp_target(entry, targets) + { + struct target *t = entry->target; + if (t->state == TARGET_HALTED) { + riscv_reg_t dcsr; + if (riscv_reg_get(t, &dcsr, GDB_REGNO_DCSR) != ERROR_OK) + return ERROR_FAIL; + if (get_field(dcsr, CSR_DCSR_CAUSE) == CSR_DCSR_CAUSE_GROUP) + cause_groups++; + else + /* This hart has halted due to something else than a halt group. + * Don't continue checking the rest - exit early. */ + break; + } + } + /* Condition: halted == cause_groups + * + * This condition indicates a paradox where: + * - All currently halted harts show CSR_DCSR_CAUSE_GROUP + * - However, no individual hart can be identified as the actual initiator of the halt condition + * + * Poll again so that the true halt reason can be discovered (e.g. CSR_DCSR_CAUSE_EBREAK) */ + if (halted == cause_groups) { + LOG_TARGET_DEBUG(target, "The harts appear to just be in the process of halting due to a halt group."); + if (i->halt_group_repoll_count < RISCV_HALT_GROUP_REPOLL_LIMIT) { + /* Wait a little, then re-poll. */ + i->halt_group_repoll_count++; + alive_sleep(10); + LOG_TARGET_DEBUG(target, "Re-polling the state of the SMP group."); + return riscv_openocd_poll(target); + } + /* We have already re-polled multiple times but the halt group is still inconsistent. */ + LOG_TARGET_DEBUG(target, "Re-polled the SMP group %d times it is still not in a consistent state.", + RISCV_HALT_GROUP_REPOLL_LIMIT); + } + + /* Halting the whole SMP group to bring it in sync. */ LOG_TARGET_DEBUG(target, "halt all; halted=%d", halted); riscv_halt(target); @@ -3736,6 +4175,8 @@ int riscv_openocd_poll(struct target *target) } } + i->halt_group_repoll_count = 0; + /* Call tick() for every hart. What happens in tick() is opaque to this * layer. The reason it's outside the previous loop is that at this point * the state of every hart has settled, so any side effects happening in @@ -3759,8 +4200,8 @@ int riscv_openocd_poll(struct target *target) return ERROR_OK; } -static int riscv_openocd_step_impl(struct target *target, int current, - target_addr_t address, int handle_breakpoints, int handle_callbacks) +static int riscv_openocd_step_impl(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, int handle_callbacks) { LOG_TARGET_DEBUG(target, "stepping hart"); @@ -3781,19 +4222,24 @@ static int riscv_openocd_step_impl(struct target *target, int current, return ERROR_FAIL; } - riscv_reg_t trigger_state[RISCV_MAX_HWBPS] = {0}; - if (disable_triggers(target, trigger_state) != ERROR_OK) + if (riscv_enumerate_triggers(target) != ERROR_OK) + return ERROR_FAIL; + + RISCV_INFO(r); + bool *wps_to_enable = calloc(r->trigger_count, sizeof(*wps_to_enable)); + if (disable_watchpoints(target, wps_to_enable) != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to temporarily disable " + "watchpoints before single-step."); return ERROR_FAIL; + } bool success = true; - uint64_t current_mstatus; + riscv_reg_t current_mstatus; RISCV_INFO(info); if (info->isrmask_mode == RISCV_ISRMASK_STEPONLY) { /* Disable Interrupts before stepping. */ - uint64_t irq_disabled_mask = MSTATUS_MIE | MSTATUS_HIE | MSTATUS_SIE | MSTATUS_UIE; - if (riscv_interrupts_disable(target, irq_disabled_mask, - ¤t_mstatus) != ERROR_OK) { + if (riscv_interrupts_disable(target, ¤t_mstatus) != ERROR_OK) { success = false; LOG_TARGET_ERROR(target, "Unable to disable interrupts."); goto _exit; @@ -3805,7 +4251,15 @@ static int riscv_openocd_step_impl(struct target *target, int current, LOG_TARGET_ERROR(target, "Unable to step rtos hart."); } - register_cache_invalidate(target->reg_cache); + if (riscv_reg_cache_any_dirty(target, LOG_LVL_ERROR)) { + /* If this happens, it means there is a bug in the previous + * register-flushing algorithm: not all registers were flushed + * back to the target prior to single-step. */ + LOG_TARGET_ERROR(target, + "BUG: registers should have been flushed by this point."); + } + + riscv_reg_cache_invalidate_all(target); if (info->isrmask_mode == RISCV_ISRMASK_STEPONLY) if (riscv_interrupts_restore(target, current_mstatus) != ERROR_OK) { @@ -3814,9 +4268,10 @@ static int riscv_openocd_step_impl(struct target *target, int current, } _exit: - if (enable_triggers(target, trigger_state) != ERROR_OK) { + if (enable_watchpoints(target, wps_to_enable) != ERROR_OK) { success = false; - LOG_TARGET_ERROR(target, "Unable to enable triggers."); + LOG_TARGET_ERROR(target, "Failed to re-enable watchpoints " + "after single-step."); } if (breakpoint && (riscv_add_breakpoint(target, breakpoint) != ERROR_OK)) { @@ -3838,8 +4293,8 @@ _exit: return success ? ERROR_OK : ERROR_FAIL; } -int riscv_openocd_step(struct target *target, int current, - target_addr_t address, int handle_breakpoints) +int riscv_openocd_step(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints) { return riscv_openocd_step_impl(target, current, address, handle_breakpoints, true /* handle_callbacks */); @@ -3848,10 +4303,9 @@ int riscv_openocd_step(struct target *target, int current, /* Command Handlers */ COMMAND_HANDLER(riscv_set_command_timeout_sec) { - if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 parameter."); + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - } + int timeout = atoi(CMD_ARGV[0]); if (timeout <= 0) { LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]); @@ -3866,10 +4320,9 @@ COMMAND_HANDLER(riscv_set_command_timeout_sec) COMMAND_HANDLER(riscv_set_reset_timeout_sec) { LOG_WARNING("The command 'riscv set_reset_timeout_sec' is deprecated! Please, use 'riscv set_command_timeout_sec'."); - if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 parameter."); + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - } + int timeout = atoi(CMD_ARGV[0]); if (timeout <= 0) { LOG_ERROR("%s is not a valid integer argument for command.", CMD_ARGV[0]); @@ -3888,9 +4341,10 @@ COMMAND_HANDLER(riscv_set_mem_access) int sysbus_cnt = 0; int abstract_cnt = 0; - if (CMD_ARGC < 1 || CMD_ARGC > RISCV_NUM_MEM_ACCESS_METHODS) { - LOG_ERROR("Command takes 1 to %d parameters", RISCV_NUM_MEM_ACCESS_METHODS); - return ERROR_COMMAND_SYNTAX_ERROR; + if (CMD_ARGC < 1 || CMD_ARGC > RISCV_MEM_ACCESS_MAX_METHODS_NUM) { + command_print(CMD, "Command takes 1 to %d parameters", + RISCV_MEM_ACCESS_MAX_METHODS_NUM); + return ERROR_COMMAND_ARGUMENT_INVALID; } /* Check argument validity */ @@ -3913,8 +4367,7 @@ COMMAND_HANDLER(riscv_set_mem_access) } /* Args are valid, store them */ - for (unsigned int i = 0; i < RISCV_NUM_MEM_ACCESS_METHODS; i++) - r->mem_access_methods[i] = RISCV_MEM_ACCESS_UNSPECIFIED; + r->num_enabled_mem_access_methods = CMD_ARGC; for (unsigned int i = 0; i < CMD_ARGC; i++) { if (strcmp("progbuf", CMD_ARGV[i]) == 0) r->mem_access_methods[i] = RISCV_MEM_ACCESS_PROGBUF; @@ -3925,91 +4378,106 @@ COMMAND_HANDLER(riscv_set_mem_access) } /* Reset warning flags */ - r->mem_access_progbuf_warn = true; - r->mem_access_sysbus_warn = true; - r->mem_access_abstract_warn = true; + for (size_t i = 0; i < RISCV_MEM_ACCESS_MAX_METHODS_NUM; ++i) + r->mem_access_warn[i] = true; return ERROR_OK; } -COMMAND_HANDLER(riscv_set_enable_virtual) -{ - if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 parameter"); - return ERROR_COMMAND_SYNTAX_ERROR; - } - COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_enable_virtual); - return ERROR_OK; -} -static int parse_ranges(struct list_head *ranges, const char *tcl_arg, const char *reg_type, unsigned int max_val) +static bool parse_csr_address(const char *reg_address_str, unsigned int *reg_addr) { - char *args = strdup(tcl_arg); - if (!args) - return ERROR_FAIL; + *reg_addr = -1; + /* skip initial spaces */ + while (isspace(reg_address_str[0])) + ++reg_address_str; + /* try to detect if string starts with 0x or 0X */ + bool is_hex_address = strncmp(reg_address_str, "0x", 2) == 0 || + strncmp(reg_address_str, "0X", 2) == 0; - /* For backward compatibility, allow multiple parameters within one TCL argument, separated by ',' */ - char *arg = strtok(args, ","); - while (arg) { - unsigned low = 0; - unsigned high = 0; + unsigned int scanned_chars; + if (is_hex_address) { + reg_address_str += 2; + if (sscanf(reg_address_str, "%x%n", reg_addr, &scanned_chars) != 1) + return false; + } else { + /* If we are here and register address string starts with zero, this is + * an indication that most likely user has an incorrect input because: + * - decimal numbers typically do not start with "0" + * - octals are not supported by our interface + * - hexadecimal numbers should have "0x" prefix + * Thus such input is rejected. */ + if (reg_address_str[0] == '0' && strlen(reg_address_str) > 1) + return false; + if (sscanf(reg_address_str, "%u%n", reg_addr, &scanned_chars) != 1) + return false; + } + return scanned_chars == strlen(reg_address_str); +} + +static int parse_reg_ranges_impl(struct list_head *ranges, char *args, + const char *reg_type, unsigned int max_val, char ** const name_buffer) +{ + /* For backward compatibility, allow multiple parameters within one TCL + * argument, separated by ',' */ + for (char *arg = strtok(args, ","); arg; arg = strtok(NULL, ",")) { + unsigned int low = 0; + unsigned int high = 0; char *name = NULL; char *dash = strchr(arg, '-'); char *equals = strchr(arg, '='); - unsigned int pos; if (!dash && !equals) { /* Expecting single register number. */ - if (sscanf(arg, "%u%n", &low, &pos) != 1 || pos != strlen(arg)) { + if (!parse_csr_address(arg, &low)) { LOG_ERROR("Failed to parse single register number from '%s'.", arg); - free(args); return ERROR_COMMAND_SYNTAX_ERROR; } } else if (dash && !equals) { /* Expecting register range - two numbers separated by a dash: ##-## */ - *dash = 0; - dash++; - if (sscanf(arg, "%u%n", &low, &pos) != 1 || pos != strlen(arg)) { - LOG_ERROR("Failed to parse single register number from '%s'.", arg); - free(args); + *dash = '\0'; + if (!parse_csr_address(arg, &low)) { + LOG_ERROR("Failed to parse '%s' - not a valid decimal or hexadecimal number.", + arg); return ERROR_COMMAND_SYNTAX_ERROR; } - if (sscanf(dash, "%u%n", &high, &pos) != 1 || pos != strlen(dash)) { - LOG_ERROR("Failed to parse single register number from '%s'.", dash); - free(args); + const char *high_num_in = dash + 1; + if (!parse_csr_address(high_num_in, &high)) { + LOG_ERROR("Failed to parse '%s' - not a valid decimal or hexadecimal number.", + high_num_in); return ERROR_COMMAND_SYNTAX_ERROR; } if (high < low) { LOG_ERROR("Incorrect range encountered [%u, %u].", low, high); - free(args); return ERROR_FAIL; } } else if (!dash && equals) { /* Expecting single register number with textual name specified: ##=name */ - *equals = 0; - equals++; - if (sscanf(arg, "%u%n", &low, &pos) != 1 || pos != strlen(arg)) { - LOG_ERROR("Failed to parse single register number from '%s'.", arg); - free(args); + *equals = '\0'; + if (!parse_csr_address(arg, &low)) { + LOG_ERROR("Failed to parse '%s' - not a valid decimal or hexadecimal number.", + arg); return ERROR_COMMAND_SYNTAX_ERROR; } - name = calloc(1, strlen(equals) + strlen(reg_type) + 2); + const char * const reg_name_in = equals + 1; + const size_t reg_type_len = strlen(reg_type); + /* format is: <reg_type>_<reg_name_in>\0 */ + *name_buffer = calloc(1, strlen(reg_name_in) + reg_type_len + 2); + name = *name_buffer; if (!name) { - LOG_ERROR("Failed to allocate register name."); - free(args); + LOG_ERROR("Out of memory"); return ERROR_FAIL; } - - /* Register prefix: "csr_" or "custom_" */ strcpy(name, reg_type); - name[strlen(reg_type)] = '_'; + name[reg_type_len] = '_'; - if (sscanf(equals, "%[_a-zA-Z0-9]%n", name + strlen(reg_type) + 1, &pos) != 1 || pos != strlen(equals)) { - LOG_ERROR("Failed to parse register name from '%s'.", equals); - free(args); - free(name); + unsigned int scanned_chars; + char *scan_dst = name + strlen(reg_type) + 1; + if (sscanf(reg_name_in, "%[_a-zA-Z0-9]%n", scan_dst, &scanned_chars) != 1 || + scanned_chars != strlen(reg_name_in)) { + LOG_ERROR("Invalid characters in register name '%s'.", reg_name_in); return ERROR_COMMAND_SYNTAX_ERROR; } } else { @@ -4018,12 +4486,11 @@ static int parse_ranges(struct list_head *ranges, const char *tcl_arg, const cha return ERROR_COMMAND_SYNTAX_ERROR; } - high = high > low ? high : low; + high = MAX(high, low); if (high > max_val) { - LOG_ERROR("Cannot expose %s register number %u, maximum allowed value is %u.", reg_type, high, max_val); - free(name); - free(args); + LOG_ERROR("Cannot expose %s register number 0x%x, maximum allowed value is 0x%x.", + reg_type, high, max_val); return ERROR_FAIL; } @@ -4041,45 +4508,53 @@ static int parse_ranges(struct list_head *ranges, const char *tcl_arg, const cha if (entry->name && name && (strcasecmp(entry->name, name) == 0)) { LOG_ERROR("Duplicate register name \"%s\" found.", name); - free(name); - free(args); return ERROR_FAIL; } } range_list_t *range = calloc(1, sizeof(range_list_t)); if (!range) { - LOG_ERROR("Failed to allocate range list."); - free(name); - free(args); + LOG_ERROR("Out of memory"); return ERROR_FAIL; } range->low = low; range->high = high; range->name = name; + /* ownership over name_buffer contents is transferred to list item here */ + *name_buffer = NULL; list_add(&range->list, ranges); - - arg = strtok(NULL, ","); } - free(args); return ERROR_OK; } +static int parse_reg_ranges(struct list_head *ranges, const char *tcl_arg, + const char *reg_type, unsigned int max_val) +{ + char *args = strdup(tcl_arg); + if (!args) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + char *name_buffer = NULL; + int result = parse_reg_ranges_impl(ranges, args, reg_type, max_val, &name_buffer); + free(name_buffer); + free(args); + return result; +} + COMMAND_HANDLER(riscv_set_expose_csrs) { - if (CMD_ARGC == 0) { - LOG_ERROR("Command expects parameters."); + if (CMD_ARGC == 0) return ERROR_COMMAND_SYNTAX_ERROR; - } struct target *target = get_current_target(CMD_CTX); RISCV_INFO(info); int ret = ERROR_OK; for (unsigned int i = 0; i < CMD_ARGC; i++) { - ret = parse_ranges(&info->expose_csr, CMD_ARGV[i], "csr", 0xfff); + ret = parse_reg_ranges(&info->expose_csr, CMD_ARGV[i], "csr", 0xfff); if (ret != ERROR_OK) break; } @@ -4089,17 +4564,15 @@ COMMAND_HANDLER(riscv_set_expose_csrs) COMMAND_HANDLER(riscv_set_expose_custom) { - if (CMD_ARGC == 0) { - LOG_ERROR("Command expects parameters."); + if (CMD_ARGC == 0) return ERROR_COMMAND_SYNTAX_ERROR; - } struct target *target = get_current_target(CMD_CTX); RISCV_INFO(info); int ret = ERROR_OK; for (unsigned int i = 0; i < CMD_ARGC; i++) { - ret = parse_ranges(&info->expose_custom, CMD_ARGV[i], "custom", 0x3fff); + ret = parse_reg_ranges(&info->expose_custom, CMD_ARGV[i], "custom", 0x3fff); if (ret != ERROR_OK) break; } @@ -4109,17 +4582,15 @@ COMMAND_HANDLER(riscv_set_expose_custom) COMMAND_HANDLER(riscv_hide_csrs) { - if (CMD_ARGC == 0) { - LOG_ERROR("Command expects parameters"); + if (CMD_ARGC == 0) return ERROR_COMMAND_SYNTAX_ERROR; - } struct target *target = get_current_target(CMD_CTX); RISCV_INFO(info); int ret = ERROR_OK; for (unsigned int i = 0; i < CMD_ARGC; i++) { - ret = parse_ranges(&info->hide_csr, CMD_ARGV[i], "csr", 0xfff); + ret = parse_reg_ranges(&info->hide_csr, CMD_ARGV[i], "csr", 0xfff); if (ret != ERROR_OK) break; } @@ -4130,14 +4601,10 @@ COMMAND_HANDLER(riscv_hide_csrs) COMMAND_HANDLER(riscv_authdata_read) { unsigned int index = 0; - if (CMD_ARGC == 0) { - /* nop */ - } else if (CMD_ARGC == 1) { + if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], index); - } else { - LOG_ERROR("Command takes at most one parameter."); + else if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; - } struct target *target = get_current_target(CMD_CTX); if (!target) { @@ -4341,10 +4808,8 @@ COMMAND_HANDLER(riscv_reset_delays) COMMAND_HANDLER(riscv_set_ir) { - if (CMD_ARGC != 2) { - LOG_ERROR("Command takes exactly 2 arguments"); + if (CMD_ARGC != 2) return ERROR_COMMAND_SYNTAX_ERROR; - } uint32_t value; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); @@ -4363,10 +4828,8 @@ COMMAND_HANDLER(riscv_set_ir) COMMAND_HANDLER(riscv_resume_order) { - if (CMD_ARGC > 1) { - LOG_ERROR("Command takes at most one argument"); + if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; - } if (!strcmp(CMD_ARGV[0], "normal")) { resume_order = RO_NORMAL; @@ -4382,18 +4845,23 @@ COMMAND_HANDLER(riscv_resume_order) COMMAND_HANDLER(riscv_use_bscan_tunnel) { - int irwidth = 0; + uint8_t irwidth = 0; int tunnel_type = BSCAN_TUNNEL_NESTED_TAP; - if (CMD_ARGC > 2) { - LOG_ERROR("Command takes at most two arguments"); + if (CMD_ARGC < 1 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; - } else if (CMD_ARGC == 1) { - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], irwidth); - } else if (CMD_ARGC == 2) { - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], irwidth); - COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tunnel_type); + + if (CMD_ARGC >= 1) { + COMMAND_PARSE_NUMBER(u8, CMD_ARGV[0], irwidth); + assert(BSCAN_TUNNEL_IR_WIDTH_NBITS < 8); + if (irwidth >= (uint8_t)1 << BSCAN_TUNNEL_IR_WIDTH_NBITS) { + command_print(CMD, "'value' does not fit into %d bits.", + BSCAN_TUNNEL_IR_WIDTH_NBITS); + return ERROR_COMMAND_ARGUMENT_OVERFLOW; + } } + if (CMD_ARGC == 2) + COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], tunnel_type); if (tunnel_type == BSCAN_TUNNEL_NESTED_TAP) LOG_INFO("Nested Tap based Bscan Tunnel Selected"); else if (tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) @@ -4410,12 +4878,11 @@ COMMAND_HANDLER(riscv_set_bscan_tunnel_ir) { int ir_id = 0; - if (CMD_ARGC > 1) { - LOG_ERROR("Command takes at most one arguments"); + if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; - } else if (CMD_ARGC == 1) { + + if (CMD_ARGC == 1) COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], ir_id); - } LOG_INFO("Bscan tunnel IR 0x%x selected", ir_id); @@ -4448,74 +4915,93 @@ COMMAND_HANDLER(riscv_set_maskisr) return ERROR_OK; } -COMMAND_HANDLER(riscv_set_enable_virt2phys) -{ - if (CMD_ARGC != 1) { - LOG_ERROR("Command takes exactly 1 parameter"); - return ERROR_COMMAND_SYNTAX_ERROR; - } - COMMAND_PARSE_ON_OFF(CMD_ARGV[0], riscv_enable_virt2phys); - return ERROR_OK; -} - -COMMAND_HANDLER(riscv_set_ebreakm) +COMMAND_HANDLER(riscv_set_autofence) { struct target *target = get_current_target(CMD_CTX); RISCV_INFO(r); if (CMD_ARGC == 0) { - command_print(CMD, "riscv_ebreakm enabled: %s", r->riscv_ebreakm ? "on" : "off"); + command_print(CMD, "autofence: %s", r->autofence ? "on" : "off"); return ERROR_OK; } else if (CMD_ARGC == 1) { - COMMAND_PARSE_ON_OFF(CMD_ARGV[0], r->riscv_ebreakm); + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], r->autofence); return ERROR_OK; } - LOG_ERROR("Command takes 0 or 1 parameters"); return ERROR_COMMAND_SYNTAX_ERROR; } -COMMAND_HANDLER(riscv_set_ebreaks) +COMMAND_HELPER(ebreakx_deprecation_helper, enum riscv_priv_mode mode) { - struct target *target = get_current_target(CMD_CTX); - RISCV_INFO(r); - + struct target * const target = get_current_target(CMD_CTX); + struct riscv_private_config * const config = riscv_private_config(target); + const char *mode_str; + switch (mode) { + case RISCV_MODE_M: + mode_str = "m"; + break; + case RISCV_MODE_S: + mode_str = "s"; + break; + case RISCV_MODE_U: + mode_str = "u"; + break; + default: + assert(0 && "Unexpected execution mode"); + mode_str = "unexpected"; + } + if (CMD_ARGC > 1) + return ERROR_COMMAND_SYNTAX_ERROR; if (CMD_ARGC == 0) { - command_print(CMD, "riscv_ebreaks enabled: %s", r->riscv_ebreaks ? "on" : "off"); - return ERROR_OK; - } else if (CMD_ARGC == 1) { - COMMAND_PARSE_ON_OFF(CMD_ARGV[0], r->riscv_ebreaks); + LOG_WARNING("DEPRECATED! use '%s cget -ebreak' not '%s'", + target_name(target), CMD_NAME); + command_print(CMD, "riscv_ebreak%s enabled: %s", mode_str, + config->dcsr_ebreak_fields[mode] ? "on" : "off"); return ERROR_OK; } - - LOG_ERROR("Command takes 0 or 1 parameters"); - return ERROR_COMMAND_SYNTAX_ERROR; + assert(CMD_ARGC == 1); + command_print(CMD, "DEPRECATED! use '%s configure -ebreak %s' not '%s'", + target_name(target), mode_str, CMD_NAME); + bool ebreak_ctl; + COMMAND_PARSE_ON_OFF(CMD_ARGV[0], ebreak_ctl); + config->dcsr_ebreak_fields[mode] = ebreak_ctl; + switch (mode) { + case RISCV_MODE_S: + config->dcsr_ebreak_fields[RISCV_MODE_VS] = ebreak_ctl; + break; + case RISCV_MODE_U: + config->dcsr_ebreak_fields[RISCV_MODE_VU] = ebreak_ctl; + break; + default: + break; + } + return ERROR_OK; } -COMMAND_HANDLER(riscv_set_ebreaku) +COMMAND_HANDLER(riscv_set_ebreakm) { - struct target *target = get_current_target(CMD_CTX); - RISCV_INFO(r); + return CALL_COMMAND_HANDLER(ebreakx_deprecation_helper, + RISCV_MODE_M); +} - if (CMD_ARGC == 0) { - command_print(CMD, "riscv_ebreaku enabled: %s", r->riscv_ebreaku ? "on" : "off"); - return ERROR_OK; - } else if (CMD_ARGC == 1) { - COMMAND_PARSE_ON_OFF(CMD_ARGV[0], r->riscv_ebreaku); - return ERROR_OK; - } +COMMAND_HANDLER(riscv_set_ebreaks) +{ + return CALL_COMMAND_HANDLER(ebreakx_deprecation_helper, + RISCV_MODE_S); +} - LOG_ERROR("Command takes 0 or 1 parameters"); - return ERROR_COMMAND_SYNTAX_ERROR; +COMMAND_HANDLER(riscv_set_ebreaku) +{ + return CALL_COMMAND_HANDLER(ebreakx_deprecation_helper, + RISCV_MODE_U); } COMMAND_HELPER(riscv_clear_trigger, int trigger_id, const char *name) { struct target *target = get_current_target(CMD_CTX); - if (CMD_ARGC != 1) { - LOG_ERROR("clear command takes no extra arguments."); + if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - } + if (find_first_trigger_by_id(target, trigger_id) < 0) { LOG_TARGET_ERROR(target, "No %s is set. Nothing to clear.", name); return ERROR_FAIL; @@ -4525,10 +5011,8 @@ COMMAND_HELPER(riscv_clear_trigger, int trigger_id, const char *name) COMMAND_HANDLER(riscv_itrigger) { - if (CMD_ARGC < 1) { - LOG_ERROR("Command takes at least 1 parameter"); + if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; - } struct target *target = get_current_target(CMD_CTX); const int ITRIGGER_UNIQUE_ID = -CSR_TDATA1_TYPE_ITRIGGER; @@ -4592,10 +5076,8 @@ COMMAND_HANDLER(riscv_itrigger) COMMAND_HANDLER(riscv_icount) { - if (CMD_ARGC < 1) { - LOG_ERROR("Command takes at least 1 parameter"); + if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; - } struct target *target = get_current_target(CMD_CTX); const int ICOUNT_UNIQUE_ID = -CSR_TDATA1_TYPE_ICOUNT; @@ -4659,10 +5141,8 @@ COMMAND_HANDLER(riscv_icount) COMMAND_HANDLER(riscv_etrigger) { - if (CMD_ARGC < 1) { - LOG_ERROR("Command takes at least 1 parameter"); + if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; - } struct target *target = get_current_target(CMD_CTX); const int ETRIGGER_UNIQUE_ID = -CSR_TDATA1_TYPE_ETRIGGER; @@ -4726,14 +5206,8 @@ COMMAND_HANDLER(handle_repeat_read) struct target *target = get_current_target(CMD_CTX); RISCV_INFO(r); - if (CMD_ARGC < 2) { - LOG_ERROR("Command requires at least count and address arguments."); + if (CMD_ARGC < 2 || CMD_ARGC > 3) return ERROR_COMMAND_SYNTAX_ERROR; - } - if (CMD_ARGC > 3) { - LOG_ERROR("Command takes at most 3 arguments."); - return ERROR_COMMAND_SYNTAX_ERROR; - } uint32_t count; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], count); @@ -4751,7 +5225,14 @@ COMMAND_HANDLER(handle_repeat_read) LOG_ERROR("malloc failed"); return ERROR_FAIL; } - int result = r->read_memory(target, address, size, count, buffer, 0); + const riscv_mem_access_args_t args = { + .address = address, + .read_buffer = buffer, + .size = size, + .count = count, + .increment = 0, + }; + int result = r->access_memory(target, args); if (result == ERROR_OK) { target_handle_md_output(cmd, target, address, size, count, buffer, false); @@ -4779,10 +5260,8 @@ COMMAND_HANDLER(handle_memory_sample_command) return ERROR_OK; } - if (CMD_ARGC < 2) { - LOG_ERROR("Command requires at least bucket and address arguments."); + if (CMD_ARGC < 2) return ERROR_COMMAND_SYNTAX_ERROR; - } uint32_t bucket; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], bucket); @@ -4828,10 +5307,9 @@ COMMAND_HANDLER(handle_dump_sample_buf_command) struct target *target = get_current_target(CMD_CTX); RISCV_INFO(r); - if (CMD_ARGC > 1) { - LOG_ERROR("Command takes at most 1 arguments."); + if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; - } + bool base64 = false; if (CMD_ARGC > 0) { if (!strcmp(CMD_ARGV[0], "base64")) { @@ -4937,10 +5415,8 @@ COMMAND_HANDLER(handle_info) COMMAND_HANDLER(riscv_exec_progbuf) { - if (CMD_ARGC < 1 || CMD_ARGC > 16) { - LOG_ERROR("Command 'exec_progbuf' takes 1 to 16 arguments."); + if (CMD_ARGC < 1 || CMD_ARGC > 16) return ERROR_COMMAND_SYNTAX_ERROR; - } struct target *target = get_current_target(CMD_CTX); @@ -4976,7 +5452,7 @@ COMMAND_HANDLER(riscv_exec_progbuf) if (riscv_reg_flush_all(target) != ERROR_OK) return ERROR_FAIL; int error = riscv_program_exec(&prog, target); - riscv_invalidate_register_cache(target); + riscv_reg_cache_invalidate_all(target); if (error != ERROR_OK) { LOG_TARGET_ERROR(target, "exec_progbuf: Program buffer execution failed."); @@ -5031,6 +5507,87 @@ COMMAND_HANDLER(riscv_set_enable_trigger_feature) return ERROR_OK; } +static COMMAND_HELPER(report_reserved_triggers, struct target *target) +{ + RISCV_INFO(r); + if (riscv_enumerate_triggers(target) != ERROR_OK) + return ERROR_FAIL; + const char *separator = ""; + for (riscv_reg_t t = 0; t < r->trigger_count; ++t) { + if (r->reserved_triggers[t]) { + command_print_sameline(CMD, "%s%" PRIu64, separator, t); + separator = " "; + } + } + command_print_sameline(CMD, "\n"); + return ERROR_OK; +} + +COMMAND_HANDLER(handle_reserve_trigger) +{ + struct target *target = get_current_target(CMD_CTX); + if (CMD_ARGC == 0) + return CALL_COMMAND_HANDLER(report_reserved_triggers, target); + + if (CMD_ARGC != 2) + return ERROR_COMMAND_SYNTAX_ERROR; + + riscv_reg_t t; + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], t); + + if (riscv_enumerate_triggers(target) != ERROR_OK) + return ERROR_FAIL; + RISCV_INFO(r); + if (r->trigger_count == 0) { + command_print(CMD, "Error: There are no triggers on the target."); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + if (t >= r->trigger_count) { + command_print(CMD, "Error: trigger with index %" PRIu64 + " does not exist. There are only %u triggers" + " on the target (with indexes 0 .. %u).", + t, r->trigger_count, r->trigger_count - 1); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + if (r->trigger_unique_id[t] != -1) { + command_print(CMD, "Error: trigger with index %" PRIu64 + " is already in use and can not be reserved.", t); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + COMMAND_PARSE_ON_OFF(CMD_ARGV[1], r->reserved_triggers[t]); + return ERROR_OK; +} + +COMMAND_HANDLER(handle_riscv_virt2phys_mode) +{ + struct riscv_info *info = riscv_info(get_current_target(CMD_CTX)); + if (CMD_ARGC == 0) { + riscv_virt2phys_mode_t mode = info->virt2phys_mode; + command_print(CMD, "%s", riscv_virt2phys_mode_to_str(mode)); + return ERROR_OK; + } + + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + // TODO: add auto mode to allow OpenOCD choose translation mode + if (!strcmp(CMD_ARGV[0], + riscv_virt2phys_mode_to_str(RISCV_VIRT2PHYS_MODE_SW))) { + info->virt2phys_mode = RISCV_VIRT2PHYS_MODE_SW; + } else if (!strcmp(CMD_ARGV[0], + riscv_virt2phys_mode_to_str(RISCV_VIRT2PHYS_MODE_HW))) { + info->virt2phys_mode = RISCV_VIRT2PHYS_MODE_HW; + } else if (!strcmp(CMD_ARGV[0], + riscv_virt2phys_mode_to_str(RISCV_VIRT2PHYS_MODE_OFF))) { + info->virt2phys_mode = RISCV_VIRT2PHYS_MODE_OFF; + } else { + command_print(CMD, "Unsupported address translation mode: %s", CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; + } + + return ERROR_OK; +} + static const struct command_registration riscv_exec_command_handlers[] = { { .name = "dump_sample_buf", @@ -5064,14 +5621,14 @@ static const struct command_registration riscv_exec_command_handlers[] = { .name = "set_command_timeout_sec", .handler = riscv_set_command_timeout_sec, .mode = COMMAND_ANY, - .usage = "[sec]", + .usage = "sec", .help = "Set the wall-clock timeout (in seconds) for individual commands" }, { .name = "set_reset_timeout_sec", .handler = riscv_set_reset_timeout_sec, .mode = COMMAND_ANY, - .usage = "[sec]", + .usage = "sec", .help = "DEPRECATED. Use 'riscv set_command_timeout_sec' instead." }, { @@ -5083,19 +5640,10 @@ static const struct command_registration riscv_exec_command_handlers[] = { "of priority. Method can be one of: 'progbuf', 'sysbus' or 'abstract'." }, { - .name = "set_enable_virtual", - .handler = riscv_set_enable_virtual, - .mode = COMMAND_ANY, - .usage = "on|off", - .help = "When on, memory accesses are performed on physical or virtual " - "memory depending on the current system configuration. " - "When off (default), all memory accessses are performed on physical memory." - }, - { .name = "expose_csrs", .handler = riscv_set_expose_csrs, .mode = COMMAND_CONFIG, - .usage = "n0[-m0|=name0][,n1[-m1|=name1]]...", + .usage = "n0[-m0|=name0][,n1[-m1|=name1]]...[,n15[-m15|=name15]]", .help = "Configure a list of inclusive ranges for CSRs to expose in " "addition to the standard ones. This must be executed before " "`init`." @@ -5104,7 +5652,7 @@ static const struct command_registration riscv_exec_command_handlers[] = { .name = "expose_custom", .handler = riscv_set_expose_custom, .mode = COMMAND_CONFIG, - .usage = "n0[-m0|=name0][,n1[-m1|=name1]]...", + .usage = "n0[-m0|=name0][,n1[-m1|=name1]]...[,n15[-m15|=name15]]", .help = "Configure a list of inclusive ranges for custom registers to " "expose. custom0 is accessed as abstract register number 0xc000, " "etc. This must be executed before `init`." @@ -5189,25 +5737,21 @@ static const struct command_registration riscv_exec_command_handlers[] = { .name = "set_ir", .handler = riscv_set_ir, .mode = COMMAND_ANY, - .usage = "[idcode|dtmcs|dmi] value", + .usage = "idcode|dtmcs|dmi value", .help = "Set IR value for specified JTAG register." }, { .name = "use_bscan_tunnel", .handler = riscv_use_bscan_tunnel, - .mode = COMMAND_ANY, + .mode = COMMAND_CONFIG, .usage = "value [type]", - .help = "Enable or disable use of a BSCAN tunnel to reach DM. Supply " - "the width of the DM transport TAP's instruction register to " - "enable. Supply a value of 0 to disable. Pass A second argument " - "(optional) to indicate Bscan Tunnel Type {0:(default) NESTED_TAP , " - "1: DATA_REGISTER}" + .help = "Enable or disable use of a BSCAN tunnel to reach DM." }, { .name = "set_bscan_tunnel_ir", .handler = riscv_set_bscan_tunnel_ir, - .mode = COMMAND_ANY, - .usage = "value", + .mode = COMMAND_CONFIG, + .usage = "[value]", .help = "Specify the JTAG TAP IR used to access the bscan tunnel. " "By default it is 0x23 << (ir_length - 6), which map some " "Xilinx FPGA (IR USER4)" @@ -5220,36 +5764,28 @@ static const struct command_registration riscv_exec_command_handlers[] = { .usage = "['off'|'steponly']", }, { - .name = "set_enable_virt2phys", - .handler = riscv_set_enable_virt2phys, - .mode = COMMAND_ANY, - .usage = "on|off", - .help = "When on (default), enable translation from virtual address to " - "physical address." - }, - { .name = "set_ebreakm", .handler = riscv_set_ebreakm, .mode = COMMAND_ANY, .usage = "[on|off]", - .help = "Control dcsr.ebreakm. When off, M-mode ebreak instructions " - "don't trap to OpenOCD. Defaults to on." + .help = "DEPRECATED! use '<target_name> configure -ebreak' or " + "'<target_name> cget -ebreak'" }, { .name = "set_ebreaks", .handler = riscv_set_ebreaks, .mode = COMMAND_ANY, .usage = "[on|off]", - .help = "Control dcsr.ebreaks. When off, S-mode ebreak instructions " - "don't trap to OpenOCD. Defaults to on." + .help = "DEPRECATED! use '<target_name> configure -ebreak' or " + "'<target_name> cget -ebreak'" }, { .name = "set_ebreaku", .handler = riscv_set_ebreaku, .mode = COMMAND_ANY, .usage = "[on|off]", - .help = "Control dcsr.ebreaku. When off, U-mode ebreak instructions " - "don't trap to OpenOCD. Defaults to on." + .help = "DEPRECATED! use '<target_name> configure -ebreak' or " + "'<target_name> cget -ebreak'" }, { .name = "etrigger", @@ -5287,6 +5823,33 @@ static const struct command_registration riscv_exec_command_handlers[] = { .usage = "[('eq'|'napot'|'ge_lt'|'all') ('wp'|'none')]", .help = "Control whether OpenOCD is allowed to use certain RISC-V trigger features for watchpoints." }, + { + .name = "reserve_trigger", + .handler = handle_reserve_trigger, + /* TODO: Move this to COMMAND_ANY */ + .mode = COMMAND_EXEC, + .usage = "[index ('on'|'off')]", + .help = "Controls which RISC-V triggers shall not be touched by OpenOCD.", + }, + { + .name = "virt2phys_mode", + .handler = handle_riscv_virt2phys_mode, + .mode = COMMAND_ANY, + .usage = "['sw'|'hw'|'off']", + .help = "Configure the virtual address translation mode: " + "sw - translate vaddr to paddr by manually traversing page tables, " + "hw - translate vaddr to paddr by hardware, " + "off - no address translation." + }, + { + .name = "autofence", + .handler = riscv_set_autofence, + .mode = COMMAND_ANY, + .usage = "[on|off]", + .help = "When on (default), OpenOCD will automatically execute fence instructions in some situations. " + "When off, users need to take care of memory coherency themselves, for example by using " + "`riscv exec_progbuf` to execute fence or CMO instructions." + }, COMMAND_REGISTRATION_DONE }; @@ -5342,6 +5905,7 @@ struct target_type riscv_target = { .name = "riscv", .target_create = riscv_create_target, + .target_jim_configure = riscv_jim_configure, .init_target = riscv_init_target, .deinit_target = riscv_deinit_target, .examine = riscv_examine, @@ -5403,15 +5967,17 @@ static void riscv_info_init(struct target *target, struct riscv_info *r) r->xlen = -1; + r->virt2phys_mode = RISCV_VIRT2PHYS_MODE_SW; + r->isrmask_mode = RISCV_ISRMASK_OFF; r->mem_access_methods[0] = RISCV_MEM_ACCESS_PROGBUF; r->mem_access_methods[1] = RISCV_MEM_ACCESS_SYSBUS; r->mem_access_methods[2] = RISCV_MEM_ACCESS_ABSTRACT; - r->mem_access_progbuf_warn = true; - r->mem_access_sysbus_warn = true; - r->mem_access_abstract_warn = true; + r->num_enabled_mem_access_methods = RISCV_MEM_ACCESS_MAX_METHODS_NUM; + for (size_t i = 0; i < RISCV_MEM_ACCESS_MAX_METHODS_NUM; ++i) + r->mem_access_warn[i] = true; INIT_LIST_HEAD(&r->expose_csr); INIT_LIST_HEAD(&r->expose_custom); @@ -5419,13 +5985,11 @@ static void riscv_info_init(struct target *target, struct riscv_info *r) r->vsew64_supported = YNM_MAYBE; - r->riscv_ebreakm = true; - r->riscv_ebreaks = true; - r->riscv_ebreaku = true; - r->wp_allow_equality_match_trigger = true; r->wp_allow_ge_lt_trigger = true; r->wp_allow_napot_trigger = true; + + r->autofence = true; } static int riscv_resume_go_all_harts(struct target *target) @@ -5439,55 +6003,38 @@ static int riscv_resume_go_all_harts(struct target *target) } else { LOG_TARGET_DEBUG(target, "Hart requested resume, but was already resumed."); } - - riscv_invalidate_register_cache(target); return ERROR_OK; } -int riscv_interrupts_disable(struct target *target, uint64_t irq_mask, uint64_t *old_mstatus) +static int riscv_interrupts_disable(struct target *target, riscv_reg_t *old_mstatus) { LOG_TARGET_DEBUG(target, "Disabling interrupts."); - struct reg *reg_mstatus = register_get_by_name(target->reg_cache, - "mstatus", true); - if (!reg_mstatus) { - LOG_TARGET_ERROR(target, "Couldn't find mstatus!"); - return ERROR_FAIL; + riscv_reg_t current_mstatus; + int ret = riscv_reg_get(target, ¤t_mstatus, GDB_REGNO_MSTATUS); + if (ret != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to read mstatus!"); + return ret; } - - int retval = reg_mstatus->type->get(reg_mstatus); - if (retval != ERROR_OK) - return retval; - - RISCV_INFO(info); - uint8_t mstatus_bytes[8] = { 0 }; - uint64_t current_mstatus = buf_get_u64(reg_mstatus->value, 0, reg_mstatus->size); - buf_set_u64(mstatus_bytes, 0, info->xlen, set_field(current_mstatus, - irq_mask, 0)); - - retval = reg_mstatus->type->set(reg_mstatus, mstatus_bytes); - if (retval != ERROR_OK) - return retval; - if (old_mstatus) *old_mstatus = current_mstatus; - - return ERROR_OK; + return riscv_reg_set(target, GDB_REGNO_MSTATUS, current_mstatus & ~mstatus_ie_mask); } -int riscv_interrupts_restore(struct target *target, uint64_t old_mstatus) +static int riscv_interrupts_restore(struct target *target, riscv_reg_t old_mstatus) { LOG_TARGET_DEBUG(target, "Restoring interrupts."); - struct reg *reg_mstatus = register_get_by_name(target->reg_cache, - "mstatus", true); - if (!reg_mstatus) { - LOG_TARGET_ERROR(target, "Couldn't find mstatus!"); - return ERROR_FAIL; + riscv_reg_t current_mstatus; + int ret = riscv_reg_get(target, ¤t_mstatus, GDB_REGNO_MSTATUS); + if (ret != ERROR_OK) { + LOG_TARGET_ERROR(target, "Failed to read mstatus!"); + return ret; } - - RISCV_INFO(info); - uint8_t mstatus_bytes[8]; - buf_set_u64(mstatus_bytes, 0, info->xlen, old_mstatus); - return reg_mstatus->type->set(reg_mstatus, mstatus_bytes); + if ((current_mstatus & mstatus_ie_mask) != 0) { + LOG_TARGET_WARNING(target, "Interrupt enable bits in mstatus changed during single-step."); + LOG_TARGET_WARNING(target, "OpenOCD might have affected the program when it restored the interrupt bits after single-step."); + LOG_TARGET_WARNING(target, "Hint: Use 'riscv set_maskisr off' to prevent OpenOCD from touching mstatus during single-step."); + } + return riscv_reg_set(target, GDB_REGNO_MSTATUS, current_mstatus | (old_mstatus & mstatus_ie_mask)); } static int riscv_step_rtos_hart(struct target *target) @@ -5512,7 +6059,7 @@ static int riscv_step_rtos_hart(struct target *target) bool riscv_supports_extension(const struct target *target, char letter) { RISCV_INFO(r); - unsigned num; + unsigned int num; if (letter >= 'a' && letter <= 'z') num = letter - 'a'; else if (letter >= 'A' && letter <= 'Z') @@ -5522,7 +6069,7 @@ bool riscv_supports_extension(const struct target *target, char letter) return r->misa & BIT(num); } -unsigned riscv_xlen(const struct target *target) +unsigned int riscv_xlen(const struct target *target) { RISCV_INFO(r); return r->xlen; @@ -5534,17 +6081,6 @@ unsigned int riscv_vlenb(const struct target *target) return r->vlenb; } -static void riscv_invalidate_register_cache(struct target *target) -{ - /* Do not invalidate the register cache if it is not yet set up - * (e.g. when the target failed to get examined). */ - if (!target->reg_cache) - return; - - LOG_TARGET_DEBUG(target, "Invalidating register cache."); - register_cache_invalidate(target->reg_cache); -} - int riscv_get_hart_state(struct target *target, enum riscv_hart_state *state) { RISCV_INFO(r); @@ -5562,17 +6098,16 @@ static enum riscv_halt_reason riscv_halt_reason(struct target *target) return r->halt_reason(target); } -size_t riscv_progbuf_size(struct target *target) +unsigned int riscv_progbuf_size(struct target *target) { RISCV_INFO(r); - return r->progbuf_size; + return r->get_progbufsize(target); } -int riscv_write_progbuf(struct target *target, int index, riscv_insn_t insn) +int riscv_write_progbuf(struct target *target, unsigned int index, riscv_insn_t insn) { RISCV_INFO(r); - r->write_progbuf(target, index, insn); - return ERROR_OK; + return r->write_progbuf(target, index, insn); } riscv_insn_t riscv_read_progbuf(struct target *target, int index) @@ -5587,28 +6122,28 @@ int riscv_execute_progbuf(struct target *target, uint32_t *cmderr) return r->execute_progbuf(target, cmderr); } -void riscv_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d) +void riscv_fill_dmi_write(const struct target *target, uint8_t *buf, uint32_t a, uint32_t d) { RISCV_INFO(r); - r->fill_dm_write(target, buf, a, d); + r->fill_dmi_write(target, buf, a, d); } -void riscv_fill_dm_read(struct target *target, char *buf, uint64_t a) +void riscv_fill_dmi_read(const struct target *target, uint8_t *buf, uint32_t a) { RISCV_INFO(r); - r->fill_dm_read(target, buf, a); + r->fill_dmi_read(target, buf, a); } -void riscv_fill_dm_nop(struct target *target, char *buf) +void riscv_fill_dm_nop(const struct target *target, uint8_t *buf) { RISCV_INFO(r); r->fill_dm_nop(target, buf); } -int riscv_get_dmi_scan_length(struct target *target) +unsigned int riscv_get_dmi_address_bits(const struct target *target) { RISCV_INFO(r); - return r->get_dmi_scan_length(target); + return r->get_dmi_address_bits(target); } static int check_if_trigger_exists(struct target *target, unsigned int index) @@ -5711,9 +6246,24 @@ int riscv_enumerate_triggers(struct target *target) "Assuming that triggers are not implemented."); r->triggers_enumerated = true; r->trigger_count = 0; + free(r->reserved_triggers); + r->reserved_triggers = NULL; return ERROR_OK; } + /* Obtaining tinfo.version value once. + * No need to enumerate per-trigger. + * See https://github.com/riscv/riscv-debug-spec/pull/1081. + */ + riscv_reg_t tinfo; + if (riscv_reg_get(target, &tinfo, GDB_REGNO_TINFO) == ERROR_OK) { + r->tinfo_version = get_field(tinfo, CSR_TINFO_VERSION); + LOG_TARGET_DEBUG(target, "Trigger tinfo.version = %d.", r->tinfo_version); + } else { + r->tinfo_version = RISCV_TINFO_VERSION_UNKNOWN; + LOG_TARGET_DEBUG(target, "Trigger tinfo.version is unknown."); + } + unsigned int t = 0; for (; t < ARRAY_SIZE(r->trigger_tinfo); ++t) { result = check_if_trigger_exists(target, t); @@ -5745,14 +6295,16 @@ int riscv_enumerate_triggers(struct target *target) r->triggers_enumerated = true; r->trigger_count = t; LOG_TARGET_INFO(target, "Found %d triggers", r->trigger_count); + free(r->reserved_triggers); + r->reserved_triggers = calloc(t, sizeof(*r->reserved_triggers)); create_wp_trigger_cache(target); return ERROR_OK; } -void riscv_add_bscan_tunneled_scan(struct target *target, const struct scan_field *field, +void riscv_add_bscan_tunneled_scan(struct jtag_tap *tap, const struct scan_field *field, riscv_bscan_tunneled_scan_context_t *ctxt) { - jtag_add_ir_scan(target->tap, &select_user4, TAP_IDLE); + jtag_add_ir_scan(tap, &select_user4, TAP_IDLE); memset(ctxt->tunneled_dr, 0, sizeof(ctxt->tunneled_dr)); if (bscan_tunnel_type == BSCAN_TUNNEL_DATA_REGISTER) { @@ -5785,5 +6337,5 @@ void riscv_add_bscan_tunneled_scan(struct target *target, const struct scan_fiel ctxt->tunneled_dr[3].num_bits = 3; ctxt->tunneled_dr[3].out_value = bscan_zero; } - jtag_add_dr_scan(target->tap, ARRAY_SIZE(ctxt->tunneled_dr), ctxt->tunneled_dr, TAP_IDLE); + jtag_add_dr_scan(tap, ARRAY_SIZE(ctxt->tunneled_dr), ctxt->tunneled_dr, TAP_IDLE); } diff --git a/src/target/riscv/riscv.h b/src/target/riscv/riscv.h index 5b75bf6..082445e 100644 --- a/src/target/riscv/riscv.h +++ b/src/target/riscv/riscv.h @@ -1,7 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0-or-later */ -#ifndef RISCV_H -#define RISCV_H +#ifndef OPENOCD_TARGET_RISCV_RISCV_H +#define OPENOCD_TARGET_RISCV_RISCV_H struct riscv_program; @@ -29,11 +29,12 @@ struct riscv_program; #define RISCV_HGATP_MODE(xlen) ((xlen) == 32 ? HGATP32_MODE : HGATP64_MODE) #define RISCV_HGATP_PPN(xlen) ((xlen) == 32 ? HGATP32_PPN : HGATP64_PPN) #define RISCV_PGSHIFT 12 +#define RISCV_PGSIZE BIT(RISCV_PGSHIFT) +#define RISCV_PGBASE(addr) ((addr) & ~(RISCV_PGSIZE - 1)) +#define RISCV_PGOFFSET(addr) ((addr) & (RISCV_PGSIZE - 1)) #define PG_MAX_LEVEL 5 -#define RISCV_NUM_MEM_ACCESS_METHODS 3 - #define RISCV_BATCH_ALLOC_SIZE 128 extern struct target_type riscv011_target; @@ -52,12 +53,20 @@ typedef enum { YNM_NO } yes_no_maybe_t; -enum riscv_mem_access_method { - RISCV_MEM_ACCESS_UNSPECIFIED, +typedef enum riscv_mem_access_method { RISCV_MEM_ACCESS_PROGBUF, RISCV_MEM_ACCESS_SYSBUS, - RISCV_MEM_ACCESS_ABSTRACT -}; + RISCV_MEM_ACCESS_ABSTRACT, + RISCV_MEM_ACCESS_MAX_METHODS_NUM +} riscv_mem_access_method_t; + +typedef enum riscv_virt2phys_mode { + RISCV_VIRT2PHYS_MODE_HW, + RISCV_VIRT2PHYS_MODE_SW, + RISCV_VIRT2PHYS_MODE_OFF +} riscv_virt2phys_mode_t; + +const char *riscv_virt2phys_mode_to_str(riscv_virt2phys_mode_t mode); enum riscv_halt_reason { RISCV_HALT_INTERRUPT, @@ -114,12 +123,48 @@ typedef struct { } range_list_t; #define DTM_DTMCS_VERSION_UNKNOWN ((unsigned int)-1) +#define RISCV_TINFO_VERSION_UNKNOWN (-1) + +#define RISCV013_DTMCS_ABITS_MIN 7 +#define RISCV013_DTMCS_ABITS_MAX 32 struct reg_name_table { unsigned int num_entries; char **reg_names; }; +typedef struct riscv_mem_access_args { + target_addr_t address; + + const uint8_t *write_buffer; + uint8_t *read_buffer; + + uint32_t size; + uint32_t count; + uint32_t increment; +} riscv_mem_access_args_t; + +static inline bool +riscv_mem_access_is_valid(const riscv_mem_access_args_t args) +{ + return !args.read_buffer != !args.write_buffer; +} + +static inline bool +riscv_mem_access_is_read(const riscv_mem_access_args_t args) +{ + assert(riscv_mem_access_is_valid(args)); + return !args.write_buffer && args.read_buffer; +} + +static inline bool +riscv_mem_access_is_write(const riscv_mem_access_args_t args) +{ + assert(riscv_mem_access_is_valid(args)); + return !args.read_buffer && args.write_buffer; +} + + struct riscv_info { unsigned int common_magic; @@ -133,15 +178,14 @@ struct riscv_info { /* It's possible that each core has a different supported ISA set. */ int xlen; + /* TODO: use the value from the register cache instead. */ riscv_reg_t misa; - /* Cached value of vlenb. 0 indicates there is no vector support. + /* TODO: use the value from the register cache instead. + * Cached value of vlenb. 0 indicates there is no vector support. * Note that you can have vector support without misa.V set, because * Zve* extensions implement vector registers without setting misa.V. */ unsigned int vlenb; - bool mtopi_readable; - bool mtopei_readable; - /* The number of triggers per hart. */ unsigned int trigger_count; @@ -154,6 +198,17 @@ struct riscv_info { /* record the tinfo of each trigger */ unsigned int trigger_tinfo[RISCV_MAX_TRIGGERS]; + /* Version of the implemented Sdtrig extension */ + int tinfo_version; + + /* Record if single-step is needed prior to resuming + * from a software breakpoint or trigger. + * Single-step is needed if the instruction that + * caused the halt was not retired. That is, + * when we halted "before" that instruction. + */ + bool need_single_step; + /* For each physical trigger contains: * -1: the hwbp is available * -4: The trigger is used by the itrigger command @@ -167,11 +222,8 @@ struct riscv_info { * most recent halt was not caused by a trigger, then this is -1. */ int64_t trigger_hit; - /* The number of entries in the program buffer. */ - int progbuf_size; - - /* This hart contains an implicit ebreak at the end of the program buffer. */ - bool impebreak; + /* The configured approach to translate virtual addresses to physical */ + riscv_virt2phys_mode_t virt2phys_mode; bool triggers_enumerated; @@ -187,6 +239,7 @@ struct riscv_info { /* Used by riscv_openocd_poll(). */ bool halted_needs_event_callback; enum target_event halted_callback_event; + unsigned int halt_group_repoll_count; enum riscv_isrmasking_mode isrmask_mode; @@ -225,10 +278,10 @@ struct riscv_info { riscv_insn_t (*read_progbuf)(struct target *target, unsigned int index); int (*execute_progbuf)(struct target *target, uint32_t *cmderr); int (*invalidate_cached_progbuf)(struct target *target); - int (*get_dmi_scan_length)(struct target *target); - void (*fill_dm_write)(struct target *target, char *buf, uint64_t a, uint32_t d); - void (*fill_dm_read)(struct target *target, char *buf, uint64_t a); - void (*fill_dm_nop)(struct target *target, char *buf); + unsigned int (*get_dmi_address_bits)(const struct target *target); + void (*fill_dmi_write)(const struct target *target, uint8_t *buf, uint32_t a, uint32_t d); + void (*fill_dmi_read)(const struct target *target, uint8_t *buf, uint32_t a); + void (*fill_dm_nop)(const struct target *target, uint8_t *buf); int (*authdata_read)(struct target *target, uint32_t *value, unsigned int index); int (*authdata_write)(struct target *target, uint32_t value, unsigned int index); @@ -236,6 +289,9 @@ struct riscv_info { int (*dmi_read)(struct target *target, uint32_t *value, uint32_t address); int (*dmi_write)(struct target *target, uint32_t address, uint32_t value); + bool (*get_impebreak)(const struct target *target); + unsigned int (*get_progbufsize)(const struct target *target); + /* Get the DMI address of target's DM's register. * The function should return the passed address * if the target is not assigned a DM yet. @@ -247,10 +303,9 @@ struct riscv_info { 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); + int (*access_memory)(struct target *target, const riscv_mem_access_args_t args); - unsigned (*data_bits)(struct target *target); + unsigned int (*data_bits)(struct target *target); COMMAND_HELPER((*print_info), struct target *target); @@ -272,18 +327,16 @@ struct riscv_info { struct reg_data_type_union vector_union; struct reg_data_type type_vector; - /* Set when trigger registers are changed by the user. This indicates we need - * to beware that we may hit a trigger that we didn't realize had been set. */ - bool manual_hwbp_set; + bool *reserved_triggers; /* Memory access methods to use, ordered by priority, highest to lowest. */ - int mem_access_methods[RISCV_NUM_MEM_ACCESS_METHODS]; + riscv_mem_access_method_t mem_access_methods[RISCV_MEM_ACCESS_MAX_METHODS_NUM]; + + unsigned int num_enabled_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; + bool mem_access_warn[RISCV_MEM_ACCESS_MAX_METHODS_NUM]; /* In addition to the ones in the standard spec, we'll also expose additional * CSRs in this list. */ @@ -307,15 +360,33 @@ struct riscv_info { bool range_trigger_fallback_encountered; - bool riscv_ebreakm; - bool riscv_ebreaks; - bool riscv_ebreaku; - bool wp_allow_equality_match_trigger; bool wp_allow_napot_trigger; bool wp_allow_ge_lt_trigger; + + bool autofence; +}; + +enum riscv_priv_mode { + RISCV_MODE_M, + RISCV_MODE_S, + RISCV_MODE_U, + RISCV_MODE_VS, + RISCV_MODE_VU, + N_RISCV_MODE }; +struct riscv_private_config { + bool dcsr_ebreak_fields[N_RISCV_MODE]; +}; + +static inline struct riscv_private_config +*riscv_private_config(const struct target *target) +{ + assert(target->private_config); + return target->private_config; +} + COMMAND_HELPER(riscv_print_info_line, const char *section, const char *key, unsigned int value); @@ -327,22 +398,23 @@ typedef struct { typedef struct { const char *name; int level; - unsigned va_bits; + unsigned int va_bits; /* log2(PTESIZE) */ - unsigned pte_shift; - unsigned vpn_shift[PG_MAX_LEVEL]; - unsigned vpn_mask[PG_MAX_LEVEL]; - unsigned pte_ppn_shift[PG_MAX_LEVEL]; - unsigned pte_ppn_mask[PG_MAX_LEVEL]; - unsigned pa_ppn_shift[PG_MAX_LEVEL]; - unsigned pa_ppn_mask[PG_MAX_LEVEL]; + unsigned int pte_shift; + unsigned int vpn_shift[PG_MAX_LEVEL]; + unsigned int vpn_mask[PG_MAX_LEVEL]; + unsigned int pte_ppn_shift[PG_MAX_LEVEL]; + unsigned int pte_ppn_mask[PG_MAX_LEVEL]; + unsigned int pa_ppn_shift[PG_MAX_LEVEL]; + unsigned int pa_ppn_mask[PG_MAX_LEVEL]; } virt2phys_info_t; +bool riscv_virt2phys_mode_is_hw(const struct target *target); +bool riscv_virt2phys_mode_is_sw(const struct target *target); + /* Wall-clock timeout for a command/access. Settable via RISC-V Target commands.*/ int riscv_get_command_timeout_sec(void); -extern bool riscv_enable_virtual; - /* Everything needs the RISC-V specific info structure, so here's a nice macro * that provides that. */ static inline struct riscv_info *riscv_info(const struct target *target) __attribute__((unused)); @@ -362,13 +434,14 @@ extern struct scan_field select_dtmcontrol; extern struct scan_field select_dbus; extern struct scan_field select_idcode; +int dtmcs_scan(struct jtag_tap *tap, uint32_t out, uint32_t *in_ptr); + extern struct scan_field *bscan_tunneled_select_dmi; extern uint32_t bscan_tunneled_select_dmi_num_fields; typedef enum { BSCAN_TUNNEL_NESTED_TAP, BSCAN_TUNNEL_DATA_REGISTER } bscan_tunnel_type_t; -extern int bscan_tunnel_ir_width; +extern uint8_t bscan_tunnel_ir_width; -int dtmcontrol_scan_via_bscan(struct target *target, uint32_t out, uint32_t *in_ptr); -void select_dmi_via_bscan(struct target *target); +void select_dmi_via_bscan(struct jtag_tap *tap); /*** OpenOCD Interface */ int riscv_openocd_poll(struct target *target); @@ -377,9 +450,9 @@ int riscv_halt(struct target *target); int riscv_openocd_step( struct target *target, - int current, + bool current, target_addr_t address, - int handle_breakpoints + bool handle_breakpoints ); /*** RISC-V Interface ***/ @@ -387,7 +460,7 @@ int riscv_openocd_step( bool riscv_supports_extension(const struct target *target, char letter); /* Returns XLEN for the given (or current) hart. */ -unsigned riscv_xlen(const struct target *target); +unsigned int riscv_xlen(const struct target *target); /* Returns VLENB for the given (or current) hart. */ unsigned int riscv_vlenb(const struct target *target); @@ -401,16 +474,16 @@ int riscv_get_hart_state(struct target *target, enum riscv_hart_state *state); /* These helper functions let the generic program interface get target-specific * information. */ -size_t riscv_progbuf_size(struct target *target); +unsigned int riscv_progbuf_size(struct target *target); riscv_insn_t riscv_read_progbuf(struct target *target, int index); -int riscv_write_progbuf(struct target *target, int index, riscv_insn_t insn); +int riscv_write_progbuf(struct target *target, unsigned int index, riscv_insn_t insn); int riscv_execute_progbuf(struct target *target, uint32_t *cmderr); -void riscv_fill_dm_nop(struct target *target, char *buf); -void riscv_fill_dm_write(struct target *target, char *buf, uint64_t a, uint32_t d); -void riscv_fill_dm_read(struct target *target, char *buf, uint64_t a); -int riscv_get_dmi_scan_length(struct target *target); +void riscv_fill_dm_nop(const struct target *target, uint8_t *buf); +void riscv_fill_dmi_write(const struct target *target, uint8_t *buf, uint32_t a, uint32_t d); +void riscv_fill_dmi_read(const struct target *target, uint8_t *buf, uint32_t a); +unsigned int riscv_get_dmi_address_bits(const struct target *target); uint32_t riscv_get_dmi_address(const struct target *target, uint32_t dm_address); @@ -424,13 +497,10 @@ void riscv_semihosting_init(struct target *target); enum semihosting_result riscv_semihosting(struct target *target, int *retval); -void riscv_add_bscan_tunneled_scan(struct target *target, const struct scan_field *field, +void riscv_add_bscan_tunneled_scan(struct jtag_tap *tap, const 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); -int riscv_interrupts_disable(struct target *target, uint64_t ie_mask, uint64_t *old_mstatus); -int riscv_interrupts_restore(struct target *target, uint64_t old_mstatus); - -#endif +#endif /* OPENOCD_TARGET_RISCV_RISCV_H */ diff --git a/src/target/riscv/riscv_reg.c b/src/target/riscv/riscv_reg.c index 6cf67dd..e35cd7f 100644 --- a/src/target/riscv/riscv_reg.c +++ b/src/target/riscv/riscv_reg.c @@ -56,7 +56,6 @@ static const char * const default_reg_names[GDB_REGNO_COUNT] = { [GDB_REGNO_T5] = "t5", [GDB_REGNO_T6] = "t6", [GDB_REGNO_PC] = "pc", - [GDB_REGNO_CSR0] = "csr0", [GDB_REGNO_PRIV] = "priv", [GDB_REGNO_FT0] = "ft0", [GDB_REGNO_FT1] = "ft1", @@ -196,7 +195,8 @@ const char *riscv_reg_gdb_regno_name(const struct target *target, enum gdb_regno } if (regno >= GDB_REGNO_CSR0 && regno <= GDB_REGNO_CSR4095) { init_custom_csr_names(target); - info->reg_names[regno] = init_reg_name_with_prefix("csr", regno - GDB_REGNO_CSR0); + if (!info->reg_names[regno]) + info->reg_names[regno] = init_reg_name_with_prefix("csr", regno - GDB_REGNO_CSR0); return info->reg_names[regno]; } assert(!"Encountered uninitialized entry in reg_names table"); @@ -346,22 +346,11 @@ static bool vlenb_exists(const struct target *target) return riscv_vlenb(target) != 0; } -static bool mtopi_exists(const struct target *target) +static bool reg_exists(const struct target *target, uint32_t regno) { - RISCV_INFO(info) - /* TODO: The naming is quite unfortunate here. `mtopi_readable` refers - * to how the fact that `mtopi` exists was deduced during examine. - */ - return info->mtopi_readable; -} - -static bool mtopei_exists(const struct target *target) -{ - RISCV_INFO(info) - /* TODO: The naming is quite unfortunate here. `mtopei_readable` refers - * to how the fact that `mtopei` exists was deduced during examine. - */ - return info->mtopei_readable; + const struct reg * const reg = riscv_reg_impl_cache_entry(target, regno); + assert(riscv_reg_impl_is_initialized(reg)); + return reg->exist; } static bool is_known_standard_csr(unsigned int csr_num) @@ -376,8 +365,19 @@ static bool is_known_standard_csr(unsigned int csr_num) return is_csr_in_buf[csr_num]; } -static bool gdb_regno_exist(const struct target *target, uint32_t regno) +bool riscv_reg_impl_gdb_regno_exist(const struct target *target, uint32_t regno) { + switch (regno) { + case GDB_REGNO_VLENB: + case GDB_REGNO_MTOPI: + case GDB_REGNO_MTOPEI: + assert(false + && "Existence of other registers is determined " + "depending on existence of these ones, so " + "whether these register exist or not should be " + "set explicitly."); + }; + if (regno <= GDB_REGNO_XPR15 || regno == GDB_REGNO_PC || regno == GDB_REGNO_PRIV) @@ -403,7 +403,6 @@ static bool gdb_regno_exist(const struct target *target, uint32_t regno) case CSR_VL: case CSR_VCSR: case CSR_VTYPE: - case CSR_VLENB: return vlenb_exists(target); case CSR_SCOUNTEREN: case CSR_SSTATUS: @@ -498,25 +497,25 @@ static bool gdb_regno_exist(const struct target *target, uint32_t regno) case CSR_MVIP: case CSR_MIEH: case CSR_MIPH: - return mtopi_exists(target); + return reg_exists(target, GDB_REGNO_MTOPI); case CSR_MIDELEGH: case CSR_MVIENH: case CSR_MVIPH: - return mtopi_exists(target) && + return reg_exists(target, GDB_REGNO_MTOPI) && riscv_xlen(target) == 32 && riscv_supports_extension(target, 'S'); /* Interrupts S-Mode CSRs. */ case CSR_SISELECT: case CSR_SIREG: case CSR_STOPI: - return mtopi_exists(target) && + return reg_exists(target, GDB_REGNO_MTOPI) && riscv_supports_extension(target, 'S'); case CSR_STOPEI: - return mtopei_exists(target) && + return reg_exists(target, GDB_REGNO_MTOPEI) && riscv_supports_extension(target, 'S'); case CSR_SIEH: case CSR_SIPH: - return mtopi_exists(target) && + return reg_exists(target, GDB_REGNO_MTOPI) && riscv_xlen(target) == 32 && riscv_supports_extension(target, 'S'); /* Interrupts Hypervisor and VS CSRs. */ @@ -527,10 +526,10 @@ static bool gdb_regno_exist(const struct target *target, uint32_t regno) case CSR_VSISELECT: case CSR_VSIREG: case CSR_VSTOPI: - return mtopi_exists(target) && + return reg_exists(target, GDB_REGNO_MTOPI) && riscv_supports_extension(target, 'H'); case CSR_VSTOPEI: - return mtopei_exists(target) && + return reg_exists(target, GDB_REGNO_MTOPEI) && riscv_supports_extension(target, 'H'); case CSR_HIDELEGH: case CSR_HVIENH: @@ -539,7 +538,7 @@ static bool gdb_regno_exist(const struct target *target, uint32_t regno) case CSR_HVIPRIO2H: case CSR_VSIEH: case CSR_VSIPH: - return mtopi_exists(target) && + return reg_exists(target, GDB_REGNO_MTOPI) && riscv_xlen(target) == 32 && riscv_supports_extension(target, 'H'); } @@ -599,14 +598,15 @@ static int resize_reg(const struct target *target, uint32_t regno, bool exist, return ERROR_OK; } -static int set_reg_exist(const struct target *target, uint32_t regno, bool exist) +int riscv_reg_impl_set_exist(const struct target *target, uint32_t regno, bool exist) { const struct reg *reg = riscv_reg_impl_cache_entry(target, regno); assert(riscv_reg_impl_is_initialized(reg)); return resize_reg(target, regno, exist, reg->size); } -int riscv_reg_impl_init_one(struct target *target, uint32_t regno, const struct reg_arch_type *reg_type) +int riscv_reg_impl_init_cache_entry(struct target *target, uint32_t regno, + bool exist, const struct reg_arch_type *reg_type) { struct reg * const reg = riscv_reg_impl_cache_entry(target, regno); if (riscv_reg_impl_is_initialized(reg)) @@ -634,8 +634,7 @@ int riscv_reg_impl_init_one(struct target *target, uint32_t regno, const struct reg_arch_info->target = target; reg_arch_info->custom_number = gdb_regno_custom_number(target, regno); } - return resize_reg(target, regno, gdb_regno_exist(target, regno), - gdb_regno_size(target, regno)); + return resize_reg(target, regno, exist, gdb_regno_size(target, regno)); } static int init_custom_register_names(struct list_head *expose_custom, @@ -725,7 +724,7 @@ int riscv_reg_impl_expose_csrs(const struct target *target) csr_number); continue; } - if (set_reg_exist(target, regno, /*exist*/ true) != ERROR_OK) + if (riscv_reg_impl_set_exist(target, regno, /*exist*/ true) != ERROR_OK) return ERROR_FAIL; LOG_TARGET_DEBUG(target, "Exposing additional CSR %d (name=%s)", csr_number, reg->name); @@ -746,7 +745,7 @@ void riscv_reg_impl_hide_csrs(const struct target *target) struct reg * const reg = riscv_reg_impl_cache_entry(target, regno); const unsigned int csr_number = regno - GDB_REGNO_CSR0; if (!reg->exist) { - LOG_TARGET_WARNING(target, + LOG_TARGET_DEBUG(target, "Not hiding CSR %d: register does not exist.", csr_number); continue; @@ -834,15 +833,8 @@ static int riscv_set_or_write_register(struct target *target, return riscv_set_or_write_register(target, GDB_REGNO_DCSR, dcsr, write_through); } - if (!target->reg_cache) { - assert(!target_was_examined(target)); - LOG_TARGET_DEBUG(target, - "No cache, writing to target: %s <- 0x%" PRIx64, - riscv_reg_gdb_regno_name(target, regid), value); - return riscv013_set_register(target, regid, value); - } - struct reg *reg = riscv_reg_impl_cache_entry(target, regid); + assert(riscv_reg_impl_is_initialized(reg)); if (!reg->exist) { LOG_TARGET_DEBUG(target, "Register %s does not exist.", reg->name); @@ -885,6 +877,34 @@ static int riscv_set_or_write_register(struct target *target, return ERROR_OK; } +bool riscv_reg_cache_any_dirty(const struct target *target, int log_level) +{ + bool any_dirty = false; + + if (!target->reg_cache) + return any_dirty; + + for (unsigned int number = 0; number < target->reg_cache->num_regs; ++number) { + const struct reg * const reg = riscv_reg_impl_cache_entry(target, number); + assert(riscv_reg_impl_is_initialized(reg)); + if (reg->dirty) { + log_printf_lf(log_level, __FILE__, __LINE__, __func__, + "[%s] Register %s is dirty!", target_name(target), reg->name); + any_dirty = true; + } + } + return any_dirty; +} + +void riscv_reg_cache_invalidate_all(struct target *target) +{ + if (!target->reg_cache) + return; + + LOG_TARGET_DEBUG(target, "Invalidating register cache."); + register_cache_invalidate(target->reg_cache); +} + /** * This function is used to change the value of a register. The new value may * be cached, and may not be written until the hart is resumed. @@ -935,21 +955,15 @@ int riscv_reg_get(struct target *target, riscv_reg_t *value, RISCV_INFO(r); assert(r); if (r->dtm_version == DTM_DTMCS_VERSION_0_11) - return riscv013_get_register(target, value, regid); + return riscv011_get_register(target, value, regid); keep_alive(); if (regid == GDB_REGNO_PC) return riscv_reg_get(target, value, GDB_REGNO_DPC); - if (!target->reg_cache) { - assert(!target_was_examined(target)); - LOG_TARGET_DEBUG(target, "No cache, reading %s from target", - riscv_reg_gdb_regno_name(target, regid)); - return riscv013_get_register(target, value, regid); - } - struct reg *reg = riscv_reg_impl_cache_entry(target, regid); + assert(riscv_reg_impl_is_initialized(reg)); if (!reg->exist) { LOG_TARGET_DEBUG(target, "Register %s does not exist.", reg->name); return ERROR_FAIL; diff --git a/src/target/riscv/riscv_reg.h b/src/target/riscv/riscv_reg.h index 264addd..dc87c55 100644 --- a/src/target/riscv/riscv_reg.h +++ b/src/target/riscv/riscv_reg.h @@ -22,6 +22,17 @@ void riscv_reg_free_all(struct target *target); /** Write all dirty registers to the target. */ int riscv_reg_flush_all(struct target *target); /** + * Check whether there are any dirty registers in the OpenOCD's register cache. + * In addition, all dirty registers will be reported to the log using the + * supplied "log_level". + */ +bool riscv_reg_cache_any_dirty(const struct target *target, int log_level); +/** + * Invalidate all registers - forget their cached register values. + * WARNING: If a register was dirty, its walue will be silently lost! + */ +void riscv_reg_cache_invalidate_all(struct target *target); +/** * Set the register value. For cacheable registers, only the cache is updated * (write-back mode). */ diff --git a/src/target/riscv/riscv_reg_impl.h b/src/target/riscv/riscv_reg_impl.h index 906a5b6..a860202 100644 --- a/src/target/riscv/riscv_reg_impl.h +++ b/src/target/riscv/riscv_reg_impl.h @@ -13,7 +13,7 @@ * This file describes the helpers to use during register cache initialization * of a RISC-V target. Each cache entry proceedes through the following stages: * - not allocated before `riscv_reg_impl_init_cache()` - * - not initialized before the call to `riscv_reg_impl_init_one()` with appropriate regno. + * - not initialized before the call to `riscv_reg_impl_init_cache_entry()` with appropriate regno. * - initialized until `riscv_reg_free_all()` is called. */ static inline bool riscv_reg_impl_is_initialized(const struct reg *reg) @@ -37,8 +37,18 @@ static inline bool riscv_reg_impl_is_initialized(const struct reg *reg) int riscv_reg_impl_init_cache(struct target *target); /** Initialize register. */ -int riscv_reg_impl_init_one(struct target *target, uint32_t regno, - const struct reg_arch_type *reg_type); +int riscv_reg_impl_init_cache_entry(struct target *target, uint32_t regno, + bool exist, const struct reg_arch_type *reg_type); + +/** + * For most registers, returns whether they exist or not. + * For some registers the "exist" bit should be set explicitly. + */ +bool riscv_reg_impl_gdb_regno_exist(const struct target *target, uint32_t regno); + +/** Mark register as existing or not. */ +int riscv_reg_impl_set_exist(const struct target *target, + uint32_t regno, bool exist); /** Return the entry in the register cache of the target. */ struct reg *riscv_reg_impl_cache_entry(const struct target *target, @@ -194,9 +204,7 @@ static inline bool riscv_reg_impl_gdb_regno_cacheable(enum gdb_regno regno, case GDB_REGNO_MISA: case GDB_REGNO_DCSR: case GDB_REGNO_DSCRATCH0: - case GDB_REGNO_MSTATUS: case GDB_REGNO_MEPC: - case GDB_REGNO_MCAUSE: case GDB_REGNO_SATP: /* * WARL registers might not contain the value we just wrote, but diff --git a/src/target/riscv/riscv_semihosting.c b/src/target/riscv/riscv_semihosting.c index 0f4f6b5..98ccf41 100644 --- a/src/target/riscv/riscv_semihosting.c +++ b/src/target/riscv/riscv_semihosting.c @@ -37,6 +37,57 @@ static int riscv_semihosting_setup(struct target *target, int enable); static int riscv_semihosting_post_result(struct target *target); +static int riscv_semihosting_detect_magic_sequence(struct target *target, + const target_addr_t pc, bool *sequence_found) +{ + assert(sequence_found); + + /* The semihosting "magic" sequence must be the exact three instructions + * listed below. All these instructions, including the ebreak, must be + * uncompressed (4 bytes long). */ + const uint32_t magic[] = { + 0x01f01013, /* slli zero,zero,0x1f */ + 0x00100073, /* ebreak */ + 0x40705013 /* srai zero,zero,0x7 */ + }; + + LOG_TARGET_DEBUG(target, "Checking for RISC-V semihosting sequence " + "at PC = 0x%" TARGET_PRIxADDR, pc); + + /* Read three uncompressed instructions: + * The previous, the current one (pointed to by PC) and the next one. */ + const target_addr_t sequence_start_address = pc - 4; + for (int i = 0; i < 3; i++) { + uint8_t buf[4]; + + /* Instruction memories may not support arbitrary read size. + * Use any size that will work. */ + const target_addr_t address = sequence_start_address + (4 * i); + int result = riscv_read_by_any_size(target, address, 4, buf); + if (result != ERROR_OK) { + *sequence_found = false; + return result; + } + + /* RISC-V instruction layout in memory is always little endian, + * regardless of the endianness of the whole system. */ + const uint32_t value = le_to_h_u32(buf); + + LOG_TARGET_DEBUG(target, "compare 0x%08" PRIx32 " from 0x%" PRIx64 " against 0x%08" PRIx32, + value, address, magic[i]); + if (value != magic[i]) { + LOG_TARGET_DEBUG(target, "Not a RISC-V semihosting sequence"); + *sequence_found = false; + return ERROR_OK; + } + } + + LOG_TARGET_DEBUG(target, "RISC-V semihosting sequence found " + "at PC = 0x%" TARGET_PRIxADDR, pc); + *sequence_found = true; + return ERROR_OK; +} + /** * Initialize RISC-V semihosting. Use common ARM code. */ @@ -57,48 +108,47 @@ void riscv_semihosting_init(struct target *target) enum semihosting_result riscv_semihosting(struct target *target, int *retval) { struct semihosting *semihosting = target->semihosting; - if (!semihosting) { - LOG_TARGET_DEBUG(target, " -> NONE (!semihosting)"); - return SEMIHOSTING_NONE; - } - - if (!semihosting->is_active) { - LOG_TARGET_DEBUG(target, " -> NONE (!semihosting->is_active)"); - return SEMIHOSTING_NONE; - } + assert(semihosting); riscv_reg_t pc; int result = riscv_reg_get(target, &pc, GDB_REGNO_PC); - if (result != ERROR_OK) + if (result != ERROR_OK) { + LOG_TARGET_DEBUG(target, "Semihosting outcome: ERROR (failed to read PC)"); return SEMIHOSTING_ERROR; + } - /* - * The instructions that trigger a semihosting call, - * always uncompressed, should look like: - */ - uint32_t magic[] = { - 0x01f01013, /* slli zero,zero,0x1f */ - 0x00100073, /* ebreak */ - 0x40705013 /* srai zero,zero,0x7 */ - }; + bool sequence_found = false; + *retval = riscv_semihosting_detect_magic_sequence(target, pc, &sequence_found); + if (*retval != ERROR_OK) { + LOG_TARGET_DEBUG(target, "Semihosting outcome: ERROR (during magic seq. detection)"); + return SEMIHOSTING_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++) { - uint8_t buf[4]; - /* Instruction memories may not support arbitrary read size. Use any size that will work. */ - target_addr_t address = (pc - 4) + 4 * i; - *retval = riscv_read_by_any_size(target, address, 4, buf); - if (*retval != ERROR_OK) - return SEMIHOSTING_ERROR; - uint32_t value = target_buffer_get_u32(target, buf); - LOG_TARGET_DEBUG(target, "compare 0x%08x from 0x%" PRIx64 " against 0x%08x", - value, address, magic[i]); - if (value != magic[i]) { - LOG_TARGET_DEBUG(target, " -> NONE (no magic)"); - return SEMIHOSTING_NONE; + if (!semihosting->is_active) { + if (sequence_found) { + // If semihositing is encountered but disabled, provide an additional hint to the user. + LOG_TARGET_WARNING(target, "RISC-V semihosting call encountered in the program " + "but semihosting is disabled!"); + LOG_TARGET_WARNING(target, "The target will remain halted (PC = 0x%" TARGET_PRIxADDR ").", pc); + LOG_TARGET_WARNING(target, "Hint: Restart your debug session and enable semihosting " + "by command 'arm semihosting enable'."); + // TODO: This can be improved: The ebreak halt cause detection and riscv_semihosting() call + // can be added also to "arm semihosting enable", which would allow the user to continue + // without restart of the debug session. } + + LOG_TARGET_DEBUG(target, "Semihosting outcome: NONE (semihosting not enabled)"); + return SEMIHOSTING_NONE; + } + + if (!sequence_found) { + LOG_TARGET_DEBUG(target, "Semihosting outcome: NONE (no magic sequence)"); + return SEMIHOSTING_NONE; } + /* Otherwise we have a semihosting call (and semihosting is enabled). + * Proceed with the handling of semihosting. */ + /* * Perform semihosting call if we are not waiting on a fileio * operation to complete. @@ -111,12 +161,14 @@ enum semihosting_result riscv_semihosting(struct target *target, int *retval) result = riscv_reg_get(target, &r0, GDB_REGNO_A0); if (result != ERROR_OK) { LOG_TARGET_ERROR(target, "Could not read semihosting operation code (register a0)"); + LOG_TARGET_DEBUG(target, "Semihosting outcome: ERROR (failed to read a0)"); return SEMIHOSTING_ERROR; } result = riscv_reg_get(target, &r1, GDB_REGNO_A1); if (result != ERROR_OK) { LOG_TARGET_ERROR(target, "Could not read semihosting operation code (register a1)"); + LOG_TARGET_DEBUG(target, "Semihosting outcome: ERROR (failed to read a1)"); return SEMIHOSTING_ERROR; } @@ -131,11 +183,13 @@ enum semihosting_result riscv_semihosting(struct target *target, int *retval) *retval = semihosting_common(target); if (*retval != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed semihosting operation (0x%02X)", semihosting->op); + LOG_TARGET_DEBUG(target, "Semihosting outcome: ERROR (error during semihosting processing)"); return SEMIHOSTING_ERROR; } } else { /* Unknown operation number, not a semihosting call. */ LOG_TARGET_ERROR(target, "Unknown semihosting operation requested (op = 0x%x)", semihosting->op); + LOG_TARGET_DEBUG(target, "Semihosting outcome: NONE (unknown semihosting opcode)"); return SEMIHOSTING_NONE; } } @@ -150,11 +204,11 @@ enum semihosting_result riscv_semihosting(struct target *target, int *retval) * operation to complete. */ if (semihosting->is_resumable && !semihosting->hit_fileio) { - LOG_TARGET_DEBUG(target, " -> HANDLED"); + LOG_TARGET_DEBUG(target, "Semihosting outcome: HANDLED"); return SEMIHOSTING_HANDLED; } - LOG_TARGET_DEBUG(target, " -> WAITING"); + LOG_TARGET_DEBUG(target, "Semihosting outcome: WAITING"); return SEMIHOSTING_WAITING; } @@ -170,19 +224,16 @@ static int riscv_semihosting_setup(struct target *target, int enable) LOG_TARGET_DEBUG(target, "enable=%d", enable); struct semihosting *semihosting = target->semihosting; - if (semihosting) - semihosting->setup_time = clock(); + assert(semihosting); + semihosting->setup_time = clock(); return ERROR_OK; } static int riscv_semihosting_post_result(struct target *target) { struct semihosting *semihosting = target->semihosting; - if (!semihosting) { - /* If not enabled, silently ignored. */ - return 0; - } + assert(semihosting); LOG_TARGET_DEBUG(target, "Result: 0x%" PRIx64, semihosting->result); riscv_reg_set(target, GDB_REGNO_A0, semihosting->result); diff --git a/src/target/riscv/startup.tcl b/src/target/riscv/startup.tcl new file mode 100644 index 0000000..28e03a4 --- /dev/null +++ b/src/target/riscv/startup.tcl @@ -0,0 +1,55 @@ +# SPDX-License-Identifier: GPL-2.0-or-later + +lappend _telnet_autocomplete_skip "riscv set_enable_virtual" +proc {riscv set_enable_virtual} on_off { + echo {DEPRECATED! use 'riscv virt2phys_mode' not 'riscv set_enable_virtual'} + foreach t [target names] { + if {[$t cget -type] ne "riscv"} { continue } + switch -- [$t riscv virt2phys_mode] { + off - + hw { + switch -- $on_off { + on {$t riscv virt2phys_mode hw} + off {$t riscv virt2phys_mode off} + } + } + sw { + if {$on_off eq "on"} { + error {Can't enable virtual while translation mode is SW} + } + } + } + } + return {} +} + +lappend _telnet_autocomplete_skip "riscv set_enable_virt2phys" +proc {riscv set_enable_virt2phys} on_off { + echo {DEPRECATED! use 'riscv virt2phys_mode' not 'riscv set_enable_virt2phys'} + foreach t [target names] { + if {[$t cget -type] ne "riscv"} { continue } + switch -- [riscv virt2phys_mode] { + off - + sw { + switch -- $on_off { + on {riscv virt2phys_mode sw} + off {riscv virt2phys_mode off} + } + } + hw { + if {$on_off eq "on"} { + error {Can't enable virt2phys while translation mode is HW} + } + } + } + } + return {} +} + +foreach mode {m s u} { + lappend _telnet_autocomplete_skip "riscv set_ebreak$mode" +} + +proc riscv {cmd args} { + tailcall "riscv $cmd" {*}$args +} diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c index 1eb1957..ffcd3aa 100644 --- a/src/target/semihosting_common.c +++ b/src/target/semihosting_common.c @@ -92,6 +92,8 @@ static int semihosting_common_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info); static int semihosting_common_fileio_end(struct target *target, int result, int fileio_errno, bool ctrl_c); +static void semihosting_set_field(struct target *target, uint64_t value, size_t index, uint8_t *fields); +static int semihosting_write_fields(struct target *target, size_t number, uint8_t *fields); /** * Initialize common semihosting support. @@ -298,7 +300,12 @@ static inline int semihosting_getchar(struct semihosting *semihosting, int fd) */ static char *semihosting_user_op_params; -const char *semihosting_opcode_to_str(const uint64_t opcode) +/** + * @brief Convert the syscall opcode to a human-readable string + * @param[in] opcode Syscall opcode + * @return String representation of syscall opcode + */ +static const char *semihosting_opcode_to_str(const uint64_t opcode) { switch (opcode) { case SEMIHOSTING_SYS_CLOSE: @@ -1729,8 +1736,7 @@ int semihosting_read_fields(struct target *target, size_t number, /** * Write all fields of a command from buffer to target. */ -int semihosting_write_fields(struct target *target, size_t number, - uint8_t *fields) +static int semihosting_write_fields(struct target *target, size_t number, uint8_t *fields) { struct semihosting *semihosting = target->semihosting; /* Use 4-byte multiples to trigger fast memory access. */ @@ -1754,9 +1760,7 @@ uint64_t semihosting_get_field(struct target *target, size_t index, /** * Store a field in the buffer, considering register size and endianness. */ -void semihosting_set_field(struct target *target, uint64_t value, - size_t index, - uint8_t *fields) +static void semihosting_set_field(struct target *target, uint64_t value, size_t index, uint8_t *fields) { struct semihosting *semihosting = target->semihosting; if (semihosting->word_size_bytes == 8) diff --git a/src/target/semihosting_common.h b/src/target/semihosting_common.h index a1848b4..1821ca4 100644 --- a/src/target/semihosting_common.h +++ b/src/target/semihosting_common.h @@ -188,13 +188,6 @@ struct semihosting { int (*post_result)(struct target *target); }; -/** - * @brief Convert the syscall opcode to a human-readable string - * @param[in] opcode Syscall opcode - * @return String representation of syscall opcode - */ -const char *semihosting_opcode_to_str(uint64_t opcode); - int semihosting_common_init(struct target *target, void *setup, void *post_result); int semihosting_common(struct target *target); @@ -202,13 +195,8 @@ int semihosting_common(struct target *target); /* utility functions which may also be used by semihosting extensions (custom vendor-defined syscalls) */ int semihosting_read_fields(struct target *target, size_t number, uint8_t *fields); -int semihosting_write_fields(struct target *target, size_t number, - uint8_t *fields); uint64_t semihosting_get_field(struct target *target, size_t index, uint8_t *fields); -void semihosting_set_field(struct target *target, uint64_t value, - size_t index, - uint8_t *fields); extern const struct command_registration semihosting_common_handlers[]; diff --git a/src/target/stm8.c b/src/target/stm8.c index 227101b..76482e8 100644 --- a/src/target/stm8.c +++ b/src/target/stm8.c @@ -38,7 +38,7 @@ static int (*adapter_speed)(int speed); extern struct adapter_driver *adapter_driver; static const struct { - unsigned id; + unsigned int id; const char *name; const uint8_t bits; enum reg_type type; @@ -689,15 +689,13 @@ static int stm8_write_flash(struct target *target, enum mem_type type, if (stm8->flash_ncr2) stm8_write_u8(target, stm8->flash_ncr2, ~(PRG + opt)); blocksize = blocksize_param; - } else - if ((bytecnt >= 4) && ((address & 0x3) == 0)) { + } else if ((bytecnt >= 4) && ((address & 0x3) == 0)) { if (stm8->flash_cr2) stm8_write_u8(target, stm8->flash_cr2, WPRG + opt); if (stm8->flash_ncr2) stm8_write_u8(target, stm8->flash_ncr2, ~(WPRG + opt)); blocksize = 4; - } else - if (blocksize != 1) { + } else if (blocksize != 1) { if (stm8->flash_cr2) stm8_write_u8(target, stm8->flash_cr2, opt); if (stm8->flash_ncr2) @@ -982,9 +980,9 @@ static int stm8_single_step_core(struct target *target) return ERROR_OK; } -static int stm8_resume(struct target *target, int current, - target_addr_t address, int handle_breakpoints, - int debug_execution) +static int stm8_resume(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, + bool debug_execution) { struct stm8_common *stm8 = target_to_stm8(target); struct breakpoint *breakpoint = NULL; @@ -1006,7 +1004,7 @@ static int stm8_resume(struct target *target, int current, stm8_set_hwbreak(target, comparator_list); } - /* current = 1: continue on current pc, + /* current = true: continue on current pc, otherwise continue at <address> */ if (!current) { buf_set_u32(stm8->core_cache->reg_list[STM8_PC].value, @@ -1292,8 +1290,8 @@ static int stm8_arch_state(struct target *target) return ERROR_OK; } -static int stm8_step(struct target *target, int current, - target_addr_t address, int handle_breakpoints) +static int stm8_step(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints) { LOG_DEBUG("%x " TARGET_ADDR_FMT " %x", current, address, handle_breakpoints); @@ -1307,7 +1305,7 @@ static int stm8_step(struct target *target, int current, return ERROR_TARGET_NOT_HALTED; } - /* current = 1: continue on current pc, otherwise continue at <address> */ + /* current = true: continue on current pc, otherwise continue at <address> */ if (!current) { buf_set_u32(stm8->core_cache->reg_list[STM8_PC].value, 0, 32, address); stm8->core_cache->reg_list[STM8_PC].dirty = true; @@ -1552,8 +1550,8 @@ static int stm8_set_watchpoint(struct target *target, } if (watchpoint->length != 1) { - LOG_ERROR("Only watchpoints of length 1 are supported"); - return ERROR_TARGET_UNALIGNED_ACCESS; + LOG_ERROR("Only watchpoints of length 1 are supported"); + return ERROR_TARGET_UNALIGNED_ACCESS; } enum hw_break_type enable = 0; @@ -1791,7 +1789,7 @@ static int stm8_run_and_wait(struct target *target, uint32_t entry_point, /* This code relies on the target specific resume() and poll()->debug_entry() sequence to write register values to the processor and the read them back */ - retval = target_resume(target, 0, entry_point, 0, 1); + retval = target_resume(target, false, entry_point, false, true); if (retval != ERROR_OK) return retval; diff --git a/src/target/target.c b/src/target/target.c index fd9c34f..442e8be 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -31,6 +31,7 @@ #endif #include <helper/align.h> +#include <helper/list.h> #include <helper/nvp.h> #include <helper/time_support.h> #include <jtag/jtag.h> @@ -52,6 +53,13 @@ /* default halt wait timeout (ms) */ #define DEFAULT_HALT_TIMEOUT 5000 +struct target_event_action { + enum target_event event; + Jim_Interp *interp; + Jim_Obj *body; + struct list_head list; +}; + static int target_read_buffer_default(struct target *target, target_addr_t address, uint32_t count, uint8_t *buffer); static int target_write_buffer_default(struct target *target, target_addr_t address, @@ -108,10 +116,10 @@ struct target *all_targets; static struct target_event_callback *target_event_callbacks; static struct target_timer_callback *target_timer_callbacks; static int64_t target_timer_next_event_value; -static LIST_HEAD(target_reset_callback_list); -static LIST_HEAD(target_trace_callback_list); +static OOCD_LIST_HEAD(target_reset_callback_list); +static OOCD_LIST_HEAD(target_trace_callback_list); static const unsigned int polling_interval = TARGET_DEFAULT_POLLING_INTERVAL; -static LIST_HEAD(empty_smp_targets); +static OOCD_LIST_HEAD(empty_smp_targets); enum nvp_assert { NVP_DEASSERT, @@ -554,8 +562,8 @@ int target_halt(struct target *target) * hand the infrastructure for running such helpers might use this * procedure but rely on hardware breakpoint to detect termination.) */ -int target_resume(struct target *target, int current, target_addr_t address, - int handle_breakpoints, int debug_execution) +int target_resume(struct target *target, bool current, target_addr_t address, + bool handle_breakpoints, bool debug_execution) { int retval; @@ -580,7 +588,8 @@ int target_resume(struct target *target, int current, target_addr_t address, * in the correct order. */ bool save_poll_mask = jtag_poll_mask(); - retval = target->type->resume(target, current, address, handle_breakpoints, debug_execution); + retval = target->type->resume(target, current, address, handle_breakpoints, + debug_execution); jtag_poll_unmask(save_poll_mask); if (retval != ERROR_OK) @@ -1414,7 +1423,7 @@ bool target_supports_gdb_connection(const struct target *target) } int target_step(struct target *target, - int current, target_addr_t address, int handle_breakpoints) + bool current, target_addr_t address, bool handle_breakpoints) { int retval; @@ -1449,14 +1458,14 @@ int target_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, target_addr_t target_address_max(struct target *target) { - unsigned bits = target_address_bits(target); + unsigned int bits = target_address_bits(target); if (sizeof(target_addr_t) * 8 == bits) return (target_addr_t) -1; else return (((target_addr_t) 1) << bits) - 1; } -unsigned target_address_bits(struct target *target) +unsigned int target_address_bits(struct target *target) { if (target->type->address_bits) return target->type->address_bits(target); @@ -2199,12 +2208,11 @@ static void target_destroy(struct target *target) jtag_unregister_event_callback(jtag_enable_callback, target); - struct target_event_action *teap = target->event_action; - while (teap) { - struct target_event_action *next = teap->next; + struct target_event_action *teap, *temp; + list_for_each_entry_safe(teap, temp, &target->events_action, list) { + list_del(&teap->list); Jim_DecrRefCount(teap->interp, teap->body); free(teap); - teap = next; } target_free_all_working_areas(target); @@ -2315,7 +2323,7 @@ int target_profiling_default(struct target *target, uint32_t *samples, uint32_t t = buf_get_u32(reg->value, 0, 32); samples[sample_count++] = t; /* current pc, addr = 0, do not handle breakpoints, not debugging */ - retval = target_resume(target, 1, 0, 0, 0); + retval = target_resume(target, true, 0, false, false); target_poll(target); alive_sleep(10); /* sleep 10ms, i.e. <100 samples/second. */ } else if (target->state == TARGET_RUNNING) { @@ -3032,14 +3040,14 @@ COMMAND_HANDLER(handle_reg_command) unsigned int count = 0; while (cache) { - unsigned i; + unsigned int i; command_print(CMD, "===== %s", cache->name); for (i = 0, reg = cache->reg_list; i < cache->num_regs; i++, reg++, count++) { - if (reg->exist == false || reg->hidden) + if (!reg->exist || reg->hidden) continue; /* only print cached values if they are valid */ if (reg->valid) { @@ -3067,13 +3075,13 @@ COMMAND_HANDLER(handle_reg_command) /* access a single register by its ordinal number */ if ((CMD_ARGV[0][0] >= '0') && (CMD_ARGV[0][0] <= '9')) { - unsigned num; + unsigned int num; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); struct reg_cache *cache = target->reg_cache; unsigned int count = 0; while (cache) { - unsigned i; + unsigned int i; for (i = 0; i < cache->num_regs; i++) { if (count++ == num) { reg = &cache->reg_list[i]; @@ -3125,11 +3133,18 @@ COMMAND_HANDLER(handle_reg_command) /* set register value */ if (CMD_ARGC == 2) { uint8_t *buf = malloc(DIV_ROUND_UP(reg->size, 8)); - if (!buf) + if (!buf) { + LOG_ERROR("Failed to allocate memory"); return ERROR_FAIL; - str_to_buf(CMD_ARGV[1], strlen(CMD_ARGV[1]), buf, reg->size, 0); + } + + int retval = CALL_COMMAND_HANDLER(command_parse_str_to_buf, CMD_ARGV[1], buf, reg->size); + if (retval != ERROR_OK) { + free(buf); + return retval; + } - int retval = reg->type->set(reg, buf); + retval = reg->type->set(reg, buf); if (retval != ERROR_OK) { LOG_ERROR("Could not write to register '%s'", reg->name); } else { @@ -3184,7 +3199,7 @@ COMMAND_HANDLER(handle_wait_halt_command) if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; - unsigned ms = DEFAULT_HALT_TIMEOUT; + unsigned int ms = DEFAULT_HALT_TIMEOUT; if (1 == CMD_ARGC) { int retval = parse_uint(CMD_ARGV[0], &ms); if (retval != ERROR_OK) @@ -3247,7 +3262,7 @@ COMMAND_HANDLER(handle_halt_command) return retval; if (CMD_ARGC == 1) { - unsigned wait_local; + unsigned int wait_local; retval = parse_uint(CMD_ARGV[0], &wait_local); if (retval != ERROR_OK) return ERROR_COMMAND_SYNTAX_ERROR; @@ -3290,7 +3305,7 @@ COMMAND_HANDLER(handle_reset_command) COMMAND_HANDLER(handle_resume_command) { - int current = 1; + bool current = true; if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; @@ -3302,10 +3317,10 @@ COMMAND_HANDLER(handle_resume_command) target_addr_t addr = 0; if (CMD_ARGC == 1) { COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); - current = 0; + current = false; } - return target_resume(target, current, addr, 1, 0); + return target_resume(target, current, addr, true, false); } COMMAND_HANDLER(handle_step_command) @@ -3327,18 +3342,18 @@ COMMAND_HANDLER(handle_step_command) struct target *target = get_current_target(CMD_CTX); - return target_step(target, current_pc, addr, 1); + return target_step(target, current_pc, addr, true); } void target_handle_md_output(struct command_invocation *cmd, struct target *target, target_addr_t address, unsigned size, - unsigned count, const uint8_t *buffer, bool include_address) + unsigned int count, const uint8_t *buffer, bool include_address) { - const unsigned line_bytecnt = 32; - unsigned line_modulo = line_bytecnt / size; + const unsigned int line_bytecnt = 32; + unsigned int line_modulo = line_bytecnt / size; char output[line_bytecnt * 4 + 1]; - unsigned output_len = 0; + unsigned int output_len = 0; const char *value_fmt; switch (size) { @@ -3399,7 +3414,7 @@ COMMAND_HANDLER(handle_md_command) if (CMD_ARGC < 1) return ERROR_COMMAND_SYNTAX_ERROR; - unsigned size = 0; + unsigned int size = 0; switch (CMD_NAME[2]) { case 'd': size = 8; @@ -3432,7 +3447,7 @@ COMMAND_HANDLER(handle_md_command) target_addr_t address; COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); - unsigned count = 1; + unsigned int count = 1; if (CMD_ARGC == 2) COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], count); @@ -3459,22 +3474,22 @@ typedef int (*target_write_fn)(struct target *target, static int target_fill_mem(struct target *target, target_addr_t address, target_write_fn fn, - unsigned data_size, + unsigned int data_size, /* value */ uint64_t b, /* count */ - unsigned c) + unsigned int c) { /* We have to write in reasonably large chunks to be able * to fill large memory areas with any sane speed */ - const unsigned chunk_size = 16384; + const unsigned int chunk_size = 16384; uint8_t *target_buf = malloc(chunk_size * data_size); if (!target_buf) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } - for (unsigned i = 0; i < chunk_size; i++) { + for (unsigned int i = 0; i < chunk_size; i++) { switch (data_size) { case 8: target_buffer_set_u64(target, target_buf + i * data_size, b); @@ -3495,8 +3510,8 @@ static int target_fill_mem(struct target *target, int retval = ERROR_OK; - for (unsigned x = 0; x < c; x += chunk_size) { - unsigned current; + for (unsigned int x = 0; x < c; x += chunk_size) { + unsigned int current; current = c - x; if (current > chunk_size) current = chunk_size; @@ -3533,12 +3548,12 @@ COMMAND_HANDLER(handle_mw_command) uint64_t value; COMMAND_PARSE_NUMBER(u64, CMD_ARGV[1], value); - unsigned count = 1; + unsigned int count = 1; if (CMD_ARGC == 3) COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], count); struct target *target = get_current_target(CMD_CTX); - unsigned wordsize; + unsigned int wordsize; switch (CMD_NAME[2]) { case 'd': wordsize = 8; @@ -3834,11 +3849,11 @@ static COMMAND_HELPER(handle_verify_image_command_internal, enum verify_mode ver for (t = 0; t < buf_cnt; t++) { if (data[t] != buffer[t]) { command_print(CMD, - "diff %d address 0x%08x. Was 0x%02x instead of 0x%02x", - diffs, - (unsigned)(t + image.sections[i].base_address), - data[t], - buffer[t]); + "diff %d address " TARGET_ADDR_FMT ". Was 0x%02" PRIx8 " instead of 0x%02" PRIx8, + diffs, + t + image.sections[i].base_address, + data[t], + buffer[t]); if (diffs++ >= 127) { command_print(CMD, "More than 128 errors, the rest are not printed."); free(data); @@ -3898,7 +3913,7 @@ static int handle_bp_command_list(struct command_invocation *cmd) while (breakpoint) { if (breakpoint->type == BKPT_SOFT) { char *buf = buf_to_hex_str(breakpoint->orig_instr, - breakpoint->length); + breakpoint->length * 8); command_print(cmd, "Software breakpoint(IVA): addr=" TARGET_ADDR_FMT ", len=0x%x, orig_instr=0x%s", breakpoint->address, breakpoint->length, @@ -3927,7 +3942,7 @@ static int handle_bp_command_list(struct command_invocation *cmd) } static int handle_bp_command_set(struct command_invocation *cmd, - target_addr_t addr, uint32_t asid, uint32_t length, int hw) + target_addr_t addr, uint32_t asid, unsigned int length, int hw) { struct target *target = get_current_target(cmd->ctx); int retval; @@ -4044,7 +4059,7 @@ COMMAND_HANDLER(handle_wp_command) while (watchpoint) { char wp_type = (watchpoint->rw == WPT_READ ? 'r' : (watchpoint->rw == WPT_WRITE ? 'w' : 'a')); command_print(CMD, "address: " TARGET_ADDR_FMT - ", len: 0x%8.8" PRIx32 + ", len: 0x%8.8x" ", r/w/a: %c, value: 0x%8.8" PRIx64 ", mask: 0x%8.8" PRIx64, watchpoint->address, @@ -4186,7 +4201,7 @@ static void write_gmon(uint32_t *samples, uint32_t sample_num, const char *filen uint32_t start_address, uint32_t end_address, struct target *target, uint32_t duration_ms) { uint32_t i; - FILE *f = fopen(filename, "w"); + FILE *f = fopen(filename, "wb"); if (!f) return; write_string(f, "gmon"); @@ -4356,7 +4371,7 @@ COMMAND_HANDLER(handle_profile_command) } else if (target->state == TARGET_HALTED && !halted_before_profiling) { /* The target was running before we started and is halted now. Resume * it, for consistency. */ - retval = target_resume(target, 1, 0, 0, 0); + retval = target_resume(target, true, 0, false, false); if (retval != ERROR_OK) { free(samples); return retval; @@ -4423,15 +4438,17 @@ COMMAND_HANDLER(handle_target_read_memory) return ERROR_COMMAND_ARGUMENT_INVALID; } - const unsigned int width = width_bits / 8; - - if ((addr + (count * width)) < addr) { - command_print(CMD, "read_memory: addr + count wraps to zero"); + if (count > 65536) { + command_print(CMD, "too large read request, exceeds 64K elements"); return ERROR_COMMAND_ARGUMENT_INVALID; } - if (count > 65536) { - command_print(CMD, "read_memory: too large read request, exceeds 64K elements"); + const unsigned int width = width_bits / 8; + /* -1 is needed to handle cases when (addr + count * width) results in zero + * due to overflow. + */ + if ((addr + count * width - 1) < addr) { + command_print(CMD, "memory region wraps over address zero"); return ERROR_COMMAND_ARGUMENT_INVALID; } @@ -4458,13 +4475,13 @@ COMMAND_HANDLER(handle_target_read_memory) retval = target_read_memory(target, addr, width, chunk_len, buffer); if (retval != ERROR_OK) { - LOG_DEBUG("read_memory: read at " TARGET_ADDR_FMT " with width=%u and count=%zu failed", + LOG_DEBUG("read at " TARGET_ADDR_FMT " with width=%u and count=%zu failed", addr, width_bits, chunk_len); /* * FIXME: we append the errmsg to the list of value already read. * Add a way to flush and replace old output, but LOG_DEBUG() it */ - command_print(CMD, "read_memory: failed to read memory"); + command_print(CMD, "failed to read memory"); free(buffer); return retval; } @@ -4500,50 +4517,36 @@ COMMAND_HANDLER(handle_target_read_memory) return ERROR_OK; } -static int target_jim_write_memory(Jim_Interp *interp, int argc, - Jim_Obj * const *argv) +COMMAND_HANDLER(handle_target_write_memory) { /* - * argv[1] = memory address - * argv[2] = desired element width in bits - * argv[3] = list of data to write - * argv[4] = optional "phys" + * CMD_ARGV[0] = memory address + * CMD_ARGV[1] = desired element width in bits + * CMD_ARGV[2] = list of data to write + * CMD_ARGV[3] = optional "phys" */ - if (argc < 4 || argc > 5) { - Jim_WrongNumArgs(interp, 1, argv, "address width data ['phys']"); - return JIM_ERR; - } + if (CMD_ARGC < 3 || CMD_ARGC > 4) + return ERROR_COMMAND_SYNTAX_ERROR; /* Arg 1: Memory address. */ - int e; - jim_wide wide_addr; - e = Jim_GetWide(interp, argv[1], &wide_addr); - - if (e != JIM_OK) - return e; - - target_addr_t addr = (target_addr_t)wide_addr; + target_addr_t addr; + COMMAND_PARSE_NUMBER(u64, CMD_ARGV[0], addr); /* Arg 2: Bit width of one element. */ - long l; - e = Jim_GetLong(interp, argv[2], &l); - - if (e != JIM_OK) - return e; + unsigned int width_bits; + COMMAND_PARSE_NUMBER(uint, CMD_ARGV[1], width_bits); - const unsigned int width_bits = l; - size_t count = Jim_ListLength(interp, argv[3]); + /* Arg 3: Elements to write. */ + size_t count = Jim_ListLength(CMD_CTX->interp, CMD_JIMTCL_ARGV[2]); /* Arg 4: Optional 'phys'. */ bool is_phys = false; - if (argc > 4) { - const char *phys = Jim_GetString(argv[4], NULL); - - if (strcmp(phys, "phys")) { - Jim_SetResultFormatted(interp, "invalid argument '%s', must be 'phys'", phys); - return JIM_ERR; + if (CMD_ARGC == 4) { + if (strcmp(CMD_ARGV[3], "phys")) { + command_print(CMD, "invalid argument '%s', must be 'phys'", CMD_ARGV[3]); + return ERROR_COMMAND_ARGUMENT_INVALID; } is_phys = true; @@ -4556,32 +4559,32 @@ static int target_jim_write_memory(Jim_Interp *interp, int argc, case 64: break; default: - Jim_SetResultString(interp, "invalid width, must be 8, 16, 32 or 64", -1); - return JIM_ERR; + command_print(CMD, "invalid width, must be 8, 16, 32 or 64"); + return ERROR_COMMAND_ARGUMENT_INVALID; } - const unsigned int width = width_bits / 8; - - if ((addr + (count * width)) < addr) { - Jim_SetResultString(interp, "write_memory: addr + len wraps to zero", -1); - return JIM_ERR; + if (count > 65536) { + command_print(CMD, "too large memory write request, exceeds 64K elements"); + return ERROR_COMMAND_ARGUMENT_INVALID; } - if (count > 65536) { - Jim_SetResultString(interp, "write_memory: too large memory write request, exceeds 64K elements", -1); - return JIM_ERR; + const unsigned int width = width_bits / 8; + /* -1 is needed to handle cases when (addr + count * width) results in zero + * due to overflow. + */ + if ((addr + count * width - 1) < addr) { + command_print(CMD, "memory region wraps over address zero"); + return ERROR_COMMAND_ARGUMENT_INVALID; } - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx != NULL); - struct target *target = get_current_target(cmd_ctx); + struct target *target = get_current_target(CMD_CTX); const size_t buffersize = 4096; uint8_t *buffer = malloc(buffersize); if (!buffer) { LOG_ERROR("Failed to allocate memory"); - return JIM_ERR; + return ERROR_FAIL; } size_t j = 0; @@ -4591,9 +4594,14 @@ static int target_jim_write_memory(Jim_Interp *interp, int argc, const size_t chunk_len = MIN(count, max_chunk_len); for (size_t i = 0; i < chunk_len; i++, j++) { - Jim_Obj *tmp = Jim_ListGetIndex(interp, argv[3], j); + Jim_Obj *tmp = Jim_ListGetIndex(CMD_CTX->interp, CMD_JIMTCL_ARGV[2], j); jim_wide element_wide; - Jim_GetWide(interp, tmp, &element_wide); + int jimretval = Jim_GetWide(CMD_CTX->interp, tmp, &element_wide); + if (jimretval != JIM_OK) { + command_print(CMD, "invalid value \"%s\"", Jim_GetString(tmp, NULL)); + free(buffer); + return ERROR_COMMAND_ARGUMENT_INVALID; + } const uint64_t v = element_wide; @@ -4623,11 +4631,11 @@ static int target_jim_write_memory(Jim_Interp *interp, int argc, retval = target_write_memory(target, addr, width, chunk_len, buffer); if (retval != ERROR_OK) { - LOG_ERROR("write_memory: write at " TARGET_ADDR_FMT " with width=%u and count=%zu failed", + LOG_DEBUG("write at " TARGET_ADDR_FMT " with width=%u and count=%zu failed", addr, width_bits, chunk_len); - Jim_SetResultString(interp, "write_memory: failed to write memory", -1); - e = JIM_ERR; - break; + command_print(CMD, "failed to write memory"); + free(buffer); + return retval; } addr += chunk_len * width; @@ -4635,7 +4643,7 @@ static int target_jim_write_memory(Jim_Interp *interp, int argc, free(buffer); - return e; + return ERROR_OK; } /* FIX? should we propagate errors here rather than printing them @@ -4646,7 +4654,7 @@ void target_handle_event(struct target *target, enum target_event e) struct target_event_action *teap; int retval; - for (teap = target->event_action; teap; teap = teap->next) { + list_for_each_entry(teap, &target->events_action, list) { if (teap->event == e) { LOG_DEBUG("target: %s (%s) event: %d (%s) action: %s", target_name(target), @@ -4685,63 +4693,46 @@ void target_handle_event(struct target *target, enum target_event e) } } -static int target_jim_get_reg(Jim_Interp *interp, int argc, - Jim_Obj * const *argv) +COMMAND_HANDLER(handle_target_get_reg) { - bool force = false; + if (CMD_ARGC < 1 || CMD_ARGC > 2) + return ERROR_COMMAND_SYNTAX_ERROR; - if (argc == 3) { - const char *option = Jim_GetString(argv[1], NULL); + bool force = false; + Jim_Obj *next_argv = CMD_JIMTCL_ARGV[0]; - if (!strcmp(option, "-force")) { - argc--; - argv++; - force = true; - } else { - Jim_SetResultFormatted(interp, "invalid option '%s'", option); - return JIM_ERR; + if (CMD_ARGC == 2) { + if (strcmp(CMD_ARGV[0], "-force")) { + command_print(CMD, "invalid argument '%s', must be '-force'", CMD_ARGV[0]); + return ERROR_COMMAND_ARGUMENT_INVALID; } - } - if (argc != 2) { - Jim_WrongNumArgs(interp, 1, argv, "[-force] list"); - return JIM_ERR; + force = true; + next_argv = CMD_JIMTCL_ARGV[1]; } - const int length = Jim_ListLength(interp, argv[1]); - - Jim_Obj *result_dict = Jim_NewDictObj(interp, NULL, 0); + const int length = Jim_ListLength(CMD_CTX->interp, next_argv); - if (!result_dict) - return JIM_ERR; - - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx != NULL); - const struct target *target = get_current_target(cmd_ctx); + const struct target *target = get_current_target(CMD_CTX); for (int i = 0; i < length; i++) { - Jim_Obj *elem = Jim_ListGetIndex(interp, argv[1], i); - - if (!elem) - return JIM_ERR; + Jim_Obj *elem = Jim_ListGetIndex(CMD_CTX->interp, next_argv, i); const char *reg_name = Jim_String(elem); - struct reg *reg = register_get_by_name(target->reg_cache, reg_name, - false); + struct reg *reg = register_get_by_name(target->reg_cache, reg_name, false); if (!reg || !reg->exist) { - Jim_SetResultFormatted(interp, "unknown register '%s'", reg_name); - return JIM_ERR; + command_print(CMD, "unknown register '%s'", reg_name); + return ERROR_COMMAND_ARGUMENT_INVALID; } if (force || !reg->valid) { int retval = reg->type->get(reg); if (retval != ERROR_OK) { - Jim_SetResultFormatted(interp, "failed to read register '%s'", - reg_name); - return JIM_ERR; + command_print(CMD, "failed to read register '%s'", reg_name); + return retval; } } @@ -4749,86 +4740,74 @@ static int target_jim_get_reg(Jim_Interp *interp, int argc, if (!reg_value) { LOG_ERROR("Failed to allocate memory"); - return JIM_ERR; + return ERROR_FAIL; } - char *tmp = alloc_printf("0x%s", reg_value); + command_print(CMD, "%s 0x%s", reg_name, reg_value); free(reg_value); - - if (!tmp) { - LOG_ERROR("Failed to allocate memory"); - return JIM_ERR; - } - - Jim_DictAddElement(interp, result_dict, elem, - Jim_NewStringObj(interp, tmp, -1)); - - free(tmp); } - Jim_SetResult(interp, result_dict); - - return JIM_OK; + return ERROR_OK; } -static int target_jim_set_reg(Jim_Interp *interp, int argc, - Jim_Obj * const *argv) +COMMAND_HANDLER(handle_set_reg_command) { - if (argc != 2) { - Jim_WrongNumArgs(interp, 1, argv, "dict"); - return JIM_ERR; - } + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; int tmp; #if JIM_VERSION >= 80 - Jim_Obj **dict = Jim_DictPairs(interp, argv[1], &tmp); + Jim_Obj **dict = Jim_DictPairs(CMD_CTX->interp, CMD_JIMTCL_ARGV[0], &tmp); if (!dict) - return JIM_ERR; + return ERROR_FAIL; #else Jim_Obj **dict; - int ret = Jim_DictPairs(interp, argv[1], &dict, &tmp); + int ret = Jim_DictPairs(CMD_CTX->interp, CMD_JIMTCL_ARGV[0], &dict, &tmp); if (ret != JIM_OK) - return ret; + return ERROR_FAIL; #endif const unsigned int length = tmp; - struct command_context *cmd_ctx = current_command_context(interp); - assert(cmd_ctx); - const struct target *target = get_current_target(cmd_ctx); + + const struct target *target = get_current_target(CMD_CTX); + assert(target); for (unsigned int i = 0; i < length; i += 2) { const char *reg_name = Jim_String(dict[i]); const char *reg_value = Jim_String(dict[i + 1]); - struct reg *reg = register_get_by_name(target->reg_cache, reg_name, - false); + struct reg *reg = register_get_by_name(target->reg_cache, reg_name, false); if (!reg || !reg->exist) { - Jim_SetResultFormatted(interp, "unknown register '%s'", reg_name); - return JIM_ERR; + command_print(CMD, "unknown register '%s'", reg_name); + return ERROR_FAIL; } uint8_t *buf = malloc(DIV_ROUND_UP(reg->size, 8)); - if (!buf) { LOG_ERROR("Failed to allocate memory"); - return JIM_ERR; + return ERROR_FAIL; } - str_to_buf(reg_value, strlen(reg_value), buf, reg->size, 0); - int retval = reg->type->set(reg, buf); + int retval = CALL_COMMAND_HANDLER(command_parse_str_to_buf, reg_value, buf, reg->size); + if (retval != ERROR_OK) { + free(buf); + return retval; + } + + retval = reg->type->set(reg, buf); free(buf); if (retval != ERROR_OK) { - Jim_SetResultFormatted(interp, "failed to set '%s' to register '%s'", + command_print(CMD, "failed to set '%s' to register '%s'", reg_value, reg_name); - return JIM_ERR; + return retval; } } - return JIM_OK; + return ERROR_OK; } /** @@ -4838,7 +4817,7 @@ bool target_has_event_action(const struct target *target, enum target_event even { struct target_event_action *teap; - for (teap = target->event_action; teap; teap = teap->next) { + list_for_each_entry(teap, &target->events_action, list) { if (teap->event == event) return true; } @@ -4914,7 +4893,7 @@ static int target_configure(struct jim_getopt_info *goi, struct target *target) switch (n->value) { case TCFG_TYPE: /* not settable */ - if (goi->isconfigure) { + if (goi->is_configure) { Jim_SetResultFormatted(goi->interp, "not settable: %s", n->name); return JIM_ERR; @@ -4943,7 +4922,7 @@ no_params: return e; } - if (goi->isconfigure) { + if (goi->is_configure) { if (goi->argc != 1) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name? ?EVENT-BODY?"); return JIM_ERR; @@ -4958,20 +4937,32 @@ no_params: { struct target_event_action *teap; - teap = target->event_action; /* replace existing? */ - while (teap) { + list_for_each_entry(teap, &target->events_action, list) if (teap->event == (enum target_event)n->value) break; - teap = teap->next; - } - if (goi->isconfigure) { + /* not found! */ + if (&teap->list == &target->events_action) + teap = NULL; + + if (goi->is_configure) { /* START_DEPRECATED_TPIU */ if (n->value == TARGET_EVENT_TRACE_CONFIG) LOG_INFO("DEPRECATED target event %s; use TPIU events {pre,post}-{enable,disable}", n->name); /* END_DEPRECATED_TPIU */ + jim_getopt_obj(goi, &o); + if (Jim_Length(o) == 0) { + /* empty action, drop existing one */ + if (teap) { + list_del(&teap->list); + Jim_DecrRefCount(teap->interp, teap->body); + free(teap); + } + break; + } + bool replace = true; if (!teap) { /* create new */ @@ -4980,7 +4971,6 @@ no_params: } teap->event = n->value; teap->interp = goi->interp; - jim_getopt_obj(goi, &o); if (teap->body) Jim_DecrRefCount(teap->interp, teap->body); teap->body = Jim_DuplicateObj(goi->interp, o); @@ -4998,8 +4988,7 @@ no_params: if (!replace) { /* add to head of event list */ - teap->next = target->event_action; - target->event_action = teap; + list_add(&teap->list, &target->events_action); } Jim_SetEmptyResult(goi->interp); } else { @@ -5014,7 +5003,7 @@ no_params: break; case TCFG_WORK_AREA_VIRT: - if (goi->isconfigure) { + if (goi->is_configure) { target_free_all_working_areas(target); e = jim_getopt_wide(goi, &w); if (e != JIM_OK) @@ -5030,7 +5019,7 @@ no_params: break; case TCFG_WORK_AREA_PHYS: - if (goi->isconfigure) { + if (goi->is_configure) { target_free_all_working_areas(target); e = jim_getopt_wide(goi, &w); if (e != JIM_OK) @@ -5046,7 +5035,7 @@ no_params: break; case TCFG_WORK_AREA_SIZE: - if (goi->isconfigure) { + if (goi->is_configure) { target_free_all_working_areas(target); e = jim_getopt_wide(goi, &w); if (e != JIM_OK) @@ -5061,7 +5050,7 @@ no_params: break; case TCFG_WORK_AREA_BACKUP: - if (goi->isconfigure) { + if (goi->is_configure) { target_free_all_working_areas(target); e = jim_getopt_wide(goi, &w); if (e != JIM_OK) @@ -5078,7 +5067,7 @@ no_params: case TCFG_ENDIAN: - if (goi->isconfigure) { + if (goi->is_configure) { e = jim_getopt_nvp(goi, nvp_target_endian, &n); if (e != JIM_OK) { jim_getopt_nvp_unknown(goi, nvp_target_endian, 1); @@ -5099,7 +5088,7 @@ no_params: break; case TCFG_COREID: - if (goi->isconfigure) { + if (goi->is_configure) { e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; @@ -5113,7 +5102,7 @@ no_params: break; case TCFG_CHAIN_POSITION: - if (goi->isconfigure) { + if (goi->is_configure) { Jim_Obj *o_t; struct jtag_tap *tap; @@ -5140,7 +5129,7 @@ no_params: /* loop for more e*/ break; case TCFG_DBGBASE: - if (goi->isconfigure) { + if (goi->is_configure) { e = jim_getopt_wide(goi, &w); if (e != JIM_OK) return e; @@ -5170,7 +5159,7 @@ no_params: break; case TCFG_GDB_PORT: - if (goi->isconfigure) { + if (goi->is_configure) { struct command_context *cmd_ctx = current_command_context(goi->interp); if (cmd_ctx->mode != COMMAND_CONFIG) { Jim_SetResultString(goi->interp, "-gdb-port must be configured before 'init'", -1); @@ -5192,7 +5181,7 @@ no_params: break; case TCFG_GDB_MAX_CONNECTIONS: - if (goi->isconfigure) { + if (goi->is_configure) { struct command_context *cmd_ctx = current_command_context(goi->interp); if (cmd_ctx->mode != COMMAND_CONFIG) { Jim_SetResultString(goi->interp, "-gdb-max-connections must be configured before 'init'", -1); @@ -5223,7 +5212,7 @@ static int jim_target_configure(Jim_Interp *interp, int argc, Jim_Obj * const *a struct jim_getopt_info goi; jim_getopt_setup(&goi, interp, argc - 1, argv + 1); - goi.isconfigure = !strcmp(c->name, "configure"); + goi.is_configure = !strcmp(c->name, "configure"); if (goi.argc < 1) { Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, "missing: -option ..."); @@ -5414,19 +5403,19 @@ COMMAND_HANDLER(handle_target_wait_state) COMMAND_HANDLER(handle_target_event_list) { struct target *target = get_current_target(CMD_CTX); - struct target_event_action *teap = target->event_action; + struct target_event_action *teap; command_print(CMD, "Event actions for target %s\n", target_name(target)); command_print(CMD, "%-25s | Body", "Event"); command_print(CMD, "------------------------- | " "----------------------------------------"); - while (teap) { + + list_for_each_entry(teap, &target->events_action, list) command_print(CMD, "%-25s | %s", target_event_name(teap->event), Jim_GetString(teap->body, NULL)); - teap = teap->next; - } + command_print(CMD, "***END***"); return ERROR_OK; } @@ -5561,14 +5550,14 @@ static const struct command_registration target_instance_command_handlers[] = { { .name = "get_reg", .mode = COMMAND_EXEC, - .jim_handler = target_jim_get_reg, + .handler = handle_target_get_reg, .help = "Get register values from the target", - .usage = "list", + .usage = "[-force] list", }, { .name = "set_reg", .mode = COMMAND_EXEC, - .jim_handler = target_jim_set_reg, + .handler = handle_set_reg_command, .help = "Set target register values", .usage = "dict", }, @@ -5582,7 +5571,7 @@ static const struct command_registration target_instance_command_handlers[] = { { .name = "write_memory", .mode = COMMAND_EXEC, - .jim_handler = target_jim_write_memory, + .handler = handle_target_write_memory, .help = "Write Tcl list of 8/16/32/64 bit numbers to target memory", .usage = "address width data ['phys']", }, @@ -5779,6 +5768,8 @@ static int target_create(struct jim_getopt_info *goi) target->halt_issued = false; + INIT_LIST_HEAD(&target->events_action); + /* initialize trace information */ target->trace_info = calloc(1, sizeof(struct trace)); if (!target->trace_info) { @@ -5789,7 +5780,7 @@ static int target_create(struct jim_getopt_info *goi) } target->dbgmsg = NULL; - target->dbg_msg_enabled = 0; + target->dbg_msg_enabled = false; target->endianness = TARGET_ENDIAN_UNKNOWN; @@ -5799,8 +5790,18 @@ static int target_create(struct jim_getopt_info *goi) target->gdb_port_override = NULL; target->gdb_max_connections = 1; + cp = Jim_GetString(new_cmd, NULL); + target->cmd_name = strdup(cp); + if (!target->cmd_name) { + LOG_ERROR("Out of memory"); + free(target->trace_info); + free(target->type); + free(target); + return JIM_ERR; + } + /* Do the rest as "configure" options */ - goi->isconfigure = 1; + goi->is_configure = true; e = target_configure(goi, target); if (e == JIM_OK) { @@ -5825,6 +5826,7 @@ static int target_create(struct jim_getopt_info *goi) free(target->gdb_port_override); free(target->trace_info); free(target->type); + free(target->private_config); free(target); return e; } @@ -5834,18 +5836,6 @@ static int target_create(struct jim_getopt_info *goi) target->endianness = TARGET_LITTLE_ENDIAN; } - cp = Jim_GetString(new_cmd, NULL); - target->cmd_name = strdup(cp); - if (!target->cmd_name) { - LOG_ERROR("Out of memory"); - rtos_destroy(target); - free(target->gdb_port_override); - free(target->trace_info); - free(target->type); - free(target); - return JIM_ERR; - } - if (target->type->target_create) { e = (*(target->type->target_create))(target, goi->interp); if (e != ERROR_OK) { @@ -5855,6 +5845,7 @@ static int target_create(struct jim_getopt_info *goi) free(target->gdb_port_override); free(target->trace_info); free(target->type); + free(target->private_config); free(target); return JIM_ERR; } @@ -5984,7 +5975,7 @@ static int get_target_with_common_rtos_type(struct command_invocation *cmd, COMMAND_HANDLER(handle_target_smp) { - static int smp_group = 1; + static unsigned int smp_group = 1; if (CMD_ARGC == 0) { LOG_DEBUG("Empty SMP target"); @@ -6696,14 +6687,14 @@ static const struct command_registration target_exec_command_handlers[] = { { .name = "get_reg", .mode = COMMAND_EXEC, - .jim_handler = target_jim_get_reg, + .handler = handle_target_get_reg, .help = "Get register values from the target", - .usage = "list", + .usage = "[-force] list", }, { .name = "set_reg", .mode = COMMAND_EXEC, - .jim_handler = target_jim_set_reg, + .handler = handle_set_reg_command, .help = "Set target register values", .usage = "dict", }, @@ -6717,7 +6708,7 @@ static const struct command_registration target_exec_command_handlers[] = { { .name = "write_memory", .mode = COMMAND_EXEC, - .jim_handler = target_jim_write_memory, + .handler = handle_target_write_memory, .help = "Write Tcl list of 8/16/32/64 bit numbers to target memory", .usage = "address width data ['phys']", }, diff --git a/src/target/target.h b/src/target/target.h index c74b8c2..d16c3a0 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -142,7 +142,7 @@ struct target { */ bool running_alg; - struct target_event_action *event_action; + struct list_head events_action; bool reset_halt; /* attempt resetting the CPU into the halted mode? */ target_addr_t working_area; /* working area (initialised RAM). Evaluated @@ -163,7 +163,7 @@ struct target { struct watchpoint *watchpoints; /* list of watchpoints */ struct trace *trace_info; /* generic trace information */ struct debug_msg_receiver *dbgmsg; /* list of debug message receivers */ - uint32_t dbg_msg_enabled; /* debug message status */ + bool dbg_msg_enabled; /* debug message status */ void *arch_info; /* architecture specific information */ void *private_config; /* pointer to target specific config data (for jim_configure hook) */ struct target *next; /* next target in list */ @@ -190,7 +190,7 @@ struct target { * poll too quickly because we'll just overwhelm the user with error * messages. */ struct backoff_timer backoff; - int smp; /* Unique non-zero number for each SMP group */ + unsigned int smp; /* Unique non-zero number for each SMP group */ struct list_head *smp_targets; /* list all targets in this smp group/cluster * The head of the list is shared between the * cluster, thus here there is a pointer */ @@ -301,13 +301,6 @@ enum target_event { TARGET_EVENT_SEMIHOSTING_USER_CMD_0X107 = 0x107, }; -struct target_event_action { - enum target_event event; - Jim_Interp *interp; - Jim_Obj *body; - struct target_event_action *next; -}; - bool target_has_event_action(const struct target *target, enum target_event event); struct target_event_callback { @@ -392,8 +385,8 @@ int target_unregister_trace_callback( * yet it is possible to detect error conditions. */ int target_poll(struct target *target); -int target_resume(struct target *target, int current, target_addr_t address, - int handle_breakpoints, int debug_execution); +int target_resume(struct target *target, bool current, target_addr_t address, + bool handle_breakpoints, bool debug_execution); int target_halt(struct target *target); int target_call_event_callbacks(struct target *target, enum target_event event); int target_call_reset_callbacks(struct target *target, enum target_reset_mode reset_mode); @@ -542,7 +535,7 @@ bool target_supports_gdb_connection(const struct target *target); * This routine is a wrapper for target->type->step. */ int target_step(struct target *target, - int current, target_addr_t address, int handle_breakpoints); + bool current, target_addr_t address, bool handle_breakpoints); /** * Run an algorithm on the @a target given. * @@ -691,7 +684,7 @@ target_addr_t target_address_max(struct target *target); * * This routine is a wrapper for target->type->address_bits. */ -unsigned target_address_bits(struct target *target); +unsigned int target_address_bits(struct target *target); /** * Return the number of data bits this target supports. @@ -785,7 +778,7 @@ void target_handle_event(struct target *t, enum target_event e); void target_handle_md_output(struct command_invocation *cmd, struct target *target, target_addr_t address, unsigned size, - unsigned count, const uint8_t *buffer, bool include_address); + unsigned int count, const uint8_t *buffer, bool include_address); int target_profiling_default(struct target *target, uint32_t *samples, uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds); @@ -805,6 +798,7 @@ int target_profiling_default(struct target *target, uint32_t *samples, uint32_t #define ERROR_TARGET_ALGO_EXIT (-313) #define ERROR_TARGET_SIZE_NOT_SUPPORTED (-314) #define ERROR_TARGET_PACKING_NOT_SUPPORTED (-315) +#define ERROR_TARGET_HALTED_DO_RESUME (-316) /* used to workaround incorrect debug halt */ extern bool get_target_reset_nag(void); diff --git a/src/target/target_request.c b/src/target/target_request.c index 72c8421..8d51dc3 100644 --- a/src/target/target_request.c +++ b/src/target/target_request.c @@ -107,7 +107,7 @@ static int target_hexmsg(struct target *target, int size, uint32_t length) */ int target_request(struct target *target, uint32_t request) { - target_req_cmd_t target_req_cmd = request & 0xff; + enum target_req_cmd target_req_cmd = request & 0xff; assert(target->type->target_request_data); @@ -164,7 +164,7 @@ static int add_debug_msg_receiver(struct command_context *cmd_ctx, struct target (*p)->next = NULL; /* enable callback */ - target->dbg_msg_enabled = 1; + target->dbg_msg_enabled = true; return ERROR_OK; } @@ -225,7 +225,7 @@ int delete_debug_msg_receiver(struct command_context *cmd_ctx, struct target *ta free(c); if (!*p) { /* disable callback */ - target->dbg_msg_enabled = 0; + target->dbg_msg_enabled = false; } return ERROR_OK; } else diff --git a/src/target/target_request.h b/src/target/target_request.h index 62d5c74..97edd9e 100644 --- a/src/target/target_request.h +++ b/src/target/target_request.h @@ -17,12 +17,12 @@ struct target; struct command_context; -typedef enum target_req_cmd { +enum target_req_cmd { TARGET_REQ_TRACEMSG, TARGET_REQ_DEBUGMSG, TARGET_REQ_DEBUGCHAR, /* TARGET_REQ_SEMIHOSTING, */ -} target_req_cmd_t; +}; struct debug_msg_receiver { struct command_context *cmd_ctx; diff --git a/src/target/target_type.h b/src/target/target_type.h index bc42c2d..ce98cba 100644 --- a/src/target/target_type.h +++ b/src/target/target_type.h @@ -42,10 +42,10 @@ struct target_type { /* halt will log a warning, but return ERROR_OK if the target is already halted. */ int (*halt)(struct target *target); /* See target.c target_resume() for documentation. */ - int (*resume)(struct target *target, int current, target_addr_t address, - int handle_breakpoints, int debug_execution); - int (*step)(struct target *target, int current, target_addr_t address, - int handle_breakpoints); + int (*resume)(struct target *target, bool current, target_addr_t address, + bool handle_breakpoints, bool debug_execution); + int (*step)(struct target *target, bool current, target_addr_t address, + bool handle_breakpoints); /* target reset control. assert reset can be invoked when OpenOCD and * the target is out of sync. * @@ -303,7 +303,7 @@ struct target_type { /* Return the number of address bits this target supports. This will * typically be 32 for 32-bit targets, and 64 for 64-bit targets. If not * implemented, it's assumed to be 32. */ - unsigned (*address_bits)(struct target *target); + unsigned int (*address_bits)(struct target *target); /* Return the number of system bus data bits this target supports. This * will typically be 32 for 32-bit targets, and 64 for 64-bit targets. If diff --git a/src/target/trace.h b/src/target/trace.h index e3d787e..dc3ab57 100644 --- a/src/target/trace.h +++ b/src/target/trace.h @@ -33,13 +33,13 @@ struct trace { * to *hardware* tracing ... split such "real" tracing out from * the contrib/libdcc support. */ -typedef enum trace_status { +enum trace_status { TRACE_IDLE = 0x0, TRACE_RUNNING = 0x1, TRACE_TRIGGERED = 0x2, TRACE_COMPLETED = 0x4, TRACE_OVERFLOWED = 0x8, -} trace_status_t; +}; int trace_point(struct target *target, uint32_t number); int trace_register_commands(struct command_context *cmd_ctx); diff --git a/src/target/x86_32_common.c b/src/target/x86_32_common.c index ecaf52b..8cca9a5 100644 --- a/src/target/x86_32_common.c +++ b/src/target/x86_32_common.c @@ -677,7 +677,7 @@ int x86_32_common_write_memory(struct target *t, target_addr_t addr, return retval; } -int x86_32_common_read_io(struct target *t, uint32_t addr, +static int x86_32_common_read_io(struct target *t, uint32_t addr, uint32_t size, uint8_t *buf) { struct x86_32_common *x86_32 = target_to_x86_32(t); @@ -1330,14 +1330,14 @@ static int write_hw_reg_from_cache(struct target *t, int num) /* x86 32 commands */ static void handle_iod_output(struct command_invocation *cmd, - struct target *target, uint32_t address, unsigned size, - unsigned count, const uint8_t *buffer) + struct target *target, uint32_t address, unsigned int size, + unsigned int count, const uint8_t *buffer) { - const unsigned line_bytecnt = 32; - unsigned line_modulo = line_bytecnt / size; + const unsigned int line_bytecnt = 32; + unsigned int line_modulo = line_bytecnt / size; char output[line_bytecnt * 4 + 1]; - unsigned output_len = 0; + unsigned int output_len = 0; const char *value_fmt; switch (size) { @@ -1356,12 +1356,12 @@ static void handle_iod_output(struct command_invocation *cmd, return; } - for (unsigned i = 0; i < count; i++) { + for (unsigned int i = 0; i < count; i++) { if (i % line_modulo == 0) { output_len += snprintf(output + output_len, sizeof(output) - output_len, - "0x%8.8x: ", - (unsigned)(address + (i*size))); + "0x%8.8" PRIx32 ": ", + address + (i * size)); } uint32_t value = 0; @@ -1399,7 +1399,7 @@ COMMAND_HANDLER(handle_iod_command) return ERROR_COMMAND_SYNTAX_ERROR; } - unsigned size = 0; + unsigned int size = 0; switch (CMD_NAME[2]) { case 'w': size = 4; @@ -1413,7 +1413,7 @@ COMMAND_HANDLER(handle_iod_command) default: return ERROR_COMMAND_SYNTAX_ERROR; } - unsigned count = 1; + unsigned int count = 1; uint8_t *buffer = calloc(count, size); struct target *target = get_current_target(CMD_CTX); int retval = x86_32_common_read_io(target, address, size, buffer); @@ -1425,7 +1425,7 @@ COMMAND_HANDLER(handle_iod_command) static int target_fill_io(struct target *target, uint32_t address, - unsigned data_size, + unsigned int data_size, /* value */ uint32_t b) { @@ -1458,7 +1458,7 @@ COMMAND_HANDLER(handle_iow_command) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); struct target *target = get_current_target(CMD_CTX); - unsigned wordsize; + unsigned int wordsize; switch (CMD_NAME[2]) { case 'w': wordsize = 4; diff --git a/src/target/x86_32_common.h b/src/target/x86_32_common.h index 7392447..e232747 100644 --- a/src/target/x86_32_common.h +++ b/src/target/x86_32_common.h @@ -309,8 +309,6 @@ int x86_32_common_read_memory(struct target *t, target_addr_t addr, uint32_t size, uint32_t count, uint8_t *buf); int x86_32_common_write_memory(struct target *t, target_addr_t addr, uint32_t size, uint32_t count, const uint8_t *buf); -int x86_32_common_read_io(struct target *t, uint32_t addr, - uint32_t size, uint8_t *buf); int x86_32_common_write_io(struct target *t, uint32_t addr, uint32_t size, const uint8_t *buf); int x86_32_common_add_breakpoint(struct target *t, struct breakpoint *bp); diff --git a/src/target/xscale.c b/src/target/xscale.c index fbf4351..5cc790a 100644 --- a/src/target/xscale.c +++ b/src/target/xscale.c @@ -47,8 +47,8 @@ */ /* forward declarations */ -static int xscale_resume(struct target *, int current, - target_addr_t address, int handle_breakpoints, int debug_execution); +static int xscale_resume(struct target *, bool current, + target_addr_t address, bool handle_breakpoints, bool debug_execution); static int xscale_debug_entry(struct target *); static int xscale_restore_banked(struct target *); static int xscale_get_reg(struct reg *reg); @@ -137,7 +137,7 @@ static int xscale_verify_pointer(struct command_invocation *cmd, return ERROR_OK; } -static int xscale_jtag_set_instr(struct jtag_tap *tap, uint32_t new_instr, tap_state_t end_state) +static int xscale_jtag_set_instr(struct jtag_tap *tap, uint32_t new_instr, enum tap_state end_state) { assert(tap); @@ -232,7 +232,7 @@ static int xscale_receive(struct target *target, uint32_t *buffer, int num_words struct xscale_common *xscale = target_to_xscale(target); int retval = ERROR_OK; - tap_state_t path[3]; + enum tap_state path[3]; struct scan_field fields[3]; uint8_t *field0 = malloc(num_words * 1); uint8_t field0_check_value = 0x2; @@ -330,8 +330,8 @@ static int xscale_receive(struct target *target, uint32_t *buffer, int num_words static int xscale_read_tx(struct target *target, int consume) { struct xscale_common *xscale = target_to_xscale(target); - tap_state_t path[3]; - tap_state_t noconsume_path[6]; + enum tap_state path[3]; + enum tap_state noconsume_path[6]; int retval; struct timeval timeout, now; struct scan_field fields[3]; @@ -840,7 +840,7 @@ static int xscale_debug_entry(struct target *target) struct arm *arm = &xscale->arm; uint32_t pc; uint32_t buffer[10]; - unsigned i; + unsigned int i; int retval; uint32_t moe; @@ -997,7 +997,7 @@ static int xscale_debug_entry(struct target *target) * can only happen in fill mode. */ if (xscale->arch_debug_reason == XSCALE_DBG_REASON_TB_FULL) { if (--xscale->trace.fill_counter > 0) - xscale_resume(target, 1, 0x0, 1, 0); + xscale_resume(target, true, 0x0, true, false); } else /* entered debug for other reason; reset counter */ xscale->trace.fill_counter = 0; } @@ -1106,8 +1106,8 @@ static void xscale_free_trace_data(struct xscale_common *xscale) xscale->trace.data = NULL; } -static int xscale_resume(struct target *target, int current, - target_addr_t address, int handle_breakpoints, int debug_execution) +static int xscale_resume(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints, bool debug_execution) { struct xscale_common *xscale = target_to_xscale(target); struct arm *arm = &xscale->arm; @@ -1130,7 +1130,7 @@ static int xscale_resume(struct target *target, int current, if (retval != ERROR_OK) return retval; - /* current = 1: continue on current pc, otherwise continue at <address> */ + /* current = true: continue on current pc, otherwise continue at <address> */ if (!current) buf_set_u32(arm->pc->value, 0, 32, address); @@ -1277,8 +1277,8 @@ static int xscale_resume(struct target *target, int current, return ERROR_OK; } -static int xscale_step_inner(struct target *target, int current, - uint32_t address, int handle_breakpoints) +static int xscale_step_inner(struct target *target, bool current, + uint32_t address, bool handle_breakpoints) { struct xscale_common *xscale = target_to_xscale(target); struct arm *arm = &xscale->arm; @@ -1372,8 +1372,8 @@ static int xscale_step_inner(struct target *target, int current, return ERROR_OK; } -static int xscale_step(struct target *target, int current, - target_addr_t address, int handle_breakpoints) +static int xscale_step(struct target *target, bool current, + target_addr_t address, bool handle_breakpoints) { struct arm *arm = target_to_arm(target); struct breakpoint *breakpoint = NULL; @@ -1386,7 +1386,7 @@ static int xscale_step(struct target *target, int current, return ERROR_TARGET_NOT_HALTED; } - /* current = 1: continue on current pc, otherwise continue at <address> */ + /* current = true: continue on current pc, otherwise continue at <address> */ if (!current) buf_set_u32(arm->pc->value, 0, 32, address); @@ -1515,7 +1515,7 @@ static int xscale_deassert_reset(struct target *target) */ { uint32_t address; - unsigned buf_cnt; + unsigned int buf_cnt; const uint8_t *buffer = xscale_debug_handler; int retval; @@ -1539,11 +1539,11 @@ static int xscale_deassert_reset(struct target *target) * coprocessors, trace data, etc. */ address = xscale->handler_address; - for (unsigned binary_size = sizeof(xscale_debug_handler); + for (unsigned int binary_size = sizeof(xscale_debug_handler); binary_size > 0; binary_size -= buf_cnt, buffer += buf_cnt) { uint32_t cache_line[8]; - unsigned i; + unsigned int i; buf_cnt = binary_size; if (buf_cnt > 32) @@ -1598,7 +1598,7 @@ static int xscale_deassert_reset(struct target *target) target->state = TARGET_HALTED; /* resume the target */ - xscale_resume(target, 1, 0x0, 1, 0); + xscale_resume(target, true, 0x0, true, false); } } @@ -3215,7 +3215,7 @@ COMMAND_HANDLER(xscale_handle_idcache_command) static const struct { char name[15]; - unsigned mask; + unsigned int mask; } vec_ids[] = { { "fiq", DCSR_TF, }, { "irq", DCSR_TI, }, @@ -3250,7 +3250,7 @@ COMMAND_HANDLER(xscale_handle_vector_catch_command) } } while (CMD_ARGC-- > 0) { - unsigned i; + unsigned int i; for (i = 0; i < ARRAY_SIZE(vec_ids); i++) { if (strcmp(CMD_ARGV[CMD_ARGC], vec_ids[i].name)) continue; @@ -3268,7 +3268,7 @@ COMMAND_HANDLER(xscale_handle_vector_catch_command) } dcsr_value = buf_get_u32(dcsr_reg->value, 0, 32); - for (unsigned i = 0; i < ARRAY_SIZE(vec_ids); i++) { + for (unsigned int i = 0; i < ARRAY_SIZE(vec_ids); i++) { command_print(CMD, "%15s: %s", vec_ids[i].name, (dcsr_value & vec_ids[i].mask) ? "catch" : "ignore"); } diff --git a/src/target/xtensa/xtensa.c b/src/target/xtensa/xtensa.c index 702b8fc..3a877ed 100644 --- a/src/target/xtensa/xtensa.c +++ b/src/target/xtensa/xtensa.c @@ -503,7 +503,7 @@ static enum xtensa_reg_id xtensa_windowbase_offset_to_canonical(struct xtensa *x } else if (reg_idx >= XT_REG_IDX_A0 && reg_idx <= XT_REG_IDX_A15) { idx = reg_idx - XT_REG_IDX_A0; } else { - LOG_ERROR("Error: can't convert register %d to non-windowbased register!", reg_idx); + LOG_ERROR("Can't convert register %d to non-windowbased register", reg_idx); return -1; } /* Each windowbase value represents 4 registers on LX and 8 on NX */ @@ -540,7 +540,7 @@ static void xtensa_queue_exec_ins_wide(struct xtensa *xtensa, uint8_t *ops, uint for (int32_t i = oplenw - 1; i > 0; i--) xtensa_queue_dbg_reg_write(xtensa, XDMREG_DIR0 + i, - target_buffer_get_u32(xtensa->target, &ops_padded[sizeof(uint32_t)*i])); + target_buffer_get_u32(xtensa->target, &ops_padded[sizeof(uint32_t) * i])); /* Write DIR0EXEC last */ xtensa_queue_dbg_reg_write(xtensa, XDMREG_DIR0EXEC, @@ -1591,10 +1591,10 @@ int xtensa_halt(struct target *target) } int xtensa_prepare_resume(struct target *target, - int current, + bool current, target_addr_t address, - int handle_breakpoints, - int debug_execution) + bool handle_breakpoints, + bool debug_execution) { struct xtensa *xtensa = target_to_xtensa(target); uint32_t bpena = 0; @@ -1671,13 +1671,14 @@ int xtensa_do_resume(struct target *target) } int xtensa_resume(struct target *target, - int current, + bool current, target_addr_t address, - int handle_breakpoints, - int debug_execution) + bool handle_breakpoints, + bool debug_execution) { LOG_TARGET_DEBUG(target, "start"); - int res = xtensa_prepare_resume(target, current, address, handle_breakpoints, debug_execution); + int res = xtensa_prepare_resume(target, current, address, + handle_breakpoints, debug_execution); if (res != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to prepare for resume!"); return res; @@ -1719,7 +1720,8 @@ static bool xtensa_pc_in_winexc(struct target *target, target_addr_t pc) return false; } -int xtensa_do_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) +int xtensa_do_step(struct target *target, bool current, target_addr_t address, + bool handle_breakpoints) { struct xtensa *xtensa = target_to_xtensa(target); int res; @@ -1727,7 +1729,7 @@ int xtensa_do_step(struct target *target, int current, target_addr_t address, in xtensa_reg_val_t dbreakc[XT_WATCHPOINTS_NUM_MAX]; xtensa_reg_val_t icountlvl, cause; xtensa_reg_val_t oldps, oldpc, cur_pc; - bool ps_lowered = false; + bool ps_modified = false; LOG_TARGET_DEBUG(target, "current=%d, address=" TARGET_ADDR_FMT ", handle_breakpoints=%i", current, address, handle_breakpoints); @@ -1783,14 +1785,23 @@ int xtensa_do_step(struct target *target, int current, target_addr_t address, in * RFI >= DBGLEVEL. */ if (xtensa->stepping_isr_mode == XT_STEPPING_ISR_OFF) { - if (!xtensa->core_config->high_irq.enabled) { - LOG_TARGET_WARNING( - target, - "disabling IRQs while stepping is not implemented w/o high prio IRQs option!"); - return ERROR_FAIL; + if (xtensa->core_config->core_type == XT_LX) { + if (!xtensa->core_config->high_irq.enabled) { + LOG_TARGET_WARNING(target, + "disabling IRQs while stepping is not implemented w/o high prio IRQs option!"); + return ERROR_FAIL; + } + /* Update ICOUNTLEVEL accordingly */ + icountlvl = MIN((oldps & 0xF) + 1, xtensa->core_config->debug.irq_level); + } else { + /* Xtensa NX does not have the ICOUNTLEVEL feature present in Xtensa LX + * and instead disable interrupts while stepping. This could change + * the timing of the system while under debug */ + xtensa_reg_val_t newps = oldps | XT_PS_DI_MSK; + xtensa_reg_set(target, XT_REG_IDX_PS, newps); + icountlvl = xtensa->core_config->debug.irq_level; + ps_modified = true; } - /* Update ICOUNTLEVEL accordingly */ - icountlvl = MIN((oldps & 0xF) + 1, xtensa->core_config->debug.irq_level); } else { icountlvl = xtensa->core_config->debug.irq_level; } @@ -1815,7 +1826,7 @@ int xtensa_do_step(struct target *target, int current, target_addr_t address, in xtensa_cause_clear(target); /* so we don't recurse into the same routine */ if (xtensa->core_config->core_type == XT_LX && ((oldps & 0xf) >= icountlvl)) { /* Lower interrupt level to allow stepping, but flag eps[dbglvl] to be restored */ - ps_lowered = true; + ps_modified = true; uint32_t newps = (oldps & ~0xf) | (icountlvl - 1); xtensa_reg_set(target, xtensa->eps_dbglevel_idx, newps); LOG_TARGET_DEBUG(target, @@ -1835,7 +1846,7 @@ int xtensa_do_step(struct target *target, int current, target_addr_t address, in /* Now that ICOUNT (LX) or DCR.StepRequest (NX) is set, * we can resume as if we were going to run */ - res = xtensa_prepare_resume(target, current, address, 0, 0); + res = xtensa_prepare_resume(target, current, address, false, false); if (res != ERROR_OK) { LOG_TARGET_ERROR(target, "Failed to prepare resume for single step"); return res; @@ -1916,11 +1927,12 @@ int xtensa_do_step(struct target *target, int current, target_addr_t address, in } /* Restore int level */ - if (ps_lowered) { + if (ps_modified) { LOG_DEBUG("Restoring %s after stepping: 0x%08" PRIx32, - xtensa->core_cache->reg_list[xtensa->eps_dbglevel_idx].name, - oldps); - xtensa_reg_set(target, xtensa->eps_dbglevel_idx, oldps); + xtensa->core_cache->reg_list[(xtensa->core_config->core_type == XT_LX) ? + xtensa->eps_dbglevel_idx : XT_REG_IDX_PS].name, oldps); + xtensa_reg_set(target, (xtensa->core_config->core_type == XT_LX) ? + xtensa->eps_dbglevel_idx : XT_REG_IDX_PS, oldps); } /* write ICOUNTLEVEL back to zero */ @@ -1931,7 +1943,8 @@ int xtensa_do_step(struct target *target, int current, target_addr_t address, in return res; } -int xtensa_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) +int xtensa_step(struct target *target, bool current, target_addr_t address, + bool handle_breakpoints) { int retval = xtensa_do_step(target, current, address, handle_breakpoints); if (retval != ERROR_OK) @@ -2796,7 +2809,7 @@ int xtensa_start_algorithm(struct target *target, } } - return xtensa_resume(target, 0, entry_point, 1, 1); + return xtensa_resume(target, false, entry_point, true, true); } /** Waits for an algorithm in the target. */ @@ -3000,13 +3013,13 @@ static int xtensa_build_reg_cache(struct target *target) /* Construct empty-register list for handling unknown register requests */ xtensa->empty_regs = calloc(xtensa->dbregs_num, sizeof(struct reg)); if (!xtensa->empty_regs) { - LOG_TARGET_ERROR(target, "ERROR: Out of memory"); + LOG_TARGET_ERROR(target, "Out of memory"); goto fail; } for (unsigned int i = 0; i < xtensa->dbregs_num; i++) { xtensa->empty_regs[i].name = calloc(8, sizeof(char)); if (!xtensa->empty_regs[i].name) { - LOG_TARGET_ERROR(target, "ERROR: Out of memory"); + LOG_TARGET_ERROR(target, "Out of memory"); goto fail; } sprintf((char *)xtensa->empty_regs[i].name, "?0x%04x", i & 0x0000FFFF); @@ -3024,7 +3037,7 @@ static int xtensa_build_reg_cache(struct target *target) if (xtensa->regmap_contiguous && xtensa->contiguous_regs_desc) { xtensa->contiguous_regs_list = calloc(xtensa->total_regs_num, sizeof(struct reg *)); if (!xtensa->contiguous_regs_list) { - LOG_TARGET_ERROR(target, "ERROR: Out of memory"); + LOG_TARGET_ERROR(target, "Out of memory"); goto fail; } for (unsigned int i = 0; i < xtensa->total_regs_num; i++) { @@ -3966,10 +3979,10 @@ COMMAND_HELPER(xtensa_cmd_xtreg_do, struct xtensa *xtensa) rptr->type = XT_REG_OTHER; } - /* Register flags */ + /* Register flags: includes intsetN, intclearN for LX8 */ if ((strcmp(rptr->name, "mmid") == 0) || (strcmp(rptr->name, "eraccess") == 0) || - (strcmp(rptr->name, "ddr") == 0) || (strcmp(rptr->name, "intset") == 0) || - (strcmp(rptr->name, "intclear") == 0)) + (strcmp(rptr->name, "ddr") == 0) || (strncmp(rptr->name, "intset", 6) == 0) || + (strncmp(rptr->name, "intclear", 8) == 0) || (strcmp(rptr->name, "mesrclr") == 0)) rptr->flags = XT_REGF_NOREAD; else rptr->flags = 0; @@ -4191,11 +4204,6 @@ COMMAND_HELPER(xtensa_cmd_mask_interrupts_do, struct xtensa *xtensa) return ERROR_OK; } - if (xtensa->core_config->core_type == XT_NX) { - command_print(CMD, "ERROR: ISR step mode only supported on Xtensa LX"); - return ERROR_FAIL; - } - /* Masking is ON -> interrupts during stepping are OFF, and vice versa */ if (!strcasecmp(CMD_ARGV[0], "off")) state = XT_STEPPING_ISR_ON; diff --git a/src/target/xtensa/xtensa.h b/src/target/xtensa/xtensa.h index 1d56f83..a920f77 100644 --- a/src/target/xtensa/xtensa.h +++ b/src/target/xtensa/xtensa.h @@ -45,6 +45,7 @@ /* PS register bits (NX) */ #define XT_PS_DIEXC_MSK BIT(2) +#define XT_PS_DI_MSK BIT(3) /* MS register bits (NX) */ #define XT_MS_DE_MSK BIT(5) @@ -377,18 +378,20 @@ int xtensa_poll(struct target *target); void xtensa_on_poll(struct target *target); int xtensa_halt(struct target *target); int xtensa_resume(struct target *target, - int current, + bool current, target_addr_t address, - int handle_breakpoints, - int debug_execution); + bool handle_breakpoints, + bool debug_execution); int xtensa_prepare_resume(struct target *target, - int current, + bool current, target_addr_t address, - int handle_breakpoints, - int debug_execution); + bool handle_breakpoints, + bool debug_execution); int xtensa_do_resume(struct target *target); -int xtensa_step(struct target *target, int current, target_addr_t address, int handle_breakpoints); -int xtensa_do_step(struct target *target, int current, target_addr_t address, int handle_breakpoints); +int xtensa_step(struct target *target, bool current, target_addr_t address, + bool handle_breakpoints); +int xtensa_do_step(struct target *target, bool current, target_addr_t address, + bool handle_breakpoints); int xtensa_mmu_is_enabled(struct target *target, int *enabled); int xtensa_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); int xtensa_read_buffer(struct target *target, target_addr_t address, uint32_t count, uint8_t *buffer); diff --git a/src/target/xtensa/xtensa_chip.c b/src/target/xtensa/xtensa_chip.c index ac4a49c..ce6d35c 100644 --- a/src/target/xtensa/xtensa_chip.c +++ b/src/target/xtensa/xtensa_chip.c @@ -103,7 +103,7 @@ static int xtensa_chip_target_create(struct target *target, Jim_Interp *interp) LOG_DEBUG("DAP: ap_num %" PRId64 " DAP %p\n", pc->ap_num, pc->dap); } else { xtensa_chip_dm_cfg.tap = target->tap; - LOG_DEBUG("JTAG: %s:%s pos %d", target->tap->chip, target->tap->tapname, + LOG_DEBUG("JTAG: %s:%s pos %u", target->tap->chip, target->tap->tapname, target->tap->abs_chain_position); } diff --git a/src/target/xtensa/xtensa_debug_module.c b/src/target/xtensa/xtensa_debug_module.c index 8045779..943f199 100644 --- a/src/target/xtensa/xtensa_debug_module.c +++ b/src/target/xtensa/xtensa_debug_module.c @@ -60,7 +60,7 @@ static void xtensa_dm_add_dr_scan(struct xtensa_debug_module *dm, int len, const uint8_t *src, uint8_t *dest, - tap_state_t endstate) + enum tap_state endstate) { struct scan_field field; diff --git a/src/target/xtensa/xtensa_debug_module.h b/src/target/xtensa/xtensa_debug_module.h index 495da2a..8391a96 100644 --- a/src/target/xtensa/xtensa_debug_module.h +++ b/src/target/xtensa/xtensa_debug_module.h @@ -75,6 +75,7 @@ enum xtensa_dm_reg { XDMREG_DELAYCNT, XDMREG_MEMADDRSTART, XDMREG_MEMADDREND, + XDMREG_DEBUGPC,/*Unsupported, undocumented, may not be present*/ XDMREG_EXTTIMELO, XDMREG_EXTTIMEHI, XDMREG_TRAXRSVD48, @@ -184,6 +185,7 @@ struct xtensa_dm_reg_offsets { { .nar = 0x07, .apb = 0x001c }, /* XDMREG_DELAYCNT */ \ { .nar = 0x08, .apb = 0x0020 }, /* XDMREG_MEMADDRSTART */ \ { .nar = 0x09, .apb = 0x0024 }, /* XDMREG_MEMADDREND */ \ + { .nar = 0x0f, .apb = 0x003c }, /* XDMREG_DEBUGPC */ \ { .nar = 0x10, .apb = 0x0040 }, /* XDMREG_EXTTIMELO */ \ { .nar = 0x11, .apb = 0x0044 }, /* XDMREG_EXTTIMEHI */ \ { .nar = 0x12, .apb = 0x0048 }, /* XDMREG_TRAXRSVD48 */ \ |