X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Ftarget%2Ftarget.c;h=6f086b3e44ff60803e3da50f7603e20a347a2a35;hb=5f993dc17c92630514287f886cffefc560a98c42;hp=f79156ad645d0cdafd3d1afafe19913e0e0a6147;hpb=7df08fc385c4c5f28eb2bfb70f07abf302b5533a;p=openocd.git diff --git a/src/target/target.c b/src/target/target.c index f79156ad64..6f086b3e44 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -2,9 +2,15 @@ * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * * * - * Copyright (C) 2007,2008 Øyvind Harboe * + * Copyright (C) 2007,2008 Øyvind Harboe * * oyvind.harboe@zylin.com * * * + * Copyright (C) 2008, Duane Ellis * + * openocd@duaneeellis.com * + * * + * Copyright (C) 2008 by Spencer Oliver * + * spen@spen-soft.co.uk * + * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * @@ -52,7 +58,7 @@ int cli_target_callback_event_handler(struct target_s *target, enum target_event event, void *priv); -int handle_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); + int handle_targets_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); int handle_working_area_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); @@ -78,7 +84,7 @@ int handle_virt2phys_command(command_context_t *cmd_ctx, char *cmd, char **args, int handle_profile_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc); static int jim_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv); static int jim_mem2array(Jim_Interp *interp, int argc, Jim_Obj *const *argv); - +static int jim_target( Jim_Interp *interp, int argc, Jim_Obj *const *argv); static int target_array2mem(Jim_Interp *interp, target_t *target, int argc, Jim_Obj *const *argv); static int target_mem2array(Jim_Interp *interp, target_t *target, int argc, Jim_Obj *const *argv); @@ -128,31 +134,77 @@ const Jim_Nvp nvp_assert[] = { { .name = NULL, .value = -1 } }; +const Jim_Nvp nvp_error_target[] = { + { .value = ERROR_TARGET_INVALID, .name = "err-invalid" }, + { .value = ERROR_TARGET_INIT_FAILED, .name = "err-init-failed" }, + { .value = ERROR_TARGET_TIMEOUT, .name = "err-timeout" }, + { .value = ERROR_TARGET_NOT_HALTED, .name = "err-not-halted" }, + { .value = ERROR_TARGET_FAILURE, .name = "err-failure" }, + { .value = ERROR_TARGET_UNALIGNED_ACCESS , .name = "err-unaligned-access" }, + { .value = ERROR_TARGET_DATA_ABORT , .name = "err-data-abort" }, + { .value = ERROR_TARGET_RESOURCE_NOT_AVAILABLE , .name = "err-resource-not-available" }, + { .value = ERROR_TARGET_TRANSLATION_FAULT , .name = "err-translation-fault" }, + { .value = ERROR_TARGET_NOT_RUNNING, .name = "err-not-running" }, + { .value = ERROR_TARGET_NOT_EXAMINED, .name = "err-not-examined" }, + { .value = -1, .name = NULL } +}; + +const char *target_strerror_safe( int err ) +{ + const Jim_Nvp *n; + + n = Jim_Nvp_value2name_simple( nvp_error_target, err ); + if( n->name == NULL ){ + return "unknown"; + } else { + return n->name; + } +} + const Jim_Nvp nvp_target_event[] = { + { .value = TARGET_EVENT_OLD_gdb_program_config , .name = "old-gdb_program_config" }, + { .value = TARGET_EVENT_OLD_pre_resume , .name = "old-pre_resume" }, + + + { .value = TARGET_EVENT_EARLY_HALTED, .name = "early-halted" }, { .value = TARGET_EVENT_HALTED, .name = "halted" }, { .value = TARGET_EVENT_RESUMED, .name = "resumed" }, { .value = TARGET_EVENT_RESUME_START, .name = "resume-start" }, { .value = TARGET_EVENT_RESUME_END, .name = "resume-end" }, /* historical name */ - { .value = TARGET_EVENT_RESET_START , .name = "pre_reset" }, + { .value = TARGET_EVENT_RESET_START, .name = "reset-start" }, - /* historical name */ - { .value = TARGET_EVENT_RESET , .name = "reset" }, + + { .value = TARGET_EVENT_RESET_ASSERT_PRE, .name = "reset-assert-pre" }, + { .value = TARGET_EVENT_RESET_ASSERT_POST, .name = "reset-assert-post" }, + { .value = TARGET_EVENT_RESET_DEASSERT_PRE, .name = "reset-deassert-pre" }, + { .value = TARGET_EVENT_RESET_DEASSERT_POST, .name = "reset-deassert-post" }, + { .value = TARGET_EVENT_RESET_HALT_PRE, .name = "reset-halt-pre" }, + { .value = TARGET_EVENT_RESET_HALT_POST, .name = "reset-halt-post" }, + { .value = TARGET_EVENT_RESET_WAIT_PRE, .name = "reset-wait-pre" }, + { .value = TARGET_EVENT_RESET_WAIT_POST, .name = "reset-wait-post" }, { .value = TARGET_EVENT_RESET_INIT , .name = "reset-init" }, { .value = TARGET_EVENT_RESET_END, .name = "reset-end" }, + + + + + { .value = TARGET_EVENT_EXAMINE_START, .name = "examine-start" }, + { .value = TARGET_EVENT_EXAMINE_START, .name = "examine-end" }, + + { .value = TARGET_EVENT_DEBUG_HALTED, .name = "debug-halted" }, { .value = TARGET_EVENT_DEBUG_RESUMED, .name = "debug-resumed" }, { .value = TARGET_EVENT_GDB_ATTACH, .name = "gdb-attach" }, { .value = TARGET_EVENT_GDB_DETACH, .name = "gdb-detach" }, + { .value = TARGET_EVENT_GDB_FLASH_WRITE_START, .name = "gdb-flash-write-start" }, { .value = TARGET_EVENT_GDB_FLASH_WRITE_END , .name = "gdb-flash-write-end" }, - { .value = TARGET_EVENT_GDB_FLASH_ERASE_START , .name = "gdb_program_config" }, - { .value = TARGET_EVENT_GDB_FLASH_ERASE_START, .name = "gdb-flash-erase-start" }, { .value = TARGET_EVENT_GDB_FLASH_ERASE_END , .name = "gdb-flash-erase-end" }, @@ -193,6 +245,30 @@ const Jim_Nvp nvp_target_endian[] = { { .name = NULL, .value = -1 }, }; +const Jim_Nvp nvp_reset_modes[] = { + { .name = "unknown", .value = RESET_UNKNOWN }, + { .name = "run" , .value = RESET_RUN }, + { .name = "halt" , .value = RESET_HALT }, + { .name = "init" , .value = RESET_INIT }, + { .name = NULL , .value = -1 }, +}; + +static int +max_target_number( void ) +{ + target_t *t; + int x; + + x = -1; + t = all_targets; + while( t ){ + if( x < t->target_number ){ + x = (t->target_number)+1; + } + t = t->next; + } + return x; +} /* determine the number of the new target */ static int @@ -271,7 +347,7 @@ target_t* get_target_by_num(int num) while (target){ if( target->target_number == num ){ return target; - } + } target = target->next; } @@ -340,103 +416,33 @@ int target_resume(struct target_s *target, int current, u32 address, int handle_ return retval; } + int target_process_reset(struct command_context_s *cmd_ctx, enum target_reset_mode reset_mode) { - int retval = ERROR_OK; - target_t *target; - - target = all_targets; - while (target) - { - target_invoke_script(cmd_ctx, target, "pre_reset"); - target = target->next; - } - - if ((retval = jtag_init_reset(cmd_ctx)) != ERROR_OK) - return retval; - - keep_alive(); /* we might be running on a very slow JTAG clk */ - - /* First time this is executed after launching OpenOCD, it will read out - * the type of CPU, etc. and init Embedded ICE registers in host - * memory. - * - * It will also set up ICE registers in the target. - * - * However, if we assert TRST later, we need to set up the registers again. - * - * For the "reset halt/init" case we must only set up the registers here. - */ - if ((retval = target_examine()) != ERROR_OK) - return retval; - - keep_alive(); /* we might be running on a very slow JTAG clk */ - - target = all_targets; - while (target) - { - /* we have no idea what state the target is in, so we - * have to drop working areas - */ - target_free_all_working_areas_restore(target, 0); - target->reset_halt=((reset_mode==RESET_HALT)||(reset_mode==RESET_INIT)); - if ((retval = target->type->assert_reset(target))!=ERROR_OK) - return retval; - target = target->next; - } - - target = all_targets; - while (target) - { - if ((retval = target->type->deassert_reset(target))!=ERROR_OK) - return retval; - target = target->next; - } - - target = all_targets; - while (target) - { - /* We can fail to bring the target into the halted state, try after reset has been deasserted */ - if (target->reset_halt) - { - /* wait up to 1 second for halt. */ - target_wait_state(target, TARGET_HALTED, 1000); - if (target->state != TARGET_HALTED) - { - LOG_WARNING("Failed to reset target into halted mode - issuing halt"); - if ((retval = target->type->halt(target))!=ERROR_OK) - return retval; - } - } - - target = target->next; + char buf[100]; + int retval; + Jim_Nvp *n; + n = Jim_Nvp_value2name_simple( nvp_reset_modes, reset_mode ); + if( n->name == NULL ){ + LOG_ERROR("invalid reset mode"); + return ERROR_FAIL; } + sprintf( buf, "ocd_process_reset %s", n->name ); + retval = Jim_Eval( interp, buf ); - LOG_DEBUG("Waiting for halted stated as appropriate"); - - if ((reset_mode == RESET_HALT) || (reset_mode == RESET_INIT)) - { - target = all_targets; - while (target) - { - /* Wait for reset to complete, maximum 5 seconds. */ - if (((retval=target_wait_state(target, TARGET_HALTED, 5000)))==ERROR_OK) - { - if (reset_mode == RESET_INIT) - target_invoke_script(cmd_ctx, target, "post_reset"); - - } - target = target->next; - } + if(retval != JIM_OK) { + Jim_PrintErrorMessage(interp); + return ERROR_FAIL; } /* We want any events to be processed before the prompt */ - target_call_timer_callbacks_now(); + retval = target_call_timer_callbacks_now(); return retval; } + static int default_virt2phys(struct target_s *target, u32 virtual, u32 *physical) { *physical = virtual; @@ -517,6 +523,7 @@ static int target_run_algorithm_imp(struct target_s *target, int num_mem_params, int target_init(struct command_context_s *cmd_ctx) { target_t *target = all_targets; + int retval; while (target) { @@ -526,10 +533,10 @@ int target_init(struct command_context_s *cmd_ctx) target->type->examine = default_examine; } - if (target->type->init_target(cmd_ctx, target) != ERROR_OK) + if ((retval = target->type->init_target(cmd_ctx, target)) != ERROR_OK) { LOG_ERROR("target '%s' init failed", target->type->name); - exit(-1); + return retval; } /* Set up default functions if none are provided by target */ @@ -560,8 +567,10 @@ int target_init(struct command_context_s *cmd_ctx) if (all_targets) { - target_register_user_commands(cmd_ctx); - target_register_timer_callback(handle_target, 100, 1, NULL); + if((retval = target_register_user_commands(cmd_ctx)) != ERROR_OK) + return retval; + if((retval = target_register_timer_callback(handle_target, 100, 1, NULL)) != ERROR_OK) + return retval; } return ERROR_OK; @@ -688,8 +697,18 @@ int target_call_event_callbacks(target_t *target, enum target_event event) target_event_callback_t *callback = target_event_callbacks; target_event_callback_t *next_callback; - LOG_DEBUG("target event %i", event); + if (event == TARGET_EVENT_HALTED) + { + /* execute early halted first */ + target_call_event_callbacks(target, TARGET_EVENT_EARLY_HALTED); + } + + + LOG_DEBUG("target event %i (%s)", + event, + Jim_Nvp_value2name_simple( nvp_target_event, event )->name ); + target_handle_event( target, event ); while (callback) { @@ -735,7 +754,11 @@ static int target_call_timer_callbacks_check_time(int checktime) } } else - target_unregister_timer_callback(callback->callback, callback->priv); + { + int retval; + if((retval = target_unregister_timer_callback(callback->callback, callback->priv)) != ERROR_OK) + return retval; + } } } @@ -753,7 +776,7 @@ int target_call_timer_callbacks(void) /* invoke periodic callbacks immediately */ int target_call_timer_callbacks_now(void) { - return target_call_timer_callbacks(); + return target_call_timer_callbacks_check_time(0); } int target_alloc_working_area(struct target_s *target, u32 size, working_area_t **area) @@ -830,8 +853,14 @@ int target_alloc_working_area(struct target_s *target, u32 size, working_area_t if (target->backup_working_area) { + int retval; new_wa->backup = malloc(new_wa->size); - target->type->read_memory(target, new_wa->address, 4, new_wa->size / 4, new_wa->backup); + if((retval = target->type->read_memory(target, new_wa->address, 4, new_wa->size / 4, new_wa->backup)) != ERROR_OK) + { + free(new_wa->backup); + free(new_wa); + return retval; + } } else { @@ -858,7 +887,11 @@ int target_free_working_area_restore(struct target_s *target, working_area_t *ar return ERROR_OK; if (restore&&target->backup_working_area) - target->type->write_memory(target, area->address, 4, area->size / 4, area->backup); + { + int retval; + if((retval = target->type->write_memory(target, area->address, 4, area->size / 4, area->backup)) != ERROR_OK) + return retval; + } area->free = 1; @@ -874,7 +907,10 @@ int target_free_working_area(struct target_s *target, working_area_t *area) return target_free_working_area_restore(target, area, 1); } -int target_free_all_working_areas_restore(struct target_s *target, int restore) +/* free resources and restore memory, if restoring memory fails, + * free up resources anyway + */ +void target_free_all_working_areas_restore(struct target_s *target, int restore) { working_area_t *c = target->working_areas; @@ -892,23 +928,22 @@ int target_free_all_working_areas_restore(struct target_s *target, int restore) } target->working_areas = NULL; - - return ERROR_OK; } -int target_free_all_working_areas(struct target_s *target) +void target_free_all_working_areas(struct target_s *target) { - return target_free_all_working_areas_restore(target, 1); + target_free_all_working_areas_restore(target, 1); } int target_register_commands(struct command_context_s *cmd_ctx) { - register_command(cmd_ctx, NULL, "target", handle_target_command, COMMAND_CONFIG, "target [reset_init default - DEPRECATED] [cpu type specifc args]"); - register_command(cmd_ctx, NULL, "targets", handle_targets_command, COMMAND_EXEC, NULL); - register_command(cmd_ctx, NULL, "working_area", handle_working_area_command, COMMAND_ANY, "working_area
<'backup'|'nobackup'> [virtual address]"); - register_command(cmd_ctx, NULL, "virt2phys", handle_virt2phys_command, COMMAND_ANY, "virt2phys "); - register_command(cmd_ctx, NULL, "profile", handle_profile_command, COMMAND_EXEC, "PRELIMINARY! - profile "); + register_command(cmd_ctx, NULL, "targets", handle_targets_command, COMMAND_EXEC, "change the current command line target (one parameter) or lists targets (with no parameter)"); + register_command(cmd_ctx, NULL, "working_area", handle_working_area_command, COMMAND_ANY, "set a new working space"); + register_command(cmd_ctx, NULL, "virt2phys", handle_virt2phys_command, COMMAND_ANY, "translate a virtual address into a physical address"); + register_command(cmd_ctx, NULL, "profile", handle_profile_command, COMMAND_EXEC, "profiling samples the CPU PC"); + + register_jim(cmd_ctx, "target", jim_target, "configure target" ); /* script procedures */ @@ -926,7 +961,7 @@ int target_arch_state(struct target_s *target) return ERROR_OK; } - LOG_USER("target state: %s", + LOG_USER("target state: %s", Jim_Nvp_value2name_simple(nvp_target_state,target->state)->name); if (target->state!=TARGET_HALTED) @@ -1091,7 +1126,7 @@ int target_checksum_memory(struct target_s *target, u32 address, u32 size, u32* } if ((retval = target->type->checksum_memory(target, address, - size, &checksum)) == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) + size, &checksum)) != ERROR_OK) { buffer = malloc(size); if (buffer == NULL) @@ -1265,7 +1300,7 @@ int target_write_u8(struct target_s *target, u32 address, u8 value) LOG_DEBUG("address: 0x%8.8x, value: 0x%2.2x", address, value); - if ((retval = target->type->read_memory(target, address, 1, 1, &value)) != ERROR_OK) + if ((retval = target->type->write_memory(target, address, 1, 1, &value)) != ERROR_OK) { LOG_DEBUG("failed: %i", retval); } @@ -1275,7 +1310,8 @@ int target_write_u8(struct target_s *target, u32 address, u8 value) int target_register_user_commands(struct command_context_s *cmd_ctx) { - register_command(cmd_ctx, NULL, "reg", handle_reg_command, COMMAND_EXEC, NULL); + int retval = ERROR_OK; + register_command(cmd_ctx, NULL, "reg", handle_reg_command, COMMAND_EXEC, "display or set a register"); register_command(cmd_ctx, NULL, "poll", handle_poll_command, COMMAND_EXEC, "poll target state"); register_command(cmd_ctx, NULL, "wait_halt", handle_wait_halt_command, COMMAND_EXEC, "wait for target halt [time (s)]"); register_command(cmd_ctx, NULL, "halt", handle_halt_command, COMMAND_EXEC, "halt target"); @@ -1301,10 +1337,13 @@ int target_register_user_commands(struct command_context_s *cmd_ctx) register_command(cmd_ctx, NULL, "dump_image", handle_dump_image_command, COMMAND_EXEC, "dump_image
"); register_command(cmd_ctx, NULL, "verify_image", handle_verify_image_command, COMMAND_EXEC, "verify_image [offset] [type]"); - target_request_register_commands(cmd_ctx); - trace_register_commands(cmd_ctx); + if((retval = target_request_register_commands(cmd_ctx)) != ERROR_OK) + return retval; + if((retval = trace_register_commands(cmd_ctx)) != ERROR_OK) + return retval; - return ERROR_OK; + + return retval; } int handle_targets_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) @@ -1320,18 +1359,18 @@ int handle_targets_command(struct command_context_s *cmd_ctx, char *cmd, char ** if( 0 == strcmp( args[0], target->cmd_name ) ){ /* MATCH */ goto Match; - } + } } } /* no match, try as number */ - + int num = strtoul(args[0], &cp, 0 ); if( *cp != 0 ){ /* then it was not a number */ command_print( cmd_ctx, "Target: %s unknown, try one of:\n", args[0] ); goto DumpTargets; } - + target = get_target_by_num( num ); if( target == NULL ){ command_print(cmd_ctx,"Target: %s is unknown, try one of:\n", args[0] ); @@ -1343,16 +1382,17 @@ int handle_targets_command(struct command_context_s *cmd_ctx, char *cmd, char ** } DumpTargets: - command_print(cmd_ctx, " CmdName Type Endian State "); - command_print(cmd_ctx, "-- ---------- ---------- ---------- ----------"); + command_print(cmd_ctx, " CmdName Type Endian ChainPos State "); + command_print(cmd_ctx, "-- ---------- ---------- ---------- -------- ----------"); while (target) { /* XX: abcdefghij abcdefghij abcdefghij abcdefghij */ - command_print(cmd_ctx, "%2d: %-10s %-10s %-10s %s", + command_print(cmd_ctx, "%2d: %-10s %-10s %-10s %8d %s", target->target_number, - "", // future: target->cmd_name - target->type->name, - Jim_Nvp_value2name_simple( nvp_target_endian, target->endianness )->name, + target->cmd_name, + target->type->name, + Jim_Nvp_value2name_simple( nvp_target_endian, target->endianness )->name, + target->chain_position, Jim_Nvp_value2name_simple( nvp_target_state, target->state )->name ); target = target->next; } @@ -1360,146 +1400,11 @@ int handle_targets_command(struct command_context_s *cmd_ctx, char *cmd, char ** return ERROR_OK; } -int handle_target_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) -{ - int i; - int found = 0; - - if (argc < 3) - { - return ERROR_COMMAND_SYNTAX_ERROR; - } - - /* search for the specified target */ - if (args[0] && (args[0][0] != 0)) - { - for (i = 0; target_types[i]; i++) - { - if (strcmp(args[0], target_types[i]->name) == 0) - { - target_t **last_target_p = &all_targets; - - /* register target specific commands */ - if (target_types[i]->register_commands(cmd_ctx) != ERROR_OK) - { - LOG_ERROR("couldn't register '%s' commands", args[0]); - exit(-1); - } - - if (*last_target_p) - { - while ((*last_target_p)->next) - last_target_p = &((*last_target_p)->next); - last_target_p = &((*last_target_p)->next); - } - - // get target number *before* adding new target to the list */ - int n = new_target_number(); - // calloc will init the memory to zero for us - *last_target_p = calloc(1,sizeof(target_t)); - // save target number. - (*last_target_p)->cmd_name = NULL; - (*last_target_p)->target_number = n; - - /* allocate memory for each unique target type */ - (*last_target_p)->type = (target_type_t*)malloc(sizeof(target_type_t)); - *((*last_target_p)->type) = *target_types[i]; - - if (strcmp(args[1], "big") == 0) - (*last_target_p)->endianness = TARGET_BIG_ENDIAN; - else if (strcmp(args[1], "little") == 0) - (*last_target_p)->endianness = TARGET_LITTLE_ENDIAN; - else - { - LOG_ERROR("endianness must be either 'little' or 'big', not '%s'", args[1]); - return ERROR_COMMAND_SYNTAX_ERROR; - } - - if (strcmp(args[2], "reset_halt") == 0) - { - LOG_WARNING("reset_mode argument is obsolete."); - return ERROR_COMMAND_SYNTAX_ERROR; - } - else if (strcmp(args[2], "reset_run") == 0) - { - LOG_WARNING("reset_mode argument is obsolete."); - return ERROR_COMMAND_SYNTAX_ERROR; - } - else if (strcmp(args[2], "reset_init") == 0) - { - LOG_WARNING("reset_mode argument is obsolete."); - return ERROR_COMMAND_SYNTAX_ERROR; - } - else if (strcmp(args[2], "run_and_halt") == 0) - { - LOG_WARNING("reset_mode argument is obsolete."); - return ERROR_COMMAND_SYNTAX_ERROR; - } - else if (strcmp(args[2], "run_and_init") == 0) - { - LOG_WARNING("reset_mode argument is obsolete."); - return ERROR_COMMAND_SYNTAX_ERROR; - } - else - { - /* Kludge! we want to make this reset arg optional while remaining compatible! */ - args--; - argc++; - } - - (*last_target_p)->working_area = 0x0; - (*last_target_p)->working_area_size = 0x0; - (*last_target_p)->working_areas = NULL; - (*last_target_p)->backup_working_area = 0; - - (*last_target_p)->state = TARGET_UNKNOWN; - (*last_target_p)->debug_reason = DBG_REASON_UNDEFINED; - (*last_target_p)->reg_cache = NULL; - (*last_target_p)->breakpoints = NULL; - (*last_target_p)->watchpoints = NULL; - (*last_target_p)->next = NULL; - (*last_target_p)->arch_info = NULL; - - /* initialize trace information */ - (*last_target_p)->trace_info = malloc(sizeof(trace_t)); - (*last_target_p)->trace_info->num_trace_points = 0; - (*last_target_p)->trace_info->trace_points_size = 0; - (*last_target_p)->trace_info->trace_points = NULL; - (*last_target_p)->trace_info->trace_history_size = 0; - (*last_target_p)->trace_info->trace_history = NULL; - (*last_target_p)->trace_info->trace_history_pos = 0; - (*last_target_p)->trace_info->trace_history_overflowed = 0; - - (*last_target_p)->dbgmsg = NULL; - (*last_target_p)->dbg_msg_enabled = 0; - - (*last_target_p)->type->target_command(cmd_ctx, cmd, args, argc, *last_target_p); - - found = 1; - break; - } - } - } - - /* no matching target found */ - if (!found) - { - LOG_ERROR("target '%s' not found", args[0]); - return ERROR_COMMAND_SYNTAX_ERROR; - } - - return ERROR_OK; -} -int target_invoke_script(struct command_context_s *cmd_ctx, target_t *target, char *name) -{ - return command_run_linef(cmd_ctx, " if {[catch {info body target_%d_%s} t]==0} {target_%d_%s}", - get_num_by_target(target), name, - get_num_by_target(target), name); -} int handle_working_area_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) { + int retval = ERROR_OK; target_t *target = NULL; if ((argc < 4) || (argc > 5)) @@ -1535,13 +1440,14 @@ int handle_working_area_command(struct command_context_s *cmd_ctx, char *cmd, ch return ERROR_COMMAND_SYNTAX_ERROR; } - return ERROR_OK; + return retval; } /* process target state changes */ int handle_target(void *priv) { + int retval = ERROR_OK; target_t *target = all_targets; while (target) @@ -1549,13 +1455,14 @@ int handle_target(void *priv) if (target_continous_poll) { /* polling may fail silently until the target has been examined */ - target_poll(target); + if((retval = target_poll(target)) != ERROR_OK) + return retval; } target = target->next; } - return ERROR_OK; + return retval; } int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) @@ -1638,11 +1545,6 @@ int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args if (reg->valid == 0) { reg_arch_type_t *arch_type = register_get_arch_type(reg->arch_type); - if (arch_type == NULL) - { - LOG_ERROR("BUG: encountered unregistered arch type"); - return ERROR_OK; - } arch_type->get(reg); } value = buf_to_str(reg->value, reg->size, 16); @@ -1658,12 +1560,6 @@ int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args str_to_buf(args[1], strlen(args[1]), buf, reg->size, 0); reg_arch_type_t *arch_type = register_get_arch_type(reg->arch_type); - if (arch_type == NULL) - { - LOG_ERROR("BUG: encountered unregistered arch type"); - return ERROR_OK; - } - arch_type->set(reg, buf); value = buf_to_str(reg->value, reg->size, 16); @@ -1683,14 +1579,18 @@ int handle_reg_command(struct command_context_s *cmd_ctx, char *cmd, char **args int handle_poll_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) { + int retval = ERROR_OK; target_t *target = get_current_target(cmd_ctx); if (argc == 0) { - target_poll(target); - target_arch_state(target); + if((retval = target_poll(target)) != ERROR_OK) + return retval; + if((retval = target_arch_state(target)) != ERROR_OK) + return retval; + } - else + else if (argc==1) { if (strcmp(args[0], "on") == 0) { @@ -1704,10 +1604,13 @@ int handle_poll_command(struct command_context_s *cmd_ctx, char *cmd, char **arg { command_print(cmd_ctx, "arg is \"on\" or \"off\""); } + } else + { + return ERROR_COMMAND_SYNTAX_ERROR; } - return ERROR_OK; + return retval; } int handle_wait_halt_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) @@ -1750,14 +1653,14 @@ int target_wait_state(target_t *target, enum target_state state, int ms) if (once) { once=0; - LOG_DEBUG("waiting for target %s...", + LOG_DEBUG("waiting for target %s...", Jim_Nvp_value2name_simple(nvp_target_state,state)->name); } gettimeofday(&now, NULL); if ((now.tv_sec > timeout.tv_sec) || ((now.tv_sec == timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) { - LOG_ERROR("timed out while waiting for target %s", + LOG_ERROR("timed out while waiting for target %s", Jim_Nvp_value2name_simple(nvp_target_state,state)->name); return ERROR_FAIL; } @@ -1794,32 +1697,29 @@ int handle_soft_reset_halt_command(struct command_context_s *cmd_ctx, char *cmd, int handle_reset_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) { + const Jim_Nvp *n; enum target_reset_mode reset_mode = RESET_RUN; if (argc >= 1) { - if (strcmp("run", args[0]) == 0) - reset_mode = RESET_RUN; - else if (strcmp("halt", args[0]) == 0) - reset_mode = RESET_HALT; - else if (strcmp("init", args[0]) == 0) - reset_mode = RESET_INIT; - else - { + n = Jim_Nvp_name2value_simple( nvp_reset_modes, args[0] ); + if( (n->name == NULL) || (n->value == RESET_UNKNOWN) ){ return ERROR_COMMAND_SYNTAX_ERROR; } + reset_mode = n->value; } /* reset *all* targets */ return target_process_reset(cmd_ctx, reset_mode); } + int handle_resume_command(struct command_context_s *cmd_ctx, char *cmd, char **args, int argc) { int retval; target_t *target = get_current_target(cmd_ctx); - target_invoke_script(cmd_ctx, target, "pre_resume"); + target_handle_event( target, TARGET_EVENT_OLD_pre_resume ); if (argc == 0) retval = target_resume(target, 1, 0, 1, 0); /* current pc, addr = 0, handle breakpoints, not debugging */ @@ -1827,7 +1727,7 @@ int handle_resume_command(struct command_context_s *cmd_ctx, char *cmd, char **a retval = target_resume(target, 0, strtoul(args[0], NULL, 0), 1, 0); /* addr = args[0], handle breakpoints, not debugging */ else { - return ERROR_COMMAND_SYNTAX_ERROR; + retval = ERROR_COMMAND_SYNTAX_ERROR; } return retval; @@ -1978,6 +1878,8 @@ int handle_mw_command(struct command_context_s *cmd_ctx, char *cmd, char **args, default: return ERROR_OK; } + keep_alive(); + if (retval!=ERROR_OK) { return retval; @@ -1996,7 +1898,7 @@ int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char u32 min_address=0; u32 max_address=0xffffffff; int i; - int retval; + int retval, retvaltemp; image_t image; @@ -2096,7 +1998,12 @@ int handle_load_image_command(struct command_context_s *cmd_ctx, char *cmd, char free(buffer); } - duration_stop_measure(&duration, &duration_text); + if((retvaltemp = duration_stop_measure(&duration, &duration_text)) != ERROR_OK) + { + image_close(&image); + return retvaltemp; + } + if (retval==ERROR_OK) { command_print(cmd_ctx, "downloaded %u byte in %s", image_size, duration_text); @@ -2116,7 +2023,7 @@ int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char u32 address; u32 size; u8 buffer[560]; - int retval=ERROR_OK; + int retval=ERROR_OK, retvaltemp; duration_t duration; char *duration_text; @@ -2166,9 +2073,12 @@ int handle_dump_image_command(struct command_context_s *cmd_ctx, char *cmd, char address += this_run_size; } - fileio_close(&fileio); + if((retvaltemp = fileio_close(&fileio)) != ERROR_OK) + return retvaltemp; + + if((retvaltemp = duration_stop_measure(&duration, &duration_text)) != ERROR_OK) + return retvaltemp; - duration_stop_measure(&duration, &duration_text); if (retval==ERROR_OK) { command_print(cmd_ctx, "dumped %"PRIi64" byte in %s", fileio.size, duration_text); @@ -2184,7 +2094,7 @@ int handle_verify_image_command(struct command_context_s *cmd_ctx, char *cmd, ch u32 buf_cnt; u32 image_size; int i; - int retval; + int retval, retvaltemp; u32 checksum = 0; u32 mem_checksum = 0; @@ -2283,6 +2193,10 @@ int handle_verify_image_command(struct command_context_s *cmd_ctx, char *cmd, ch retval=ERROR_FAIL; goto done; } + if ((t%16384)==0) + { + keep_alive(); + } } } @@ -2293,7 +2207,13 @@ int handle_verify_image_command(struct command_context_s *cmd_ctx, char *cmd, ch image_size += buf_cnt; } done: - duration_stop_measure(&duration, &duration_text); + + if((retvaltemp = duration_stop_measure(&duration, &duration_text)) != ERROR_OK) + { + image_close(&image); + return retvaltemp; + } + if (retval==ERROR_OK) { command_print(cmd_ctx, "verified %u bytes in %s", image_size, duration_text); @@ -2619,7 +2539,11 @@ int handle_profile_command(struct command_context_s *cmd_ctx, char *cmd, char ** } else if (target->state == TARGET_RUNNING) { // We want to quickly sample the PC. - target_halt(target); + if((retval = target_halt(target)) != ERROR_OK) + { + free(samples); + return retval; + } } else { command_print(cmd_ctx, "Target not halted or running"); @@ -2635,12 +2559,20 @@ int handle_profile_command(struct command_context_s *cmd_ctx, char *cmd, char ** if ((numSamples>=maxSample) || ((now.tv_sec >= timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) { command_print(cmd_ctx, "Profiling completed. %d samples.", numSamples); - target_poll(target); + if((retval = target_poll(target)) != ERROR_OK) + { + free(samples); + return retval; + } if (target->state == TARGET_HALTED) { target_resume(target, 1, 0, 0, 0); /* current pc, addr = 0, do not handle breakpoints, not debugging */ } - target_poll(target); + if((retval = target_poll(target)) != ERROR_OK) + { + free(samples); + return retval; + } writeGmon(samples, numSamples, args[1]); command_print(cmd_ctx, "Wrote %s", args[1]); break; @@ -2866,7 +2798,7 @@ static int jim_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { command_context_t *context; target_t *target; - + context = Jim_GetAssocData(interp, "context"); if (context == NULL){ LOG_ERROR("array2mem: no command context"); @@ -2877,10 +2809,10 @@ static int jim_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv) LOG_ERROR("array2mem: no current target"); return JIM_ERR; } - + return target_array2mem( interp,target, argc, argv ); } - + static int target_array2mem(Jim_Interp *interp, target_t *target, int argc, Jim_Obj *const *argv) { @@ -3014,10 +2946,1097 @@ static int target_array2mem(Jim_Interp *interp, target_t *target, int argc, Jim_ return JIM_OK; } +void +target_all_handle_event( enum target_event e ) +{ + target_t *target; + -/* - * Local Variables: *** - * c-basic-offset: 4 *** - * tab-width: 4 *** - * End: *** - */ + LOG_DEBUG( "**all*targets: event: %d, %s", + e, + Jim_Nvp_value2name_simple( nvp_target_event, e )->name ); + + target = all_targets; + while (target){ + target_handle_event( target, e ); + target = target->next; + } +} + +void +target_handle_event( target_t *target, enum target_event e ) +{ + target_event_action_t *teap; + int done; + + teap = target->event_action; + + done = 0; + while( teap ){ + if( teap->event == e ){ + done = 1; + LOG_DEBUG( "target: (%d) %s (%s) event: %d (%s) action: %s\n", + target->target_number, + target->cmd_name, + target->type->name, + e, + Jim_Nvp_value2name_simple( nvp_target_event, e )->name, + Jim_GetString( teap->body, NULL ) ); + if (Jim_EvalObj( interp, teap->body )!=JIM_OK) + { + Jim_PrintErrorMessage(interp); + } + } + teap = teap->next; + } + if( !done ){ + LOG_DEBUG( "event: %d %s - no action", + e, + Jim_Nvp_value2name_simple( nvp_target_event, e )->name ); + } +} + +enum target_cfg_param { + TCFG_TYPE, + TCFG_EVENT, + TCFG_WORK_AREA_VIRT, + TCFG_WORK_AREA_PHYS, + TCFG_WORK_AREA_SIZE, + TCFG_WORK_AREA_BACKUP, + TCFG_ENDIAN, + TCFG_VARIANT, + TCFG_CHAIN_POSITION, +}; + + +static Jim_Nvp nvp_config_opts[] = { + { .name = "-type", .value = TCFG_TYPE }, + { .name = "-event", .value = TCFG_EVENT }, + { .name = "-work-area-virt", .value = TCFG_WORK_AREA_VIRT }, + { .name = "-work-area-phys", .value = TCFG_WORK_AREA_PHYS }, + { .name = "-work-area-size", .value = TCFG_WORK_AREA_SIZE }, + { .name = "-work-area-backup", .value = TCFG_WORK_AREA_BACKUP }, + { .name = "-endian" , .value = TCFG_ENDIAN }, + { .name = "-variant", .value = TCFG_VARIANT }, + { .name = "-chain-position", .value = TCFG_CHAIN_POSITION }, + + { .name = NULL, .value = -1 } +}; + + +static int +target_configure( Jim_GetOptInfo *goi, + target_t *target ) +{ + Jim_Nvp *n; + Jim_Obj *o; + jim_wide w; + char *cp; + int e; + + + /* parse config or cget options ... */ + while( goi->argc > 0 ){ + Jim_SetEmptyResult( goi->interp ); + //Jim_GetOpt_Debug( goi ); + + if( target->type->target_jim_configure ){ + /* target defines a configure function */ + /* target gets first dibs on parameters */ + e = (*(target->type->target_jim_configure))( target, goi ); + if( e == JIM_OK ){ + /* more? */ + continue; + } + if( e == JIM_ERR ){ + /* An error */ + return e; + } + /* otherwise we 'continue' below */ + } + e = Jim_GetOpt_Nvp( goi, nvp_config_opts, &n ); + if( e != JIM_OK ){ + Jim_GetOpt_NvpUnknown( goi, nvp_config_opts, 0 ); + return e; + } + switch( n->value ){ + case TCFG_TYPE: + /* not setable */ + if( goi->isconfigure ){ + Jim_SetResult_sprintf( goi->interp, "not setable: %s", n->name ); + return JIM_ERR; + } else { + no_params: + if( goi->argc != 0 ){ + Jim_WrongNumArgs( goi->interp, goi->argc, goi->argv, "NO PARAMS"); + return JIM_ERR; + } + } + Jim_SetResultString( goi->interp, target->type->name, -1 ); + /* loop for more */ + break; + case TCFG_EVENT: + if( goi->argc == 0 ){ + Jim_WrongNumArgs( goi->interp, goi->argc, goi->argv, "-event ?event-name? ..."); + return JIM_ERR; + } + + e = Jim_GetOpt_Nvp( goi, nvp_target_event, &n ); + if( e != JIM_OK ){ + Jim_GetOpt_NvpUnknown( goi, nvp_target_event, 1 ); + return e; + } + + if( goi->isconfigure ){ + if( goi->argc != 1 ){ + Jim_WrongNumArgs( goi->interp, goi->argc, goi->argv, "-event ?event-name? ?EVENT-BODY?"); + return JIM_ERR; + } + } else { + if( goi->argc != 0 ){ + Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, "-event ?event-name?"); + return JIM_ERR; + } + } + + + { + target_event_action_t *teap; + + teap = target->event_action; + /* replace existing? */ + while( teap ){ + if( teap->event == n->value ){ + break; + } + teap = teap->next; + } + + if( goi->isconfigure ){ + if( teap == NULL ){ + /* create new */ + teap = calloc( 1, sizeof(*teap) ); + } + teap->event = n->value; + Jim_GetOpt_Obj( goi, &o ); + if( teap->body ){ + Jim_DecrRefCount( interp, teap->body ); + } + teap->body = Jim_DuplicateObj( goi->interp, o ); + /* + * FIXME: + * Tcl/TK - "tk events" have a nice feature. + * See the "BIND" command. + * We should support that here. + * You can specify %X and %Y in the event code. + * The idea is: %T - target name. + * The idea is: %N - target number + * The idea is: %E - event name. + */ + Jim_IncrRefCount( teap->body ); + + /* add to head of event list */ + teap->next = target->event_action; + target->event_action = teap; + Jim_SetEmptyResult(goi->interp); + } else { + /* get */ + if( teap == NULL ){ + Jim_SetEmptyResult( goi->interp ); + } else { + Jim_SetResult( goi->interp, Jim_DuplicateObj( goi->interp, teap->body ) ); + } + } + } + /* loop for more */ + break; + + case TCFG_WORK_AREA_VIRT: + if( goi->isconfigure ){ + target_free_all_working_areas(target); + e = Jim_GetOpt_Wide( goi, &w ); + if( e != JIM_OK ){ + return e; + } + target->working_area_virt = w; + } else { + if( goi->argc != 0 ){ + goto no_params; + } + } + Jim_SetResult( interp, Jim_NewIntObj( goi->interp, target->working_area_virt ) ); + /* loop for more */ + break; + + case TCFG_WORK_AREA_PHYS: + if( goi->isconfigure ){ + target_free_all_working_areas(target); + e = Jim_GetOpt_Wide( goi, &w ); + if( e != JIM_OK ){ + return e; + } + target->working_area_phys = w; + } else { + if( goi->argc != 0 ){ + goto no_params; + } + } + Jim_SetResult( interp, Jim_NewIntObj( goi->interp, target->working_area_phys ) ); + /* loop for more */ + break; + + case TCFG_WORK_AREA_SIZE: + if( goi->isconfigure ){ + target_free_all_working_areas(target); + e = Jim_GetOpt_Wide( goi, &w ); + if( e != JIM_OK ){ + return e; + } + target->working_area_size = w; + } else { + if( goi->argc != 0 ){ + goto no_params; + } + } + Jim_SetResult( interp, Jim_NewIntObj( goi->interp, target->working_area_size ) ); + /* loop for more */ + break; + + case TCFG_WORK_AREA_BACKUP: + if( goi->isconfigure ){ + target_free_all_working_areas(target); + e = Jim_GetOpt_Wide( goi, &w ); + if( e != JIM_OK ){ + return e; + } + /* make this exactly 1 or 0 */ + target->backup_working_area = (!!w); + } else { + if( goi->argc != 0 ){ + goto no_params; + } + } + Jim_SetResult( interp, Jim_NewIntObj( goi->interp, target->working_area_size ) ); + /* loop for more e*/ + break; + + case TCFG_ENDIAN: + if( goi->isconfigure ){ + e = Jim_GetOpt_Nvp( goi, nvp_target_endian, &n ); + if( e != JIM_OK ){ + Jim_GetOpt_NvpUnknown( goi, nvp_target_endian, 1 ); + return e; + } + target->endianness = n->value; + } else { + if( goi->argc != 0 ){ + goto no_params; + } + } + n = Jim_Nvp_value2name_simple( nvp_target_endian, target->endianness ); + if( n->name == NULL ){ + target->endianness = TARGET_LITTLE_ENDIAN; + n = Jim_Nvp_value2name_simple( nvp_target_endian, target->endianness ); + } + Jim_SetResultString( goi->interp, n->name, -1 ); + /* loop for more */ + break; + + case TCFG_VARIANT: + if( goi->isconfigure ){ + if( goi->argc < 1 ){ + Jim_SetResult_sprintf( goi->interp, + "%s ?STRING?", + n->name ); + return JIM_ERR; + } + if( target->variant ){ + free((void *)(target->variant)); + } + e = Jim_GetOpt_String( goi, &cp, NULL ); + target->variant = strdup(cp); + } else { + if( goi->argc != 0 ){ + goto no_params; + } + } + Jim_SetResultString( goi->interp, target->variant,-1 ); + /* loop for more */ + break; + case TCFG_CHAIN_POSITION: + if( goi->isconfigure ){ + target_free_all_working_areas(target); + e = Jim_GetOpt_Wide( goi, &w ); + if( e != JIM_OK ){ + return e; + } + /* make this exactly 1 or 0 */ + target->chain_position = w; + } else { + if( goi->argc != 0 ){ + goto no_params; + } + } + Jim_SetResult( interp, Jim_NewIntObj( goi->interp, target->chain_position ) ); + /* loop for more e*/ + break; + } + } /* while( goi->argc ) */ + /* done - we return */ + return JIM_OK; +} + + +/** this is the 'tcl' handler for the target specific command */ +static int +tcl_target_func( Jim_Interp *interp, + int argc, + Jim_Obj *const *argv ) +{ + Jim_GetOptInfo goi; + jim_wide a,b,c; + int x,y,z; + u8 target_buf[32]; + Jim_Nvp *n; + target_t *target; + struct command_context_s *cmd_ctx; + int e; + + + enum { + TS_CMD_CONFIGURE, + TS_CMD_CGET, + + TS_CMD_MWW, TS_CMD_MWH, TS_CMD_MWB, + TS_CMD_MDW, TS_CMD_MDH, TS_CMD_MDB, + TS_CMD_MRW, TS_CMD_MRH, TS_CMD_MRB, + TS_CMD_MEM2ARRAY, TS_CMD_ARRAY2MEM, + TS_CMD_EXAMINE, + TS_CMD_POLL, + TS_CMD_RESET, + TS_CMD_HALT, + TS_CMD_WAITSTATE, + TS_CMD_EVENTLIST, + TS_CMD_CURSTATE, + TS_CMD_INVOKE_EVENT, + }; + + static const Jim_Nvp target_options[] = { + { .name = "configure", .value = TS_CMD_CONFIGURE }, + { .name = "cget", .value = TS_CMD_CGET }, + { .name = "mww", .value = TS_CMD_MWW }, + { .name = "mwh", .value = TS_CMD_MWH }, + { .name = "mwb", .value = TS_CMD_MWB }, + { .name = "mdw", .value = TS_CMD_MDW }, + { .name = "mdh", .value = TS_CMD_MDH }, + { .name = "mdb", .value = TS_CMD_MDB }, + { .name = "mem2array", .value = TS_CMD_MEM2ARRAY }, + { .name = "array2mem", .value = TS_CMD_ARRAY2MEM }, + { .name = "eventlist", .value = TS_CMD_EVENTLIST }, + { .name = "curstate", .value = TS_CMD_CURSTATE }, + + { .name = "arp_examine", .value = TS_CMD_EXAMINE }, + { .name = "arp_poll", .value = TS_CMD_POLL }, + { .name = "arp_reset", .value = TS_CMD_RESET }, + { .name = "arp_halt", .value = TS_CMD_HALT }, + { .name = "arp_waitstate", .value = TS_CMD_WAITSTATE }, + { .name = "invoke-event", .value = TS_CMD_INVOKE_EVENT }, + + { .name = NULL, .value = -1 }, + }; + + + /* go past the "command" */ + Jim_GetOpt_Setup( &goi, interp, argc-1, argv+1 ); + + target = Jim_CmdPrivData( goi.interp ); + cmd_ctx = Jim_GetAssocData(goi.interp, "context"); + + /* commands here are in an NVP table */ + e = Jim_GetOpt_Nvp( &goi, target_options, &n ); + if( e != JIM_OK ){ + Jim_GetOpt_NvpUnknown( &goi, target_options, 0 ); + return e; + } + // Assume blank result + Jim_SetEmptyResult( goi.interp ); + + switch( n->value ){ + case TS_CMD_CONFIGURE: + if( goi.argc < 2 ){ + Jim_WrongNumArgs( goi.interp, goi.argc, goi.argv, "missing: -option VALUE ..."); + return JIM_ERR; + } + goi.isconfigure = 1; + return target_configure( &goi, target ); + case TS_CMD_CGET: + // some things take params + if( goi.argc < 1 ){ + Jim_WrongNumArgs( goi.interp, 0, goi.argv, "missing: ?-option?"); + return JIM_ERR; + } + goi.isconfigure = 0; + return target_configure( &goi, target ); + break; + case TS_CMD_MWW: + case TS_CMD_MWH: + case TS_CMD_MWB: + /* argv[0] = cmd + * argv[1] = address + * argv[2] = data + * argv[3] = optional count. + */ + + if( (goi.argc == 3) || (goi.argc == 4) ){ + /* all is well */ + } else { + mwx_error: + Jim_SetResult_sprintf( goi.interp, "expected: %s ADDR DATA [COUNT]", n->name ); + return JIM_ERR; + } + + e = Jim_GetOpt_Wide( &goi, &a ); + if( e != JIM_OK ){ + goto mwx_error; + } + + e = Jim_GetOpt_Wide( &goi, &b ); + if( e != JIM_OK ){ + goto mwx_error; + } + if( goi.argc ){ + e = Jim_GetOpt_Wide( &goi, &c ); + if( e != JIM_OK ){ + goto mwx_error; + } + } else { + c = 1; + } + + switch( n->value ){ + case TS_CMD_MWW: + target_buffer_set_u32( target, target_buf, b ); + b = 4; + break; + case TS_CMD_MWH: + target_buffer_set_u16( target, target_buf, b ); + b = 2; + break; + case TS_CMD_MWB: + target_buffer_set_u8( target, target_buf, b ); + b = 1; + break; + } + for( x = 0 ; x < c ; x++ ){ + e = target->type->write_memory( target, a, b, 1, target_buf ); + if( e != ERROR_OK ){ + Jim_SetResult_sprintf( interp, "Error writing @ 0x%08x: %d\n", (int)(a), e ); + return JIM_ERR; + } + /* b = width */ + a = a + b; + } + return JIM_OK; + break; + + /* display */ + case TS_CMD_MDW: + case TS_CMD_MDH: + case TS_CMD_MDB: + /* argv[0] = command + * argv[1] = address + * argv[2] = optional count + */ + if( (goi.argc == 2) || (goi.argc == 3) ){ + Jim_SetResult_sprintf( goi.interp, "expected: %s ADDR [COUNT]", n->name ); + return JIM_ERR; + } + e = Jim_GetOpt_Wide( &goi, &a ); + if( e != JIM_OK ){ + return JIM_ERR; + } + if( goi.argc ){ + e = Jim_GetOpt_Wide( &goi, &c ); + if( e != JIM_OK ){ + return JIM_ERR; + } + } else { + c = 1; + } + b = 1; /* shut up gcc */ + switch( n->value ){ + case TS_CMD_MDW: + b = 4; + break; + case TS_CMD_MDH: + b = 2; + break; + case TS_CMD_MDB: + b = 1; + break; + } + + /* convert to "bytes" */ + c = c * b; + /* count is now in 'BYTES' */ + while( c > 0 ){ + y = c; + if( y > 16 ){ + y = 16; + } + e = target->type->read_memory( target, a, b, y / b, target_buf ); + if( e != ERROR_OK ){ + Jim_SetResult_sprintf( interp, "error reading target @ 0x%08lx", (int)(a) ); + return JIM_ERR; + } + + Jim_fprintf( interp, interp->cookie_stdout, "0x%08x ", (int)(a) ); + switch( b ){ + case 4: + for( x = 0 ; (x < 16) && (x < y) ; x += 4 ){ + z = target_buffer_get_u32( target, &(target_buf[ x * 4 ]) ); + Jim_fprintf( interp, interp->cookie_stdout, "%08x ", (int)(z) ); + } + for( ; (x < 16) ; x += 4 ){ + Jim_fprintf( interp, interp->cookie_stdout, " " ); + } + break; + case 2: + for( x = 0 ; (x < 16) && (x < y) ; x += 2 ){ + z = target_buffer_get_u16( target, &(target_buf[ x * 2 ]) ); + Jim_fprintf( interp, interp->cookie_stdout, "%04x ", (int)(z) ); + } + for( ; (x < 16) ; x += 2 ){ + Jim_fprintf( interp, interp->cookie_stdout, " " ); + } + break; + case 1: + default: + for( x = 0 ; (x < 16) && (x < y) ; x += 1 ){ + z = target_buffer_get_u8( target, &(target_buf[ x * 4 ]) ); + Jim_fprintf( interp, interp->cookie_stdout, "%02x ", (int)(z) ); + } + for( ; (x < 16) ; x += 1 ){ + Jim_fprintf( interp, interp->cookie_stdout, " " ); + } + break; + } + /* ascii-ify the bytes */ + for( x = 0 ; x < y ; x++ ){ + if( (target_buf[x] >= 0x20) && + (target_buf[x] <= 0x7e) ){ + /* good */ + } else { + /* smack it */ + target_buf[x] = '.'; + } + } + /* space pad */ + while( x < 16 ){ + target_buf[x] = ' '; + x++; + } + /* terminate */ + target_buf[16] = 0; + /* print - with a newline */ + Jim_fprintf( interp, interp->cookie_stdout, "%s\n", target_buf ); + /* NEXT... */ + c -= 16; + a += 16; + } + return JIM_OK; + case TS_CMD_MEM2ARRAY: + return target_mem2array( goi.interp, target, goi.argc, goi.argv ); + break; + case TS_CMD_ARRAY2MEM: + return target_array2mem( goi.interp, target, goi.argc, goi.argv ); + break; + case TS_CMD_EXAMINE: + if( goi.argc ){ + Jim_WrongNumArgs( goi.interp, 2, argv, "[no parameters]"); + return JIM_ERR; + } + e = target->type->examine( target ); + if( e != ERROR_OK ){ + Jim_SetResult_sprintf( interp, "examine-fails: %d", e ); + return JIM_ERR; + } + return JIM_OK; + case TS_CMD_POLL: + if( goi.argc ){ + Jim_WrongNumArgs( goi.interp, 2, argv, "[no parameters]"); + return JIM_ERR; + } + if( !(target->type->examined) ){ + e = ERROR_TARGET_NOT_EXAMINED; + } else { + e = target->type->poll( target ); + } + if( e != ERROR_OK ){ + Jim_SetResult_sprintf( interp, "poll-fails: %d", e ); + return JIM_ERR; + } else { + return JIM_OK; + } + break; + case TS_CMD_RESET: + if( goi.argc != 2 ){ + Jim_WrongNumArgs( interp, 2, argv, "t|f|assert|deassert BOOL"); + return JIM_ERR; + } + e = Jim_GetOpt_Nvp( &goi, nvp_assert, &n ); + if( e != JIM_OK ){ + Jim_GetOpt_NvpUnknown( &goi, nvp_assert, 1 ); + return e; + } + // the halt or not param + e = Jim_GetOpt_Wide( &goi, &a); + if( e != JIM_OK ){ + return e; + } + // determine if we should halt or not. + target->reset_halt = !!a; + // When this happens - all workareas are invalid. + target_free_all_working_areas_restore(target, 0); + + // do the assert + if( n->value == NVP_ASSERT ){ + target->type->assert_reset( target ); + } else { + target->type->deassert_reset( target ); + } + return JIM_OK; + case TS_CMD_HALT: + if( goi.argc ){ + Jim_WrongNumArgs( goi.interp, 0, argv, "halt [no parameters]"); + return JIM_ERR; + } + target->type->halt( target ); + return JIM_OK; + case TS_CMD_WAITSTATE: + // params: statename timeoutmsecs + if( goi.argc != 2 ){ + Jim_SetResult_sprintf( goi.interp, "%s STATENAME TIMEOUTMSECS", n->name ); + return JIM_ERR; + } + e = Jim_GetOpt_Nvp( &goi, nvp_target_state, &n ); + if( e != JIM_OK ){ + Jim_GetOpt_NvpUnknown( &goi, nvp_target_state,1 ); + return e; + } + e = Jim_GetOpt_Wide( &goi, &a ); + if( e != JIM_OK ){ + return e; + } + e = target_wait_state( target, n->value, a ); + if( e != ERROR_OK ){ + Jim_SetResult_sprintf( goi.interp, + "target: %s wait %s fails (%d) %s", + target->cmd_name, + n->name, + e, target_strerror_safe(e) ); + return JIM_ERR; + } else { + return JIM_OK; + } + case TS_CMD_EVENTLIST: + /* List for human, Events defined for this target. + * scripts/programs should use 'name cget -event NAME' + */ + { + target_event_action_t *teap; + teap = target->event_action; + command_print( cmd_ctx, "Event actions for target (%d) %s\n", + target->target_number, + target->cmd_name ); + command_print( cmd_ctx, "%-25s | Body", "Event"); + command_print( cmd_ctx, "------------------------- | ----------------------------------------"); + while( teap ){ + command_print( cmd_ctx, + "%-25s | %s", + Jim_Nvp_value2name_simple( nvp_target_event, teap->event )->name, + Jim_GetString( teap->body, NULL ) ); + teap = teap->next; + } + command_print( cmd_ctx, "***END***"); + return JIM_OK; + } + case TS_CMD_CURSTATE: + if( goi.argc != 0 ){ + Jim_WrongNumArgs( goi.interp, 0, argv, "[no parameters]"); + return JIM_ERR; + } + Jim_SetResultString( goi.interp, + Jim_Nvp_value2name_simple(nvp_target_state,target->state)->name,-1); + return JIM_OK; + case TS_CMD_INVOKE_EVENT: + if( goi.argc != 1 ){ + Jim_SetResult_sprintf( goi.interp, "%s ?EVENTNAME?",n->name); + return JIM_ERR; + } + e = Jim_GetOpt_Nvp( &goi, nvp_target_event, &n ); + if( e != JIM_OK ){ + Jim_GetOpt_NvpUnknown( &goi, nvp_target_event, 1 ); + return e; + } + target_handle_event( target, n->value ); + return JIM_OK; + } + return JIM_ERR; +} + + +static int +target_create( Jim_GetOptInfo *goi ) +{ + + Jim_Obj *new_cmd; + Jim_Cmd *cmd; + const char *cp; + char *cp2; + int e; + int x; + target_t *target; + struct command_context_s *cmd_ctx; + + cmd_ctx = Jim_GetAssocData(goi->interp, "context"); + if( goi->argc < 3 ){ + Jim_WrongNumArgs( goi->interp, 1, goi->argv, "?name? ?type? ..options..."); + return JIM_ERR; + } + + /* COMMAND */ + Jim_GetOpt_Obj( goi, &new_cmd ); + /* does this command exist? */ + cmd = Jim_GetCommand( goi->interp, new_cmd, JIM_ERRMSG ); + if( cmd ){ + cp = Jim_GetString( new_cmd, NULL ); + Jim_SetResult_sprintf(goi->interp, "Command/target: %s Exists", cp); + return JIM_ERR; + } + + /* TYPE */ + e = Jim_GetOpt_String( goi, &cp2, NULL ); + cp = cp2; + /* now does target type exist */ + for( x = 0 ; target_types[x] ; x++ ){ + if( 0 == strcmp( cp, target_types[x]->name ) ){ + /* found */ + break; + } + } + if( target_types[x] == NULL ){ + Jim_SetResult_sprintf( goi->interp, "Unknown target type %s, try one of ", cp ); + for( x = 0 ; target_types[x] ; x++ ){ + if( target_types[x+1] ){ + Jim_AppendStrings( goi->interp, + Jim_GetResult(goi->interp), + target_types[x]->name, + ", ", NULL); + } else { + Jim_AppendStrings( goi->interp, + Jim_GetResult(goi->interp), + " or ", + target_types[x]->name,NULL ); + } + } + return JIM_ERR; + } + + + /* Create it */ + target = calloc(1,sizeof(target_t)); + /* set target number */ + target->target_number = new_target_number(); + + /* allocate memory for each unique target type */ + target->type = (target_type_t*)calloc(1,sizeof(target_type_t)); + + memcpy( target->type, target_types[x], sizeof(target_type_t)); + + /* will be set by "-endian" */ + target->endianness = TARGET_ENDIAN_UNKNOWN; + + target->working_area = 0x0; + target->working_area_size = 0x0; + target->working_areas = NULL; + target->backup_working_area = 0; + + target->state = TARGET_UNKNOWN; + target->debug_reason = DBG_REASON_UNDEFINED; + target->reg_cache = NULL; + target->breakpoints = NULL; + target->watchpoints = NULL; + target->next = NULL; + target->arch_info = NULL; + + /* initialize trace information */ + target->trace_info = malloc(sizeof(trace_t)); + target->trace_info->num_trace_points = 0; + target->trace_info->trace_points_size = 0; + target->trace_info->trace_points = NULL; + target->trace_info->trace_history_size = 0; + target->trace_info->trace_history = NULL; + target->trace_info->trace_history_pos = 0; + target->trace_info->trace_history_overflowed = 0; + + target->dbgmsg = NULL; + target->dbg_msg_enabled = 0; + + target->endianness = TARGET_ENDIAN_UNKNOWN; + + /* Do the rest as "configure" options */ + goi->isconfigure = 1; + e = target_configure( goi, target); + if( e != JIM_OK ){ + free( target->type ); + free( target ); + return e; + } + + if( target->endianness == TARGET_ENDIAN_UNKNOWN ){ + /* default endian to little if not specified */ + target->endianness = TARGET_LITTLE_ENDIAN; + } + + /* create the target specific commands */ + if( target->type->register_commands ){ + (*(target->type->register_commands))( cmd_ctx ); + } + if( target->type->target_create ){ + (*(target->type->target_create))( target, goi->interp ); + } + + /* append to end of list */ + { + target_t **tpp; + tpp = &(all_targets); + while( *tpp ){ + tpp = &( (*tpp)->next ); + } + *tpp = target; + } + + cp = Jim_GetString( new_cmd, NULL ); + target->cmd_name = strdup(cp); + + /* now - create the new target name command */ + e = Jim_CreateCommand( goi->interp, + /* name */ + cp, + tcl_target_func, /* C function */ + target, /* private data */ + NULL ); /* no del proc */ + + (*(target->type->target_create))( target, goi->interp ); + return e; +} + +static int +jim_target( Jim_Interp *interp, int argc, Jim_Obj *const *argv ) +{ + int x,r,e; + jim_wide w; + struct command_context_s *cmd_ctx; + const char *cp; + target_t *target; + Jim_GetOptInfo goi; + enum tcmd { + /* TG = target generic */ + TG_CMD_CREATE, + TG_CMD_TYPES, + TG_CMD_NAMES, + TG_CMD_CURRENT, + TG_CMD_NUMBER, + TG_CMD_COUNT, + }; + const char *target_cmds[] = { + "create", "types", "names", "current", "number", + "count", + NULL // terminate + }; + + LOG_DEBUG("Target command params:"); + LOG_DEBUG(Jim_Debug_ArgvString( interp, argc, argv) ); + + cmd_ctx = Jim_GetAssocData( interp, "context" ); + + Jim_GetOpt_Setup( &goi, interp, argc-1, argv+1 ); + + if( goi.argc == 0 ){ + Jim_WrongNumArgs(interp, 1, argv, "missing: command ..."); + return JIM_ERR; + } + + /* is this old syntax? */ + /* To determine: We have to peek at argv[0]*/ + cp = Jim_GetString( goi.argv[0], NULL ); + for( x = 0 ; target_types[x] ; x++ ){ + if( 0 == strcmp(cp,target_types[x]->name) ){ + break; + } + } + if( target_types[x] ){ + /* YES IT IS OLD SYNTAX */ + int chain_position_offset; + Jim_Obj *new_argv[10]; + int new_argc; + + /* target_old_syntax + * + * It appears that there are 2 old syntaxes: + * + * target + * + * and + * + * target + * + * The following uses the number of arguments to switch between them. + */ + if( argc < 5 ){ + Jim_WrongNumArgs( interp, 1, argv, "[OLDSYNTAX] ?TYPE? ?ENDIAN? ?CHAIN-POSITION? ?VARIANT?"); + return JIM_ERR; + } + + /* Use the correct argument offset for the chain position */ + if (argc < 6) { + /* target */ + chain_position_offset = 2; + } else { + chain_position_offset = 3; + /* target */ + } + + /* the command */ + new_argv[0] = argv[0]; + new_argv[1] = Jim_NewStringObj( interp, "create", -1 ); + { + char buf[ 30 ]; + sprintf( buf, "target%d", new_target_number() ); + new_argv[2] = Jim_NewStringObj( interp, buf , -1 ); + } + new_argv[3] = goi.argv[0]; /* typename */ + new_argv[4] = Jim_NewStringObj( interp, "-endian", -1 ); + new_argv[5] = goi.argv[1]; + new_argv[6] = Jim_NewStringObj( interp, "-chain-position", -1 ); + new_argv[7] = goi.argv[chain_position_offset]; + new_argv[8] = Jim_NewStringObj( interp, "-variant", -1 ); + new_argv[9] = goi.argv[chain_position_offset + 1]; + new_argc = 10; + + /* + * new arg syntax: + * argv[0] = command + * argv[1] = create + * argv[2] = cmdname + * argv[3] = typename + * argv[4] = **FIRST** "configure" option. + * + * Here, we make them: + * + * argv[4] = -endian + * argv[5] = little + * argv[6] = -position + * argv[7] = NUMBER + * argv[8] = -variant + * argv[9] = "somestring" + */ + + /* don't let these be released */ + for( x = 0 ; x < new_argc ; x++ ){ + Jim_IncrRefCount( new_argv[x]); + } + /* call our self */ + LOG_DEBUG("Target OLD SYNTAX - converted to new syntax"); + + r = jim_target( goi.interp, new_argc, new_argv ); + + /* release? these items */ + for( x = 0 ; x < new_argc ; x++ ){ + Jim_DecrRefCount( interp, new_argv[x] ); + } + return r; + } + + //Jim_GetOpt_Debug( &goi ); + r = Jim_GetOpt_Enum( &goi, target_cmds, &x ); + if( r != JIM_OK ){ + return r; + } + + switch(x){ + default: + Jim_Panic(goi.interp,"Why am I here?"); + return JIM_ERR; + case TG_CMD_CURRENT: + if( goi.argc != 0 ){ + Jim_WrongNumArgs( goi.interp, 1, goi.argv, "Too many parameters"); + return JIM_ERR; + } + Jim_SetResultString( goi.interp, get_current_target( cmd_ctx )->cmd_name, -1 ); + return JIM_OK; + case TG_CMD_TYPES: + if( goi.argc != 0 ){ + Jim_WrongNumArgs( goi.interp, 1, goi.argv, "Too many parameters" ); + return JIM_ERR; + } + Jim_SetResult( goi.interp, Jim_NewListObj( goi.interp, NULL, 0 ) ); + for( x = 0 ; target_types[x] ; x++ ){ + Jim_ListAppendElement( goi.interp, + Jim_GetResult(goi.interp), + Jim_NewStringObj( goi.interp, target_types[x]->name, -1 ) ); + } + return JIM_OK; + case TG_CMD_NAMES: + if( goi.argc != 0 ){ + Jim_WrongNumArgs( goi.interp, 1, goi.argv, "Too many parameters" ); + return JIM_ERR; + } + Jim_SetResult( goi.interp, Jim_NewListObj( goi.interp, NULL, 0 ) ); + target = all_targets; + while( target ){ + Jim_ListAppendElement( goi.interp, + Jim_GetResult(goi.interp), + Jim_NewStringObj( goi.interp, target->cmd_name, -1 ) ); + target = target->next; + } + return JIM_OK; + case TG_CMD_CREATE: + if( goi.argc < 3 ){ + Jim_WrongNumArgs( goi.interp, goi.argc, goi.argv, "?name ... config options ..."); + return JIM_ERR; + } + return target_create( &goi ); + break; + case TG_CMD_NUMBER: + if( goi.argc != 1 ){ + Jim_SetResult_sprintf( goi.interp, "expected: target number ?NUMBER?"); + return JIM_ERR; + } + e = Jim_GetOpt_Wide( &goi, &w ); + if( e != JIM_OK ){ + return JIM_ERR; + } + { + target_t *t; + t = get_target_by_num(w); + if( t == NULL ){ + Jim_SetResult_sprintf( goi.interp,"Target: number %d does not exist", (int)(w)); + return JIM_ERR; + } + Jim_SetResultString( goi.interp, t->cmd_name, -1 ); + return JIM_OK; + } + case TG_CMD_COUNT: + if( goi.argc != 0 ){ + Jim_WrongNumArgs( goi.interp, 0, goi.argv, ""); + return JIM_ERR; + } + Jim_SetResult( goi.interp, + Jim_NewIntObj( goi.interp, max_target_number())); + return JIM_OK; + } + + return JIM_ERR; +}