X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Ftarget%2Ftarget.c;h=dcb6725065ee766d57bbbd62e5c4e440f6c49ef8;hp=bfa0db79e1718e7727c868a959ea202095d04ea9;hb=020cb12077cb15be1700bf7733178acfb2b26428;hpb=cf8a3c3d7075abad3c88cd604f8add4d06898abc diff --git a/src/target/target.c b/src/target/target.c index bfa0db79e1..dcb6725065 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -34,9 +34,7 @@ * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. * + * along with this program. If not, see . * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -55,16 +53,26 @@ #include "trace.h" #include "image.h" #include "rtos/rtos.h" +#include "transport/transport.h" -static int target_read_buffer_default(struct target *target, uint32_t address, - uint32_t size, uint8_t *buffer); -static int target_write_buffer_default(struct target *target, uint32_t address, - uint32_t size, const uint8_t *buffer); +/* default halt wait timeout (ms) */ +#define DEFAULT_HALT_TIMEOUT 5000 + +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, + uint32_t count, const uint8_t *buffer); static int target_array2mem(Jim_Interp *interp, struct target *target, int argc, Jim_Obj * const *argv); static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, Jim_Obj * const *argv); static int target_register_user_commands(struct command_context *cmd_ctx); +static int target_get_gdb_fileio_info_default(struct target *target, + struct gdb_fileio_info *fileio_info); +static int target_gdb_fileio_end_default(struct target *target, int retcode, + int fileio_errno, bool ctrl_c); +static int target_profiling_default(struct target *target, uint32_t *samples, + uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds); /* targets */ extern struct target_type arm7tdmi_target; @@ -78,10 +86,12 @@ extern struct target_type fa526_target; extern struct target_type feroceon_target; extern struct target_type dragonite_target; extern struct target_type xscale_target; -extern struct target_type cortexm3_target; -extern struct target_type cortexa8_target; +extern struct target_type cortexm_target; +extern struct target_type cortexa_target; +extern struct target_type aarch64_target; extern struct target_type cortexr4_target; extern struct target_type arm11_target; +extern struct target_type ls1_sap_target; extern struct target_type mips_m4k_target; extern struct target_type avr_target; extern struct target_type dsp563xx_target; @@ -92,6 +102,10 @@ extern struct target_type hla_target; extern struct target_type nds32_v2_target; extern struct target_type nds32_v3_target; extern struct target_type nds32_v3m_target; +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; static struct target_type *target_types[] = { &arm7tdmi_target, @@ -105,10 +119,11 @@ static struct target_type *target_types[] = { &feroceon_target, &dragonite_target, &xscale_target, - &cortexm3_target, - &cortexa8_target, + &cortexm_target, + &cortexa_target, &cortexr4_target, &arm11_target, + &ls1_sap_target, &mips_m4k_target, &avr_target, &dsp563xx_target, @@ -119,12 +134,21 @@ static struct target_type *target_types[] = { &nds32_v2_target, &nds32_v3_target, &nds32_v3m_target, + &or1k_target, + &quark_x10xx_target, + &quark_d20xx_target, + &stm8_target, +#if BUILD_TARGET64 + &aarch64_target, +#endif NULL, }; struct target *all_targets; static struct target_event_callback *target_event_callbacks; static struct target_timer_callback *target_timer_callbacks; +LIST_HEAD(target_reset_callback_list); +LIST_HEAD(target_trace_callback_list); static const int polling_interval = 100; static const Jim_Nvp nvp_assert[] = { @@ -202,6 +226,8 @@ static const Jim_Nvp nvp_target_event[] = { { .value = TARGET_EVENT_GDB_FLASH_ERASE_START, .name = "gdb-flash-erase-start" }, { .value = TARGET_EVENT_GDB_FLASH_ERASE_END , .name = "gdb-flash-erase-end" }, + { .value = TARGET_EVENT_TRACE_CONFIG, .name = "trace-config" }, + { .name = NULL, .value = -1 } }; @@ -221,6 +247,7 @@ static const Jim_Nvp nvp_target_debug_reason[] = { { .name = "watchpoint-and-breakpoint", .value = DBG_REASON_WPTANDBKPT }, { .name = "single-step" , .value = DBG_REASON_SINGLESTEP }, { .name = "target-not-halted" , .value = DBG_REASON_NOTHALTED }, + { .name = "program-exit" , .value = DBG_REASON_EXIT }, { .name = "undefined" , .value = DBG_REASON_UNDEFINED }, { .name = NULL, .value = -1 }, }; @@ -262,6 +289,32 @@ const char *target_state_name(struct target *t) LOG_ERROR("Invalid target state: %d", (int)(t->state)); cp = "(*BUG*unknown*BUG*)"; } + + if (!target_was_examined(t) && t->defer_examine) + cp = "examine deferred"; + + return cp; +} + +const char *target_event_name(enum target_event event) +{ + const char *cp; + cp = Jim_Nvp_value2name_simple(nvp_target_event, event)->name; + if (!cp) { + LOG_ERROR("Invalid target event: %d", (int)(event)); + cp = "(*BUG*unknown*BUG*)"; + } + return cp; +} + +const char *target_reset_mode_name(enum target_reset_mode reset_mode) +{ + const char *cp; + cp = Jim_Nvp_value2name_simple(nvp_reset_modes, reset_mode)->name; + if (!cp) { + LOG_ERROR("Invalid target reset mode: %d", (int)(reset_mode)); + cp = "(*BUG*unknown*BUG*)"; + } return cp; } @@ -282,6 +335,15 @@ static int new_target_number(void) return x + 1; } +/* read a uint64_t from a buffer in target memory endianness */ +uint64_t target_buffer_get_u64(struct target *target, const uint8_t *buffer) +{ + if (target->endianness == TARGET_LITTLE_ENDIAN) + return le_to_h_u64(buffer); + else + return be_to_h_u64(buffer); +} + /* read a uint32_t from a buffer in target memory endianness */ uint32_t target_buffer_get_u32(struct target *target, const uint8_t *buffer) { @@ -315,6 +377,15 @@ static uint8_t target_buffer_get_u8(struct target *target, const uint8_t *buffer return *buffer & 0x0ff; } +/* write a uint64_t to a buffer in target memory endianness */ +void target_buffer_set_u64(struct target *target, uint8_t *buffer, uint64_t value) +{ + if (target->endianness == TARGET_LITTLE_ENDIAN) + h_u64_to_le(buffer, value); + else + h_u64_to_be(buffer, value); +} + /* write a uint32_t to a buffer in target memory endianness */ void target_buffer_set_u32(struct target *target, uint8_t *buffer, uint32_t value) { @@ -348,6 +419,14 @@ static void target_buffer_set_u8(struct target *target, uint8_t *buffer, uint8_t *buffer = value; } +/* write a uint64_t array to a buffer in target memory endianness */ +void target_buffer_get_u64_array(struct target *target, const uint8_t *buffer, uint32_t count, uint64_t *dstbuf) +{ + uint32_t i; + for (i = 0; i < count; i++) + dstbuf[i] = target_buffer_get_u64(target, &buffer[i * 8]); +} + /* write a uint32_t array to a buffer in target memory endianness */ void target_buffer_get_u32_array(struct target *target, const uint8_t *buffer, uint32_t count, uint32_t *dstbuf) { @@ -364,8 +443,16 @@ void target_buffer_get_u16_array(struct target *target, const uint8_t *buffer, u dstbuf[i] = target_buffer_get_u16(target, &buffer[i * 2]); } +/* write a uint64_t array to a buffer in target memory endianness */ +void target_buffer_set_u64_array(struct target *target, uint8_t *buffer, uint32_t count, const uint64_t *srcbuf) +{ + uint32_t i; + for (i = 0; i < count; i++) + target_buffer_set_u64(target, &buffer[i * 8], srcbuf[i]); +} + /* write a uint32_t array to a buffer in target memory endianness */ -void target_buffer_set_u32_array(struct target *target, uint8_t *buffer, uint32_t count, uint32_t *srcbuf) +void target_buffer_set_u32_array(struct target *target, uint8_t *buffer, uint32_t count, const uint32_t *srcbuf) { uint32_t i; for (i = 0; i < count; i++) @@ -373,7 +460,7 @@ void target_buffer_set_u32_array(struct target *target, uint8_t *buffer, uint32_ } /* write a uint16_t array to a buffer in target memory endianness */ -void target_buffer_set_u16_array(struct target *target, uint8_t *buffer, uint32_t count, uint16_t *srcbuf) +void target_buffer_set_u16_array(struct target *target, uint8_t *buffer, uint32_t count, const uint16_t *srcbuf) { uint32_t i; for (i = 0; i < count; i++) @@ -412,7 +499,7 @@ struct target *get_target(const char *id) } /* returns a pointer to the n-th configured target */ -static struct target *get_target_by_num(int num) +struct target *get_target_by_num(int num) { struct target *target = all_targets; @@ -455,8 +542,8 @@ int target_poll(struct target *target) if (target->state == TARGET_HALTED) target->halt_issued = false; else { - long long t = timeval_ms() - target->halt_issued_time; - if (t > 1000) { + int64_t t = timeval_ms() - target->halt_issued_time; + if (t > DEFAULT_HALT_TIMEOUT) { target->halt_issued = false; LOG_INFO("Halt timed out, wake up GDB."); target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); @@ -516,7 +603,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, uint32_t address, int handle_breakpoints, int debug_execution) +int target_resume(struct target *target, int current, target_addr_t address, + int handle_breakpoints, int debug_execution) { int retval; @@ -552,6 +640,10 @@ static int target_process_reset(struct command_context *cmd_ctx, enum target_res return ERROR_FAIL; } + struct target *target; + for (target = all_targets; target; target = target->next) + target_call_reset_callbacks(target, reset_mode); + /* disable polling during reset to make reset event scripts * more predictable, i.e. dr/irscan & pathmove in events will * not have JTAG operations injected into the middle of a sequence. @@ -574,15 +666,16 @@ static int target_process_reset(struct command_context *cmd_ctx, enum target_res /* We want any events to be processed before the prompt */ retval = target_call_timer_callbacks_now(); - struct target *target; - for (target = all_targets; target; target = target->next) + for (target = all_targets; target; target = target->next) { target->type->check_reset(target); + target->running_alg = false; + } return retval; } static int identity_virt2phys(struct target *target, - uint32_t virtual, uint32_t *physical) + target_addr_t virtual, target_addr_t *physical) { *physical = virtual; return ERROR_OK; @@ -608,7 +701,15 @@ static int default_check_reset(struct target *target) int target_examine_one(struct target *target) { - return target->type->examine(target); + target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_START); + + int retval = target->type->examine(target); + if (retval != ERROR_OK) + return retval; + + target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_END); + + return ERROR_OK; } static int jtag_enable_callback(enum jtag_event event, void *priv) @@ -620,15 +721,7 @@ static int jtag_enable_callback(enum jtag_event event, void *priv) jtag_unregister_event_callback(jtag_enable_callback, target); - target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_START); - - int retval = target_examine_one(target); - if (retval != ERROR_OK) - return retval; - - target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_END); - - return retval; + return target_examine_one(target); } /* Targets that correctly implement init + examine, i.e. @@ -649,13 +742,12 @@ int target_examine(void) continue; } - target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_START); + if (target->defer_examine) + continue; retval = target_examine_one(target); if (retval != ERROR_OK) return retval; - - target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_END); } return retval; } @@ -803,7 +895,7 @@ done: */ int target_run_flash_async_algorithm(struct target *target, - uint8_t *buffer, uint32_t count, int block_size, + const uint8_t *buffer, uint32_t count, int block_size, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t buffer_start, uint32_t buffer_size, @@ -812,6 +904,8 @@ int target_run_flash_async_algorithm(struct target *target, int retval; int timeout = 0; + const uint8_t *buffer_orig = buffer; + /* Set up working area. First word is write pointer, second word is read pointer, * rest is fifo data area. */ uint32_t wp_addr = buffer_start; @@ -852,7 +946,8 @@ int target_run_flash_async_algorithm(struct target *target, break; } - LOG_DEBUG("count 0x%" PRIx32 " wp 0x%" PRIx32 " rp 0x%" PRIx32, count, wp, rp); + LOG_DEBUG("offs 0x%zx count 0x%" PRIx32 " wp 0x%" PRIx32 " rp 0x%" PRIx32, + (size_t) (buffer - buffer_orig), count, wp, rp); if (rp == 0) { LOG_ERROR("flash write algorithm aborted by target"); @@ -860,7 +955,7 @@ int target_run_flash_async_algorithm(struct target *target, break; } - if ((rp & (block_size - 1)) || rp < fifo_start_addr || rp >= fifo_end_addr) { + if (((rp - fifo_start_addr) & (block_size - 1)) || rp < fifo_start_addr || rp >= fifo_end_addr) { LOG_ERROR("corrupted fifo read pointer 0x%" PRIx32, rp); break; } @@ -933,60 +1028,79 @@ int target_run_flash_async_algorithm(struct target *target, retval = retval2; } + if (retval == ERROR_OK) { + /* check if algorithm set rp = 0 after fifo writer loop finished */ + retval = target_read_u32(target, rp_addr, &rp); + if (retval == ERROR_OK && rp == 0) { + LOG_ERROR("flash write algorithm aborted by target"); + retval = ERROR_FLASH_OPERATION_FAILED; + } + } + return retval; } int target_read_memory(struct target *target, - uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) + target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } + if (!target->type->read_memory) { + LOG_ERROR("Target %s doesn't support read_memory", target_name(target)); + return ERROR_FAIL; + } return target->type->read_memory(target, address, size, count, buffer); } int target_read_phys_memory(struct target *target, - uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) + target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } + if (!target->type->read_phys_memory) { + LOG_ERROR("Target %s doesn't support read_phys_memory", target_name(target)); + return ERROR_FAIL; + } return target->type->read_phys_memory(target, address, size, count, buffer); } int target_write_memory(struct target *target, - uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) + target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } + if (!target->type->write_memory) { + LOG_ERROR("Target %s doesn't support write_memory", target_name(target)); + return ERROR_FAIL; + } return target->type->write_memory(target, address, size, count, buffer); } int target_write_phys_memory(struct target *target, - uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) + target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } + if (!target->type->write_phys_memory) { + LOG_ERROR("Target %s doesn't support write_phys_memory", target_name(target)); + return ERROR_FAIL; + } return target->type->write_phys_memory(target, address, size, count, buffer); } -static int target_bulk_write_memory_default(struct target *target, - uint32_t address, uint32_t count, const uint8_t *buffer) -{ - return target_write_memory(target, address, 4, count, buffer); -} - int target_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { if ((target->state != TARGET_HALTED) && (breakpoint->type != BKPT_HARD)) { - LOG_WARNING("target %s is not halted", target_name(target)); + LOG_WARNING("target %s is not halted (add breakpoint)", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_breakpoint(target, breakpoint); @@ -996,7 +1110,7 @@ int target_add_context_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted", target_name(target)); + LOG_WARNING("target %s is not halted (add context breakpoint)", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_context_breakpoint(target, breakpoint); @@ -1006,7 +1120,7 @@ int target_add_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted", target_name(target)); + LOG_WARNING("target %s is not halted (add hybrid breakpoint)", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_hybrid_breakpoint(target, breakpoint); @@ -1022,7 +1136,7 @@ int target_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted", target_name(target)); + LOG_WARNING("target %s is not halted (add watchpoint)", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_watchpoint(target, watchpoint); @@ -1032,39 +1146,72 @@ int target_remove_watchpoint(struct target *target, { return target->type->remove_watchpoint(target, watchpoint); } +int target_hit_watchpoint(struct target *target, + struct watchpoint **hit_watchpoint) +{ + if (target->state != TARGET_HALTED) { + LOG_WARNING("target %s is not halted (hit watchpoint)", target->cmd_name); + return ERROR_TARGET_NOT_HALTED; + } + + if (target->type->hit_watchpoint == NULL) { + /* For backward compatible, if hit_watchpoint is not implemented, + * return ERROR_FAIL such that gdb_server will not take the nonsense + * information. */ + return ERROR_FAIL; + } + + return target->type->hit_watchpoint(target, hit_watchpoint); +} int target_get_gdb_reg_list(struct target *target, - struct reg **reg_list[], int *reg_list_size) + 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); + return target->type->get_gdb_reg_list(target, reg_list, reg_list_size, reg_class); } int target_step(struct target *target, - int current, uint32_t address, int handle_breakpoints) + int current, target_addr_t address, int handle_breakpoints) { return target->type->step(target, current, address, handle_breakpoints); } -/** - * Reset the @c examined flag for the given target. - * Pure paranoia -- targets are zeroed on allocation. - */ -static void target_reset_examined(struct target *target) +int target_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info) { - target->examined = false; + if (target->state != TARGET_HALTED) { + LOG_WARNING("target %s is not halted (gdb fileio)", target->cmd_name); + return ERROR_TARGET_NOT_HALTED; + } + return target->type->get_gdb_fileio_info(target, fileio_info); } -static int err_read_phys_memory(struct target *target, uint32_t address, - uint32_t size, uint32_t count, uint8_t *buffer) +int target_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c) { - LOG_ERROR("Not implemented: %s", __func__); - return ERROR_FAIL; + if (target->state != TARGET_HALTED) { + LOG_WARNING("target %s is not halted (gdb fileio end)", target->cmd_name); + return ERROR_TARGET_NOT_HALTED; + } + return target->type->gdb_fileio_end(target, retcode, fileio_errno, ctrl_c); } -static int err_write_phys_memory(struct target *target, uint32_t address, - uint32_t size, uint32_t count, const uint8_t *buffer) +int target_profiling(struct target *target, uint32_t *samples, + uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds) { - LOG_ERROR("Not implemented: %s", __func__); - return ERROR_FAIL; + if (target->state != TARGET_HALTED) { + LOG_WARNING("target %s is not halted (profiling)", target->cmd_name); + return ERROR_TARGET_NOT_HALTED; + } + return target->type->profiling(target, samples, max_num_samples, + num_samples, seconds); +} + +/** + * Reset the @c examined flag for the given target. + * Pure paranoia -- targets are zeroed on allocation. + */ +static void target_reset_examined(struct target *target) +{ + target->examined = false; } static int handle_target(void *priv); @@ -1093,16 +1240,6 @@ static int target_init_one(struct command_context *cmd_ctx, * implement it in stages, but warn if we need to do so. */ if (type->mmu) { - if (type->write_phys_memory == NULL) { - LOG_ERROR("type '%s' is missing write_phys_memory", - type->name); - type->write_phys_memory = err_write_phys_memory; - } - if (type->read_phys_memory == NULL) { - LOG_ERROR("type '%s' is missing read_phys_memory", - type->name); - type->read_phys_memory = err_read_phys_memory; - } if (type->virt2phys == NULL) { LOG_ERROR("type '%s' is missing virt2phys", type->name); type->virt2phys = identity_virt2phys; @@ -1127,8 +1264,14 @@ static int target_init_one(struct command_context *cmd_ctx, if (target->type->write_buffer == NULL) target->type->write_buffer = target_write_buffer_default; - if (target->type->bulk_write_memory == NULL) - target->type->bulk_write_memory = target_bulk_write_memory_default; + if (target->type->get_gdb_fileio_info == NULL) + target->type->get_gdb_fileio_info = target_get_gdb_fileio_info_default; + + if (target->type->gdb_fileio_end == NULL) + target->type->gdb_fileio_end = target_gdb_fileio_end_default; + + if (target->type->profiling == NULL) + target->type->profiling = target_profiling_default; return ERROR_OK; } @@ -1177,6 +1320,10 @@ COMMAND_HANDLER(handle_target_init_command) if (ERROR_OK != retval) return retval; + retval = command_run_line(CMD_CTX, "init_target_events"); + if (ERROR_OK != retval) + return retval; + retval = command_run_line(CMD_CTX, "init_board"); if (ERROR_OK != retval) return retval; @@ -1207,6 +1354,50 @@ int target_register_event_callback(int (*callback)(struct target *target, return ERROR_OK; } +int target_register_reset_callback(int (*callback)(struct target *target, + enum target_reset_mode reset_mode, void *priv), void *priv) +{ + struct target_reset_callback *entry; + + if (callback == NULL) + return ERROR_COMMAND_SYNTAX_ERROR; + + entry = malloc(sizeof(struct target_reset_callback)); + if (entry == NULL) { + LOG_ERROR("error allocating buffer for reset callback entry"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + entry->callback = callback; + entry->priv = priv; + list_add(&entry->list, &target_reset_callback_list); + + + return ERROR_OK; +} + +int target_register_trace_callback(int (*callback)(struct target *target, + size_t len, uint8_t *data, void *priv), void *priv) +{ + struct target_trace_callback *entry; + + if (callback == NULL) + return ERROR_COMMAND_SYNTAX_ERROR; + + entry = malloc(sizeof(struct target_trace_callback)); + if (entry == NULL) { + LOG_ERROR("error allocating buffer for trace callback entry"); + return ERROR_COMMAND_SYNTAX_ERROR; + } + + entry->callback = callback; + entry->priv = priv; + list_add(&entry->list, &target_trace_callback_list); + + + return ERROR_OK; +} + int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int periodic, void *priv) { struct target_timer_callback **callbacks_p = &target_timer_callbacks; @@ -1225,6 +1416,7 @@ int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int (*callbacks_p)->callback = callback; (*callbacks_p)->periodic = periodic; (*callbacks_p)->time_ms = time_ms; + (*callbacks_p)->removed = false; gettimeofday(&now, NULL); (*callbacks_p)->when.tv_usec = now.tv_usec + (time_ms % 1000) * 1000; @@ -1264,26 +1456,58 @@ int target_unregister_event_callback(int (*callback)(struct target *target, return ERROR_OK; } -static int target_unregister_timer_callback(int (*callback)(void *priv), void *priv) +int target_unregister_reset_callback(int (*callback)(struct target *target, + enum target_reset_mode reset_mode, void *priv), void *priv) { - struct target_timer_callback **p = &target_timer_callbacks; - struct target_timer_callback *c = target_timer_callbacks; + struct target_reset_callback *entry; if (callback == NULL) return ERROR_COMMAND_SYNTAX_ERROR; - while (c) { - struct target_timer_callback *next = c->next; + list_for_each_entry(entry, &target_reset_callback_list, list) { + if (entry->callback == callback && entry->priv == priv) { + list_del(&entry->list); + free(entry); + break; + } + } + + return ERROR_OK; +} + +int target_unregister_trace_callback(int (*callback)(struct target *target, + size_t len, uint8_t *data, void *priv), void *priv) +{ + struct target_trace_callback *entry; + + if (callback == NULL) + return ERROR_COMMAND_SYNTAX_ERROR; + + list_for_each_entry(entry, &target_trace_callback_list, list) { + if (entry->callback == callback && entry->priv == priv) { + list_del(&entry->list); + free(entry); + break; + } + } + + return ERROR_OK; +} + +int target_unregister_timer_callback(int (*callback)(void *priv), void *priv) +{ + if (callback == NULL) + return ERROR_COMMAND_SYNTAX_ERROR; + + for (struct target_timer_callback *c = target_timer_callbacks; + c; c = c->next) { if ((c->callback == callback) && (c->priv == priv)) { - *p = next; - free(c); + c->removed = true; return ERROR_OK; - } else - p = &(c->next); - c = next; + } } - return ERROR_OK; + return ERROR_FAIL; } int target_call_event_callbacks(struct target *target, enum target_event event) @@ -1310,6 +1534,29 @@ int target_call_event_callbacks(struct target *target, enum target_event event) return ERROR_OK; } +int target_call_reset_callbacks(struct target *target, enum target_reset_mode reset_mode) +{ + struct target_reset_callback *callback; + + LOG_DEBUG("target reset %i (%s)", reset_mode, + Jim_Nvp_value2name_simple(nvp_reset_modes, reset_mode)->name); + + list_for_each_entry(callback, &target_reset_callback_list, list) + callback->callback(target, reset_mode, callback->priv); + + return ERROR_OK; +} + +int target_call_trace_callbacks(struct target *target, size_t len, uint8_t *data) +{ + struct target_trace_callback *callback; + + list_for_each_entry(callback, &target_trace_callback_list, list) + callback->callback(target, len, data, callback->priv); + + return ERROR_OK; +} + static int target_timer_callback_periodic_restart( struct target_timer_callback *cb, struct timeval *now) { @@ -1337,31 +1584,44 @@ static int target_call_timer_callback(struct target_timer_callback *cb, static int target_call_timer_callbacks_check_time(int checktime) { + static bool callback_processing; + + /* Do not allow nesting */ + if (callback_processing) + return ERROR_OK; + + callback_processing = true; + keep_alive(); struct timeval now; gettimeofday(&now, NULL); - struct target_timer_callback *callback = target_timer_callbacks; - while (callback) { - /* cleaning up may unregister and free this callback */ - struct target_timer_callback *next_callback = callback->next; + /* Store an address of the place containing a pointer to the + * next item; initially, that's a standalone "root of the + * list" variable. */ + struct target_timer_callback **callback = &target_timer_callbacks; + while (*callback) { + if ((*callback)->removed) { + struct target_timer_callback *p = *callback; + *callback = (*callback)->next; + free(p); + continue; + } - bool call_it = callback->callback && - ((!checktime && callback->periodic) || - now.tv_sec > callback->when.tv_sec || - (now.tv_sec == callback->when.tv_sec && - now.tv_usec >= callback->when.tv_usec)); + bool call_it = (*callback)->callback && + ((!checktime && (*callback)->periodic) || + now.tv_sec > (*callback)->when.tv_sec || + (now.tv_sec == (*callback)->when.tv_sec && + now.tv_usec >= (*callback)->when.tv_usec)); - if (call_it) { - int retval = target_call_timer_callback(callback, &now); - if (retval != ERROR_OK) - return retval; - } + if (call_it) + target_call_timer_callback(*callback, &now); - callback = next_callback; + callback = &(*callback)->next; } + callback_processing = false; return ERROR_OK; } @@ -1382,7 +1642,7 @@ static void print_wa_layout(struct target *target) struct working_area *c = target->working_areas; while (c) { - LOG_DEBUG("%c%c 0x%08"PRIx32"-0x%08"PRIx32" (%"PRIu32" bytes)", + LOG_DEBUG("%c%c " TARGET_ADDR_FMT "-" TARGET_ADDR_FMT " (%" PRIu32 " bytes)", c->backup ? 'b' : ' ', c->free ? ' ' : '*', c->address, c->address + c->size - 1, c->size); c = c->next; @@ -1467,7 +1727,7 @@ int target_alloc_working_area_try(struct target *target, uint32_t size, struct w if (!enabled) { if (target->working_area_phys_spec) { LOG_DEBUG("MMU disabled, using physical " - "address for working memory 0x%08"PRIx32, + "address for working memory " TARGET_ADDR_FMT, target->working_area_phys); target->working_area = target->working_area_phys; } else { @@ -1478,7 +1738,7 @@ int target_alloc_working_area_try(struct target *target, uint32_t size, struct w } else { if (target->working_area_virt_spec) { LOG_DEBUG("MMU enabled, using virtual " - "address for working memory 0x%08"PRIx32, + "address for working memory " TARGET_ADDR_FMT, target->working_area_virt); target->working_area = target->working_area_virt; } else { @@ -1521,7 +1781,8 @@ int target_alloc_working_area_try(struct target *target, uint32_t size, struct w /* Split the working area into the requested size */ target_split_working_area(c, size); - LOG_DEBUG("allocated new working area of %"PRIu32" bytes at address 0x%08"PRIx32, size, c->address); + LOG_DEBUG("allocated new working area of %" PRIu32 " bytes at address " TARGET_ADDR_FMT, + size, c->address); if (target->backup_working_area) { if (c->backup == NULL) { @@ -1565,7 +1826,7 @@ static int target_restore_working_area(struct target *target, struct working_are if (target->backup_working_area && area->backup != NULL) { retval = target_write_memory(target, area->address, 4, area->size / 4, area->backup); if (retval != ERROR_OK) - LOG_ERROR("failed to restore %"PRIu32" bytes of working area at address 0x%08"PRIx32, + LOG_ERROR("failed to restore %" PRIu32 " bytes of working area at address " TARGET_ADDR_FMT, area->size, area->address); } @@ -1589,7 +1850,7 @@ static int target_free_working_area_restore(struct target *target, struct workin area->free = true; - LOG_DEBUG("freed %"PRIu32" bytes of working area at address 0x%08"PRIx32, + LOG_DEBUG("freed %" PRIu32 " bytes of working area at address " TARGET_ADDR_FMT, area->size, area->address); /* mark user pointer invalid */ @@ -1611,6 +1872,46 @@ int target_free_working_area(struct target *target, struct working_area *area) return target_free_working_area_restore(target, area, 1); } +static void target_destroy(struct target *target) +{ + if (target->type->deinit_target) + target->type->deinit_target(target); + + free(target->type); + free(target->trace_info); + free(target->cmd_name); + free(target); +} + +void target_quit(void) +{ + struct target_event_callback *pe = target_event_callbacks; + while (pe) { + struct target_event_callback *t = pe->next; + free(pe); + pe = t; + } + target_event_callbacks = NULL; + + struct target_timer_callback *pt = target_timer_callbacks; + while (pt) { + struct target_timer_callback *t = pt->next; + free(pt); + pt = t; + } + target_timer_callbacks = NULL; + + for (struct target *target = all_targets; target;) { + struct target *tmp; + + tmp = target->next; + target_destroy(target); + target = tmp; + } + + all_targets = NULL; +} + /* free resources and restore memory, if restoring memory fails, * free up resources anyway */ @@ -1666,12 +1967,10 @@ int target_arch_state(struct target *target) { int retval; if (target == NULL) { - LOG_USER("No target has been configured"); + LOG_WARNING("No target has been configured"); return ERROR_OK; } - LOG_USER("target state: %s", target_state_name(target)); - if (target->state != TARGET_HALTED) return ERROR_OK; @@ -1679,14 +1978,79 @@ int target_arch_state(struct target *target) return retval; } +static int target_get_gdb_fileio_info_default(struct target *target, + struct gdb_fileio_info *fileio_info) +{ + /* If target does not support semi-hosting function, target + has no need to provide .get_gdb_fileio_info callback. + It just return ERROR_FAIL and gdb_server will return "Txx" + as target halted every time. */ + return ERROR_FAIL; +} + +static int target_gdb_fileio_end_default(struct target *target, + int retcode, int fileio_errno, bool ctrl_c) +{ + return ERROR_OK; +} + +static int target_profiling_default(struct target *target, uint32_t *samples, + uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds) +{ + struct timeval timeout, now; + + gettimeofday(&timeout, NULL); + timeval_add_time(&timeout, seconds, 0); + + LOG_INFO("Starting profiling. Halting and resuming the" + " target as often as we can..."); + + uint32_t sample_count = 0; + /* hopefully it is safe to cache! We want to stop/restart as quickly as possible. */ + struct reg *reg = register_get_by_name(target->reg_cache, "pc", 1); + + int retval = ERROR_OK; + for (;;) { + target_poll(target); + if (target->state == TARGET_HALTED) { + 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); + target_poll(target); + alive_sleep(10); /* sleep 10ms, i.e. <100 samples/second. */ + } else if (target->state == TARGET_RUNNING) { + /* We want to quickly sample the PC. */ + retval = target_halt(target); + } else { + LOG_INFO("Target not halted or running"); + retval = ERROR_OK; + break; + } + + if (retval != ERROR_OK) + break; + + gettimeofday(&now, NULL); + if ((sample_count >= max_num_samples) || + ((now.tv_sec >= timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) { + LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count); + break; + } + } + + *num_samples = sample_count; + return retval; +} + /* Single aligned words are guaranteed to use 16 or 32 bit access * mode respectively, otherwise data is handled as quickly as * possible */ -int target_write_buffer(struct target *target, uint32_t address, uint32_t size, const uint8_t *buffer) +int target_write_buffer(struct target *target, target_addr_t address, uint32_t size, const uint8_t *buffer) { - LOG_DEBUG("writing buffer of %i byte at 0x%8.8x", - (int)size, (unsigned)address); + LOG_DEBUG("writing buffer of %" PRIi32 " byte at " TARGET_ADDR_FMT, + size, address); if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); @@ -1697,77 +2061,58 @@ int target_write_buffer(struct target *target, uint32_t address, uint32_t size, return ERROR_OK; if ((address + size - 1) < address) { - /* GDB can request this when e.g. PC is 0xfffffffc*/ - LOG_ERROR("address + size wrapped(0x%08x, 0x%08x)", - (unsigned)address, - (unsigned)size); + /* GDB can request this when e.g. PC is 0xfffffffc */ + LOG_ERROR("address + size wrapped (" TARGET_ADDR_FMT ", 0x%08" PRIx32 ")", + address, + size); return ERROR_FAIL; } return target->type->write_buffer(target, address, size, buffer); } -static int target_write_buffer_default(struct target *target, uint32_t address, uint32_t size, const uint8_t *buffer) +static int target_write_buffer_default(struct target *target, + target_addr_t address, uint32_t count, const uint8_t *buffer) { - int retval = ERROR_OK; - - if (((address % 2) == 0) && (size == 2)) - return target_write_memory(target, address, 2, 1, buffer); - - /* handle unaligned head bytes */ - if (address % 4) { - uint32_t unaligned = 4 - (address % 4); - - if (unaligned > size) - unaligned = size; - - retval = target_write_memory(target, address, 1, unaligned, buffer); - if (retval != ERROR_OK) - return retval; - - buffer += unaligned; - address += unaligned; - size -= unaligned; - } - - /* handle aligned words */ - if (size >= 4) { - int aligned = size - (size % 4); + uint32_t size; - /* use bulk writes above a certain limit. This may have to be changed */ - if (aligned > 128) { - retval = target->type->bulk_write_memory(target, address, aligned / 4, buffer); - if (retval != ERROR_OK) - return retval; - } else { - retval = target_write_memory(target, address, 4, aligned / 4, buffer); + /* Align up to maximum 4 bytes. The loop condition makes sure the next pass + * will have something to do with the size we leave to it. */ + for (size = 1; size < 4 && count >= size * 2 + (address & size); size *= 2) { + if (address & size) { + int retval = target_write_memory(target, address, size, 1, buffer); if (retval != ERROR_OK) return retval; + address += size; + count -= size; + buffer += size; } - - buffer += aligned; - address += aligned; - size -= aligned; } - /* handle tail writes of less than 4 bytes */ - if (size > 0) { - retval = target_write_memory(target, address, 1, size, buffer); - if (retval != ERROR_OK) - return retval; + /* Write the data with as large access size as possible. */ + for (; size > 0; size /= 2) { + uint32_t aligned = count - count % size; + if (aligned > 0) { + int retval = target_write_memory(target, address, size, aligned / size, buffer); + if (retval != ERROR_OK) + return retval; + address += aligned; + count -= aligned; + buffer += aligned; + } } - return retval; + return ERROR_OK; } /* Single aligned words are guaranteed to use 16 or 32 bit access * mode respectively, otherwise data is handled as quickly as * possible */ -int target_read_buffer(struct target *target, uint32_t address, uint32_t size, uint8_t *buffer) +int target_read_buffer(struct target *target, target_addr_t address, uint32_t size, uint8_t *buffer) { - LOG_DEBUG("reading buffer of %i byte at 0x%8.8x", - (int)size, (unsigned)address); + LOG_DEBUG("reading buffer of %" PRIi32 " byte at " TARGET_ADDR_FMT, + size, address); if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); @@ -1778,8 +2123,8 @@ int target_read_buffer(struct target *target, uint32_t address, uint32_t size, u return ERROR_OK; if ((address + size - 1) < address) { - /* GDB can request this when e.g. PC is 0xfffffffc*/ - LOG_ERROR("address + size wrapped(0x%08" PRIx32 ", 0x%08" PRIx32 ")", + /* GDB can request this when e.g. PC is 0xfffffffc */ + LOG_ERROR("address + size wrapped (" TARGET_ADDR_FMT ", 0x%08" PRIx32 ")", address, size); return ERROR_FAIL; @@ -1788,64 +2133,40 @@ int target_read_buffer(struct target *target, uint32_t address, uint32_t size, u return target->type->read_buffer(target, address, size, buffer); } -static int target_read_buffer_default(struct target *target, uint32_t address, uint32_t size, uint8_t *buffer) +static int target_read_buffer_default(struct target *target, target_addr_t address, uint32_t count, uint8_t *buffer) { - int retval = ERROR_OK; + uint32_t size; - if (((address % 2) == 0) && (size == 2)) - return target_read_memory(target, address, 2, 1, buffer); - - /* handle unaligned head bytes */ - if (address % 4) { - uint32_t unaligned = 4 - (address % 4); - - if (unaligned > size) - unaligned = size; - - retval = target_read_memory(target, address, 1, unaligned, buffer); - if (retval != ERROR_OK) - return retval; - - buffer += unaligned; - address += unaligned; - size -= unaligned; - } - - /* handle aligned words */ - if (size >= 4) { - int aligned = size - (size % 4); - - retval = target_read_memory(target, address, 4, aligned / 4, buffer); - if (retval != ERROR_OK) - return retval; - - buffer += aligned; - address += aligned; - size -= aligned; + /* Align up to maximum 4 bytes. The loop condition makes sure the next pass + * will have something to do with the size we leave to it. */ + for (size = 1; size < 4 && count >= size * 2 + (address & size); size *= 2) { + if (address & size) { + int retval = target_read_memory(target, address, size, 1, buffer); + if (retval != ERROR_OK) + return retval; + address += size; + count -= size; + buffer += size; + } } - /*prevent byte access when possible (avoid AHB access limitations in some cases)*/ - if (size >= 2) { - int aligned = size - (size % 2); - retval = target_read_memory(target, address, 2, aligned / 2, buffer); - if (retval != ERROR_OK) - return retval; - - buffer += aligned; - address += aligned; - size -= aligned; - } - /* handle tail writes of less than 4 bytes */ - if (size > 0) { - retval = target_read_memory(target, address, 1, size, buffer); - if (retval != ERROR_OK) - return retval; + /* Read the data with as large access size as possible. */ + for (; size > 0; size /= 2) { + uint32_t aligned = count - count % size; + if (aligned > 0) { + int retval = target_read_memory(target, address, size, aligned / size, buffer); + if (retval != ERROR_OK) + return retval; + address += aligned; + count -= aligned; + buffer += aligned; + } } return ERROR_OK; } -int target_checksum_memory(struct target *target, uint32_t address, uint32_t size, uint32_t* crc) +int target_checksum_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t* crc) { uint8_t *buffer; int retval; @@ -1860,7 +2181,7 @@ int target_checksum_memory(struct target *target, uint32_t address, uint32_t siz if (retval != ERROR_OK) { buffer = malloc(size); if (buffer == NULL) { - LOG_ERROR("error allocating buffer for section (%d bytes)", (int)size); + LOG_ERROR("error allocating buffer for section (%" PRId32 " bytes)", size); return ERROR_COMMAND_SYNTAX_ERROR; } retval = target_read_buffer(target, address, size, buffer); @@ -1885,7 +2206,8 @@ int target_checksum_memory(struct target *target, uint32_t address, uint32_t siz return retval; } -int target_blank_check_memory(struct target *target, uint32_t address, uint32_t size, uint32_t* blank) +int target_blank_check_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t* blank, + uint8_t erased_value) { int retval; if (!target_was_examined(target)) { @@ -1896,12 +2218,36 @@ int target_blank_check_memory(struct target *target, uint32_t address, uint32_t if (target->type->blank_check_memory == 0) return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - retval = target->type->blank_check_memory(target, address, size, blank); + retval = target->type->blank_check_memory(target, address, size, blank, erased_value); return retval; } -int target_read_u32(struct target *target, uint32_t address, uint32_t *value) +int target_read_u64(struct target *target, target_addr_t address, uint64_t *value) +{ + uint8_t value_buf[8]; + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_FAIL; + } + + int retval = target_read_memory(target, address, 8, 1, value_buf); + + if (retval == ERROR_OK) { + *value = target_buffer_get_u64(target, value_buf); + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%16.16" PRIx64 "", + address, + *value); + } else { + *value = 0x0; + LOG_DEBUG("address: " TARGET_ADDR_FMT " failed", + address); + } + + return retval; +} + +int target_read_u32(struct target *target, target_addr_t address, uint32_t *value) { uint8_t value_buf[4]; if (!target_was_examined(target)) { @@ -1913,19 +2259,19 @@ int target_read_u32(struct target *target, uint32_t address, uint32_t *value) if (retval == ERROR_OK) { *value = target_buffer_get_u32(target, value_buf); - LOG_DEBUG("address: 0x%8.8" PRIx32 ", value: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx32 "", address, *value); } else { *value = 0x0; - LOG_DEBUG("address: 0x%8.8" PRIx32 " failed", + LOG_DEBUG("address: " TARGET_ADDR_FMT " failed", address); } return retval; } -int target_read_u16(struct target *target, uint32_t address, uint16_t *value) +int target_read_u16(struct target *target, target_addr_t address, uint16_t *value) { uint8_t value_buf[2]; if (!target_was_examined(target)) { @@ -1937,40 +2283,62 @@ int target_read_u16(struct target *target, uint32_t address, uint16_t *value) if (retval == ERROR_OK) { *value = target_buffer_get_u16(target, value_buf); - LOG_DEBUG("address: 0x%8.8" PRIx32 ", value: 0x%4.4x", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%4.4" PRIx16, address, *value); } else { *value = 0x0; - LOG_DEBUG("address: 0x%8.8" PRIx32 " failed", + LOG_DEBUG("address: " TARGET_ADDR_FMT " failed", address); } return retval; } -int target_read_u8(struct target *target, uint32_t address, uint8_t *value) +int target_read_u8(struct target *target, target_addr_t address, uint8_t *value) { - int retval = target_read_memory(target, address, 1, 1, value); if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } + int retval = target_read_memory(target, address, 1, 1, value); + if (retval == ERROR_OK) { - LOG_DEBUG("address: 0x%8.8" PRIx32 ", value: 0x%2.2x", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%2.2" PRIx8, address, *value); } else { *value = 0x0; - LOG_DEBUG("address: 0x%8.8" PRIx32 " failed", + LOG_DEBUG("address: " TARGET_ADDR_FMT " failed", address); } return retval; } -int target_write_u32(struct target *target, uint32_t address, uint32_t value) +int target_write_u64(struct target *target, target_addr_t address, uint64_t value) +{ + int retval; + uint8_t value_buf[8]; + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_FAIL; + } + + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%16.16" PRIx64 "", + address, + value); + + target_buffer_set_u64(target, value_buf, value); + retval = target_write_memory(target, address, 8, 1, value_buf); + if (retval != ERROR_OK) + LOG_DEBUG("failed: %i", retval); + + return retval; +} + +int target_write_u32(struct target *target, target_addr_t address, uint32_t value) { int retval; uint8_t value_buf[4]; @@ -1979,7 +2347,7 @@ int target_write_u32(struct target *target, uint32_t address, uint32_t value) return ERROR_FAIL; } - LOG_DEBUG("address: 0x%8.8" PRIx32 ", value: 0x%8.8" PRIx32 "", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx32 "", address, value); @@ -1991,7 +2359,7 @@ int target_write_u32(struct target *target, uint32_t address, uint32_t value) return retval; } -int target_write_u16(struct target *target, uint32_t address, uint16_t value) +int target_write_u16(struct target *target, target_addr_t address, uint16_t value) { int retval; uint8_t value_buf[2]; @@ -2000,7 +2368,7 @@ int target_write_u16(struct target *target, uint32_t address, uint16_t value) return ERROR_FAIL; } - LOG_DEBUG("address: 0x%8.8" PRIx32 ", value: 0x%8.8x", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx16, address, value); @@ -2012,7 +2380,7 @@ int target_write_u16(struct target *target, uint32_t address, uint16_t value) return retval; } -int target_write_u8(struct target *target, uint32_t address, uint8_t value) +int target_write_u8(struct target *target, target_addr_t address, uint8_t value) { int retval; if (!target_was_examined(target)) { @@ -2020,7 +2388,7 @@ int target_write_u8(struct target *target, uint32_t address, uint8_t value) return ERROR_FAIL; } - LOG_DEBUG("address: 0x%8.8" PRIx32 ", value: 0x%2.2x", + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%2.2" PRIx8, address, value); retval = target_write_memory(target, address, 1, 1, &value); @@ -2030,6 +2398,87 @@ int target_write_u8(struct target *target, uint32_t address, uint8_t value) return retval; } +int target_write_phys_u64(struct target *target, target_addr_t address, uint64_t value) +{ + int retval; + uint8_t value_buf[8]; + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_FAIL; + } + + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%16.16" PRIx64 "", + address, + value); + + target_buffer_set_u64(target, value_buf, value); + retval = target_write_phys_memory(target, address, 8, 1, value_buf); + if (retval != ERROR_OK) + LOG_DEBUG("failed: %i", retval); + + return retval; +} + +int target_write_phys_u32(struct target *target, target_addr_t address, uint32_t value) +{ + int retval; + uint8_t value_buf[4]; + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_FAIL; + } + + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx32 "", + address, + value); + + target_buffer_set_u32(target, value_buf, value); + retval = target_write_phys_memory(target, address, 4, 1, value_buf); + if (retval != ERROR_OK) + LOG_DEBUG("failed: %i", retval); + + return retval; +} + +int target_write_phys_u16(struct target *target, target_addr_t address, uint16_t value) +{ + int retval; + uint8_t value_buf[2]; + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_FAIL; + } + + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%8.8" PRIx16, + address, + value); + + target_buffer_set_u16(target, value_buf, value); + retval = target_write_phys_memory(target, address, 2, 1, value_buf); + if (retval != ERROR_OK) + LOG_DEBUG("failed: %i", retval); + + return retval; +} + +int target_write_phys_u8(struct target *target, target_addr_t address, uint8_t value) +{ + int retval; + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_FAIL; + } + + LOG_DEBUG("address: " TARGET_ADDR_FMT ", value: 0x%2.2" PRIx8, + address, value); + + retval = target_write_phys_memory(target, address, 1, 1, &value); + if (retval != ERROR_OK) + LOG_DEBUG("failed: %i", retval); + + return retval; +} + static int find_target(struct command_context *cmd_ctx, const char *name) { struct target *target = get_target(name); @@ -2116,9 +2565,9 @@ static int sense_handler(void) if (powerRestored) runPowerRestore = 1; - long long current = timeval_ms(); - static long long lastPower; - int waitMore = lastPower + 2000 > current; + int64_t current = timeval_ms(); + static int64_t lastPower; + bool waitMore = lastPower + 2000 > current; if (powerDropout && !waitMore) { runPowerDropout = 1; lastPower = current; @@ -2131,7 +2580,7 @@ static int sense_handler(void) int srstDeasserted; srstDeasserted = prevSrstAsserted && !srstAsserted; - static long long lastSrst; + static int64_t lastSrst; waitMore = lastSrst + 2000 > current; if (srstDeasserted && !waitMore) { runSrstDeasserted = 1; @@ -2215,6 +2664,10 @@ static int handle_target(void *priv) for (struct target *target = all_targets; is_jtag_poll_safe() && target; target = target->next) { + + if (!target_was_examined(target)) + continue; + if (!target->tap->enabled) continue; @@ -2235,19 +2688,27 @@ static int handle_target(void *priv) target->backoff.times *= 2; target->backoff.times++; } - LOG_USER("Polling target %s failed, GDB will be halted. Polling again in %dms", - target_name(target), - target->backoff.times * polling_interval); /* Tell GDB to halt the debugger. This allows the user to * run monitor commands to handle the situation. */ target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); - return retval; } + if (target->backoff.times > 0) { + LOG_USER("Polling target %s failed, trying to reexamine", target_name(target)); + target_reset_examined(target); + retval = target_examine_one(target); + /* Target examination could have failed due to unstable connection, + * but we set the examined flag anyway to repoll it later */ + if (retval != ERROR_OK) { + target->examined = true; + LOG_USER("Examination failed, GDB will be halted. Polling again in %dms", + target->backoff.times * polling_interval); + return retval; + } + } + /* Since we succeeded, we reset backoff count */ - if (target->backoff.times > 0) - LOG_USER("Polling target %s succeeded again", target_name(target)); target->backoff.times = 0; } } @@ -2409,13 +2870,11 @@ COMMAND_HANDLER(handle_wait_halt_command) if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; - unsigned ms = 5000; + unsigned ms = DEFAULT_HALT_TIMEOUT; if (1 == CMD_ARGC) { int retval = parse_uint(CMD_ARGV[0], &ms); if (ERROR_OK != retval) return ERROR_COMMAND_SYNTAX_ERROR; - /* convert seconds (given) to milliseconds (needed) */ - ms *= 1000; } struct target *target = get_current_target(CMD_CTX); @@ -2431,8 +2890,8 @@ COMMAND_HANDLER(handle_wait_halt_command) int target_wait_state(struct target *target, enum target_state state, int ms) { int retval; - long long then = 0, cur; - int once = 1; + int64_t then = 0, cur; + bool once = true; for (;;) { retval = target_poll(target); @@ -2442,7 +2901,7 @@ int target_wait_state(struct target *target, enum target_state state, int ms) break; cur = timeval_ms(); if (once) { - once = 0; + once = false; then = timeval_ms(); LOG_DEBUG("waiting for target %s...", Jim_Nvp_value2name_simple(nvp_target_state, state)->name); @@ -2523,9 +2982,9 @@ COMMAND_HANDLER(handle_resume_command) /* with no CMD_ARGV, resume from current pc, addr = 0, * with one arguments, addr = CMD_ARGV[0], * handle breakpoints, not debugging */ - uint32_t addr = 0; + target_addr_t addr = 0; if (CMD_ARGC == 1) { - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); current = 0; } @@ -2542,10 +3001,10 @@ COMMAND_HANDLER(handle_step_command) /* with no CMD_ARGV, step from current pc, addr = 0, * with one argument addr = CMD_ARGV[0], * handle breakpoints, debugging */ - uint32_t addr = 0; + target_addr_t addr = 0; int current_pc = 1; if (CMD_ARGC == 1) { - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); current_pc = 0; } @@ -2555,7 +3014,7 @@ COMMAND_HANDLER(handle_step_command) } static void handle_md_output(struct command_context *cmd_ctx, - struct target *target, uint32_t address, unsigned size, + struct target *target, target_addr_t address, unsigned size, unsigned count, const uint8_t *buffer) { const unsigned line_bytecnt = 32; @@ -2566,14 +3025,17 @@ static void handle_md_output(struct command_context *cmd_ctx, const char *value_fmt; switch (size) { + case 8: + value_fmt = "%16.16"PRIx64" "; + break; case 4: - value_fmt = "%8.8x "; + value_fmt = "%8.8"PRIx64" "; break; case 2: - value_fmt = "%4.4x "; + value_fmt = "%4.4"PRIx64" "; break; case 1: - value_fmt = "%2.2x "; + value_fmt = "%2.2"PRIx64" "; break; default: /* "can't happen", caller checked */ @@ -2585,13 +3047,16 @@ static void handle_md_output(struct command_context *cmd_ctx, if (i % line_modulo == 0) { output_len += snprintf(output + output_len, sizeof(output) - output_len, - "0x%8.8x: ", - (unsigned)(address + (i*size))); + TARGET_ADDR_FMT ": ", + (address + (i * size))); } - uint32_t value = 0; + uint64_t value = 0; const uint8_t *value_ptr = buffer + i * size; switch (size) { + case 8: + value = target_buffer_get_u64(target, value_ptr); + break; case 4: value = target_buffer_get_u32(target, value_ptr); break; @@ -2619,6 +3084,9 @@ COMMAND_HANDLER(handle_md_command) unsigned size = 0; switch (CMD_NAME[2]) { + case 'd': + size = 8; + break; case 'w': size = 4; break; @@ -2634,7 +3102,7 @@ COMMAND_HANDLER(handle_md_command) bool physical = strcmp(CMD_ARGV[0], "phys") == 0; int (*fn)(struct target *target, - uint32_t address, uint32_t size_value, uint32_t count, uint8_t *buffer); + target_addr_t address, uint32_t size_value, uint32_t count, uint8_t *buffer); if (physical) { CMD_ARGC--; CMD_ARGV++; @@ -2644,8 +3112,8 @@ COMMAND_HANDLER(handle_md_command) if ((CMD_ARGC < 1) || (CMD_ARGC > 2)) return ERROR_COMMAND_SYNTAX_ERROR; - uint32_t address; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); + target_addr_t address; + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); unsigned count = 1; if (CMD_ARGC == 2) @@ -2664,20 +3132,14 @@ COMMAND_HANDLER(handle_md_command) } typedef int (*target_write_fn)(struct target *target, - uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer); - -static int target_write_memory_fast(struct target *target, - uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) -{ - return target_write_buffer(target, address, size * count, buffer); -} + target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer); static int target_fill_mem(struct target *target, - uint32_t address, + target_addr_t address, target_write_fn fn, unsigned data_size, /* value */ - uint32_t b, + uint64_t b, /* count */ unsigned c) { @@ -2692,6 +3154,9 @@ static int target_fill_mem(struct target *target, for (unsigned i = 0; i < chunk_size; i++) { switch (data_size) { + case 8: + target_buffer_set_u64(target, target_buf + i * data_size, b); + break; case 4: target_buffer_set_u32(target, target_buf + i * data_size, b); break; @@ -2736,15 +3201,15 @@ COMMAND_HANDLER(handle_mw_command) CMD_ARGV++; fn = target_write_phys_memory; } else - fn = target_write_memory_fast; + fn = target_write_memory; if ((CMD_ARGC < 2) || (CMD_ARGC > 3)) return ERROR_COMMAND_SYNTAX_ERROR; - uint32_t address; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); + target_addr_t address; + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); - uint32_t value; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], value); + target_addr_t value; + COMMAND_PARSE_ADDRESS(CMD_ARGV[1], value); unsigned count = 1; if (CMD_ARGC == 3) @@ -2753,6 +3218,9 @@ COMMAND_HANDLER(handle_mw_command) struct target *target = get_current_target(CMD_CTX); unsigned wordsize; switch (CMD_NAME[2]) { + case 'd': + wordsize = 8; + break; case 'w': wordsize = 4; break; @@ -2770,7 +3238,7 @@ COMMAND_HANDLER(handle_mw_command) } static COMMAND_HELPER(parse_load_image_command_CMD_ARGV, struct image *image, - uint32_t *min_address, uint32_t *max_address) + target_addr_t *min_address, target_addr_t *max_address) { if (CMD_ARGC < 1 || CMD_ARGC > 5) return ERROR_COMMAND_SYNTAX_ERROR; @@ -2778,8 +3246,8 @@ static COMMAND_HELPER(parse_load_image_command_CMD_ARGV, struct image *image, /* a base address isn't always necessary, * default to 0x0 (i.e. don't relocate) */ if (CMD_ARGC >= 2) { - uint32_t addr; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], addr); + target_addr_t addr; + COMMAND_PARSE_ADDRESS(CMD_ARGV[1], addr); image->base_address = addr; image->base_address_set = 1; } else @@ -2788,9 +3256,9 @@ static COMMAND_HELPER(parse_load_image_command_CMD_ARGV, struct image *image, image->start_address_set = 0; if (CMD_ARGC >= 4) - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], *min_address); + COMMAND_PARSE_ADDRESS(CMD_ARGV[3], *min_address); if (CMD_ARGC == 5) { - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], *max_address); + COMMAND_PARSE_ADDRESS(CMD_ARGV[4], *max_address); /* use size (given) to find max (required) */ *max_address += *min_address; } @@ -2806,8 +3274,8 @@ COMMAND_HANDLER(handle_load_image_command) uint8_t *buffer; size_t buf_cnt; uint32_t image_size; - uint32_t min_address = 0; - uint32_t max_address = 0xffffffff; + target_addr_t min_address = 0; + target_addr_t max_address = -1; int i; struct image image; @@ -2822,7 +3290,7 @@ COMMAND_HANDLER(handle_load_image_command) duration_start(&bench); if (image_open(&image, CMD_ARGV[0], (CMD_ARGC >= 3) ? CMD_ARGV[2] : NULL) != ERROR_OK) - return ERROR_OK; + return ERROR_FAIL; image_size = 0x0; retval = ERROR_OK; @@ -2832,6 +3300,7 @@ COMMAND_HANDLER(handle_load_image_command) command_print(CMD_CTX, "error allocating buffer for section (%d bytes)", (int)(image.sections[i].size)); + retval = ERROR_FAIL; break; } @@ -2865,7 +3334,7 @@ COMMAND_HANDLER(handle_load_image_command) break; } image_size += length; - command_print(CMD_CTX, "%u bytes written at address 0x%8.8" PRIx32 "", + command_print(CMD_CTX, "%u bytes written at address " TARGET_ADDR_FMT "", (unsigned int)length, image.sections[i].base_address + offset); } @@ -2887,18 +3356,18 @@ COMMAND_HANDLER(handle_load_image_command) COMMAND_HANDLER(handle_dump_image_command) { - struct fileio fileio; + struct fileio *fileio; uint8_t *buffer; int retval, retvaltemp; - uint32_t address, size; + target_addr_t address, size; struct duration bench; struct target *target = get_current_target(CMD_CTX); if (CMD_ARGC != 3) return ERROR_COMMAND_SYNTAX_ERROR; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], address); - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], size); + COMMAND_PARSE_ADDRESS(CMD_ARGV[1], address); + COMMAND_PARSE_ADDRESS(CMD_ARGV[2], size); uint32_t buf_size = (size > 4096) ? 4096 : size; buffer = malloc(buf_size); @@ -2920,7 +3389,7 @@ COMMAND_HANDLER(handle_dump_image_command) if (retval != ERROR_OK) break; - retval = fileio_write(&fileio, this_run_size, buffer, &size_written); + retval = fileio_write(fileio, this_run_size, buffer, &size_written); if (retval != ERROR_OK) break; @@ -2931,23 +3400,29 @@ COMMAND_HANDLER(handle_dump_image_command) free(buffer); if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { - int filesize; - retval = fileio_size(&fileio, &filesize); + size_t filesize; + retval = fileio_size(fileio, &filesize); if (retval != ERROR_OK) return retval; command_print(CMD_CTX, - "dumped %ld bytes in %fs (%0.3f KiB/s)", (long)filesize, + "dumped %zu bytes in %fs (%0.3f KiB/s)", filesize, duration_elapsed(&bench), duration_kbps(&bench, filesize)); } - retvaltemp = fileio_close(&fileio); + retvaltemp = fileio_close(fileio); if (retvaltemp != ERROR_OK) return retvaltemp; return retval; } -static COMMAND_HELPER(handle_verify_image_command_internal, int verify) +enum verify_mode { + IMAGE_TEST = 0, + IMAGE_VERIFY = 1, + IMAGE_CHECKSUM_ONLY = 2 +}; + +static COMMAND_HELPER(handle_verify_image_command_internal, enum verify_mode verify) { uint8_t *buffer; size_t buf_cnt; @@ -2973,8 +3448,8 @@ static COMMAND_HELPER(handle_verify_image_command_internal, int verify) duration_start(&bench); if (CMD_ARGC >= 2) { - uint32_t addr; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], addr); + target_addr_t addr; + COMMAND_PARSE_ADDRESS(CMD_ARGV[1], addr); image.base_address = addr; image.base_address_set = 1; } else { @@ -3005,7 +3480,7 @@ static COMMAND_HELPER(handle_verify_image_command_internal, int verify) break; } - if (verify) { + if (verify >= IMAGE_VERIFY) { /* calculate checksum of image */ retval = image_calculate_checksum(buffer, buf_cnt, &checksum); if (retval != ERROR_OK) { @@ -3018,7 +3493,12 @@ static COMMAND_HELPER(handle_verify_image_command_internal, int verify) free(buffer); break; } - + if ((checksum != mem_checksum) && (verify == IMAGE_CHECKSUM_ONLY)) { + LOG_ERROR("checksum mismatch"); + free(buffer); + retval = ERROR_FAIL; + goto done; + } if (checksum != mem_checksum) { /* failed crc checksum, fall back to a binary compare */ uint8_t *data; @@ -3026,7 +3506,7 @@ static COMMAND_HELPER(handle_verify_image_command_internal, int verify) if (diffs == 0) LOG_ERROR("checksum mismatch - attempting binary compare"); - data = (uint8_t *)malloc(buf_cnt); + data = malloc(buf_cnt); /* Can we use 32bit word accesses? */ int size = 1; @@ -3059,7 +3539,7 @@ static COMMAND_HELPER(handle_verify_image_command_internal, int verify) free(data); } } else { - command_print(CMD_CTX, "address 0x%08" PRIx32 " length 0x%08zx", + command_print(CMD_CTX, "address " TARGET_ADDR_FMT " length 0x%08zx", image.sections[i].base_address, buf_cnt); } @@ -3083,14 +3563,19 @@ done: return retval; } +COMMAND_HANDLER(handle_verify_image_checksum_command) +{ + return CALL_COMMAND_HANDLER(handle_verify_image_command_internal, IMAGE_CHECKSUM_ONLY); +} + COMMAND_HANDLER(handle_verify_image_command) { - return CALL_COMMAND_HANDLER(handle_verify_image_command_internal, 1); + return CALL_COMMAND_HANDLER(handle_verify_image_command_internal, IMAGE_VERIFY); } COMMAND_HANDLER(handle_test_image_command) { - return CALL_COMMAND_HANDLER(handle_verify_image_command_internal, 0); + return CALL_COMMAND_HANDLER(handle_verify_image_command_internal, IMAGE_TEST); } static int handle_bp_command_list(struct command_context *cmd_ctx) @@ -3101,7 +3586,7 @@ static int handle_bp_command_list(struct command_context *cmd_ctx) if (breakpoint->type == BKPT_SOFT) { char *buf = buf_to_str(breakpoint->orig_instr, breakpoint->length, 16); - command_print(cmd_ctx, "IVA breakpoint: 0x%8.8" PRIx32 ", 0x%x, %i, 0x%s", + command_print(cmd_ctx, "IVA breakpoint: " TARGET_ADDR_FMT ", 0x%x, %i, 0x%s", breakpoint->address, breakpoint->length, breakpoint->set, buf); @@ -3112,13 +3597,13 @@ static int handle_bp_command_list(struct command_context *cmd_ctx) breakpoint->asid, breakpoint->length, breakpoint->set); else if ((breakpoint->address != 0) && (breakpoint->asid != 0)) { - command_print(cmd_ctx, "Hybrid breakpoint(IVA): 0x%8.8" PRIx32 ", 0x%x, %i", + command_print(cmd_ctx, "Hybrid breakpoint(IVA): " TARGET_ADDR_FMT ", 0x%x, %i", breakpoint->address, breakpoint->length, breakpoint->set); command_print(cmd_ctx, "\t|--->linked with ContextID: 0x%8.8" PRIx32, breakpoint->asid); } else - command_print(cmd_ctx, "Breakpoint(IVA): 0x%8.8" PRIx32 ", 0x%x, %i", + command_print(cmd_ctx, "Breakpoint(IVA): " TARGET_ADDR_FMT ", 0x%x, %i", breakpoint->address, breakpoint->length, breakpoint->set); } @@ -3129,20 +3614,25 @@ static int handle_bp_command_list(struct command_context *cmd_ctx) } static int handle_bp_command_set(struct command_context *cmd_ctx, - uint32_t addr, uint32_t asid, uint32_t length, int hw) + target_addr_t addr, uint32_t asid, uint32_t length, int hw) { struct target *target = get_current_target(cmd_ctx); + int retval; if (asid == 0) { - int retval = breakpoint_add(target, addr, length, hw); + retval = breakpoint_add(target, addr, length, hw); if (ERROR_OK == retval) - command_print(cmd_ctx, "breakpoint set at 0x%8.8" PRIx32 "", addr); + command_print(cmd_ctx, "breakpoint set at " TARGET_ADDR_FMT "", addr); else { LOG_ERROR("Failure setting breakpoint, the same address(IVA) is already used"); return retval; } } else if (addr == 0) { - int retval = context_breakpoint_add(target, asid, length, hw); + if (target->type->add_context_breakpoint == NULL) { + LOG_WARNING("Context breakpoint not available"); + return ERROR_OK; + } + retval = context_breakpoint_add(target, asid, length, hw); if (ERROR_OK == retval) command_print(cmd_ctx, "Context breakpoint set at 0x%8.8" PRIx32 "", asid); else { @@ -3150,7 +3640,11 @@ static int handle_bp_command_set(struct command_context *cmd_ctx, return retval; } } else { - int retval = hybrid_breakpoint_add(target, addr, asid, length, hw); + if (target->type->add_hybrid_breakpoint == NULL) { + LOG_WARNING("Hybrid breakpoint not available"); + return ERROR_OK; + } + retval = hybrid_breakpoint_add(target, addr, asid, length, hw); if (ERROR_OK == retval) command_print(cmd_ctx, "Hybrid breakpoint set at 0x%8.8" PRIx32 "", asid); else { @@ -3163,7 +3657,7 @@ static int handle_bp_command_set(struct command_context *cmd_ctx, COMMAND_HANDLER(handle_bp_command) { - uint32_t addr; + target_addr_t addr; uint32_t asid; uint32_t length; int hw = BKPT_SOFT; @@ -3174,17 +3668,15 @@ COMMAND_HANDLER(handle_bp_command) case 2: asid = 0; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); return handle_bp_command_set(CMD_CTX, addr, asid, length, hw); case 3: if (strcmp(CMD_ARGV[2], "hw") == 0) { hw = BKPT_HARD; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); - + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); - asid = 0; return handle_bp_command_set(CMD_CTX, addr, asid, length, hw); } else if (strcmp(CMD_ARGV[2], "hw_ctx") == 0) { @@ -3194,10 +3686,10 @@ COMMAND_HANDLER(handle_bp_command) addr = 0; return handle_bp_command_set(CMD_CTX, addr, asid, length, hw); } - + /* fallthrough */ case 4: hw = BKPT_HARD; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], asid); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], length); return handle_bp_command_set(CMD_CTX, addr, asid, length, hw); @@ -3212,8 +3704,8 @@ COMMAND_HANDLER(handle_rbp_command) if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - uint32_t addr; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); + target_addr_t addr; + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr); struct target *target = get_current_target(CMD_CTX); breakpoint_remove(target, addr); @@ -3229,7 +3721,7 @@ COMMAND_HANDLER(handle_wp_command) struct watchpoint *watchpoint = target->watchpoints; while (watchpoint) { - command_print(CMD_CTX, "address: 0x%8.8" PRIx32 + command_print(CMD_CTX, "address: " TARGET_ADDR_FMT ", len: 0x%8.8" PRIx32 ", r/w/a: %i, value: 0x%8.8" PRIx32 ", mask: 0x%8.8" PRIx32, @@ -3314,14 +3806,14 @@ COMMAND_HANDLER(handle_virt2phys_command) if (CMD_ARGC != 1) return ERROR_COMMAND_SYNTAX_ERROR; - uint32_t va; - COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], va); - uint32_t pa; + target_addr_t va; + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], va); + target_addr_t pa; struct target *target = get_current_target(CMD_CTX); int retval = target->type->virt2phys(target, va, &pa); if (retval == ERROR_OK) - command_print(CMD_CTX, "Physical address 0x%08" PRIx32 "", pa); + command_print(CMD_CTX, "Physical address " TARGET_ADDR_FMT "", pa); return retval; } @@ -3333,14 +3825,12 @@ static void writeData(FILE *f, const void *data, size_t len) LOG_ERROR("failed to write %zu bytes: %s", len, strerror(errno)); } -static void writeLong(FILE *f, int l) +static void writeLong(FILE *f, int l, struct target *target) { - int i; - for (i = 0; i < 4; i++) { - char c = (l >> (i*8))&0xff; - writeData(f, &c, 1); - } + uint8_t val[4]; + target_buffer_set_u32(target, val, l); + writeData(f, val, 4); } static void writeString(FILE *f, char *s) @@ -3348,59 +3838,79 @@ static void writeString(FILE *f, char *s) writeData(f, s, strlen(s)); } +typedef unsigned char UNIT[2]; /* unit of profiling */ + /* Dump a gmon.out histogram file. */ -static void writeGmon(uint32_t *samples, uint32_t sampleNum, const char *filename) +static void write_gmon(uint32_t *samples, uint32_t sampleNum, const char *filename, bool with_range, + uint32_t start_address, uint32_t end_address, struct target *target) { uint32_t i; FILE *f = fopen(filename, "w"); if (f == NULL) return; writeString(f, "gmon"); - writeLong(f, 0x00000001); /* Version */ - writeLong(f, 0); /* padding */ - writeLong(f, 0); /* padding */ - writeLong(f, 0); /* padding */ + writeLong(f, 0x00000001, target); /* Version */ + writeLong(f, 0, target); /* padding */ + writeLong(f, 0, target); /* padding */ + writeLong(f, 0, target); /* padding */ uint8_t zero = 0; /* GMON_TAG_TIME_HIST */ writeData(f, &zero, 1); /* figure out bucket size */ - uint32_t min = samples[0]; - uint32_t max = samples[0]; - for (i = 0; i < sampleNum; i++) { - if (min > samples[i]) - min = samples[i]; - if (max < samples[i]) - max = samples[i]; + uint32_t min; + uint32_t max; + if (with_range) { + min = start_address; + max = end_address; + } else { + min = samples[0]; + max = samples[0]; + for (i = 0; i < sampleNum; i++) { + if (min > samples[i]) + min = samples[i]; + if (max < samples[i]) + max = samples[i]; + } + + /* max should be (largest sample + 1) + * Refer to binutils/gprof/hist.c (find_histogram_for_pc) */ + max++; } - int addressSpace = (max - min + 1); + int addressSpace = max - min; assert(addressSpace >= 2); - static const uint32_t maxBuckets = 16 * 1024; /* maximum buckets. */ - uint32_t length = addressSpace; - if (length > maxBuckets) - length = maxBuckets; - int *buckets = malloc(sizeof(int)*length); + /* FIXME: What is the reasonable number of buckets? + * The profiling result will be more accurate if there are enough buckets. */ + static const uint32_t maxBuckets = 128 * 1024; /* maximum buckets. */ + uint32_t numBuckets = addressSpace / sizeof(UNIT); + if (numBuckets > maxBuckets) + numBuckets = maxBuckets; + int *buckets = malloc(sizeof(int) * numBuckets); if (buckets == NULL) { fclose(f); return; } - memset(buckets, 0, sizeof(int) * length); + memset(buckets, 0, sizeof(int) * numBuckets); for (i = 0; i < sampleNum; i++) { uint32_t address = samples[i]; + + if ((address < min) || (max <= address)) + continue; + long long a = address - min; - long long b = length - 1; - long long c = addressSpace - 1; + long long b = numBuckets; + long long c = addressSpace; int index_t = (a * b) / c; /* danger!!!! int32 overflows */ buckets[index_t]++; } /* append binary memory gmon.out &profile_hist_hdr ((char*)&profile_hist_hdr + sizeof(struct gmon_hist_hdr)) */ - writeLong(f, min); /* low_pc */ - writeLong(f, max); /* high_pc */ - writeLong(f, length); /* # of samples */ - writeLong(f, 100); /* KLUDGE! We lie, ca. 100Hz best case. */ + writeLong(f, min, target); /* low_pc */ + writeLong(f, max, target); /* high_pc */ + writeLong(f, numBuckets, target); /* # of buckets */ + writeLong(f, 100, target); /* KLUDGE! We lie, ca. 100Hz best case. */ writeString(f, "seconds"); for (i = 0; i < (15-strlen("seconds")); i++) writeData(f, &zero, 1); @@ -3408,9 +3918,9 @@ static void writeGmon(uint32_t *samples, uint32_t sampleNum, const char *filenam /*append binary memory gmon.out profile_hist_data (profile_hist_data + profile_hist_hdr.hist_size) */ - char *data = malloc(2 * length); + char *data = malloc(2 * numBuckets); if (data != NULL) { - for (i = 0; i < length; i++) { + for (i = 0; i < numBuckets; i++) { int val; val = buckets[i]; if (val > 65535) @@ -3419,7 +3929,7 @@ static void writeGmon(uint32_t *samples, uint32_t sampleNum, const char *filenam data[i * 2 + 1] = (val >> 8) & 0xff; } free(buckets); - writeData(f, data, length * 2); + writeData(f, data, numBuckets * 2); free(data); } else free(buckets); @@ -3432,84 +3942,70 @@ static void writeGmon(uint32_t *samples, uint32_t sampleNum, const char *filenam COMMAND_HANDLER(handle_profile_command) { struct target *target = get_current_target(CMD_CTX); - struct timeval timeout, now; - gettimeofday(&timeout, NULL); - if (CMD_ARGC != 2) + if ((CMD_ARGC != 2) && (CMD_ARGC != 4)) return ERROR_COMMAND_SYNTAX_ERROR; - unsigned offset; - COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], offset); - timeval_add_time(&timeout, offset, 0); + const uint32_t MAX_PROFILE_SAMPLE_NUM = 10000; + uint32_t offset; + uint32_t num_of_samples; + int retval = ERROR_OK; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], offset); + + uint32_t *samples = malloc(sizeof(uint32_t) * MAX_PROFILE_SAMPLE_NUM); + if (samples == NULL) { + LOG_ERROR("No memory to store samples."); + return ERROR_FAIL; + } /** - * @todo: Some cores let us sample the PC without the + * Some cores let us sample the PC without the * annoying halt/resume step; for example, ARMv7 PCSR. * Provide a way to use that more efficient mechanism. */ + retval = target_profiling(target, samples, MAX_PROFILE_SAMPLE_NUM, + &num_of_samples, offset); + if (retval != ERROR_OK) { + free(samples); + return retval; + } - command_print(CMD_CTX, "Starting profiling. Halting and resuming the target as often as we can..."); + assert(num_of_samples <= MAX_PROFILE_SAMPLE_NUM); + + retval = target_poll(target); + if (retval != ERROR_OK) { + free(samples); + return retval; + } + if (target->state == TARGET_RUNNING) { + retval = target_halt(target); + if (retval != ERROR_OK) { + free(samples); + return retval; + } + } - static const int maxSample = 10000; - uint32_t *samples = malloc(sizeof(uint32_t)*maxSample); - if (samples == NULL) - return ERROR_OK; + retval = target_poll(target); + if (retval != ERROR_OK) { + free(samples); + return retval; + } - int numSamples = 0; - /* hopefully it is safe to cache! We want to stop/restart as quickly as possible. */ - struct reg *reg = register_get_by_name(target->reg_cache, "pc", 1); + uint32_t start_address = 0; + uint32_t end_address = 0; + bool with_range = false; + if (CMD_ARGC == 4) { + with_range = true; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], start_address); + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], end_address); + } - int retval = ERROR_OK; - for (;;) { - target_poll(target); - if (target->state == TARGET_HALTED) { - uint32_t t = *((uint32_t *)reg->value); - samples[numSamples++] = t; - /* current pc, addr = 0, do not handle breakpoints, not debugging */ - retval = target_resume(target, 1, 0, 0, 0); - target_poll(target); - alive_sleep(10); /* sleep 10ms, i.e. <100 samples/second. */ - } else if (target->state == TARGET_RUNNING) { - /* We want to quickly sample the PC. */ - retval = target_halt(target); - if (retval != ERROR_OK) { - free(samples); - return retval; - } - } else { - command_print(CMD_CTX, "Target not halted or running"); - retval = ERROR_OK; - break; - } - if (retval != ERROR_OK) - break; + write_gmon(samples, num_of_samples, CMD_ARGV[1], + with_range, start_address, end_address, target); + command_print(CMD_CTX, "Wrote %s", CMD_ARGV[1]); - gettimeofday(&now, NULL); - if ((numSamples >= maxSample) || ((now.tv_sec >= timeout.tv_sec) - && (now.tv_usec >= timeout.tv_usec))) { - command_print(CMD_CTX, "Profiling completed. %d samples.", numSamples); - retval = target_poll(target); - if (retval != ERROR_OK) { - free(samples); - return retval; - } - if (target->state == TARGET_HALTED) { - /* current pc, addr = 0, do not handle - * breakpoints, not debugging */ - target_resume(target, 1, 0, 0, 0); - } - retval = target_poll(target); - if (retval != ERROR_OK) { - free(samples); - return retval; - } - writeGmon(samples, numSamples, CMD_ARGV[1]); - command_print(CMD_CTX, "Wrote %s", CMD_ARGV[1]); - break; - } - } free(samples); - return retval; } @@ -3566,6 +4062,8 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, uint32_t count; uint32_t v; const char *varname; + const char *phys; + bool is_phys; int n, e, retval; uint32_t i; @@ -3574,8 +4072,8 @@ 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) { - Jim_WrongNumArgs(interp, 1, argv, "varname width addr nelems"); + if (argc < 4 || argc > 5) { + Jim_WrongNumArgs(interp, 1, argv, "varname width addr nelems [phys]"); return JIM_ERR; } varname = Jim_GetString(argv[0], &len); @@ -3594,6 +4092,14 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, len = l; if (e != JIM_OK) return e; + is_phys = false; + if (argc > 4) { + phys = Jim_GetString(argv[4], &n); + if (!strncmp(phys, "phys", n)) + is_phys = true; + else + return JIM_ERR; + } switch (width) { case 8: width = 1; @@ -3636,7 +4142,7 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, sprintf(buf, "mem2array address: 0x%08" PRIx32 " is not aligned for %" PRId32 " byte reads", addr, width); - Jim_AppendStrings(interp, Jim_GetResult(interp), buf , NULL); + Jim_AppendStrings(interp, Jim_GetResult(interp), buf, NULL); return JIM_ERR; } @@ -3659,13 +4165,16 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, if (count > (buffersize / width)) count = (buffersize / width); - retval = target_read_memory(target, addr, width, count, buffer); + if (is_phys) + retval = target_read_phys_memory(target, addr, width, count, buffer); + else + retval = target_read_memory(target, addr, width, count, buffer); if (retval != ERROR_OK) { /* BOO !*/ - LOG_ERROR("mem2array: Read @ 0x%08x, w=%d, cnt=%d, failed", - (unsigned int)addr, - (int)width, - (int)count); + LOG_ERROR("mem2array: Read @ 0x%08" PRIx32 ", w=%" PRId32 ", cnt=%" PRId32 ", failed", + addr, + width, + count); Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: cannot read memory", NULL); e = JIM_ERR; @@ -3687,6 +4196,7 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, new_int_array_element(interp, varname, n, v); } len -= count; + addr += count * width; } } @@ -3754,6 +4264,8 @@ static int target_array2mem(Jim_Interp *interp, struct target *target, uint32_t count; uint32_t v; const char *varname; + const char *phys; + bool is_phys; int n, e, retval; uint32_t i; @@ -3762,8 +4274,8 @@ static int target_array2mem(Jim_Interp *interp, struct target *target, * argv[3] = memory address * argv[4] = count to write */ - if (argc != 4) { - Jim_WrongNumArgs(interp, 0, argv, "varname width addr nelems"); + if (argc < 4 || argc > 5) { + Jim_WrongNumArgs(interp, 0, argv, "varname width addr nelems [phys]"); return JIM_ERR; } varname = Jim_GetString(argv[0], &len); @@ -3782,6 +4294,14 @@ static int target_array2mem(Jim_Interp *interp, struct target *target, len = l; if (e != JIM_OK) return e; + is_phys = false; + if (argc > 4) { + phys = Jim_GetString(argv[4], &n); + if (!strncmp(phys, "phys", n)) + is_phys = true; + else + return JIM_ERR; + } switch (width) { case 8: width = 1; @@ -3825,10 +4345,10 @@ static int target_array2mem(Jim_Interp *interp, struct target *target, } else { char buf[100]; Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - sprintf(buf, "array2mem address: 0x%08x is not aligned for %d byte reads", - (unsigned int)addr, - (int)width); - Jim_AppendStrings(interp, Jim_GetResult(interp), buf , NULL); + sprintf(buf, "array2mem address: 0x%08" PRIx32 " is not aligned for %" PRId32 " byte reads", + addr, + width); + Jim_AppendStrings(interp, Jim_GetResult(interp), buf, NULL); return JIM_ERR; } @@ -3868,18 +4388,22 @@ static int target_array2mem(Jim_Interp *interp, struct target *target, } len -= count; - retval = target_write_memory(target, addr, width, count, buffer); + if (is_phys) + retval = target_write_phys_memory(target, addr, width, count, buffer); + else + retval = target_write_memory(target, addr, width, count, buffer); if (retval != ERROR_OK) { /* BOO !*/ - LOG_ERROR("array2mem: Write @ 0x%08x, w=%d, cnt=%d, failed", - (unsigned int)addr, - (int)width, - (int)count); + LOG_ERROR("array2mem: Write @ 0x%08" PRIx32 ", w=%" PRId32 ", cnt=%" PRId32 ", failed", + addr, + width, + count); Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: cannot read memory", NULL); e = JIM_ERR; break; } + addr += count * width; } free(buffer); @@ -3935,11 +4459,12 @@ enum target_cfg_param { TCFG_WORK_AREA_SIZE, TCFG_WORK_AREA_BACKUP, TCFG_ENDIAN, - TCFG_VARIANT, TCFG_COREID, TCFG_CHAIN_POSITION, TCFG_DBGBASE, + TCFG_CTIBASE, TCFG_RTOS, + TCFG_DEFER_EXAMINE, }; static Jim_Nvp nvp_config_opts[] = { @@ -3950,11 +4475,12 @@ static Jim_Nvp nvp_config_opts[] = { { .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 = "-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 = NULL, .value = -1 } }; @@ -3963,7 +4489,6 @@ static int target_configure(Jim_GetOptInfo *goi, struct target *target) Jim_Nvp *n; Jim_Obj *o; jim_wide w; - char *cp; int e; /* parse config or cget options ... */ @@ -4172,28 +4697,6 @@ no_params: /* loop for more */ break; - case TCFG_VARIANT: - if (goi->isconfigure) { - if (goi->argc < 1) { - Jim_SetResultFormatted(goi->interp, - "%s ?STRING?", - n->name); - return JIM_ERR; - } - if (target->variant) - free((void *)(target->variant)); - e = Jim_GetOpt_String(goi, &cp, NULL); - if (e != JIM_OK) - return e; - 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_COREID: if (goi->isconfigure) { e = Jim_GetOpt_Wide(goi, &w); @@ -4242,7 +4745,20 @@ 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 */ { @@ -4252,6 +4768,13 @@ no_params: } /* loop for more */ break; + + case TCFG_DEFER_EXAMINE: + /* DEFER_EXAMINE */ + target->defer_examine = true; + /* loop for more */ + break; + } } /* while (goi->argc) */ @@ -4266,12 +4789,9 @@ static int jim_target_configure(Jim_Interp *interp, int argc, Jim_Obj * const *a Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); goi.isconfigure = !strcmp(Jim_GetString(argv[0], NULL), "configure"); - int need_args = 1 + goi.isconfigure; - if (goi.argc < need_args) { + if (goi.argc < 1) { Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, - goi.isconfigure - ? "missing: -option VALUE ..." - : "missing: -option ..."); + "missing: -option ..."); return JIM_ERR; } struct target *target = Jim_CmdPrivData(goi.interp); @@ -4292,7 +4812,7 @@ static int jim_target_mw(Jim_Interp *interp, int argc, Jim_Obj *const *argv) } target_write_fn fn; - fn = target_write_memory_fast; + fn = target_write_memory; int e; if (strcmp(Jim_GetString(argv[1], NULL), "phys") == 0) { @@ -4384,7 +4904,7 @@ static int jim_target_md(Jim_Interp *interp, int argc, Jim_Obj *const *argv) } int (*fn)(struct target *target, - uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer); + target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer); fn = target_read_memory; int e; @@ -4522,20 +5042,58 @@ static int jim_target_tap_disabled(Jim_Interp *interp) static int jim_target_examine(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - if (argc != 1) { - Jim_WrongNumArgs(interp, 1, argv, "[no parameters]"); + bool allow_defer = false; + + Jim_GetOptInfo goi; + Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); + if (goi.argc > 1) { + const char *cmd_name = Jim_GetString(argv[0], NULL); + Jim_SetResultFormatted(goi.interp, + "usage: %s ['allow-defer']", cmd_name); return JIM_ERR; } + if (goi.argc > 0 && + strcmp(Jim_GetString(argv[1], NULL), "allow-defer") == 0) { + /* consume it */ + struct Jim_Obj *obj; + int e = Jim_GetOpt_Obj(&goi, &obj); + if (e != JIM_OK) + return e; + allow_defer = true; + } + struct target *target = Jim_CmdPrivData(interp); if (!target->tap->enabled) return jim_target_tap_disabled(interp); + if (allow_defer && target->defer_examine) { + LOG_INFO("Deferring arp_examine of %s", target_name(target)); + LOG_INFO("Use arp_examine command to examine it manually!"); + return JIM_OK; + } + int e = target->type->examine(target); if (e != ERROR_OK) return JIM_ERR; return JIM_OK; } +static int jim_target_was_examined(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +{ + struct target *target = Jim_CmdPrivData(interp); + + Jim_SetResultBool(interp, target_was_examined(target)); + return JIM_OK; +} + +static int jim_target_examine_deferred(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +{ + struct target *target = Jim_CmdPrivData(interp); + + Jim_SetResultBool(interp, target->defer_examine); + return JIM_OK; +} + static int jim_target_halt_gdb(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { if (argc != 1) { @@ -4596,16 +5154,17 @@ static int jim_target_reset(Jim_Interp *interp, int argc, Jim_Obj *const *argv) struct target *target = Jim_CmdPrivData(goi.interp); if (!target->tap->enabled) return jim_target_tap_disabled(interp); - if (!(target_was_examined(target))) { - LOG_ERROR("Target not examined yet"); - return ERROR_TARGET_NOT_EXAMINED; - } + if (!target->type->assert_reset || !target->type->deassert_reset) { Jim_SetResultFormatted(interp, "No target-specific reset for %s", target_name(target)); return JIM_ERR; } + + if (target->defer_examine) + target_reset_examined(target); + /* determine if we should halt or not. */ target->reset_halt = !!a; /* When this happens - all workareas are invalid. */ @@ -4816,6 +5375,21 @@ 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']", + }, + { + .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", @@ -4862,7 +5436,6 @@ static int target_create(Jim_GetOptInfo *goi) Jim_Obj *new_cmd; Jim_Cmd *cmd; const char *cp; - char *cp2; int e; int x; struct target *target; @@ -4887,10 +5460,18 @@ static int target_create(Jim_GetOptInfo *goi) } /* TYPE */ - e = Jim_GetOpt_String(goi, &cp2, NULL); + e = Jim_GetOpt_String(goi, &cp, NULL); if (e != JIM_OK) return e; - cp = cp2; + struct transport *tr = get_current_transport(); + if (tr->override_target) { + e = tr->override_target(&cp); + if (e != ERROR_OK) { + LOG_ERROR("The selected transport doesn't support this target"); + return JIM_ERR; + } + LOG_INFO("The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD"); + } /* now does target type exist */ for (x = 0 ; target_types[x] ; x++) { if (0 == strcmp(cp, target_types[x]->name)) { @@ -4929,9 +5510,10 @@ static int target_create(Jim_GetOptInfo *goi) target = calloc(1, sizeof(struct target)); /* set target number */ target->target_number = new_target_number(); + cmd_ctx->current_target = target->target_number; /* allocate memory for each unique target type */ - target->type = (struct target_type *)calloc(1, sizeof(struct target_type)); + target->type = calloc(1, sizeof(struct target_type)); memcpy(target->type, target_types[x], sizeof(struct target_type)); @@ -4959,14 +5541,7 @@ static int target_create(Jim_GetOptInfo *goi) target->halt_issued = false; /* initialize trace information */ - target->trace_info = malloc(sizeof(struct trace)); - 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->trace_info = calloc(1, sizeof(struct trace)); target->dbgmsg = NULL; target->dbg_msg_enabled = 0; @@ -4996,10 +5571,6 @@ static int target_create(Jim_GetOptInfo *goi) target->endianness = TARGET_LITTLE_ENDIAN; } - /* incase variant is not set */ - if (!target->variant) - target->variant = strdup(""); - cp = Jim_GetString(new_cmd, NULL); target->cmd_name = strdup(cp); @@ -5022,7 +5593,7 @@ static int target_create(Jim_GetOptInfo *goi) } /* now - create the new target name command */ - const const struct command_registration target_subcommands[] = { + const struct command_registration target_subcommands[] = { { .chain = target_instance_command_handlers, }, @@ -5031,7 +5602,7 @@ static int target_create(Jim_GetOptInfo *goi) }, COMMAND_REGISTRATION_DONE }; - const const struct command_registration target_commands[] = { + const struct command_registration target_commands[] = { { .name = cp, .mode = COMMAND_ANY, @@ -5159,55 +5730,6 @@ static int jim_target_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return target_create(&goi); } -static int jim_target_number(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - Jim_GetOptInfo goi; - Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); - - /* It's OK to remove this mechanism sometime after August 2010 or so */ - LOG_WARNING("don't use numbers as target identifiers; use names"); - if (goi.argc != 1) { - Jim_SetResultFormatted(goi.interp, "usage: target number "); - return JIM_ERR; - } - jim_wide w; - int e = Jim_GetOpt_Wide(&goi, &w); - if (e != JIM_OK) - return JIM_ERR; - - struct target *target; - for (target = all_targets; NULL != target; target = target->next) { - if (target->target_number != w) - continue; - - Jim_SetResultString(goi.interp, target_name(target), -1); - return JIM_OK; - } - { - Jim_Obj *wObj = Jim_NewIntObj(goi.interp, w); - Jim_SetResultFormatted(goi.interp, - "Target: number %#s does not exist", wObj); - Jim_FreeNewObj(interp, wObj); - } - return JIM_ERR; -} - -static int jim_target_count(Jim_Interp *interp, int argc, Jim_Obj *const *argv) -{ - if (argc != 1) { - Jim_WrongNumArgs(interp, 1, argv, ""); - return JIM_ERR; - } - unsigned count = 0; - struct target *target = all_targets; - while (NULL != target) { - target = target->next; - count++; - } - Jim_SetResult(interp, Jim_NewIntObj(interp, count)); - return JIM_OK; -} - static const struct command_registration target_subcommand_handlers[] = { { .name = "init", @@ -5242,21 +5764,6 @@ static const struct command_registration target_subcommand_handlers[] = { .jim_handler = jim_target_names, .help = "Returns the names of all targets as a list of strings", }, - { - .name = "number", - .mode = COMMAND_ANY, - .jim_handler = jim_target_number, - .usage = "number", - .help = "Returns the name of the numbered target " - "(DEPRECATED)", - }, - { - .name = "count", - .mode = COMMAND_ANY, - .jim_handler = jim_target_count, - .help = "Returns the number of targets as an integer " - "(DEPRECATED)", - }, { .name = "smp", .mode = COMMAND_ANY, @@ -5269,7 +5776,7 @@ static const struct command_registration target_subcommand_handlers[] = { }; struct FastLoad { - uint32_t address; + target_addr_t address; uint8_t *data; int length; @@ -5296,8 +5803,8 @@ COMMAND_HANDLER(handle_fast_load_image_command) uint8_t *buffer; size_t buf_cnt; uint32_t image_size; - uint32_t min_address = 0; - uint32_t max_address = 0xffffffff; + target_addr_t min_address = 0; + target_addr_t max_address = -1; int i; struct image image; @@ -5317,7 +5824,7 @@ COMMAND_HANDLER(handle_fast_load_image_command) image_size = 0x0; retval = ERROR_OK; fastload_num = image.num_sections; - fastload = (struct FastLoad *)malloc(sizeof(struct FastLoad)*image.num_sections); + fastload = malloc(sizeof(struct FastLoad)*image.num_sections); if (fastload == NULL) { command_print(CMD_CTX, "out of memory"); image_close(&image); @@ -5359,7 +5866,7 @@ COMMAND_HANDLER(handle_fast_load_image_command) fastload[i].data = malloc(length); if (fastload[i].data == NULL) { free(buffer); - command_print(CMD_CTX, "error allocating buffer for section (%d bytes)", + command_print(CMD_CTX, "error allocating buffer for section (%" PRIu32 " bytes)", length); retval = ERROR_FAIL; break; @@ -5403,7 +5910,7 @@ COMMAND_HANDLER(handle_fast_load_command) return ERROR_FAIL; } int i; - int ms = timeval_ms(); + int64_t ms = timeval_ms(); int size = 0; int retval = ERROR_OK; for (i = 0; i < fastload_num; i++) { @@ -5417,7 +5924,7 @@ COMMAND_HANDLER(handle_fast_load_command) size += fastload[i].length; } if (retval == ERROR_OK) { - int after = timeval_ms(); + int64_t after = timeval_ms(); command_print(CMD_CTX, "Loaded image %f kBytes/s", (float)(size/1024.0)/((float)(after-ms)/1000.0)); } return retval; @@ -5482,6 +5989,198 @@ COMMAND_HANDLER(handle_ps_command) } } +static void binprint(struct command_context *cmd_ctx, const char *text, const uint8_t *buf, int size) +{ + if (text != NULL) + command_print_sameline(cmd_ctx, "%s", text); + for (int i = 0; i < size; i++) + command_print_sameline(cmd_ctx, " %02x", buf[i]); + command_print(cmd_ctx, " "); +} + +COMMAND_HANDLER(handle_test_mem_access_command) +{ + struct target *target = get_current_target(CMD_CTX); + uint32_t test_size; + int retval = ERROR_OK; + + if (target->state != TARGET_HALTED) { + LOG_INFO("target not halted !!"); + return ERROR_FAIL; + } + + if (CMD_ARGC != 1) + return ERROR_COMMAND_SYNTAX_ERROR; + + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], test_size); + + /* Test reads */ + size_t num_bytes = test_size + 4; + + struct working_area *wa = NULL; + retval = target_alloc_working_area(target, num_bytes, &wa); + if (retval != ERROR_OK) { + LOG_ERROR("Not enough working area"); + return ERROR_FAIL; + } + + uint8_t *test_pattern = malloc(num_bytes); + + for (size_t i = 0; i < num_bytes; i++) + test_pattern[i] = rand(); + + retval = target_write_memory(target, wa->address, 1, num_bytes, test_pattern); + if (retval != ERROR_OK) { + LOG_ERROR("Test pattern write failed"); + goto out; + } + + for (int host_offset = 0; host_offset <= 1; host_offset++) { + for (int size = 1; size <= 4; size *= 2) { + for (int offset = 0; offset < 4; offset++) { + uint32_t count = test_size / size; + size_t host_bufsiz = (count + 2) * size + host_offset; + uint8_t *read_ref = malloc(host_bufsiz); + uint8_t *read_buf = malloc(host_bufsiz); + + for (size_t i = 0; i < host_bufsiz; i++) { + read_ref[i] = rand(); + read_buf[i] = read_ref[i]; + } + command_print_sameline(CMD_CTX, + "Test read %" PRIu32 " x %d @ %d to %saligned buffer: ", count, + size, offset, host_offset ? "un" : ""); + + struct duration bench; + duration_start(&bench); + + retval = target_read_memory(target, wa->address + offset, size, count, + read_buf + size + host_offset); + + duration_measure(&bench); + + if (retval == ERROR_TARGET_UNALIGNED_ACCESS) { + command_print(CMD_CTX, "Unsupported alignment"); + goto next; + } else if (retval != ERROR_OK) { + command_print(CMD_CTX, "Memory read failed"); + goto next; + } + + /* replay on host */ + memcpy(read_ref + size + host_offset, test_pattern + offset, count * size); + + /* check result */ + int result = memcmp(read_ref, read_buf, host_bufsiz); + if (result == 0) { + command_print(CMD_CTX, "Pass in %fs (%0.3f KiB/s)", + duration_elapsed(&bench), + duration_kbps(&bench, count * size)); + } else { + command_print(CMD_CTX, "Compare failed"); + binprint(CMD_CTX, "ref:", read_ref, host_bufsiz); + binprint(CMD_CTX, "buf:", read_buf, host_bufsiz); + } +next: + free(read_ref); + free(read_buf); + } + } + } + +out: + free(test_pattern); + + if (wa != NULL) + target_free_working_area(target, wa); + + /* Test writes */ + num_bytes = test_size + 4 + 4 + 4; + + retval = target_alloc_working_area(target, num_bytes, &wa); + if (retval != ERROR_OK) { + LOG_ERROR("Not enough working area"); + return ERROR_FAIL; + } + + test_pattern = malloc(num_bytes); + + for (size_t i = 0; i < num_bytes; i++) + test_pattern[i] = rand(); + + for (int host_offset = 0; host_offset <= 1; host_offset++) { + for (int size = 1; size <= 4; size *= 2) { + for (int offset = 0; offset < 4; offset++) { + uint32_t count = test_size / size; + size_t host_bufsiz = count * size + host_offset; + uint8_t *read_ref = malloc(num_bytes); + uint8_t *read_buf = malloc(num_bytes); + uint8_t *write_buf = malloc(host_bufsiz); + + for (size_t i = 0; i < host_bufsiz; i++) + write_buf[i] = rand(); + command_print_sameline(CMD_CTX, + "Test write %" PRIu32 " x %d @ %d from %saligned buffer: ", count, + size, offset, host_offset ? "un" : ""); + + retval = target_write_memory(target, wa->address, 1, num_bytes, test_pattern); + if (retval != ERROR_OK) { + command_print(CMD_CTX, "Test pattern write failed"); + goto nextw; + } + + /* replay on host */ + memcpy(read_ref, test_pattern, num_bytes); + memcpy(read_ref + size + offset, write_buf + host_offset, count * size); + + struct duration bench; + duration_start(&bench); + + retval = target_write_memory(target, wa->address + size + offset, size, count, + write_buf + host_offset); + + duration_measure(&bench); + + if (retval == ERROR_TARGET_UNALIGNED_ACCESS) { + command_print(CMD_CTX, "Unsupported alignment"); + goto nextw; + } else if (retval != ERROR_OK) { + command_print(CMD_CTX, "Memory write failed"); + goto nextw; + } + + /* read back */ + retval = target_read_memory(target, wa->address, 1, num_bytes, read_buf); + if (retval != ERROR_OK) { + command_print(CMD_CTX, "Test pattern write failed"); + goto nextw; + } + + /* check result */ + int result = memcmp(read_ref, read_buf, num_bytes); + if (result == 0) { + command_print(CMD_CTX, "Pass in %fs (%0.3f KiB/s)", + duration_elapsed(&bench), + duration_kbps(&bench, count * size)); + } else { + command_print(CMD_CTX, "Compare failed"); + binprint(CMD_CTX, "ref:", read_ref, num_bytes); + binprint(CMD_CTX, "buf:", read_buf, num_bytes); + } +nextw: + free(read_ref); + free(read_buf); + } + } + } + + free(test_pattern); + + if (wa != NULL) + target_free_working_area(target, wa); + return retval; +} + static const struct command_registration target_exec_command_handlers[] = { { .name = "fast_load_image", @@ -5504,7 +6203,7 @@ static const struct command_registration target_exec_command_handlers[] = { .name = "profile", .handler = handle_profile_command, .mode = COMMAND_EXEC, - .usage = "seconds filename", + .usage = "seconds filename [start end]", .help = "profiling samples the CPU PC", }, /** @todo don't register virt2phys() unless target supports it */ @@ -5519,9 +6218,9 @@ static const struct command_registration target_exec_command_handlers[] = { .name = "reg", .handler = handle_reg_command, .mode = COMMAND_EXEC, - .help = "display or set a register; with no arguments, " - "displays all registers and their values", - .usage = "[(register_name|register_number) [value]]", + .help = "display (reread from target with \"force\") or set a register; " + "with no arguments, displays all registers and their values", + .usage = "[(register_number|register_name) [(value|'force')]]", }, { .name = "poll", @@ -5535,7 +6234,7 @@ static const struct command_registration target_exec_command_handlers[] = { .handler = handle_wait_halt_command, .mode = COMMAND_EXEC, .help = "wait up to the specified number of milliseconds " - "(default 5) for a previously requested halt", + "(default 5000) for a previously requested halt", .usage = "[milliseconds]", }, { @@ -5543,7 +6242,7 @@ static const struct command_registration target_exec_command_handlers[] = { .handler = handle_halt_command, .mode = COMMAND_EXEC, .help = "request target to halt, then wait up to the specified" - "number of milliseconds (default 5) for it to complete", + "number of milliseconds (default 5000) for it to complete", .usage = "[milliseconds]", }, { @@ -5575,6 +6274,13 @@ static const struct command_registration target_exec_command_handlers[] = { .help = "step one instruction from current PC or address", .usage = "[address]", }, + { + .name = "mdd", + .handler = handle_md_command, + .mode = COMMAND_EXEC, + .help = "display memory words", + .usage = "['phys'] address [count]", + }, { .name = "mdw", .handler = handle_md_command, @@ -5596,6 +6302,13 @@ static const struct command_registration target_exec_command_handlers[] = { .help = "display memory bytes", .usage = "['phys'] address [count]", }, + { + .name = "mwd", + .handler = handle_mw_command, + .mode = COMMAND_EXEC, + .help = "write memory word", + .usage = "['phys'] address value [count]", + }, { .name = "mww", .handler = handle_mw_command, @@ -5658,6 +6371,12 @@ static const struct command_registration target_exec_command_handlers[] = { .mode = COMMAND_EXEC, .usage = "filename address size", }, + { + .name = "verify_image_checksum", + .handler = handle_verify_image_checksum_command, + .mode = COMMAND_EXEC, + .usage = "filename [offset [type]]", + }, { .name = "verify_image", .handler = handle_verify_image_command, @@ -5701,6 +6420,13 @@ static const struct command_registration target_exec_command_handlers[] = { .help = "list all tasks ", .usage = " ", }, + { + .name = "test_mem_access", + .handler = handle_test_mem_access_command, + .mode = COMMAND_EXEC, + .help = "Test the target's memory access functions", + .usage = "size", + }, COMMAND_REGISTRATION_DONE };