X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Ftarget%2Ftarget.c;h=7e30d789b62d9e50a0972af2219909ff8ed478fc;hp=bd9d56b04673395718209eb8a463be98b05b556c;hb=a851b91c4c1db76dd1e26a7d1a99124ad456b020;hpb=7ad11de2fa37b504fc84f608ee355cf02221429a diff --git a/src/target/target.c b/src/target/target.c index bd9d56b046..7e30d789b6 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -54,6 +54,7 @@ #include "image.h" #include "rtos/rtos.h" #include "transport/transport.h" +#include "arm_cti.h" /* default halt wait timeout (ms) */ #define DEFAULT_HALT_TIMEOUT 5000 @@ -106,6 +107,9 @@ extern struct target_type or1k_target; extern struct target_type quark_x10xx_target; extern struct target_type quark_d20xx_target; extern struct target_type stm8_target; +extern struct target_type riscv_target; +extern struct target_type mem_ap_target; +extern struct target_type esirisc_target; static struct target_type *target_types[] = { &arm7tdmi_target, @@ -138,6 +142,9 @@ static struct target_type *target_types[] = { &quark_x10xx_target, &quark_d20xx_target, &stm8_target, + &riscv_target, + &mem_ap_target, + &esirisc_target, #if BUILD_TARGET64 &aarch64_target, #endif @@ -510,9 +517,7 @@ struct target *get_target_by_num(int num) struct target *get_current_target(struct command_context *cmd_ctx) { - struct target *target = cmd_ctx->current_target_override - ? cmd_ctx->current_target_override - : cmd_ctx->current_target; + struct target *target = get_current_target_or_null(cmd_ctx); if (target == NULL) { LOG_ERROR("BUG: current_target out of bounds"); @@ -522,6 +527,13 @@ struct target *get_current_target(struct command_context *cmd_ctx) return target; } +struct target *get_current_target_or_null(struct command_context *cmd_ctx) +{ + return cmd_ctx->current_target_override + ? cmd_ctx->current_target_override + : cmd_ctx->current_target; +} + int target_poll(struct target *target) { int retval; @@ -1040,6 +1052,9 @@ int target_run_flash_async_algorithm(struct target *target, retval = target_write_u32(target, wp_addr, wp); if (retval != ERROR_OK) break; + + /* Avoid GDB timeouts */ + keep_alive(); } if (retval != ERROR_OK) { @@ -1194,12 +1209,29 @@ int target_hit_watchpoint(struct target *target, return target->type->hit_watchpoint(target, hit_watchpoint); } +const char *target_get_gdb_arch(struct target *target) +{ + if (target->type->get_gdb_arch == NULL) + return NULL; + return target->type->get_gdb_arch(target); +} + int target_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { return target->type->get_gdb_reg_list(target, reg_list, reg_list_size, reg_class); } + +bool target_supports_gdb_connection(struct target *target) +{ + /* + * based on current code, we can simply exclude all the targets that + * don't provide get_gdb_reg_list; this could change with new targets. + */ + return !!target->type->get_gdb_reg_list; +} + int target_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { @@ -1887,11 +1919,75 @@ int target_free_working_area(struct target *target, struct working_area *area) return target_free_working_area_restore(target, area, 1); } +/* free resources and restore memory, if restoring memory fails, + * free up resources anyway + */ +static void target_free_all_working_areas_restore(struct target *target, int restore) +{ + struct working_area *c = target->working_areas; + + LOG_DEBUG("freeing all working areas"); + + /* Loop through all areas, restoring the allocated ones and marking them as free */ + while (c) { + if (!c->free) { + if (restore) + target_restore_working_area(target, c); + c->free = true; + *c->user = NULL; /* Same as above */ + c->user = NULL; + } + c = c->next; + } + + /* Run a merge pass to combine all areas into one */ + target_merge_working_areas(target); + + print_wa_layout(target); +} + +void target_free_all_working_areas(struct target *target) +{ + target_free_all_working_areas_restore(target, 1); + + /* Now we have none or only one working area marked as free */ + if (target->working_areas) { + /* Free the last one to allow on-the-fly moving and resizing */ + free(target->working_areas->backup); + free(target->working_areas); + target->working_areas = NULL; + } +} + +/* Find the largest number of bytes that can be allocated */ +uint32_t target_get_working_area_avail(struct target *target) +{ + struct working_area *c = target->working_areas; + uint32_t max_size = 0; + + if (c == NULL) + return target->working_area_size; + + while (c) { + if (c->free && max_size < c->size) + max_size = c->size; + + c = c->next; + } + + return max_size; +} + static void target_destroy(struct target *target) { if (target->type->deinit_target) target->type->deinit_target(target); + if (target->semihosting) + free(target->semihosting); + + 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; @@ -1901,12 +1997,20 @@ static void target_destroy(struct target *target) } target_free_all_working_areas(target); - /* Now we have none or only one working area marked as free */ - if (target->working_areas) { - free(target->working_areas->backup); - free(target->working_areas); + + /* release the targets SMP list */ + if (target->smp) { + struct target_list *head = target->head; + while (head != NULL) { + struct target_list *pos = head->next; + head->target->smp = 0; + free(head); + head = pos; + } + target->smp = 0; } + free(target->gdb_port_override); free(target->type); free(target->trace_info); free(target->fileio_info); @@ -1943,57 +2047,6 @@ void target_quit(void) all_targets = NULL; } -/* free resources and restore memory, if restoring memory fails, - * free up resources anyway - */ -static void target_free_all_working_areas_restore(struct target *target, int restore) -{ - struct working_area *c = target->working_areas; - - LOG_DEBUG("freeing all working areas"); - - /* Loop through all areas, restoring the allocated ones and marking them as free */ - while (c) { - if (!c->free) { - if (restore) - target_restore_working_area(target, c); - c->free = true; - *c->user = NULL; /* Same as above */ - c->user = NULL; - } - c = c->next; - } - - /* Run a merge pass to combine all areas into one */ - target_merge_working_areas(target); - - print_wa_layout(target); -} - -void target_free_all_working_areas(struct target *target) -{ - target_free_all_working_areas_restore(target, 1); -} - -/* Find the largest number of bytes that can be allocated */ -uint32_t target_get_working_area_avail(struct target *target) -{ - struct working_area *c = target->working_areas; - uint32_t max_size = 0; - - if (c == NULL) - return target->working_area_size; - - while (c) { - if (c->free && max_size < c->size) - max_size = c->size; - - c = c->next; - } - - return max_size; -} - int target_arch_state(struct target *target) { int retval; @@ -2236,21 +2289,19 @@ int target_checksum_memory(struct target *target, target_addr_t address, uint32_ return retval; } -int target_blank_check_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t* blank, +int target_blank_check_memory(struct target *target, + struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value) { - int retval; if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } - if (target->type->blank_check_memory == 0) + if (target->type->blank_check_memory == NULL) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - retval = target->type->blank_check_memory(target, address, size, blank, erased_value); - - return retval; + return target->type->blank_check_memory(target, blocks, num_blocks, erased_value); } int target_read_u64(struct target *target, target_addr_t address, uint64_t *value) @@ -2773,6 +2824,8 @@ COMMAND_HANDLER(handle_reg_command) for (i = 0, reg = cache->reg_list; i < cache->num_regs; i++, reg++, count++) { + if (reg->exist == false) + continue; /* only print cached values if they are valid */ if (reg->valid) { value = buf_to_str(reg->value, @@ -2826,14 +2879,15 @@ COMMAND_HANDLER(handle_reg_command) /* access a single register by its name */ reg = register_get_by_name(target->reg_cache, CMD_ARGV[0], 1); - if (!reg) { - command_print(CMD_CTX, "register %s not found in current target", CMD_ARGV[0]); - return ERROR_OK; - } + if (!reg) + goto not_found; } assert(reg != NULL); /* give clang a hint that we *know* reg is != NULL here */ + if (!reg->exist) + goto not_found; + /* display a register */ if ((CMD_ARGC == 1) || ((CMD_ARGC == 2) && !((CMD_ARGV[1][0] >= '0') && (CMD_ARGV[1][0] <= '9')))) { @@ -2867,6 +2921,10 @@ COMMAND_HANDLER(handle_reg_command) } return ERROR_COMMAND_SYNTAX_ERROR; + +not_found: + command_print(CMD_CTX, "register %s not found in current target", CMD_ARGV[0]); + return ERROR_OK; } COMMAND_HANDLER(handle_poll_command) @@ -2958,6 +3016,9 @@ COMMAND_HANDLER(handle_halt_command) LOG_DEBUG("-"); struct target *target = get_current_target(CMD_CTX); + + target->verbose_halt_msg = true; + int retval = target_halt(target); if (ERROR_OK != retval) return retval; @@ -4112,8 +4173,9 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, * argv[3] = memory address * argv[4] = count of times to read */ + if (argc < 4 || argc > 5) { - Jim_WrongNumArgs(interp, 1, argv, "varname width addr nelems [phys]"); + Jim_WrongNumArgs(interp, 0, argv, "varname width addr nelems [phys]"); return JIM_ERR; } varname = Jim_GetString(argv[0], &len); @@ -4513,9 +4575,9 @@ enum target_cfg_param { TCFG_COREID, TCFG_CHAIN_POSITION, TCFG_DBGBASE, - TCFG_CTIBASE, TCFG_RTOS, TCFG_DEFER_EXAMINE, + TCFG_GDB_PORT, }; static Jim_Nvp nvp_config_opts[] = { @@ -4529,9 +4591,9 @@ static Jim_Nvp nvp_config_opts[] = { { .name = "-coreid", .value = TCFG_COREID }, { .name = "-chain-position", .value = TCFG_CHAIN_POSITION }, { .name = "-dbgbase", .value = TCFG_DBGBASE }, - { .name = "-ctibase", .value = TCFG_CTIBASE }, { .name = "-rtos", .value = TCFG_RTOS }, { .name = "-defer-examine", .value = TCFG_DEFER_EXAMINE }, + { .name = "-gdb-port", .value = TCFG_GDB_PORT }, { .name = NULL, .value = -1 } }; @@ -4766,6 +4828,13 @@ no_params: if (goi->isconfigure) { Jim_Obj *o_t; struct jtag_tap *tap; + + if (target->has_dap) { + Jim_SetResultString(goi->interp, + "target requires -dap parameter instead of -chain-position!", -1); + return JIM_ERR; + } + target_free_all_working_areas(target); e = Jim_GetOpt_Obj(goi, &o_t); if (e != JIM_OK) @@ -4773,8 +4842,8 @@ no_params: tap = jtag_tap_by_jim_obj(goi->interp, o_t); if (tap == NULL) return JIM_ERR; - /* make this exactly 1 or 0 */ target->tap = tap; + target->tap_configured = true; } else { if (goi->argc != 0) goto no_params; @@ -4796,20 +4865,6 @@ no_params: Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->dbgbase)); /* loop for more */ break; - case TCFG_CTIBASE: - if (goi->isconfigure) { - e = Jim_GetOpt_Wide(goi, &w); - if (e != JIM_OK) - return e; - target->ctibase = (uint32_t)w; - target->ctibase_set = true; - } else { - if (goi->argc != 0) - goto no_params; - } - Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->ctibase)); - /* loop for more */ - break; case TCFG_RTOS: /* RTOS */ { @@ -4826,6 +4881,20 @@ no_params: /* loop for more */ break; + case TCFG_GDB_PORT: + if (goi->isconfigure) { + const char *s; + e = Jim_GetOpt_String(goi, &s, NULL); + if (e != JIM_OK) + return e; + target->gdb_port_override = strdup(s); + } else { + if (goi->argc != 0) + goto no_params; + } + Jim_SetResultString(goi->interp, target->gdb_port_override ? : "undefined", -1); + /* loop for more */ + break; } } /* while (goi->argc) */ @@ -5426,21 +5495,19 @@ static const struct command_registration target_instance_command_handlers[] = { .mode = COMMAND_EXEC, .jim_handler = jim_target_examine, .help = "used internally for reset processing", - .usage = "arp_examine ['allow-defer']", + .usage = "['allow-defer']", }, { .name = "was_examined", .mode = COMMAND_EXEC, .jim_handler = jim_target_was_examined, .help = "used internally for reset processing", - .usage = "was_examined", }, { .name = "examine_deferred", .mode = COMMAND_EXEC, .jim_handler = jim_target_examine_deferred, .help = "used internally for reset processing", - .usage = "examine_deferred", }, { .name = "arp_halt_gdb", @@ -5587,7 +5654,7 @@ static int target_create(Jim_GetOptInfo *goi) target->next = NULL; target->arch_info = NULL; - target->display = 1; + target->verbose_halt_msg = true; target->halt_issued = false; @@ -5602,16 +5669,31 @@ static int target_create(Jim_GetOptInfo *goi) target->rtos = NULL; target->rtos_auto_detect = false; + target->gdb_port_override = NULL; + /* Do the rest as "configure" options */ goi->isconfigure = 1; e = target_configure(goi, target); - if (target->tap == NULL) { - Jim_SetResultString(goi->interp, "-chain-position required when creating target", -1); - e = JIM_ERR; + if (e == JIM_OK) { + if (target->has_dap) { + if (!target->dap_configured) { + Jim_SetResultString(goi->interp, "-dap ?name? required when creating target", -1); + e = JIM_ERR; + } + } else { + if (!target->tap_configured) { + Jim_SetResultString(goi->interp, "-chain-position ?name? required when creating target", -1); + e = JIM_ERR; + } + } + /* tap must be set after target was configured */ + if (target->tap == NULL) + e = JIM_ERR; } if (e != JIM_OK) { + free(target->gdb_port_override); free(target->type); free(target); return e; @@ -5625,14 +5707,24 @@ static int target_create(Jim_GetOptInfo *goi) cp = Jim_GetString(new_cmd, NULL); target->cmd_name = strdup(cp); + if (target->type->target_create) { + e = (*(target->type->target_create))(target, goi->interp); + if (e != ERROR_OK) { + LOG_DEBUG("target_create failed"); + free(target->gdb_port_override); + free(target->type); + free(target->cmd_name); + free(target); + return JIM_ERR; + } + } + /* create the target specific commands */ if (target->type->commands) { e = register_commands(cmd_ctx, NULL, target->type->commands); if (ERROR_OK != e) LOG_ERROR("unable to register '%s' commands", cp); } - if (target->type->target_create) - (*(target->type->target_create))(target, goi->interp); /* append to end of list */ { @@ -5790,8 +5882,7 @@ static const struct command_registration target_subcommand_handlers[] = { }, { .name = "create", - /* REVISIT this should be COMMAND_CONFIG ... */ - .mode = COMMAND_ANY, + .mode = COMMAND_CONFIG, .jim_handler = jim_target_create, .usage = "name type '-chain-position' name [options ...]", .help = "Creates and selects a new target", @@ -6386,7 +6477,7 @@ static const struct command_registration target_exec_command_handlers[] = { .handler = handle_bp_command, .mode = COMMAND_EXEC, .help = "list or set hardware or software breakpoint", - .usage = "
[] ['hw'|'hw_ctx']", + .usage = "
[] ['hw'|'hw_ctx']", }, { .name = "rbp",