X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Ftarget%2Ftarget.c;h=6f458bcebe63d378a3cda378a5c1957a84798a4a;hp=6b034665c757540c799706bcc6e1d53d4a441694;hb=2eacb8fdfb4ea761acc3a3fbb51d048fefccd9b6;hpb=033d1053ae42b913ff7100221628c0376e596d71 diff --git a/src/target/target.c b/src/target/target.c index 6b034665c7..6f458bcebe 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -20,6 +20,9 @@ * Copyright (C) ST-Ericsson SA 2011 * * michel.jaouen@stericsson.com : smp minimum support * * * + * Copyright (C) 2011 Andreas Fritiofson * + * andreas.fritiofson@gmail.com * + * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * @@ -33,8 +36,9 @@ * 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. * + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * ***************************************************************************/ + #ifdef HAVE_CONFIG_H #include "config.h" #endif @@ -51,17 +55,26 @@ #include "trace.h" #include "image.h" #include "rtos/rtos.h" +#include "transport/transport.h" +/* default halt wait timeout (ms) */ +#define DEFAULT_HALT_TIMEOUT 5000 static int target_read_buffer_default(struct target *target, uint32_t address, - uint32_t size, uint8_t *buffer); + uint32_t count, uint8_t *buffer); static int target_write_buffer_default(struct target *target, uint32_t address, - uint32_t size, const uint8_t *buffer); + uint32_t count, const uint8_t *buffer); static int target_array2mem(Jim_Interp *interp, struct target *target, - int argc, Jim_Obj *const *argv); + int argc, Jim_Obj * const *argv); static int target_mem2array(Jim_Interp *interp, struct target *target, - int argc, Jim_Obj *const *argv); + 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; @@ -75,8 +88,9 @@ 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 cortexr4_target; extern struct target_type arm11_target; extern struct target_type mips_m4k_target; extern struct target_type avr_target; @@ -84,10 +98,14 @@ extern struct target_type dsp563xx_target; extern struct target_type dsp5680xx_target; extern struct target_type testee_target; extern struct target_type avr32_ap7k_target; -extern struct target_type stm32_stlink_target; - -static struct target_type *target_types[] = -{ +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; + +static struct target_type *target_types[] = { &arm7tdmi_target, &arm9tdmi_target, &arm920t_target, @@ -99,8 +117,9 @@ static struct target_type *target_types[] = &feroceon_target, &dragonite_target, &xscale_target, - &cortexm3_target, - &cortexa8_target, + &cortexm_target, + &cortexa_target, + &cortexr4_target, &arm11_target, &mips_m4k_target, &avr_target, @@ -108,13 +127,18 @@ static struct target_type *target_types[] = &dsp5680xx_target, &testee_target, &avr32_ap7k_target, - &stm32_stlink_target, + &hla_target, + &nds32_v2_target, + &nds32_v3_target, + &nds32_v3m_target, + &or1k_target, + &quark_x10xx_target, NULL, }; -struct target *all_targets = NULL; -static struct target_event_callback *target_event_callbacks = NULL; -static struct target_timer_callback *target_timer_callbacks = NULL; +struct target *all_targets; +static struct target_event_callback *target_event_callbacks; +static struct target_timer_callback *target_timer_callbacks; static const int polling_interval = 100; static const Jim_Nvp nvp_assert[] = { @@ -147,16 +171,13 @@ static const char *target_strerror_safe(int err) const Jim_Nvp *n; n = Jim_Nvp_value2name_simple(nvp_error_target, err); - if (n->name == NULL) { + if (n->name == NULL) return "unknown"; - } else { + else return n->name; - } } static const Jim_Nvp nvp_target_event[] = { - { .value = TARGET_EVENT_OLD_gdb_program_config , .name = "old-gdb_program_config" }, - { .value = TARGET_EVENT_OLD_pre_resume , .name = "old-pre_resume" }, { .value = TARGET_EVENT_GDB_HALT, .name = "gdb-halt" }, { .value = TARGET_EVENT_HALTED, .name = "halted" }, @@ -167,10 +188,7 @@ static const Jim_Nvp nvp_target_event[] = { { .name = "gdb-start", .value = TARGET_EVENT_GDB_START }, { .name = "gdb-end", .value = TARGET_EVENT_GDB_END }, - /* historical name */ - - { .value = TARGET_EVENT_RESET_START, .name = "reset-start" }, - + { .value = TARGET_EVENT_RESET_START, .name = "reset-start" }, { .value = TARGET_EVENT_RESET_ASSERT_PRE, .name = "reset-assert-pre" }, { .value = TARGET_EVENT_RESET_ASSERT, .name = "reset-assert" }, { .value = TARGET_EVENT_RESET_ASSERT_POST, .name = "reset-assert-post" }, @@ -198,10 +216,6 @@ 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_RESUME_START, .name = "resume-start" }, - { .value = TARGET_EVENT_RESUMED , .name = "resume-ok" }, - { .value = TARGET_EVENT_RESUME_END , .name = "resume-end" }, - { .name = NULL, .value = -1 } }; @@ -214,13 +228,14 @@ static const Jim_Nvp nvp_target_state[] = { { .name = NULL, .value = -1 }, }; -static const Jim_Nvp nvp_target_debug_reason [] = { +static const Jim_Nvp nvp_target_debug_reason[] = { { .name = "debug-request" , .value = DBG_REASON_DBGRQ }, { .name = "breakpoint" , .value = DBG_REASON_BREAKPOINT }, { .name = "watchpoint" , .value = DBG_REASON_WATCHPOINT }, { .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 }, }; @@ -254,12 +269,11 @@ const char *debug_reason_name(struct target *t) return cp; } -const char * -target_state_name( struct target *t ) +const char *target_state_name(struct target *t) { const char *cp; cp = Jim_Nvp_value2name_simple(nvp_target_state, t->state)->name; - if( !cp ){ + if (!cp) { LOG_ERROR("Invalid target state: %d", (int)(t->state)); cp = "(*BUG*unknown*BUG*)"; } @@ -276,14 +290,22 @@ static int new_target_number(void) x = -1; t = all_targets; while (t) { - if (x < t->target_number) { + if (x < t->target_number) x = t->target_number; - } t = t->next; } 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) { @@ -317,6 +339,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) { @@ -350,36 +381,52 @@ 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) { uint32_t i; - for(i = 0; i < count; i ++) - dstbuf[i] = target_buffer_get_u32(target,&buffer[i*4]); + for (i = 0; i < count; i++) + dstbuf[i] = target_buffer_get_u32(target, &buffer[i * 4]); } /* write a uint16_t array to a buffer in target memory endianness */ void target_buffer_get_u16_array(struct target *target, const uint8_t *buffer, uint32_t count, uint16_t *dstbuf) { uint32_t i; - for(i = 0; i < count; i ++) - dstbuf[i] = target_buffer_get_u16(target,&buffer[i*2]); + for (i = 0; i < count; i++) + 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 ++) - target_buffer_set_u32(target,&buffer[i*4],srcbuf[i]); + for (i = 0; i < count; i++) + target_buffer_set_u32(target, &buffer[i * 4], srcbuf[i]); } /* 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 ++) - target_buffer_set_u16(target,&buffer[i*2],srcbuf[i]); + for (i = 0; i < count; i++) + target_buffer_set_u16(target, &buffer[i * 2], srcbuf[i]); } /* return a pointer to a configured target; id is name or number */ @@ -389,9 +436,9 @@ struct target *get_target(const char *id) /* try as tcltarget name */ for (target = all_targets; target; target = target->next) { - if (target->cmd_name == NULL) + if (target_name(target) == NULL) continue; - if (strcmp(id, target->cmd_name) == 0) + if (strcmp(id, target_name(target)) == 0) return target; } @@ -405,7 +452,7 @@ struct target *get_target(const char *id) for (target = all_targets; target; target = target->next) { if (target->target_number == (int)num) { LOG_WARNING("use '%s' as target identifier, not '%u'", - target->cmd_name, num); + target_name(target), num); return target; } } @@ -419,21 +466,19 @@ static struct target *get_target_by_num(int num) struct target *target = all_targets; while (target) { - if (target->target_number == num) { + if (target->target_number == num) return target; - } target = target->next; } return NULL; } -struct target* get_current_target(struct command_context *cmd_ctx) +struct target *get_current_target(struct command_context *cmd_ctx) { struct target *target = get_target_by_num(cmd_ctx->current_target); - if (target == NULL) - { + if (target == NULL) { LOG_ERROR("BUG: current_target out of bounds"); exit(-1); } @@ -446,8 +491,7 @@ int target_poll(struct target *target) int retval; /* We can't poll until after examine */ - if (!target_was_examined(target)) - { + if (!target_was_examined(target)) { /* Fail silently lest we pollute the log */ return ERROR_FAIL; } @@ -456,16 +500,12 @@ int target_poll(struct target *target) if (retval != ERROR_OK) return retval; - if (target->halt_issued) - { + if (target->halt_issued) { if (target->state == TARGET_HALTED) - { target->halt_issued = false; - } else - { + else { long long t = timeval_ms() - target->halt_issued_time; - if (t>1000) - { + 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); @@ -480,8 +520,7 @@ int target_halt(struct target *target) { int retval; /* We can't poll until after examine */ - if (!target_was_examined(target)) - { + if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } @@ -531,19 +570,23 @@ int target_resume(struct target *target, int current, uint32_t address, int hand int retval; /* We can't poll until after examine */ - if (!target_was_examined(target)) - { + if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } + target_call_event_callbacks(target, TARGET_EVENT_RESUME_START); + /* note that resume *must* be asynchronous. The CPU can halt before * we poll. The CPU can even halt at the current PC as a result of * a software breakpoint being inserted by (a bug?) the application. */ - if ((retval = target->type->resume(target, current, address, handle_breakpoints, debug_execution)) != ERROR_OK) + retval = target->type->resume(target, current, address, handle_breakpoints, debug_execution); + if (retval != ERROR_OK) return retval; + target_call_event_callbacks(target, TARGET_EVENT_RESUME_END); + return retval; } @@ -573,7 +616,7 @@ static int target_process_reset(struct command_context *cmd_ctx, enum target_res if (retval != JIM_OK) { Jim_MakeErrorMessage(cmd_ctx->interp); - command_print(NULL,"%s\n", Jim_GetString(Jim_GetResult(cmd_ctx->interp), NULL)); + command_print(NULL, "%s\n", Jim_GetString(Jim_GetResult(cmd_ctx->interp), NULL)); return ERROR_FAIL; } @@ -583,6 +626,7 @@ static int target_process_reset(struct command_context *cmd_ctx, enum target_res struct target *target; for (target = all_targets; target; target = target->next) { target->type->check_reset(target); + target->running_alg = false; } return retval; @@ -626,9 +670,17 @@ static int jtag_enable_callback(enum jtag_event event, void *priv) return ERROR_OK; jtag_unregister_event_callback(jtag_enable_callback, target); - return target_examine_one(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; +} /* Targets that correctly implement init + examine, i.e. * no communication with target during init: @@ -640,57 +692,42 @@ int target_examine(void) int retval = ERROR_OK; struct target *target; - for (target = all_targets; target; target = target->next) - { + for (target = all_targets; target; target = target->next) { /* defer examination, but don't skip it */ if (!target->tap->enabled) { jtag_register_event_callback(jtag_enable_callback, target); continue; } - if ((retval = target_examine_one(target)) != ERROR_OK) + + target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_START); + + retval = target_examine_one(target); + if (retval != ERROR_OK) return retval; + + target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_END); } return retval; } + const char *target_type_name(struct target *target) { return target->type->name; } -static int target_write_memory_imp(struct target *target, uint32_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; - } - return target->type->write_memory_imp(target, address, size, count, buffer); -} - -static int target_read_memory_imp(struct target *target, uint32_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; - } - return target->type->read_memory_imp(target, address, size, count, buffer); -} - -static int target_soft_reset_halt_imp(struct target *target) +static int target_soft_reset_halt(struct target *target) { - if (!target_was_examined(target)) - { + if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } - if (!target->type->soft_reset_halt_imp) { + if (!target->type->soft_reset_halt) { LOG_ERROR("Target %s does not support soft_reset_halt", target_name(target)); return ERROR_FAIL; } - return target->type->soft_reset_halt_imp(target); + return target->type->soft_reset_halt(target); } /** @@ -712,8 +749,7 @@ int target_run_algorithm(struct target *target, { int retval = ERROR_FAIL; - if (!target_was_examined(target)) - { + if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); goto done; } @@ -749,8 +785,7 @@ int target_start_algorithm(struct target *target, { int retval = ERROR_FAIL; - if (!target_was_examined(target)) - { + if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); goto done; } @@ -809,42 +844,197 @@ done: return retval; } +/** + * Executes a target-specific native code algorithm in the target. + * It differs from target_run_algorithm in that the algorithm is asynchronous. + * Because of this it requires an compliant algorithm: + * see contrib/loaders/flash/stm32f1x.S for example. + * + * @param target used to run the algorithm + */ + +int target_run_flash_async_algorithm(struct target *target, + 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, + uint32_t entry_point, uint32_t exit_point, void *arch_info) +{ + 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; + uint32_t rp_addr = buffer_start + 4; + uint32_t fifo_start_addr = buffer_start + 8; + uint32_t fifo_end_addr = buffer_start + buffer_size; + + uint32_t wp = fifo_start_addr; + uint32_t rp = fifo_start_addr; + + /* validate block_size is 2^n */ + assert(!block_size || !(block_size & (block_size - 1))); + + retval = target_write_u32(target, wp_addr, wp); + if (retval != ERROR_OK) + return retval; + retval = target_write_u32(target, rp_addr, rp); + if (retval != ERROR_OK) + return retval; + + /* Start up algorithm on target and let it idle while writing the first chunk */ + retval = target_start_algorithm(target, num_mem_params, mem_params, + num_reg_params, reg_params, + entry_point, + exit_point, + arch_info); + + if (retval != ERROR_OK) { + LOG_ERROR("error starting target flash write algorithm"); + return retval; + } + + while (count > 0) { + + retval = target_read_u32(target, rp_addr, &rp); + if (retval != ERROR_OK) { + LOG_ERROR("failed to get read pointer"); + break; + } + + 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"); + retval = ERROR_FLASH_OPERATION_FAILED; + break; + } + + if ((rp & (block_size - 1)) || rp < fifo_start_addr || rp >= fifo_end_addr) { + LOG_ERROR("corrupted fifo read pointer 0x%" PRIx32, rp); + break; + } + + /* Count the number of bytes available in the fifo without + * crossing the wrap around. Make sure to not fill it completely, + * because that would make wp == rp and that's the empty condition. */ + uint32_t thisrun_bytes; + if (rp > wp) + thisrun_bytes = rp - wp - block_size; + else if (rp > fifo_start_addr) + thisrun_bytes = fifo_end_addr - wp; + else + thisrun_bytes = fifo_end_addr - wp - block_size; + + if (thisrun_bytes == 0) { + /* Throttle polling a bit if transfer is (much) faster than flash + * programming. The exact delay shouldn't matter as long as it's + * less than buffer size / flash speed. This is very unlikely to + * run when using high latency connections such as USB. */ + alive_sleep(10); + + /* to stop an infinite loop on some targets check and increment a timeout + * this issue was observed on a stellaris using the new ICDI interface */ + if (timeout++ >= 500) { + LOG_ERROR("timeout waiting for algorithm, a target reset is recommended"); + return ERROR_FLASH_OPERATION_FAILED; + } + continue; + } + + /* reset our timeout */ + timeout = 0; + + /* Limit to the amount of data we actually want to write */ + if (thisrun_bytes > count * block_size) + thisrun_bytes = count * block_size; + + /* Write data to fifo */ + retval = target_write_buffer(target, wp, thisrun_bytes, buffer); + if (retval != ERROR_OK) + break; + + /* Update counters and wrap write pointer */ + buffer += thisrun_bytes; + count -= thisrun_bytes / block_size; + wp += thisrun_bytes; + if (wp >= fifo_end_addr) + wp = fifo_start_addr; + + /* Store updated write pointer to target */ + retval = target_write_u32(target, wp_addr, wp); + if (retval != ERROR_OK) + break; + } + + if (retval != ERROR_OK) { + /* abort flash write algorithm on target */ + target_write_u32(target, wp_addr, 0); + } + + int retval2 = target_wait_algorithm(target, num_mem_params, mem_params, + num_reg_params, reg_params, + exit_point, + 10000, + arch_info); + + if (retval2 != ERROR_OK) { + LOG_ERROR("error waiting for target flash write algorithm"); + retval = retval2; + } + + return retval; +} int target_read_memory(struct target *target, uint32_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; + } return target->type->read_memory(target, address, size, count, buffer); } -static int target_read_phys_memory(struct target *target, +int target_read_phys_memory(struct target *target, uint32_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; + } 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) { + if (!target_was_examined(target)) { + LOG_ERROR("Target not examined yet"); + return ERROR_FAIL; + } return target->type->write_memory(target, address, size, count, buffer); } -static int target_write_phys_memory(struct target *target, +int target_write_phys_memory(struct target *target, uint32_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; + } return target->type->write_phys_memory(target, address, size, count, buffer); } -int target_bulk_write_memory(struct target *target, - uint32_t address, uint32_t count, const uint8_t *buffer) -{ - return target->type->bulk_write_memory(target, address, 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->cmd_name); + if ((target->state != TARGET_HALTED) && (breakpoint->type != BKPT_HARD)) { + LOG_WARNING("target %s is not halted", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_breakpoint(target, breakpoint); @@ -854,7 +1044,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->cmd_name); + LOG_WARNING("target %s is not halted", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_context_breakpoint(target, breakpoint); @@ -864,7 +1054,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->cmd_name); + LOG_WARNING("target %s is not halted", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_hybrid_breakpoint(target, breakpoint); @@ -880,7 +1070,7 @@ int target_add_watchpoint(struct target *target, struct watchpoint *watchpoint) { if (target->state != TARGET_HALTED) { - LOG_WARNING("target %s is not halted", target->cmd_name); + LOG_WARNING("target %s is not halted", target_name(target)); return ERROR_TARGET_NOT_HALTED; } return target->type->add_watchpoint(target, watchpoint); @@ -890,11 +1080,29 @@ 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", 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) @@ -902,6 +1110,34 @@ int target_step(struct target *target, return target->type->step(target, current, address, handle_breakpoints); } +int target_get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info) +{ + if (target->state != TARGET_HALTED) { + LOG_WARNING("target %s is not halted", target->cmd_name); + return ERROR_TARGET_NOT_HALTED; + } + return target->type->get_gdb_fileio_info(target, fileio_info); +} + +int target_gdb_fileio_end(struct target *target, int retcode, int fileio_errno, bool ctrl_c) +{ + if (target->state != TARGET_HALTED) { + LOG_WARNING("target %s is not halted", target->cmd_name); + return ERROR_TARGET_NOT_HALTED; + } + return target->type->gdb_fileio_end(target, retcode, fileio_errno, ctrl_c); +} + +int target_profiling(struct target *target, uint32_t *samples, + uint32_t max_num_samples, uint32_t *num_samples, uint32_t seconds) +{ + if (target->state != TARGET_HALTED) { + LOG_WARNING("target %s is not halted", 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. @@ -912,16 +1148,14 @@ static void target_reset_examined(struct target *target) target->examined = false; } -static int -err_read_phys_memory(struct target *target, uint32_t address, +static int err_read_phys_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { LOG_ERROR("Not implemented: %s", __func__); return ERROR_FAIL; } -static int -err_write_phys_memory(struct target *target, uint32_t address, +static int err_write_phys_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { LOG_ERROR("Not implemented: %s", __func__); @@ -939,69 +1173,42 @@ static int target_init_one(struct command_context *cmd_ctx, if (type->examine == NULL) type->examine = default_examine; - if (type->check_reset== NULL) + if (type->check_reset == NULL) type->check_reset = default_check_reset; assert(type->init_target != NULL); int retval = type->init_target(cmd_ctx, target); - if (ERROR_OK != retval) - { + if (ERROR_OK != retval) { LOG_ERROR("target '%s' init failed", target_name(target)); return retval; } - /** - * @todo get rid of those *memory_imp() methods, now that all - * callers are using target_*_memory() accessors ... and make - * sure the "physical" paths handle the same issues. - */ - /* a non-invasive way(in terms of patches) to add some code that - * runs before the type->write/read_memory implementation - */ - type->write_memory_imp = target->type->write_memory; - type->write_memory = target_write_memory_imp; - - type->read_memory_imp = target->type->read_memory; - type->read_memory = target_read_memory_imp; - - type->soft_reset_halt_imp = target->type->soft_reset_halt; - type->soft_reset_halt = target_soft_reset_halt_imp; - /* Sanity-check MMU support ... stub in what we must, to help * implement it in stages, but warn if we need to do so. */ - if (type->mmu) - { - if (type->write_phys_memory == NULL) - { + 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) - { + 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) - { + if (type->virt2phys == NULL) { LOG_ERROR("type '%s' is missing virt2phys", type->name); type->virt2phys = identity_virt2phys; } - } - else - { + } else { /* Make sure no-MMU targets all behave the same: make no * distinction between physical and virtual addresses, and * ensure that virt2phys() is always an identity mapping. */ - if (type->write_phys_memory || type->read_phys_memory - || type->virt2phys) - { + if (type->write_phys_memory || type->read_phys_memory || type->virt2phys) LOG_WARNING("type '%s' has bad MMU hooks", type->name); - } type->mmu = no_mmu; type->write_phys_memory = type->write_memory; @@ -1015,6 +1222,15 @@ 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->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; } @@ -1023,8 +1239,7 @@ static int target_init(struct command_context *cmd_ctx) struct target *target; int retval; - for (target = all_targets; target; target = target->next) - { + for (target = all_targets; target; target = target->next) { retval = target_init_one(cmd_ctx, target); if (ERROR_OK != retval) return retval; @@ -1052,9 +1267,8 @@ COMMAND_HANDLER(handle_target_init_command) if (CMD_ARGC != 0) return ERROR_COMMAND_SYNTAX_ERROR; - static bool target_initialized = false; - if (target_initialized) - { + static bool target_initialized; + if (target_initialized) { LOG_INFO("'target init' has already been called"); return ERROR_OK; } @@ -1064,21 +1278,27 @@ 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; + LOG_DEBUG("Initializing targets..."); return target_init(CMD_CTX); } -int target_register_event_callback(int (*callback)(struct target *target, enum target_event event, void *priv), void *priv) +int target_register_event_callback(int (*callback)(struct target *target, + enum target_event event, void *priv), void *priv) { struct target_event_callback **callbacks_p = &target_event_callbacks; if (callback == NULL) - { - return ERROR_INVALID_ARGUMENTS; - } + return ERROR_COMMAND_SYNTAX_ERROR; - if (*callbacks_p) - { + if (*callbacks_p) { while ((*callbacks_p)->next) callbacks_p = &((*callbacks_p)->next); callbacks_p = &((*callbacks_p)->next); @@ -1098,12 +1318,9 @@ int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int struct timeval now; if (callback == NULL) - { - return ERROR_INVALID_ARGUMENTS; - } + return ERROR_COMMAND_SYNTAX_ERROR; - if (*callbacks_p) - { + if (*callbacks_p) { while ((*callbacks_p)->next) callbacks_p = &((*callbacks_p)->next); callbacks_p = &((*callbacks_p)->next); @@ -1118,8 +1335,7 @@ int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int (*callbacks_p)->when.tv_usec = now.tv_usec + (time_ms % 1000) * 1000; time_ms -= (time_ms % 1000); (*callbacks_p)->when.tv_sec = now.tv_sec + (time_ms / 1000); - if ((*callbacks_p)->when.tv_usec > 1000000) - { + if ((*callbacks_p)->when.tv_usec > 1000000) { (*callbacks_p)->when.tv_usec = (*callbacks_p)->when.tv_usec - 1000000; (*callbacks_p)->when.tv_sec += 1; } @@ -1130,26 +1346,22 @@ int target_register_timer_callback(int (*callback)(void *priv), int time_ms, int return ERROR_OK; } -int target_unregister_event_callback(int (*callback)(struct target *target, enum target_event event, void *priv), void *priv) +int target_unregister_event_callback(int (*callback)(struct target *target, + enum target_event event, void *priv), void *priv) { struct target_event_callback **p = &target_event_callbacks; struct target_event_callback *c = target_event_callbacks; if (callback == NULL) - { - return ERROR_INVALID_ARGUMENTS; - } + return ERROR_COMMAND_SYNTAX_ERROR; - while (c) - { + while (c) { struct target_event_callback *next = c->next; - if ((c->callback == callback) && (c->priv == priv)) - { + if ((c->callback == callback) && (c->priv == priv)) { *p = next; free(c); return ERROR_OK; - } - else + } else p = &(c->next); c = next; } @@ -1157,26 +1369,21 @@ int target_unregister_event_callback(int (*callback)(struct target *target, enum return ERROR_OK; } -static int target_unregister_timer_callback(int (*callback)(void *priv), void *priv) +int target_unregister_timer_callback(int (*callback)(void *priv), void *priv) { struct target_timer_callback **p = &target_timer_callbacks; struct target_timer_callback *c = target_timer_callbacks; if (callback == NULL) - { - return ERROR_INVALID_ARGUMENTS; - } + return ERROR_COMMAND_SYNTAX_ERROR; - while (c) - { + while (c) { struct target_timer_callback *next = c->next; - if ((c->callback == callback) && (c->priv == priv)) - { + if ((c->callback == callback) && (c->priv == priv)) { *p = next; free(c); return ERROR_OK; - } - else + } else p = &(c->next); c = next; } @@ -1189,20 +1396,17 @@ int target_call_event_callbacks(struct target *target, enum target_event event) struct target_event_callback *callback = target_event_callbacks; struct target_event_callback *next_callback; - if (event == TARGET_EVENT_HALTED) - { + if (event == TARGET_EVENT_HALTED) { /* execute early halted first */ target_call_event_callbacks(target, TARGET_EVENT_GDB_HALT); } - LOG_DEBUG("target event %i (%s)", - event, - Jim_Nvp_value2name_simple(nvp_target_event, event)->name); + LOG_DEBUG("target event %i (%s)", event, + Jim_Nvp_value2name_simple(nvp_target_event, event)->name); target_handle_event(target, event); - while (callback) - { + while (callback) { next_callback = callback->next; callback->callback(target, event, callback->priv); callback = next_callback; @@ -1218,8 +1422,7 @@ static int target_timer_callback_periodic_restart( cb->when.tv_usec = now->tv_usec + (time_ms % 1000) * 1000; time_ms -= (time_ms % 1000); cb->when.tv_sec = now->tv_sec + time_ms / 1000; - if (cb->when.tv_usec > 1000000) - { + if (cb->when.tv_usec > 1000000) { cb->when.tv_usec = cb->when.tv_usec - 1000000; cb->when.tv_sec += 1; } @@ -1245,9 +1448,8 @@ static int target_call_timer_callbacks_check_time(int checktime) gettimeofday(&now, NULL); struct target_timer_callback *callback = target_timer_callbacks; - while (callback) - { - // cleaning up may unregister and free this callback + while (callback) { + /* cleaning up may unregister and free this callback */ struct target_timer_callback *next_callback = callback->next; bool call_it = callback->callback && @@ -1256,8 +1458,7 @@ static int target_call_timer_callbacks_check_time(int checktime) (now.tv_sec == callback->when.tv_sec && now.tv_usec >= callback->when.tv_usec)); - if (call_it) - { + if (call_it) { int retval = target_call_timer_callback(callback, &now); if (retval != ERROR_OK) return retval; @@ -1280,28 +1481,99 @@ int target_call_timer_callbacks_now(void) return target_call_timer_callbacks_check_time(0); } -int target_alloc_working_area_try(struct target *target, uint32_t size, struct working_area **area) +/* Prints the working area layout for debug purposes */ +static void print_wa_layout(struct target *target) { struct working_area *c = target->working_areas; - struct working_area *new_wa = NULL; - /* Reevaluate working area address based on MMU state*/ - if (target->working_areas == NULL) - { - int retval; - int enabled; + while (c) { + LOG_DEBUG("%c%c 0x%08"PRIx32"-0x%08"PRIx32" (%"PRIu32" bytes)", + c->backup ? 'b' : ' ', c->free ? ' ' : '*', + c->address, c->address + c->size - 1, c->size); + c = c->next; + } +} - retval = target->type->mmu(target, &enabled); +/* Reduce area to size bytes, create a new free area from the remaining bytes, if any. */ +static void target_split_working_area(struct working_area *area, uint32_t size) +{ + assert(area->free); /* Shouldn't split an allocated area */ + assert(size <= area->size); /* Caller should guarantee this */ + + /* Split only if not already the right size */ + if (size < area->size) { + struct working_area *new_wa = malloc(sizeof(*new_wa)); + + if (new_wa == NULL) + return; + + new_wa->next = area->next; + new_wa->size = area->size - size; + new_wa->address = area->address + size; + new_wa->backup = NULL; + new_wa->user = NULL; + new_wa->free = true; + + area->next = new_wa; + area->size = size; + + /* If backup memory was allocated to this area, it has the wrong size + * now so free it and it will be reallocated if/when needed */ + if (area->backup) { + free(area->backup); + area->backup = NULL; + } + } +} + +/* Merge all adjacent free areas into one */ +static void target_merge_working_areas(struct target *target) +{ + struct working_area *c = target->working_areas; + + while (c && c->next) { + assert(c->next->address == c->address + c->size); /* This is an invariant */ + + /* Find two adjacent free areas */ + if (c->free && c->next->free) { + /* Merge the last into the first */ + c->size += c->next->size; + + /* Remove the last */ + struct working_area *to_be_freed = c->next; + c->next = c->next->next; + if (to_be_freed->backup) + free(to_be_freed->backup); + free(to_be_freed); + + /* If backup memory was allocated to the remaining area, it's has + * the wrong size now */ + if (c->backup) { + free(c->backup); + c->backup = NULL; + } + } else { + c = c->next; + } + } +} + +int target_alloc_working_area_try(struct target *target, uint32_t size, struct working_area **area) +{ + /* Reevaluate working area address based on MMU state*/ + if (target->working_areas == NULL) { + int retval; + int enabled; + + retval = target->type->mmu(target, &enabled); if (retval != ERROR_OK) - { return retval; - } if (!enabled) { if (target->working_area_phys_spec) { LOG_DEBUG("MMU disabled, using physical " - "address for working memory 0x%08x", - (unsigned)target->working_area_phys); + "address for working memory 0x%08"PRIx32, + target->working_area_phys); target->working_area = target->working_area_phys; } else { LOG_ERROR("No working memory available. " @@ -1311,8 +1583,8 @@ 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%08x", - (unsigned)target->working_area_virt); + "address for working memory 0x%08"PRIx32, + target->working_area_virt); target->working_area = target->working_area_virt; } else { LOG_ERROR("No working memory available. " @@ -1320,80 +1592,62 @@ int target_alloc_working_area_try(struct target *target, uint32_t size, struct w return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } } + + /* Set up initial working area on first call */ + struct working_area *new_wa = malloc(sizeof(*new_wa)); + if (new_wa) { + new_wa->next = NULL; + new_wa->size = target->working_area_size & ~3UL; /* 4-byte align */ + new_wa->address = target->working_area; + new_wa->backup = NULL; + new_wa->user = NULL; + new_wa->free = true; + } + + target->working_areas = new_wa; } /* only allocate multiples of 4 byte */ if (size % 4) - { - LOG_ERROR("BUG: code tried to allocate unaligned number of bytes (0x%08x), padding", ((unsigned)(size))); - size = (size + 3) & (~3); - } + size = (size + 3) & (~3UL); - /* see if there's already a matching working area */ - while (c) - { - if ((c->free) && (c->size == size)) - { - new_wa = c; + struct working_area *c = target->working_areas; + + /* Find the first large enough working area */ + while (c) { + if (c->free && c->size >= size) break; - } c = c->next; } - /* if not, allocate a new one */ - if (!new_wa) - { - struct working_area **p = &target->working_areas; - uint32_t first_free = target->working_area; - uint32_t free_size = target->working_area_size; - - c = target->working_areas; - while (c) - { - first_free += c->size; - free_size -= c->size; - p = &c->next; - c = c->next; - } - - if (free_size < size) - { - return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - } + if (c == NULL) + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; - LOG_DEBUG("allocated new working area at address 0x%08x", (unsigned)first_free); + /* Split the working area into the requested size */ + target_split_working_area(c, size); - new_wa = malloc(sizeof(struct working_area)); - new_wa->next = NULL; - new_wa->size = size; - new_wa->address = first_free; + LOG_DEBUG("allocated new working area of %"PRIu32" bytes at address 0x%08"PRIx32, size, c->address); - if (target->backup_working_area) - { - int retval; - new_wa->backup = malloc(new_wa->size); - if ((retval = target_read_memory(target, new_wa->address, 4, new_wa->size / 4, new_wa->backup)) != ERROR_OK) - { - free(new_wa->backup); - free(new_wa); - return retval; - } - } - else - { - new_wa->backup = NULL; + if (target->backup_working_area) { + if (c->backup == NULL) { + c->backup = malloc(c->size); + if (c->backup == NULL) + return ERROR_FAIL; } - /* put new entry in list */ - *p = new_wa; + int retval = target_read_memory(target, c->address, 4, c->size / 4, c->backup); + if (retval != ERROR_OK) + return retval; } /* mark as used, and return the new (reused) area */ - new_wa->free = false; - *area = new_wa; + c->free = false; + *area = c; /* user pointer */ - new_wa->user = area; + c->user = area; + + print_wa_layout(target); return ERROR_OK; } @@ -1404,32 +1658,57 @@ int target_alloc_working_area(struct target *target, uint32_t size, struct worki retval = target_alloc_working_area_try(target, size, area); if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) - { - LOG_WARNING("not enough working area available(requested %u)", (unsigned)(size)); - } + LOG_WARNING("not enough working area available(requested %"PRIu32")", size); return retval; } +static int target_restore_working_area(struct target *target, struct working_area *area) +{ + int retval = ERROR_OK; + + 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, + area->size, area->address); + } + + return retval; +} + +/* Restore the area's backup memory, if any, and return the area to the allocation pool */ static int target_free_working_area_restore(struct target *target, struct working_area *area, int restore) { + int retval = ERROR_OK; + if (area->free) - return ERROR_OK; + return retval; - if (restore && target->backup_working_area) - { - int retval; - if ((retval = target_write_memory(target, area->address, 4, area->size / 4, area->backup)) != ERROR_OK) + if (restore) { + retval = target_restore_working_area(target, area); + /* REVISIT: Perhaps the area should be freed even if restoring fails. */ + if (retval != ERROR_OK) return retval; } area->free = true; + LOG_DEBUG("freed %"PRIu32" bytes of working area at address 0x%08"PRIx32, + area->size, area->address); + /* mark user pointer invalid */ + /* TODO: Is this really safe? It points to some previous caller's memory. + * How could we know that the area pointer is still in that place and not + * some other vital data? What's the purpose of this, anyway? */ *area->user = NULL; area->user = NULL; - return ERROR_OK; + target_merge_working_areas(target); + + print_wa_layout(target); + + return retval; } int target_free_working_area(struct target *target, struct working_area *area) @@ -1444,20 +1723,24 @@ static void target_free_all_working_areas_restore(struct target *target, int res { struct working_area *c = target->working_areas; - while (c) - { - struct working_area *next = c->next; - target_free_working_area_restore(target, c, restore); - - if (c->backup) - free(c->backup); - - free(c); + LOG_DEBUG("freeing all working areas"); - c = next; + /* Loop through all areas, restoring the allocated ones and marking them as free */ + while (c) { + if (!c->free) { + if (restore) + target_restore_working_area(target, c); + c->free = true; + *c->user = NULL; /* Same as above */ + c->user = NULL; + } + c = c->next; } - target->working_areas = NULL; + /* Run a merge pass to combine all areas into one */ + target_merge_working_areas(target); + + print_wa_layout(target); } void target_free_all_working_areas(struct target *target) @@ -1465,16 +1748,34 @@ void target_free_all_working_areas(struct target *target) target_free_all_working_areas_restore(target, 1); } +/* Find the largest number of bytes that can be allocated */ +uint32_t target_get_working_area_avail(struct target *target) +{ + struct working_area *c = target->working_areas; + uint32_t max_size = 0; + + if (c == NULL) + return target->working_area_size; + + while (c) { + if (c->free && max_size < c->size) + max_size = c->size; + + c = c->next; + } + + return max_size; +} + int target_arch_state(struct target *target) { int retval; - if (target == NULL) - { + if (target == NULL) { LOG_USER("No target has been configured"); return ERROR_OK; } - LOG_USER("target state: %s", target_state_name( target )); + LOG_USER("target state: %s", target_state_name(target)); if (target->state != TARGET_HALTED) return ERROR_OK; @@ -1483,6 +1784,71 @@ 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 = *((uint32_t *)reg->value); + 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 @@ -1490,20 +1856,17 @@ int target_arch_state(struct target *target) int target_write_buffer(struct target *target, uint32_t address, uint32_t size, const uint8_t *buffer) { LOG_DEBUG("writing buffer of %i byte at 0x%8.8x", - (int)size, (unsigned)address); + (int)size, (unsigned)address); - if (!target_was_examined(target)) - { + if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } - if (size == 0) { + if (size == 0) return ERROR_OK; - } - if ((address + size - 1) < address) - { + 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, @@ -1514,61 +1877,37 @@ int target_write_buffer(struct target *target, uint32_t address, uint32_t size, 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, uint32_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); + uint32_t size; - if (unaligned > size) - unaligned = size; - - if ((retval = target_write_memory(target, address, 1, unaligned, buffer)) != ERROR_OK) - return retval; - - buffer += unaligned; - address += unaligned; - size -= unaligned; - } - - /* handle aligned words */ - if (size >= 4) - { - int aligned = size - (size % 4); - - /* use bulk writes above a certain limit. This may have to be changed */ - if (aligned > 128) - { - if ((retval = target->type->bulk_write_memory(target, address, aligned / 4, buffer)) != ERROR_OK) - return retval; - } - else - { - if ((retval = target_write_memory(target, address, 4, aligned / 4, buffer)) != ERROR_OK) + /* 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) - { - if ((retval = target_write_memory(target, address, 1, size, buffer)) != 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 @@ -1580,18 +1919,15 @@ int target_read_buffer(struct target *target, uint32_t address, uint32_t size, u LOG_DEBUG("reading buffer of %i byte at 0x%8.8x", (int)size, (unsigned)address); - if (!target_was_examined(target)) - { + if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } - if (size == 0) { + if (size == 0) return ERROR_OK; - } - if ((address + size - 1) < address) - { + 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 ")", address, @@ -1602,61 +1938,34 @@ 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, uint32_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; - - if ((retval = target_read_memory(target, address, 1, unaligned, buffer)) != ERROR_OK) - return retval; - - buffer += unaligned; - address += unaligned; - size -= unaligned; - } - - /* handle aligned words */ - if (size >= 4) - { - int aligned = size - (size % 4); - - if ((retval = target_read_memory(target, address, 4, aligned / 4, buffer)) != 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) - { - if ((retval = target_read_memory(target, address, 1, size, buffer)) != 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; @@ -1668,31 +1977,26 @@ int target_checksum_memory(struct target *target, uint32_t address, uint32_t siz int retval; uint32_t i; uint32_t checksum = 0; - if (!target_was_examined(target)) - { + if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } - if ((retval = target->type->checksum_memory(target, address, - size, &checksum)) != ERROR_OK) - { + retval = target->type->checksum_memory(target, address, size, &checksum); + if (retval != ERROR_OK) { buffer = malloc(size); - if (buffer == NULL) - { + if (buffer == NULL) { LOG_ERROR("error allocating buffer for section (%d bytes)", (int)size); - return ERROR_INVALID_ARGUMENTS; + return ERROR_COMMAND_SYNTAX_ERROR; } retval = target_read_buffer(target, address, size, buffer); - if (retval != ERROR_OK) - { + if (retval != ERROR_OK) { free(buffer); return retval; } /* convert to target endianness */ - for (i = 0; i < (size/sizeof(uint32_t)); i++) - { + for (i = 0; i < (size/sizeof(uint32_t)); i++) { uint32_t target_data; target_data = target_buffer_get_u32(target, &buffer[i*sizeof(uint32_t)]); target_buffer_set_u32(target, &buffer[i*sizeof(uint32_t)], target_data); @@ -1710,8 +2014,7 @@ int target_checksum_memory(struct target *target, uint32_t address, uint32_t siz int target_blank_check_memory(struct target *target, uint32_t address, uint32_t size, uint32_t* blank) { int retval; - if (!target_was_examined(target)) - { + if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } @@ -1724,26 +2027,46 @@ int target_blank_check_memory(struct target *target, uint32_t address, uint32_t return retval; } +int target_read_u64(struct target *target, uint64_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: 0x%" PRIx64 ", value: 0x%16.16" PRIx64 "", + address, + *value); + } else { + *value = 0x0; + LOG_DEBUG("address: 0x%" PRIx64 " failed", + address); + } + + return retval; +} + int target_read_u32(struct target *target, uint32_t address, uint32_t *value) { uint8_t value_buf[4]; - if (!target_was_examined(target)) - { + if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } int retval = target_read_memory(target, address, 4, 1, value_buf); - if (retval == ERROR_OK) - { + if (retval == ERROR_OK) { *value = target_buffer_get_u32(target, value_buf); LOG_DEBUG("address: 0x%8.8" PRIx32 ", value: 0x%8.8" PRIx32 "", address, *value); - } - else - { + } else { *value = 0x0; LOG_DEBUG("address: 0x%8.8" PRIx32 " failed", address); @@ -1755,23 +2078,19 @@ int target_read_u32(struct target *target, uint32_t address, uint32_t *value) int target_read_u16(struct target *target, uint32_t address, uint16_t *value) { uint8_t value_buf[2]; - if (!target_was_examined(target)) - { + if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } int retval = target_read_memory(target, address, 2, 1, value_buf); - if (retval == ERROR_OK) - { + if (retval == ERROR_OK) { *value = target_buffer_get_u16(target, value_buf); LOG_DEBUG("address: 0x%8.8" PRIx32 ", value: 0x%4.4x", address, *value); - } - else - { + } else { *value = 0x0; LOG_DEBUG("address: 0x%8.8" PRIx32 " failed", address); @@ -1782,21 +2101,18 @@ int target_read_u16(struct target *target, uint32_t address, uint16_t *value) int target_read_u8(struct target *target, uint32_t address, uint8_t *value) { - int retval = target_read_memory(target, address, 1, 1, value); - if (!target_was_examined(target)) - { + if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } - if (retval == ERROR_OK) - { + 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", address, *value); - } - else - { + } else { *value = 0x0; LOG_DEBUG("address: 0x%8.8" PRIx32 " failed", address); @@ -1805,12 +2121,32 @@ int target_read_u8(struct target *target, uint32_t address, uint8_t *value) return retval; } +int target_write_u64(struct target *target, uint64_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: 0x%" PRIx64 ", 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, uint32_t address, uint32_t value) { int retval; uint8_t value_buf[4]; - if (!target_was_examined(target)) - { + if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } @@ -1820,10 +2156,9 @@ int target_write_u32(struct target *target, uint32_t address, uint32_t value) value); target_buffer_set_u32(target, value_buf, value); - if ((retval = target_write_memory(target, address, 4, 1, value_buf)) != ERROR_OK) - { + retval = target_write_memory(target, address, 4, 1, value_buf); + if (retval != ERROR_OK) LOG_DEBUG("failed: %i", retval); - } return retval; } @@ -1832,8 +2167,7 @@ int target_write_u16(struct target *target, uint32_t address, uint16_t value) { int retval; uint8_t value_buf[2]; - if (!target_was_examined(target)) - { + if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } @@ -1843,10 +2177,9 @@ int target_write_u16(struct target *target, uint32_t address, uint16_t value) value); target_buffer_set_u16(target, value_buf, value); - if ((retval = target_write_memory(target, address, 2, 1, value_buf)) != ERROR_OK) - { + retval = target_write_memory(target, address, 2, 1, value_buf); + if (retval != ERROR_OK) LOG_DEBUG("failed: %i", retval); - } return retval; } @@ -1854,8 +2187,7 @@ int target_write_u16(struct target *target, uint32_t address, uint16_t value) int target_write_u8(struct target *target, uint32_t address, uint8_t value) { int retval; - if (!target_was_examined(target)) - { + if (!target_was_examined(target)) { LOG_ERROR("Target not examined yet"); return ERROR_FAIL; } @@ -1863,10 +2195,9 @@ int target_write_u8(struct target *target, uint32_t address, uint8_t value) LOG_DEBUG("address: 0x%8.8" PRIx32 ", value: 0x%2.2x", address, value); - if ((retval = target_write_memory(target, address, 1, 1, &value)) != ERROR_OK) - { + retval = target_write_memory(target, address, 1, 1, &value); + if (retval != ERROR_OK) LOG_DEBUG("failed: %i", retval); - } return retval; } @@ -1893,8 +2224,7 @@ static int find_target(struct command_context *cmd_ctx, const char *name) COMMAND_HANDLER(handle_targets_command) { int retval = ERROR_OK; - if (CMD_ARGC == 1) - { + if (CMD_ARGC == 1) { retval = find_target(CMD_CTX, CMD_ARGV[0]); if (retval == ERROR_OK) { /* we're done! */ @@ -1905,13 +2235,12 @@ COMMAND_HANDLER(handle_targets_command) struct target *target = all_targets; command_print(CMD_CTX, " TargetName Type Endian TapName State "); command_print(CMD_CTX, "-- ------------------ ---------- ------ ------------------ ------------"); - while (target) - { + while (target) { const char *state; char marker = ' '; if (target->tap->enabled) - state = target_state_name( target ); + state = target_state_name(target); else state = "tap-disabled"; @@ -1947,53 +2276,47 @@ static int runSrstDeasserted; static int sense_handler(void) { - static int prevSrstAsserted = 0; - static int prevPowerdropout = 0; + static int prevSrstAsserted; + static int prevPowerdropout; - int retval; - if ((retval = jtag_power_dropout(&powerDropout)) != ERROR_OK) + int retval = jtag_power_dropout(&powerDropout); + if (retval != ERROR_OK) return retval; int powerRestored; powerRestored = prevPowerdropout && !powerDropout; if (powerRestored) - { runPowerRestore = 1; - } long long current = timeval_ms(); - static long long lastPower = 0; + static long long lastPower; int waitMore = lastPower + 2000 > current; - if (powerDropout && !waitMore) - { + if (powerDropout && !waitMore) { runPowerDropout = 1; lastPower = current; } - if ((retval = jtag_srst_asserted(&srstAsserted)) != ERROR_OK) + retval = jtag_srst_asserted(&srstAsserted); + if (retval != ERROR_OK) return retval; int srstDeasserted; srstDeasserted = prevSrstAsserted && !srstAsserted; - static long long lastSrst = 0; + static long long lastSrst; waitMore = lastSrst + 2000 > current; - if (srstDeasserted && !waitMore) - { + if (srstDeasserted && !waitMore) { runSrstDeasserted = 1; lastSrst = current; } if (!prevSrstAsserted && srstAsserted) - { runSrstAsserted = 1; - } prevSrstAsserted = srstAsserted; prevPowerdropout = powerDropout; - if (srstDeasserted || powerRestored) - { + if (srstDeasserted || powerRestored) { /* Other than logging the event we can't do anything here. * Issuing a reset is a particularly bad idea as we might * be inside a reset already. @@ -2003,25 +2326,20 @@ static int sense_handler(void) return ERROR_OK; } -static int backoff_times = 0; -static int backoff_count = 0; - /* process target state changes */ static int handle_target(void *priv) { Jim_Interp *interp = (Jim_Interp *)priv; int retval = ERROR_OK; - if (!is_jtag_poll_safe()) - { + if (!is_jtag_poll_safe()) { /* polling is disabled currently */ return ERROR_OK; } /* we do not want to recurse here... */ - static int recursive = 0; - if (! recursive) - { + static int recursive; + if (!recursive) { recursive = 1; sense_handler(); /* danger! running these procedures can trigger srst assertions and power dropouts. @@ -2029,31 +2347,26 @@ static int handle_target(void *priv) * clearing the flags after running these events. */ int did_something = 0; - if (runSrstAsserted) - { + if (runSrstAsserted) { LOG_INFO("srst asserted detected, running srst_asserted proc."); Jim_Eval(interp, "srst_asserted"); did_something = 1; } - if (runSrstDeasserted) - { + if (runSrstDeasserted) { Jim_Eval(interp, "srst_deasserted"); did_something = 1; } - if (runPowerDropout) - { + if (runPowerDropout) { LOG_INFO("Power dropout detected, running power_dropout proc."); Jim_Eval(interp, "power_dropout"); did_something = 1; } - if (runPowerRestore) - { + if (runPowerRestore) { Jim_Eval(interp, "power_restore"); did_something = 1; } - if (did_something) - { + if (did_something) { /* clear detect flags */ sense_handler(); } @@ -2068,37 +2381,39 @@ static int handle_target(void *priv) recursive = 0; } - if (backoff_times > backoff_count) - { - /* do not poll this time as we failed previously */ - backoff_count++; - return ERROR_OK; - } - backoff_count = 0; - /* Poll targets for state changes unless that's globally disabled. * Skip targets that are currently disabled. */ for (struct target *target = all_targets; is_jtag_poll_safe() && target; - target = target->next) - { + target = target->next) { + + if (!target_was_examined(target)) + continue; + if (!target->tap->enabled) continue; + if (target->backoff.times > target->backoff.count) { + /* do not poll this time as we failed previously */ + target->backoff.count++; + continue; + } + target->backoff.count = 0; + /* only poll target if we've got power and srst isn't asserted */ - if (!powerDropout && !srstAsserted) - { + if (!powerDropout && !srstAsserted) { /* polling may fail silently until the target has been examined */ - if ((retval = target_poll(target)) != ERROR_OK) - { + retval = target_poll(target); + if (retval != ERROR_OK) { /* 100ms polling interval. Increase interval between polling up to 5000ms */ - if (backoff_times * polling_interval < 5000) - { - backoff_times *= 2; - backoff_times++; + if (target->backoff.times * polling_interval < 5000) { + target->backoff.times *= 2; + target->backoff.times++; } - LOG_USER("Polling target failed, GDB will be halted. Polling again in %dms", backoff_times * polling_interval); + 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. @@ -2107,11 +2422,19 @@ static int handle_target(void *priv) return retval; } /* Since we succeeded, we reset backoff count */ - if (backoff_times > 0) - { - LOG_USER("Polling succeeded again"); + if (target->backoff.times > 0) { + LOG_USER("Polling target %s succeeded again, 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; + return retval; + } } - backoff_times = 0; + + target->backoff.times = 0; } } @@ -2130,21 +2453,18 @@ COMMAND_HANDLER(handle_reg_command) target = get_current_target(CMD_CTX); /* list all available registers for the current target */ - if (CMD_ARGC == 0) - { + if (CMD_ARGC == 0) { struct reg_cache *cache = target->reg_cache; count = 0; - while (cache) - { + while (cache) { unsigned i; command_print(CMD_CTX, "===== %s", cache->name); for (i = 0, reg = cache->reg_list; i < cache->num_regs; - i++, reg++, count++) - { + i++, reg++, count++) { /* only print cached values if they are valid */ if (reg->valid) { value = buf_to_str(reg->value, @@ -2170,20 +2490,16 @@ COMMAND_HANDLER(handle_reg_command) } /* access a single register by its ordinal number */ - if ((CMD_ARGV[0][0] >= '0') && (CMD_ARGV[0][0] <= '9')) - { + if ((CMD_ARGV[0][0] >= '0') && (CMD_ARGV[0][0] <= '9')) { unsigned num; COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], num); struct reg_cache *cache = target->reg_cache; count = 0; - while (cache) - { + while (cache) { unsigned i; - for (i = 0; i < cache->num_regs; i++) - { - if (count++ == num) - { + for (i = 0; i < cache->num_regs; i++) { + if (count++ == num) { reg = &cache->reg_list[i]; break; } @@ -2193,17 +2509,16 @@ COMMAND_HANDLER(handle_reg_command) cache = cache->next; } - if (!reg) - { - command_print(CMD_CTX, "%i is out of bounds, the current target has only %i registers (0 - %i)", num, count, count - 1); + if (!reg) { + command_print(CMD_CTX, "%i is out of bounds, the current target " + "has only %i registers (0 - %i)", num, count, count - 1); return ERROR_OK; } - } else /* access a single register by its name */ - { + } else { + /* access a single register by its name */ reg = register_get_by_name(target->reg_cache, CMD_ARGV[0], 1); - if (!reg) - { + if (!reg) { command_print(CMD_CTX, "register %s not found in current target", CMD_ARGV[0]); return ERROR_OK; } @@ -2212,15 +2527,13 @@ COMMAND_HANDLER(handle_reg_command) assert(reg != NULL); /* give clang a hint that we *know* reg is != NULL here */ /* display a register */ - if ((CMD_ARGC == 1) || ((CMD_ARGC == 2) && !((CMD_ARGV[1][0] >= '0') && (CMD_ARGV[1][0] <= '9')))) - { + if ((CMD_ARGC == 1) || ((CMD_ARGC == 2) && !((CMD_ARGV[1][0] >= '0') + && (CMD_ARGV[1][0] <= '9')))) { if ((CMD_ARGC == 2) && (strcmp(CMD_ARGV[1], "force") == 0)) reg->valid = 0; if (reg->valid == 0) - { reg->type->get(reg); - } value = buf_to_str(reg->value, reg->size, 16); command_print(CMD_CTX, "%s (/%i): 0x%s", reg->name, (int)(reg->size), value); free(value); @@ -2228,8 +2541,7 @@ COMMAND_HANDLER(handle_reg_command) } /* set register value */ - if (CMD_ARGC == 2) - { + if (CMD_ARGC == 2) { uint8_t *buf = malloc(DIV_ROUND_UP(reg->size, 8)); if (buf == NULL) return ERROR_FAIL; @@ -2246,9 +2558,7 @@ COMMAND_HANDLER(handle_reg_command) return ERROR_OK; } - command_print(CMD_CTX, "usage: reg <#|name> [value]"); - - return ERROR_OK; + return ERROR_COMMAND_SYNTAX_ERROR; } COMMAND_HANDLER(handle_poll_command) @@ -2256,8 +2566,7 @@ COMMAND_HANDLER(handle_poll_command) int retval = ERROR_OK; struct target *target = get_current_target(CMD_CTX); - if (CMD_ARGC == 0) - { + if (CMD_ARGC == 0) { command_print(CMD_CTX, "background polling: %s", jtag_poll_get_enabled() ? "on" : "off"); command_print(CMD_CTX, "TAP: %s (%s)", @@ -2265,21 +2574,18 @@ COMMAND_HANDLER(handle_poll_command) target->tap->enabled ? "enabled" : "disabled"); if (!target->tap->enabled) return ERROR_OK; - if ((retval = target_poll(target)) != ERROR_OK) + retval = target_poll(target); + if (retval != ERROR_OK) return retval; - if ((retval = target_arch_state(target)) != ERROR_OK) + retval = target_arch_state(target); + if (retval != ERROR_OK) return retval; - } - else if (CMD_ARGC == 1) - { + } else if (CMD_ARGC == 1) { bool enable; COMMAND_PARSE_ON_OFF(CMD_ARGV[0], enable); jtag_poll_set_enabled(enable); - } - else - { + } else return ERROR_COMMAND_SYNTAX_ERROR; - } return retval; } @@ -2289,17 +2595,11 @@ COMMAND_HANDLER(handle_wait_halt_command) if (CMD_ARGC > 1) return ERROR_COMMAND_SYNTAX_ERROR; - unsigned ms = 5000; - if (1 == CMD_ARGC) - { + unsigned ms = DEFAULT_HALT_TIMEOUT; + if (1 == CMD_ARGC) { int retval = parse_uint(CMD_ARGV[0], &ms); if (ERROR_OK != retval) - { - command_print(CMD_CTX, "usage: %s [seconds]", CMD_NAME); return ERROR_COMMAND_SYNTAX_ERROR; - } - // convert seconds (given) to milliseconds (needed) - ms *= 1000; } struct target *target = get_current_target(CMD_CTX); @@ -2318,32 +2618,26 @@ int target_wait_state(struct target *target, enum target_state state, int ms) long long then = 0, cur; int once = 1; - for (;;) - { - if ((retval = target_poll(target)) != ERROR_OK) + for (;;) { + retval = target_poll(target); + if (retval != ERROR_OK) return retval; if (target->state == state) - { break; - } cur = timeval_ms(); - if (once) - { + if (once) { once = 0; then = timeval_ms(); LOG_DEBUG("waiting for target %s...", - Jim_Nvp_value2name_simple(nvp_target_state,state)->name); + Jim_Nvp_value2name_simple(nvp_target_state, state)->name); } if (cur-then > 500) - { keep_alive(); - } - if ((cur-then) > ms) - { + if ((cur-then) > ms) { LOG_ERROR("timed out while waiting for target %s", - Jim_Nvp_value2name_simple(nvp_target_state,state)->name); + Jim_Nvp_value2name_simple(nvp_target_state, state)->name); return ERROR_FAIL; } } @@ -2360,8 +2654,7 @@ COMMAND_HANDLER(handle_halt_command) if (ERROR_OK != retval) return retval; - if (CMD_ARGC == 1) - { + if (CMD_ARGC == 1) { unsigned wait_local; retval = parse_uint(CMD_ARGV[0], &wait_local); if (ERROR_OK != retval) @@ -2379,7 +2672,7 @@ COMMAND_HANDLER(handle_soft_reset_halt_command) LOG_USER("requesting target halt and executing a soft reset"); - target->type->soft_reset_halt(target); + target_soft_reset_halt(target); return ERROR_OK; } @@ -2390,13 +2683,11 @@ COMMAND_HANDLER(handle_reset_command) return ERROR_COMMAND_SYNTAX_ERROR; enum target_reset_mode reset_mode = RESET_RUN; - if (CMD_ARGC == 1) - { + if (CMD_ARGC == 1) { const Jim_Nvp *n; n = Jim_Nvp_name2value_simple(nvp_reset_modes, CMD_ARGV[0]); - if ((n->name == NULL) || (n->value == RESET_UNKNOWN)) { + if ((n->name == NULL) || (n->value == RESET_UNKNOWN)) return ERROR_COMMAND_SYNTAX_ERROR; - } reset_mode = n->value; } @@ -2412,14 +2703,12 @@ COMMAND_HANDLER(handle_resume_command) return ERROR_COMMAND_SYNTAX_ERROR; struct target *target = get_current_target(CMD_CTX); - target_handle_event(target, TARGET_EVENT_OLD_pre_resume); /* 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; - if (CMD_ARGC == 1) - { + if (CMD_ARGC == 1) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); current = 0; } @@ -2439,8 +2728,7 @@ COMMAND_HANDLER(handle_step_command) * handle breakpoints, debugging */ uint32_t addr = 0; int current_pc = 1; - if (CMD_ARGC == 1) - { + if (CMD_ARGC == 1) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); current_pc = 0; } @@ -2462,19 +2750,23 @@ static void handle_md_output(struct command_context *cmd_ctx, const char *value_fmt; switch (size) { - case 4: value_fmt = "%8.8x "; break; - case 2: value_fmt = "%4.4x "; break; - case 1: value_fmt = "%2.2x "; break; + case 4: + value_fmt = "%8.8x "; + break; + case 2: + value_fmt = "%4.4x "; + break; + case 1: + value_fmt = "%2.2x "; + break; default: /* "can't happen", caller checked */ LOG_ERROR("invalid memory read size: %u", size); return; } - for (unsigned i = 0; i < count; i++) - { - if (i % line_modulo == 0) - { + for (unsigned i = 0; i < count; i++) { + if (i % line_modulo == 0) { output_len += snprintf(output + output_len, sizeof(output) - output_len, "0x%8.8x: ", @@ -2484,16 +2776,20 @@ static void handle_md_output(struct command_context *cmd_ctx, uint32_t value = 0; const uint8_t *value_ptr = buffer + i * size; switch (size) { - case 4: value = target_buffer_get_u32(target, value_ptr); break; - case 2: value = target_buffer_get_u16(target, value_ptr); break; - case 1: value = *value_ptr; + case 4: + value = target_buffer_get_u32(target, value_ptr); + break; + case 2: + value = target_buffer_get_u16(target, value_ptr); + break; + case 1: + value = *value_ptr; } output_len += snprintf(output + output_len, sizeof(output) - output_len, value_fmt, value); - if ((i % line_modulo == line_modulo - 1) || (i == count - 1)) - { + if ((i % line_modulo == line_modulo - 1) || (i == count - 1)) { command_print(cmd_ctx, "%s", output); output_len = 0; } @@ -2507,28 +2803,30 @@ COMMAND_HANDLER(handle_md_command) unsigned size = 0; switch (CMD_NAME[2]) { - case 'w': size = 4; break; - case 'h': size = 2; break; - case 'b': size = 1; break; - default: return ERROR_COMMAND_SYNTAX_ERROR; + case 'w': + size = 4; + break; + case 'h': + size = 2; + break; + case 'b': + size = 1; + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; } - bool physical=strcmp(CMD_ARGV[0], "phys")==0; + 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); - if (physical) - { + if (physical) { CMD_ARGC--; CMD_ARGV++; - fn=target_read_phys_memory; + fn = target_read_phys_memory; } else - { - fn=target_read_memory; - } + fn = target_read_memory; if ((CMD_ARGC < 1) || (CMD_ARGC > 2)) - { return ERROR_COMMAND_SYNTAX_ERROR; - } uint32_t address; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], address); @@ -2552,12 +2850,6 @@ 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); -} - static int target_fill_mem(struct target *target, uint32_t address, target_write_fn fn, @@ -2571,24 +2863,21 @@ static int target_fill_mem(struct target *target, * to fill large memory areas with any sane speed */ const unsigned chunk_size = 16384; uint8_t *target_buf = malloc(chunk_size * data_size); - if (target_buf == NULL) - { + if (target_buf == NULL) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } - for (unsigned i = 0; i < chunk_size; i ++) - { - switch (data_size) - { + for (unsigned i = 0; i < chunk_size; i++) { + switch (data_size) { case 4: - target_buffer_set_u32(target, target_buf + i*data_size, b); + target_buffer_set_u32(target, target_buf + i * data_size, b); break; case 2: - target_buffer_set_u16(target, target_buf + i*data_size, b); + target_buffer_set_u16(target, target_buf + i * data_size, b); break; case 1: - target_buffer_set_u8(target, target_buf + i*data_size, b); + target_buffer_set_u8(target, target_buf + i * data_size, b); break; default: exit(-1); @@ -2597,19 +2886,14 @@ static int target_fill_mem(struct target *target, int retval = ERROR_OK; - for (unsigned x = 0; x < c; x += chunk_size) - { + for (unsigned x = 0; x < c; x += chunk_size) { unsigned current; current = c - x; if (current > chunk_size) - { current = chunk_size; - } retval = fn(target, address + x * data_size, data_size, current, target_buf); if (retval != ERROR_OK) - { break; - } /* avoid GDB timeouts */ keep_alive(); } @@ -2622,20 +2906,15 @@ static int target_fill_mem(struct target *target, COMMAND_HANDLER(handle_mw_command) { if (CMD_ARGC < 2) - { return ERROR_COMMAND_SYNTAX_ERROR; - } - bool physical=strcmp(CMD_ARGV[0], "phys")==0; + bool physical = strcmp(CMD_ARGV[0], "phys") == 0; target_write_fn fn; - if (physical) - { + if (physical) { CMD_ARGC--; CMD_ARGV++; - fn=target_write_phys_memory; + 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; @@ -2651,8 +2930,7 @@ COMMAND_HANDLER(handle_mw_command) struct target *target = get_current_target(CMD_CTX); unsigned wordsize; - switch (CMD_NAME[2]) - { + switch (CMD_NAME[2]) { case 'w': wordsize = 4; break; @@ -2677,26 +2955,21 @@ 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) - { + if (CMD_ARGC >= 2) { uint32_t addr; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], addr); image->base_address = addr; image->base_address_set = 1; - } - else + } else image->base_address_set = 0; image->start_address_set = 0; if (CMD_ARGC >= 4) - { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], *min_address); - } - if (CMD_ARGC == 5) - { + if (CMD_ARGC == 5) { COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], *max_address); - // use size (given) to find max (required) + /* use size (given) to find max (required) */ *max_address += *min_address; } @@ -2727,25 +3000,21 @@ 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; - } image_size = 0x0; retval = ERROR_OK; - for (i = 0; i < image.num_sections; i++) - { + for (i = 0; i < image.num_sections; i++) { buffer = malloc(image.sections[i].size); - if (buffer == NULL) - { + if (buffer == NULL) { command_print(CMD_CTX, "error allocating buffer for section (%d bytes)", (int)(image.sections[i].size)); break; } - if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK) - { + retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt); + if (retval != ERROR_OK) { free(buffer); break; } @@ -2755,37 +3024,34 @@ COMMAND_HANDLER(handle_load_image_command) /* DANGER!!! beware of unsigned comparision here!!! */ - if ((image.sections[i].base_address + buf_cnt >= min_address)&& - (image.sections[i].base_address < max_address)) - { - if (image.sections[i].base_address < min_address) - { + if ((image.sections[i].base_address + buf_cnt >= min_address) && + (image.sections[i].base_address < max_address)) { + + if (image.sections[i].base_address < min_address) { /* clip addresses below */ offset += min_address-image.sections[i].base_address; length -= offset; } if (image.sections[i].base_address + buf_cnt > max_address) - { length -= (image.sections[i].base_address + buf_cnt)-max_address; - } - if ((retval = target_write_buffer(target, image.sections[i].base_address + offset, length, buffer + offset)) != ERROR_OK) - { + retval = target_write_buffer(target, + image.sections[i].base_address + offset, length, buffer + offset); + if (retval != ERROR_OK) { free(buffer); break; } image_size += length; command_print(CMD_CTX, "%u bytes written at address 0x%8.8" PRIx32 "", - (unsigned int)length, - image.sections[i].base_address + offset); + (unsigned int)length, + image.sections[i].base_address + offset); } free(buffer); } - if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) - { + if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD_CTX, "downloaded %" PRIu32 " bytes " "in %fs (%0.3f KiB/s)", image_size, duration_elapsed(&bench), duration_kbps(&bench, image_size)); @@ -2800,7 +3066,7 @@ COMMAND_HANDLER(handle_load_image_command) COMMAND_HANDLER(handle_dump_image_command) { struct fileio fileio; - uint8_t buffer[560]; + uint8_t *buffer; int retval, retvaltemp; uint32_t address, size; struct duration bench; @@ -2812,35 +3078,37 @@ COMMAND_HANDLER(handle_dump_image_command) COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], address); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], size); + uint32_t buf_size = (size > 4096) ? 4096 : size; + buffer = malloc(buf_size); + if (!buffer) + return ERROR_FAIL; + retval = fileio_open(&fileio, CMD_ARGV[0], FILEIO_WRITE, FILEIO_BINARY); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { + free(buffer); return retval; + } duration_start(&bench); - retval = ERROR_OK; - while (size > 0) - { + while (size > 0) { size_t size_written; - uint32_t this_run_size = (size > 560) ? 560 : size; + uint32_t this_run_size = (size > buf_size) ? buf_size : size; retval = target_read_buffer(target, address, this_run_size, buffer); if (retval != ERROR_OK) - { break; - } retval = fileio_write(&fileio, this_run_size, buffer, &size_written); if (retval != ERROR_OK) - { break; - } size -= this_run_size; address += this_run_size; } - if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) - { + free(buffer); + + if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { int filesize; retval = fileio_size(&fileio, &filesize); if (retval != ERROR_OK) @@ -2850,7 +3118,8 @@ COMMAND_HANDLER(handle_dump_image_command) duration_elapsed(&bench), duration_kbps(&bench, filesize)); } - if ((retvaltemp = fileio_close(&fileio)) != ERROR_OK) + retvaltemp = fileio_close(&fileio); + if (retvaltemp != ERROR_OK) return retvaltemp; return retval; @@ -2871,12 +3140,9 @@ static COMMAND_HELPER(handle_verify_image_command_internal, int verify) struct target *target = get_current_target(CMD_CTX); if (CMD_ARGC < 1) - { return ERROR_COMMAND_SYNTAX_ERROR; - } - if (!target) - { + if (!target) { LOG_ERROR("no target selected"); return ERROR_FAIL; } @@ -2884,98 +3150,81 @@ static COMMAND_HELPER(handle_verify_image_command_internal, int verify) struct duration bench; duration_start(&bench); - if (CMD_ARGC >= 2) - { + if (CMD_ARGC >= 2) { uint32_t addr; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], addr); image.base_address = addr; image.base_address_set = 1; - } - else - { + } else { image.base_address_set = 0; image.base_address = 0x0; } image.start_address_set = 0; - if ((retval = image_open(&image, CMD_ARGV[0], (CMD_ARGC == 3) ? CMD_ARGV[2] : NULL)) != ERROR_OK) - { + retval = image_open(&image, CMD_ARGV[0], (CMD_ARGC == 3) ? CMD_ARGV[2] : NULL); + if (retval != ERROR_OK) return retval; - } image_size = 0x0; int diffs = 0; retval = ERROR_OK; - for (i = 0; i < image.num_sections; i++) - { + for (i = 0; i < image.num_sections; i++) { buffer = malloc(image.sections[i].size); - if (buffer == NULL) - { + if (buffer == NULL) { command_print(CMD_CTX, - "error allocating buffer for section (%d bytes)", - (int)(image.sections[i].size)); + "error allocating buffer for section (%d bytes)", + (int)(image.sections[i].size)); break; } - if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK) - { + retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt); + if (retval != ERROR_OK) { free(buffer); break; } - if (verify) - { + if (verify) { /* calculate checksum of image */ retval = image_calculate_checksum(buffer, buf_cnt, &checksum); - if (retval != ERROR_OK) - { + if (retval != ERROR_OK) { free(buffer); break; } retval = target_checksum_memory(target, image.sections[i].base_address, buf_cnt, &mem_checksum); - if (retval != ERROR_OK) - { + if (retval != ERROR_OK) { free(buffer); break; } - if (checksum != mem_checksum) - { + if (checksum != mem_checksum) { /* failed crc checksum, fall back to a binary compare */ uint8_t *data; 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; int count = buf_cnt; - if ((count % 4) == 0) - { + if ((count % 4) == 0) { size *= 4; count /= 4; } retval = target_read_memory(target, image.sections[i].base_address, size, count, data); - if (retval == ERROR_OK) - { + if (retval == ERROR_OK) { uint32_t t; - for (t = 0; t < buf_cnt; t++) - { - if (data[t] != buffer[t]) - { + for (t = 0; t < buf_cnt; t++) { + if (data[t] != buffer[t]) { command_print(CMD_CTX, "diff %d address 0x%08x. Was 0x%02x instead of 0x%02x", diffs, (unsigned)(t + image.sections[i].base_address), data[t], buffer[t]); - if (diffs++ >= 127) - { + if (diffs++ >= 127) { command_print(CMD_CTX, "More than 128 errors, the rest are not printed."); free(data); free(buffer); @@ -2987,8 +3236,7 @@ static COMMAND_HELPER(handle_verify_image_command_internal, int verify) } free(data); } - } else - { + } else { command_print(CMD_CTX, "address 0x%08" PRIx32 " length 0x%08zx", image.sections[i].base_address, buf_cnt); @@ -2998,16 +3246,11 @@ static COMMAND_HELPER(handle_verify_image_command_internal, int verify) image_size += buf_cnt; } if (diffs > 0) - { command_print(CMD_CTX, "No more differences found."); - } done: if (diffs > 0) - { retval = ERROR_FAIL; - } - if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) - { + if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD_CTX, "verified %" PRIu32 " bytes " "in %fs (%0.3f KiB/s)", image_size, duration_elapsed(&bench), duration_kbps(&bench, image_size)); @@ -3032,33 +3275,27 @@ static int handle_bp_command_list(struct command_context *cmd_ctx) { struct target *target = get_current_target(cmd_ctx); struct breakpoint *breakpoint = target->breakpoints; - while (breakpoint) - { - if (breakpoint->type == BKPT_SOFT) - { - char* buf = buf_to_str(breakpoint->orig_instr, + while (breakpoint) { + 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", breakpoint->address, breakpoint->length, breakpoint->set, buf); free(buf); - } - else - { + } else { if ((breakpoint->address == 0) && (breakpoint->asid != 0)) command_print(cmd_ctx, "Context breakpoint: 0x%8.8" PRIx32 ", 0x%x, %i", breakpoint->asid, breakpoint->length, breakpoint->set); - else if ((breakpoint->address != 0) && (breakpoint->asid != 0)) - { + else if ((breakpoint->address != 0) && (breakpoint->asid != 0)) { command_print(cmd_ctx, "Hybrid breakpoint(IVA): 0x%8.8" PRIx32 ", 0x%x, %i", breakpoint->address, breakpoint->length, breakpoint->set); command_print(cmd_ctx, "\t|--->linked with ContextID: 0x%8.8" PRIx32, breakpoint->asid); - } - else + } else command_print(cmd_ctx, "Breakpoint(IVA): 0x%8.8" PRIx32 ", 0x%x, %i", breakpoint->address, breakpoint->length, breakpoint->set); @@ -3074,35 +3311,27 @@ static int handle_bp_command_set(struct command_context *cmd_ctx, { struct target *target = get_current_target(cmd_ctx); - if (asid == 0) - { + if (asid == 0) { int retval = breakpoint_add(target, addr, length, hw); if (ERROR_OK == retval) command_print(cmd_ctx, "breakpoint set at 0x%8.8" PRIx32 "", addr); - else - { + else { LOG_ERROR("Failure setting breakpoint, the same address(IVA) is already used"); return retval; } - } - else if (addr == 0) - { + } else if (addr == 0) { int 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 - { + else { LOG_ERROR("Failure setting breakpoint, the same address(CONTEXTID) is already used"); return retval; } - } - else - { + } else { int retval = hybrid_breakpoint_add(target, addr, asid, length, hw); - if(ERROR_OK == retval) + if (ERROR_OK == retval) command_print(cmd_ctx, "Hybrid breakpoint set at 0x%8.8" PRIx32 "", asid); - else - { + else { LOG_ERROR("Failure setting breakpoint, the same address is already used"); return retval; } @@ -3116,8 +3345,8 @@ COMMAND_HANDLER(handle_bp_command) uint32_t asid; uint32_t length; int hw = BKPT_SOFT; - switch(CMD_ARGC) - { + + switch (CMD_ARGC) { case 0: return handle_bp_command_list(CMD_CTX); @@ -3128,8 +3357,7 @@ COMMAND_HANDLER(handle_bp_command) return handle_bp_command_set(CMD_CTX, addr, asid, length, hw); case 3: - if(strcmp(CMD_ARGV[2], "hw") == 0) - { + if (strcmp(CMD_ARGV[2], "hw") == 0) { hw = BKPT_HARD; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); @@ -3137,9 +3365,7 @@ COMMAND_HANDLER(handle_bp_command) asid = 0; return handle_bp_command_set(CMD_CTX, addr, asid, length, hw); - } - else if(strcmp(CMD_ARGV[2], "hw_ctx") == 0) - { + } else if (strcmp(CMD_ARGV[2], "hw_ctx") == 0) { hw = BKPT_HARD; COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], asid); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); @@ -3155,7 +3381,6 @@ COMMAND_HANDLER(handle_bp_command) return handle_bp_command_set(CMD_CTX, addr, asid, length, hw); default: - command_print(CMD_CTX, "usage: bp
[] ['hw'|'hw_ctx']"); return ERROR_COMMAND_SYNTAX_ERROR; } } @@ -3178,12 +3403,10 @@ COMMAND_HANDLER(handle_wp_command) { struct target *target = get_current_target(CMD_CTX); - if (CMD_ARGC == 0) - { + if (CMD_ARGC == 0) { struct watchpoint *watchpoint = target->watchpoints; - while (watchpoint) - { + while (watchpoint) { command_print(CMD_CTX, "address: 0x%8.8" PRIx32 ", len: 0x%8.8" PRIx32 ", r/w/a: %i, value: 0x%8.8" PRIx32 @@ -3204,17 +3427,15 @@ COMMAND_HANDLER(handle_wp_command) uint32_t data_value = 0x0; uint32_t data_mask = 0xffffffff; - switch (CMD_ARGC) - { + switch (CMD_ARGC) { case 5: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], data_mask); - // fall through + /* fall through */ case 4: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], data_value); - // fall through + /* fall through */ case 3: - switch (CMD_ARGV[2][0]) - { + switch (CMD_ARGV[2][0]) { case 'r': type = WPT_READ; break; @@ -3228,15 +3449,13 @@ COMMAND_HANDLER(handle_wp_command) LOG_ERROR("invalid watchpoint mode ('%c')", CMD_ARGV[2][0]); return ERROR_COMMAND_SYNTAX_ERROR; } - // fall through + /* fall through */ case 2: COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length); COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr); break; default: - command_print(CMD_CTX, "usage: wp [address length " - "[(r|w|a) [value [mask]]]]"); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -3262,7 +3481,6 @@ COMMAND_HANDLER(handle_rwp_command) return ERROR_OK; } - /** * Translate a virtual address to a physical address. * @@ -3296,8 +3514,7 @@ static void writeData(FILE *f, const void *data, size_t len) static void writeLong(FILE *f, int l) { int i; - for (i = 0; i < 4; i++) - { + for (i = 0; i < 4; i++) { char c = (l >> (i*8))&0xff; writeData(f, &c, 1); } @@ -3309,8 +3526,11 @@ 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) { uint32_t i; FILE *f = fopen(filename, "w"); @@ -3326,51 +3546,59 @@ static void writeGmon(uint32_t *samples, uint32_t sampleNum, const char *filenam 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); - if (buckets == NULL) - { + /* 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); - for (i = 0; i < sampleNum;i++) - { + memset(buckets, 0, sizeof(int) * numBuckets); + for (i = 0; i < sampleNum; i++) { uint32_t address = samples[i]; - long long a = address-min; - long long b = length-1; - long long c = addressSpace-1; - int index_t = (a*b)/c; /* danger!!!! int32 overflows */ + + if ((address < min) || (max <= address)) + continue; + + long long a = address - min; + 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, 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, numBuckets); /* # of buckets */ + writeLong(f, 100); /* KLUDGE! We lie, ca. 100Hz best case. */ writeString(f, "seconds"); for (i = 0; i < (15-strlen("seconds")); i++) writeData(f, &zero, 1); @@ -3378,27 +3606,21 @@ 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); - if (data != NULL) - { - for (i = 0; i < length;i++) - { + char *data = malloc(2 * numBuckets); + if (data != NULL) { + for (i = 0; i < numBuckets; i++) { int val; val = buckets[i]; if (val > 65535) - { val = 65535; - } - data[i*2]=val&0xff; - data[i*2 + 1]=(val >> 8)&0xff; + data[i * 2] = val&0xff; + data[i * 2 + 1] = (val >> 8) & 0xff; } free(buckets); - writeData(f, data, length * 2); + writeData(f, data, numBuckets * 2); free(data); } else - { free(buckets); - } fclose(f); } @@ -3408,94 +3630,74 @@ 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..."); - - static const int maxSample = 10000; - uint32_t *samples = malloc(sizeof(uint32_t)*maxSample); - if (samples == NULL) - return ERROR_OK; - - 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); + assert(num_of_samples <= MAX_PROFILE_SAMPLE_NUM); - int retval = ERROR_OK; - for (;;) - { - target_poll(target); - if (target->state == TARGET_HALTED) - { - uint32_t t=*((uint32_t *)reg->value); - samples[numSamples++]=t; - retval = target_resume(target, 1, 0, 0, 0); /* current pc, addr = 0, do not handle breakpoints, not debugging */ - 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. */ - if ((retval = target_halt(target)) != 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; + 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; } + } - 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); - if ((retval = target_poll(target)) != ERROR_OK) - { - free(samples); - return retval; - } - if (target->state == TARGET_HALTED) - { - target_resume(target, 1, 0, 0, 0); /* current pc, addr = 0, do not handle breakpoints, not debugging */ - } - if ((retval = target_poll(target)) != ERROR_OK) - { - free(samples); - return retval; - } - writeGmon(samples, numSamples, CMD_ARGV[1]); - command_print(CMD_CTX, "Wrote %s", CMD_ARGV[1]); - break; - } + retval = target_poll(target); + if (retval != ERROR_OK) { + free(samples); + return retval; } - free(samples); + 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); + } + + write_gmon(samples, num_of_samples, CMD_ARGV[1], + with_range, start_address, end_address); + command_print(CMD_CTX, "Wrote %s", CMD_ARGV[1]); + + free(samples); return retval; } -static int new_int_array_element(Jim_Interp * interp, const char *varname, int idx, uint32_t val) +static int new_int_array_element(Jim_Interp *interp, const char *varname, int idx, uint32_t val) { char *namebuf; Jim_Obj *nameObjPtr, *valObjPtr; @@ -3507,8 +3709,7 @@ static int new_int_array_element(Jim_Interp * interp, const char *varname, int i nameObjPtr = Jim_NewStringObj(interp, namebuf, -1); valObjPtr = Jim_NewIntObj(interp, val); - if (!nameObjPtr || !valObjPtr) - { + if (!nameObjPtr || !valObjPtr) { free(namebuf); return JIM_ERR; } @@ -3529,16 +3730,15 @@ static int jim_mem2array(Jim_Interp *interp, int argc, Jim_Obj *const *argv) struct target *target; context = current_command_context(interp); - assert (context != NULL); + assert(context != NULL); target = get_current_target(context); - if (target == NULL) - { + if (target == NULL) { LOG_ERROR("mem2array: no current target"); return JIM_ERR; } - return target_mem2array(interp, target, argc-1, argv + 1); + return target_mem2array(interp, target, argc - 1, argv + 1); } static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, Jim_Obj *const *argv) @@ -3567,20 +3767,17 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, e = Jim_GetLong(interp, argv[1], &l); width = l; - if (e != JIM_OK) { + if (e != JIM_OK) return e; - } e = Jim_GetLong(interp, argv[2], &l); addr = l; - if (e != JIM_OK) { + if (e != JIM_OK) return e; - } e = Jim_GetLong(interp, argv[3], &l); len = l; - if (e != JIM_OK) { + if (e != JIM_OK) return e; - } switch (width) { case 8: width = 1; @@ -3643,9 +3840,8 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, /* Slurp... in buffer size chunks */ count = len; /* in objects.. */ - if (count > (buffersize/width)) { - count = (buffersize/width); - } + if (count > (buffersize / width)) + count = (buffersize / width); retval = target_read_memory(target, addr, width, count, buffer); if (retval != ERROR_OK) { @@ -3660,7 +3856,7 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, break; } else { v = 0; /* shut up gcc */ - for (i = 0 ;i < count ;i++, n++) { + for (i = 0; i < count ; i++, n++) { switch (width) { case 4: v = target_buffer_get_u32(target, &buffer[i*width]); @@ -3675,6 +3871,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; } } @@ -3685,7 +3882,7 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, return e; } -static int get_int_array_element(Jim_Interp * interp, const char *varname, int idx, uint32_t *val) +static int get_int_array_element(Jim_Interp *interp, const char *varname, int idx, uint32_t *val) { char *namebuf; Jim_Obj *nameObjPtr, *valObjPtr; @@ -3697,8 +3894,7 @@ static int get_int_array_element(Jim_Interp * interp, const char *varname, int i return JIM_ERR; nameObjPtr = Jim_NewStringObj(interp, namebuf, -1); - if (!nameObjPtr) - { + if (!nameObjPtr) { free(namebuf); return JIM_ERR; } @@ -3722,7 +3918,7 @@ static int jim_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv) struct target *target; context = current_command_context(interp); - assert (context != NULL); + assert(context != NULL); target = get_current_target(context); if (target == NULL) { @@ -3730,7 +3926,7 @@ static int jim_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return JIM_ERR; } - return target_array2mem(interp,target, argc-1, argv + 1); + return target_array2mem(interp, target, argc-1, argv + 1); } static int target_array2mem(Jim_Interp *interp, struct target *target, @@ -3760,20 +3956,17 @@ static int target_array2mem(Jim_Interp *interp, struct target *target, e = Jim_GetLong(interp, argv[1], &l); width = l; - if (e != JIM_OK) { + if (e != JIM_OK) return e; - } e = Jim_GetLong(interp, argv[2], &l); addr = l; - if (e != JIM_OK) { + if (e != JIM_OK) return e; - } e = Jim_GetLong(interp, argv[3], &l); len = l; - if (e != JIM_OK) { + if (e != JIM_OK) return e; - } switch (width) { case 8: width = 1; @@ -3786,23 +3979,27 @@ static int target_array2mem(Jim_Interp *interp, struct target *target, break; default: Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - Jim_AppendStrings(interp, Jim_GetResult(interp), "Invalid width param, must be 8/16/32", NULL); + Jim_AppendStrings(interp, Jim_GetResult(interp), + "Invalid width param, must be 8/16/32", NULL); return JIM_ERR; } if (len == 0) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: zero width read?", NULL); + Jim_AppendStrings(interp, Jim_GetResult(interp), + "array2mem: zero width read?", NULL); return JIM_ERR; } if ((addr + (len * width)) < addr) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: addr + len - wraps to zero?", NULL); + Jim_AppendStrings(interp, Jim_GetResult(interp), + "array2mem: addr + len - wraps to zero?", NULL); return JIM_ERR; } /* absurd transfer size? */ if (len > 65536) { Jim_SetResult(interp, Jim_NewEmptyStringObj(interp)); - Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: absurd > 64K item request", NULL); + Jim_AppendStrings(interp, Jim_GetResult(interp), + "array2mem: absurd > 64K item request", NULL); return JIM_ERR; } @@ -3836,19 +4033,18 @@ static int target_array2mem(Jim_Interp *interp, struct target *target, /* Slurp... in buffer size chunks */ count = len; /* in objects.. */ - if (count > (buffersize/width)) { - count = (buffersize/width); - } + if (count > (buffersize / width)) + count = (buffersize / width); v = 0; /* shut up gcc */ - for (i = 0 ;i < count ;i++, n++) { + for (i = 0; i < count; i++, n++) { get_int_array_element(interp, varname, n, &v); switch (width) { case 4: - target_buffer_set_u32(target, &buffer[i*width], v); + target_buffer_set_u32(target, &buffer[i * width], v); break; case 2: - target_buffer_set_u16(target, &buffer[i*width], v); + target_buffer_set_u16(target, &buffer[i * width], v); break; case 1: buffer[i] = v & 0x0ff; @@ -3869,6 +4065,7 @@ static int target_array2mem(Jim_Interp *interp, struct target *target, e = JIM_ERR; break; } + addr += count * width; } free(buffer); @@ -3894,10 +4091,9 @@ void target_handle_event(struct target *target, enum target_event e) e, Jim_Nvp_value2name_simple(nvp_target_event, e)->name, Jim_GetString(teap->body, NULL)); - if (Jim_EvalObj(teap->interp, teap->body) != JIM_OK) - { + if (Jim_EvalObj(teap->interp, teap->body) != JIM_OK) { Jim_MakeErrorMessage(teap->interp); - command_print(NULL,"%s\n", Jim_GetString(Jim_GetResult(teap->interp), NULL)); + command_print(NULL, "%s\n", Jim_GetString(Jim_GetResult(teap->interp), NULL)); } } } @@ -3925,7 +4121,6 @@ enum target_cfg_param { TCFG_WORK_AREA_SIZE, TCFG_WORK_AREA_BACKUP, TCFG_ENDIAN, - TCFG_VARIANT, TCFG_COREID, TCFG_CHAIN_POSITION, TCFG_DBGBASE, @@ -3940,7 +4135,6 @@ 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 }, @@ -3953,7 +4147,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 ... */ @@ -3988,7 +4181,7 @@ static int target_configure(Jim_GetOptInfo *goi, struct target *target) "not settable: %s", n->name); return JIM_ERR; } else { - no_params: +no_params: if (goi->argc != 0) { Jim_WrongNumArgs(goi->interp, goi->argc, goi->argv, @@ -4030,9 +4223,8 @@ static int target_configure(Jim_GetOptInfo *goi, struct target *target) teap = target->event_action; /* replace existing? */ while (teap) { - if (teap->event == (enum target_event)n->value) { + if (teap->event == (enum target_event)n->value) break; - } teap = teap->next; } @@ -4046,9 +4238,8 @@ static int target_configure(Jim_GetOptInfo *goi, struct target *target) teap->event = n->value; teap->interp = goi->interp; Jim_GetOpt_Obj(goi, &o); - if (teap->body) { + if (teap->body) Jim_DecrRefCount(teap->interp, teap->body); - } teap->body = Jim_DuplicateObj(goi->interp, o); /* * FIXME: @@ -4062,8 +4253,7 @@ static int target_configure(Jim_GetOptInfo *goi, struct target *target) */ Jim_IncrRefCount(teap->body); - if (!replace) - { + if (!replace) { /* add to head of event list */ teap->next = target->event_action; target->event_action = teap; @@ -4071,11 +4261,10 @@ static int target_configure(Jim_GetOptInfo *goi, struct target *target) Jim_SetEmptyResult(goi->interp); } else { /* get */ - if (teap == NULL) { + if (teap == NULL) Jim_SetEmptyResult(goi->interp); - } else { + else Jim_SetResult(goi->interp, Jim_DuplicateObj(goi->interp, teap->body)); - } } } /* loop for more */ @@ -4085,15 +4274,13 @@ static int target_configure(Jim_GetOptInfo *goi, struct target *target) if (goi->isconfigure) { target_free_all_working_areas(target); e = Jim_GetOpt_Wide(goi, &w); - if (e != JIM_OK) { + if (e != JIM_OK) return e; - } target->working_area_virt = w; target->working_area_virt_spec = true; } else { - if (goi->argc != 0) { + if (goi->argc != 0) goto no_params; - } } Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->working_area_virt)); /* loop for more */ @@ -4103,15 +4290,13 @@ static int target_configure(Jim_GetOptInfo *goi, struct target *target) if (goi->isconfigure) { target_free_all_working_areas(target); e = Jim_GetOpt_Wide(goi, &w); - if (e != JIM_OK) { + if (e != JIM_OK) return e; - } target->working_area_phys = w; target->working_area_phys_spec = true; } else { - if (goi->argc != 0) { + if (goi->argc != 0) goto no_params; - } } Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->working_area_phys)); /* loop for more */ @@ -4121,14 +4306,12 @@ static int target_configure(Jim_GetOptInfo *goi, struct target *target) if (goi->isconfigure) { target_free_all_working_areas(target); e = Jim_GetOpt_Wide(goi, &w); - if (e != JIM_OK) { + if (e != JIM_OK) return e; - } target->working_area_size = w; } else { - if (goi->argc != 0) { + if (goi->argc != 0) goto no_params; - } } Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->working_area_size)); /* loop for more */ @@ -4138,15 +4321,13 @@ static int target_configure(Jim_GetOptInfo *goi, struct target *target) if (goi->isconfigure) { target_free_all_working_areas(target); e = Jim_GetOpt_Wide(goi, &w); - if (e != JIM_OK) { + if (e != JIM_OK) return e; - } /* make this exactly 1 or 0 */ target->backup_working_area = (!!w); } else { - if (goi->argc != 0) { + if (goi->argc != 0) goto no_params; - } } Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->backup_working_area)); /* loop for more e*/ @@ -4162,54 +4343,27 @@ static int target_configure(Jim_GetOptInfo *goi, struct target *target) } target->endianness = n->value; } else { - if (goi->argc != 0) { - goto no_params; - } - } - n = Jim_Nvp_value2name_simple(nvp_target_endian, target->endianness); - if (n->name == NULL) { - target->endianness = TARGET_LITTLE_ENDIAN; - n = Jim_Nvp_value2name_simple(nvp_target_endian, target->endianness); - } - Jim_SetResultString(goi->interp, n->name, -1); - /* loop for more */ - break; - - case TCFG_VARIANT: - if (goi->isconfigure) { - if (goi->argc < 1) { - Jim_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) { + if (goi->argc != 0) goto no_params; - } } - Jim_SetResultString(goi->interp, target->variant,-1); + n = Jim_Nvp_value2name_simple(nvp_target_endian, target->endianness); + if (n->name == NULL) { + target->endianness = TARGET_LITTLE_ENDIAN; + n = Jim_Nvp_value2name_simple(nvp_target_endian, target->endianness); + } + Jim_SetResultString(goi->interp, n->name, -1); /* loop for more */ break; case TCFG_COREID: if (goi->isconfigure) { e = Jim_GetOpt_Wide(goi, &w); - if (e != JIM_OK) { + if (e != JIM_OK) return e; - } target->coreid = (int32_t)w; } else { - if (goi->argc != 0) { + if (goi->argc != 0) goto no_params; - } } Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->working_area_size)); /* loop for more */ @@ -4221,19 +4375,16 @@ static int target_configure(Jim_GetOptInfo *goi, struct target *target) struct jtag_tap *tap; target_free_all_working_areas(target); e = Jim_GetOpt_Obj(goi, &o_t); - if (e != JIM_OK) { + if (e != JIM_OK) return e; - } tap = jtag_tap_by_jim_obj(goi->interp, o_t); - if (tap == NULL) { + if (tap == NULL) return JIM_ERR; - } /* make this exactly 1 or 0 */ target->tap = tap; } else { - if (goi->argc != 0) { + if (goi->argc != 0) goto no_params; - } } Jim_SetResultString(goi->interp, target->tap->dotted_name, -1); /* loop for more e*/ @@ -4241,15 +4392,13 @@ static int target_configure(Jim_GetOptInfo *goi, struct target *target) case TCFG_DBGBASE: if (goi->isconfigure) { e = Jim_GetOpt_Wide(goi, &w); - if (e != JIM_OK) { + if (e != JIM_OK) return e; - } target->dbgbase = (uint32_t)w; target->dbgbase_set = true; } else { - if (goi->argc != 0) { + if (goi->argc != 0) goto no_params; - } } Jim_SetResult(goi->interp, Jim_NewIntObj(goi->interp, target->dbgbase)); /* loop for more */ @@ -4258,11 +4407,9 @@ static int target_configure(Jim_GetOptInfo *goi, struct target *target) case TCFG_RTOS: /* RTOS */ { - int result = rtos_create( goi, target ); - if ( result != JIM_OK ) - { + int result = rtos_create(goi, target); + if (result != JIM_OK) return result; - } } /* loop for more */ break; @@ -4274,16 +4421,14 @@ static int target_configure(Jim_GetOptInfo *goi, struct target *target) return JIM_OK; } -static int -jim_target_configure(Jim_Interp *interp, int argc, Jim_Obj *const *argv) +static int jim_target_configure(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { Jim_GetOptInfo goi; 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 < need_args) { Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, goi.isconfigure ? "missing: -option VALUE ..." @@ -4301,19 +4446,17 @@ static int jim_target_mw(Jim_Interp *interp, int argc, Jim_Obj *const *argv) Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); - if (goi.argc < 2 || goi.argc > 4) - { + if (goi.argc < 2 || goi.argc > 4) { Jim_SetResultFormatted(goi.interp, "usage: %s [phys]
[]", cmd_name); return JIM_ERR; } target_write_fn fn; - fn = target_write_memory_fast; + fn = target_write_memory; int e; - if (strcmp(Jim_GetString(argv[1], NULL), "phys") == 0) - { + if (strcmp(Jim_GetString(argv[1], NULL), "phys") == 0) { /* consume it */ struct Jim_Obj *obj; e = Jim_GetOpt_Obj(&goi, &obj); @@ -4334,8 +4477,7 @@ static int jim_target_mw(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return e; jim_wide c = 1; - if (goi.argc == 1) - { + if (goi.argc == 1) { e = Jim_GetOpt_Wide(&goi, &c); if (e != JIM_OK) return e; @@ -4343,21 +4485,17 @@ static int jim_target_mw(Jim_Interp *interp, int argc, Jim_Obj *const *argv) /* all args must be consumed */ if (goi.argc != 0) - { return JIM_ERR; - } struct target *target = Jim_CmdPrivData(goi.interp); unsigned data_size; - if (strcasecmp(cmd_name, "mww") == 0) { + if (strcasecmp(cmd_name, "mww") == 0) data_size = 4; - } - else if (strcasecmp(cmd_name, "mwh") == 0) { + else if (strcasecmp(cmd_name, "mwh") == 0) data_size = 2; - } - else if (strcasecmp(cmd_name, "mwb") == 0) { + else if (strcasecmp(cmd_name, "mwb") == 0) data_size = 1; - } else { + else { LOG_ERROR("command '%s' unknown: ", cmd_name); return JIM_ERR; } @@ -4365,6 +4503,34 @@ static int jim_target_mw(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return (target_fill_mem(target, a, fn, data_size, b, c) == ERROR_OK) ? JIM_OK : JIM_ERR; } +/** +* @brief Reads an array of words/halfwords/bytes from target memory starting at specified address. +* +* Usage: mdw [phys]
[] - for 32 bit reads +* mdh [phys]
[] - for 16 bit reads +* mdb [phys]
[] - for 8 bit reads +* +* Count defaults to 1. +* +* Calls target_read_memory or target_read_phys_memory depending on +* the presence of the "phys" argument +* Reads the target memory in blocks of max. 32 bytes, and returns an array of ints formatted +* to int representation in base16. +* Also outputs read data in a human readable form using command_print +* +* @param phys if present target_read_phys_memory will be used instead of target_read_memory +* @param address address where to start the read. May be specified in decimal or hex using the standard "0x" prefix +* @param count optional count parameter to read an array of values. If not specified, defaults to 1. +* @returns: JIM_ERR on error or JIM_OK on success and sets the result string to an array of ascii formatted numbers +* on success, with [] number of elements. +* +* In case of little endian target: +* Example1: "mdw 0x00000000" returns "10123456" +* Exmaple2: "mdh 0x00000000 1" returns "3456" +* Example3: "mdb 0x00000000" returns "56" +* Example4: "mdh 0x00000000 2" returns "3456 1012" +* Example5: "mdb 0x00000000 3" returns "56 34 12" +**/ static int jim_target_md(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { const char *cmd_name = Jim_GetString(argv[0], NULL); @@ -4372,8 +4538,7 @@ static int jim_target_md(Jim_Interp *interp, int argc, Jim_Obj *const *argv) Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); - if ((goi.argc < 1) || (goi.argc > 3)) - { + if ((goi.argc < 1) || (goi.argc > 3)) { Jim_SetResultFormatted(goi.interp, "usage: %s [phys]
[]", cmd_name); return JIM_ERR; @@ -4381,103 +4546,93 @@ 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); - fn=target_read_memory; + fn = target_read_memory; int e; - if (strcmp(Jim_GetString(argv[1], NULL), "phys") == 0) - { + if (strcmp(Jim_GetString(argv[1], NULL), "phys") == 0) { /* consume it */ struct Jim_Obj *obj; e = Jim_GetOpt_Obj(&goi, &obj); if (e != JIM_OK) return e; - fn=target_read_phys_memory; + fn = target_read_phys_memory; } - jim_wide a; - e = Jim_GetOpt_Wide(&goi, &a); - if (e != JIM_OK) { + /* Read address parameter */ + jim_wide addr; + e = Jim_GetOpt_Wide(&goi, &addr); + if (e != JIM_OK) return JIM_ERR; - } - jim_wide c; + + /* If next parameter exists, read it out as the count parameter, if not, set it to 1 (default) */ + jim_wide count; if (goi.argc == 1) { - e = Jim_GetOpt_Wide(&goi, &c); - if (e != JIM_OK) { + e = Jim_GetOpt_Wide(&goi, &count); + if (e != JIM_OK) return JIM_ERR; - } - } else { - c = 1; - } + } else + count = 1; /* all args must be consumed */ if (goi.argc != 0) - { return JIM_ERR; - } - jim_wide b = 1; /* shut up gcc */ + jim_wide dwidth = 1; /* shut up gcc */ if (strcasecmp(cmd_name, "mdw") == 0) - b = 4; + dwidth = 4; else if (strcasecmp(cmd_name, "mdh") == 0) - b = 2; + dwidth = 2; else if (strcasecmp(cmd_name, "mdb") == 0) - b = 1; + dwidth = 1; else { LOG_ERROR("command '%s' unknown: ", cmd_name); return JIM_ERR; } /* convert count to "bytes" */ - c = c * b; + int bytes = count * dwidth; struct target *target = Jim_CmdPrivData(goi.interp); uint8_t target_buf[32]; jim_wide x, y, z; - while (c > 0) { - y = c; - if (y > 16) { - y = 16; - } - e = fn(target, a, b, y / b, target_buf); + while (bytes > 0) { + y = (bytes < 16) ? bytes : 16; /* y = min(bytes, 16); */ + + /* Try to read out next block */ + e = fn(target, addr, dwidth, y / dwidth, target_buf); + if (e != ERROR_OK) { - char tmp[10]; - snprintf(tmp, sizeof(tmp), "%08lx", (long)a); - Jim_SetResultFormatted(interp, "error reading target @ 0x%s", tmp); + Jim_SetResultFormatted(interp, "error reading target @ 0x%08lx", (long)addr); return JIM_ERR; } - command_print(NULL, "0x%08x ", (int)(a)); - switch (b) { + command_print_sameline(NULL, "0x%08x ", (int)(addr)); + switch (dwidth) { case 4: - for (x = 0; x < 16 && x < y; x += 4) - { - z = target_buffer_get_u32(target, &(target_buf[ x ])); - command_print(NULL, "%08x ", (int)(z)); - } - for (; (x < 16) ; x += 4) { - command_print(NULL, " "); + for (x = 0; x < 16 && x < y; x += 4) { + z = target_buffer_get_u32(target, &(target_buf[x])); + command_print_sameline(NULL, "%08x ", (int)(z)); } + for (; (x < 16) ; x += 4) + command_print_sameline(NULL, " "); break; case 2: - for (x = 0; x < 16 && x < y; x += 2) - { - z = target_buffer_get_u16(target, &(target_buf[ x ])); - command_print(NULL, "%04x ", (int)(z)); - } - for (; (x < 16) ; x += 2) { - command_print(NULL, " "); + for (x = 0; x < 16 && x < y; x += 2) { + z = target_buffer_get_u16(target, &(target_buf[x])); + command_print_sameline(NULL, "%04x ", (int)(z)); } + for (; (x < 16) ; x += 2) + command_print_sameline(NULL, " "); break; case 1: default: for (x = 0 ; (x < 16) && (x < y) ; x += 1) { - z = target_buffer_get_u8(target, &(target_buf[ x ])); - command_print(NULL, "%02x ", (int)(z)); - } - for (; (x < 16) ; x += 1) { - command_print(NULL, " "); + z = target_buffer_get_u8(target, &(target_buf[x])); + command_print_sameline(NULL, "%02x ", (int)(z)); } + for (; (x < 16) ; x += 1) + command_print_sameline(NULL, " "); break; } /* ascii-ify the bytes */ @@ -4498,10 +4653,10 @@ static int jim_target_md(Jim_Interp *interp, int argc, Jim_Obj *const *argv) /* terminate */ target_buf[16] = 0; /* print - with a newline */ - command_print(NULL, "%s\n", target_buf); + command_print_sameline(NULL, "%s\n", target_buf); /* NEXT... */ - c -= 16; - a += 16; + bytes -= 16; + addr += 16; } return JIM_OK; } @@ -4528,8 +4683,7 @@ 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) - { + if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, "[no parameters]"); return JIM_ERR; } @@ -4539,16 +4693,13 @@ static int jim_target_examine(Jim_Interp *interp, int argc, Jim_Obj *const *argv int e = target->type->examine(target); if (e != ERROR_OK) - { return JIM_ERR; - } return JIM_OK; } static int jim_target_halt_gdb(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - if (argc != 1) - { + if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, "[no parameters]"); return JIM_ERR; } @@ -4562,8 +4713,7 @@ static int jim_target_halt_gdb(Jim_Interp *interp, int argc, Jim_Obj *const *arg static int jim_target_poll(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - if (argc != 1) - { + if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, "[no parameters]"); return JIM_ERR; } @@ -4572,15 +4722,12 @@ static int jim_target_poll(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return jim_target_tap_disabled(interp); int e; - if (!(target_was_examined(target))) { + if (!(target_was_examined(target))) e = ERROR_TARGET_NOT_EXAMINED; - } else { + else e = target->type->poll(target); - } if (e != ERROR_OK) - { return JIM_ERR; - } return JIM_OK; } @@ -4589,8 +4736,7 @@ static int jim_target_reset(Jim_Interp *interp, int argc, Jim_Obj *const *argv) Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); - if (goi.argc != 2) - { + if (goi.argc != 2) { Jim_WrongNumArgs(interp, 0, argv, "([tT]|[fF]|assert|deassert) BOOL"); return JIM_ERR; @@ -4598,8 +4744,7 @@ static int jim_target_reset(Jim_Interp *interp, int argc, Jim_Obj *const *argv) Jim_Nvp *n; int e = Jim_GetOpt_Nvp(&goi, nvp_assert, &n); - if (e != JIM_OK) - { + if (e != JIM_OK) { Jim_GetOpt_NvpUnknown(&goi, nvp_assert, 1); return e; } @@ -4612,13 +4757,11 @@ 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))) - { + 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) - { + if (!target->type->assert_reset || !target->type->deassert_reset) { Jim_SetResultFormatted(interp, "No target-specific reset for %s", target_name(target)); @@ -4630,11 +4773,10 @@ static int jim_target_reset(Jim_Interp *interp, int argc, Jim_Obj *const *argv) target_free_all_working_areas_restore(target, 0); /* do the assert */ - if (n->value == NVP_ASSERT) { + if (n->value == NVP_ASSERT) e = target->type->assert_reset(target); - } else { + else e = target->type->deassert_reset(target); - } return (e == ERROR_OK) ? JIM_OK : JIM_ERR; } @@ -4657,8 +4799,7 @@ static int jim_target_wait_state(Jim_Interp *interp, int argc, Jim_Obj *const *a Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); /* params: statename timeoutmsecs */ - if (goi.argc != 2) - { + if (goi.argc != 2) { const char *cmd_name = Jim_GetString(argv[0], NULL); Jim_SetResultFormatted(goi.interp, "%s ", cmd_name); @@ -4668,21 +4809,19 @@ static int jim_target_wait_state(Jim_Interp *interp, int argc, Jim_Obj *const *a Jim_Nvp *n; int e = Jim_GetOpt_Nvp(&goi, nvp_target_state, &n); if (e != JIM_OK) { - Jim_GetOpt_NvpUnknown(&goi, nvp_target_state,1); + Jim_GetOpt_NvpUnknown(&goi, nvp_target_state, 1); return e; } jim_wide a; e = Jim_GetOpt_Wide(&goi, &a); - if (e != JIM_OK) { + if (e != JIM_OK) return e; - } struct target *target = Jim_CmdPrivData(interp); if (!target->tap->enabled) return jim_target_tap_disabled(interp); e = target_wait_state(target, n->value, a); - if (e != ERROR_OK) - { + if (e != ERROR_OK) { Jim_Obj *eObj = Jim_NewIntObj(interp, e); Jim_SetResultFormatted(goi.interp, "target: %s wait %s fails (%#s) %s", @@ -4699,7 +4838,7 @@ static int jim_target_wait_state(Jim_Interp *interp, int argc, Jim_Obj *const *a static int jim_target_event_list(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { struct command_context *cmd_ctx = current_command_context(interp); - assert (cmd_ctx != NULL); + assert(cmd_ctx != NULL); struct target *target = Jim_CmdPrivData(interp); struct target_event_action *teap = target->event_action; @@ -4709,8 +4848,7 @@ static int jim_target_event_list(Jim_Interp *interp, int argc, Jim_Obj *const *a command_print(cmd_ctx, "%-25s | Body", "Event"); command_print(cmd_ctx, "------------------------- | " "----------------------------------------"); - while (teap) - { + while (teap) { Jim_Nvp *opt = Jim_Nvp_value2name_simple(nvp_target_event, teap->event); command_print(cmd_ctx, "%-25s | %s", opt->name, Jim_GetString(teap->body, NULL)); @@ -4721,8 +4859,7 @@ static int jim_target_event_list(Jim_Interp *interp, int argc, Jim_Obj *const *a } static int jim_target_current_state(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - if (argc != 1) - { + if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, "[no parameters]"); return JIM_ERR; } @@ -4734,16 +4871,14 @@ static int jim_target_invoke_event(Jim_Interp *interp, int argc, Jim_Obj *const { Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); - if (goi.argc != 1) - { + if (goi.argc != 1) { const char *cmd_name = Jim_GetString(argv[0], NULL); Jim_SetResultFormatted(goi.interp, "%s ", cmd_name); return JIM_ERR; } Jim_Nvp *n; int e = Jim_GetOpt_Nvp(&goi, nvp_target_event, &n); - if (e != JIM_OK) - { + if (e != JIM_OK) { Jim_GetOpt_NvpUnknown(&goi, nvp_target_event, 1); return e; } @@ -4895,7 +5030,7 @@ static int target_create(Jim_GetOptInfo *goi) struct command_context *cmd_ctx; cmd_ctx = current_command_context(goi->interp); - assert (cmd_ctx != NULL); + assert(cmd_ctx != NULL); if (goi->argc < 3) { Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ?type? ..options..."); @@ -4917,12 +5052,30 @@ static int target_create(Jim_GetOptInfo *goi) 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)) { /* found */ break; } + + /* check for deprecated name */ + if (target_types[x]->deprecated_name) { + if (0 == strcmp(cp, target_types[x]->deprecated_name)) { + /* found */ + LOG_WARNING("target name is deprecated use: \'%s\'", target_types[x]->name); + break; + } + } } if (target_types[x] == NULL) { Jim_SetResultFormatted(goi->interp, "Unknown target type %s, try one of ", cp); @@ -4936,19 +5089,20 @@ static int target_create(Jim_GetOptInfo *goi) Jim_AppendStrings(goi->interp, Jim_GetResult(goi->interp), " or ", - target_types[x]->name,NULL); + target_types[x]->name, NULL); } } return JIM_ERR; } /* Create it */ - target = calloc(1,sizeof(struct target)); + 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)); @@ -4997,8 +5151,7 @@ static int target_create(Jim_GetOptInfo *goi) goi->isconfigure = 1; e = target_configure(goi, target); - if (target->tap == NULL) - { + if (target->tap == NULL) { Jim_SetResultString(goi->interp, "-chain-position required when creating target", -1); e = JIM_ERR; } @@ -5014,10 +5167,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); @@ -5027,22 +5176,20 @@ static int target_create(Jim_GetOptInfo *goi) if (ERROR_OK != e) LOG_ERROR("unable to register '%s' commands", cp); } - if (target->type->target_create) { + if (target->type->target_create) (*(target->type->target_create))(target, goi->interp); - } /* append to end of list */ { struct target **tpp; tpp = &(all_targets); - while (*tpp) { + while (*tpp) tpp = &((*tpp)->next); - } *tpp = target; } /* 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, }, @@ -5051,11 +5198,12 @@ 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, .help = "target command group", + .usage = "", .chain = target_subcommands, }, COMMAND_REGISTRATION_DONE @@ -5073,28 +5221,25 @@ static int target_create(Jim_GetOptInfo *goi) static int jim_target_current(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - if (argc != 1) - { + if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); return JIM_ERR; } struct command_context *cmd_ctx = current_command_context(interp); - assert (cmd_ctx != NULL); + assert(cmd_ctx != NULL); - Jim_SetResultString(interp, get_current_target(cmd_ctx)->cmd_name, -1); + Jim_SetResultString(interp, target_name(get_current_target(cmd_ctx)), -1); return JIM_OK; } static int jim_target_types(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - if (argc != 1) - { + if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); return JIM_ERR; } Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0)); - for (unsigned x = 0; NULL != target_types[x]; x++) - { + for (unsigned x = 0; NULL != target_types[x]; x++) { Jim_ListAppendElement(interp, Jim_GetResult(interp), Jim_NewStringObj(interp, target_types[x]->name, -1)); } @@ -5103,15 +5248,13 @@ static int jim_target_types(Jim_Interp *interp, int argc, Jim_Obj *const *argv) static int jim_target_names(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - if (argc != 1) - { + if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, "Too many parameters"); return JIM_ERR; } Jim_SetResult(interp, Jim_NewListObj(interp, NULL, 0)); struct target *target = all_targets; - while (target) - { + while (target) { Jim_ListAppendElement(interp, Jim_GetResult(interp), Jim_NewStringObj(interp, target_name(target), -1)); target = target->next; @@ -5123,53 +5266,50 @@ static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { int i; const char *targetname; - int retval,len; - struct target *target; - struct target_list *head, *curr; - curr = (struct target_list*) NULL; - head = (struct target_list*) NULL; - + int retval, len; + struct target *target = (struct target *) NULL; + struct target_list *head, *curr, *new; + curr = (struct target_list *) NULL; + head = (struct target_list *) NULL; + retval = 0; - LOG_DEBUG("%d",argc); + LOG_DEBUG("%d", argc); /* argv[1] = target to associate in smp * argv[2] = target to assoicate in smp * argv[3] ... */ - for(i=1;itarget = target; - new->next = (struct target_list*)NULL; - if (head == (struct target_list*)NULL) - { + new->next = (struct target_list *)NULL; + if (head == (struct target_list *)NULL) { head = new; curr = head; - } - else - { + } else { curr->next = new; curr = new; } } } - /* now parse the list of cpu and put the target in smp mode*/ - curr=head; + /* now parse the list of cpu and put the target in smp mode*/ + curr = head; - while(curr!=(struct target_list *)NULL) - { - target=curr->target; - target->smp = 1; - target->head = head; - curr=curr->next; + while (curr != (struct target_list *)NULL) { + target = curr->target; + target->smp = 1; + target->head = head; + curr = curr->next; } + + if (target && target->rtos) + retval = rtos_smp_init(head->target); + return retval; } @@ -5178,8 +5318,7 @@ static int jim_target_create(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { Jim_GetOptInfo goi; Jim_GetOpt_Setup(&goi, interp, argc - 1, argv + 1); - if (goi.argc < 3) - { + if (goi.argc < 3) { Jim_WrongNumArgs(goi.interp, goi.argc, goi.argv, " [ ...]"); return JIM_ERR; @@ -5194,8 +5333,7 @@ static int jim_target_number(Jim_Interp *interp, int argc, Jim_Obj *const *argv) /* 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) - { + if (goi.argc != 1) { Jim_SetResultFormatted(goi.interp, "usage: target number "); return JIM_ERR; } @@ -5205,8 +5343,7 @@ static int jim_target_number(Jim_Interp *interp, int argc, Jim_Obj *const *argv) return JIM_ERR; struct target *target; - for (target = all_targets; NULL != target; target = target->next) - { + for (target = all_targets; NULL != target; target = target->next) { if (target->target_number != w) continue; @@ -5224,15 +5361,13 @@ static int jim_target_number(Jim_Interp *interp, int argc, Jim_Obj *const *argv) static int jim_target_count(Jim_Interp *interp, int argc, Jim_Obj *const *argv) { - if (argc != 1) - { + if (argc != 1) { Jim_WrongNumArgs(interp, 1, argv, ""); return JIM_ERR; } unsigned count = 0; struct target *target = all_targets; - while (NULL != target) - { + while (NULL != target) { target = target->next; count++; } @@ -5300,8 +5435,7 @@ static const struct command_registration target_subcommand_handlers[] = { COMMAND_REGISTRATION_DONE }; -struct FastLoad -{ +struct FastLoad { uint32_t address; uint8_t *data; int length; @@ -5313,11 +5447,9 @@ static struct FastLoad *fastload; static void free_fastload(void) { - if (fastload != NULL) - { + if (fastload != NULL) { int i; - for (i = 0; i < fastload_num; i++) - { + for (i = 0; i < fastload_num; i++) { if (fastload[i].data) free(fastload[i].data); } @@ -5326,9 +5458,6 @@ static void free_fastload(void) } } - - - COMMAND_HANDLER(handle_fast_load_image_command) { uint8_t *buffer; @@ -5350,34 +5479,29 @@ COMMAND_HANDLER(handle_fast_load_image_command) retval = image_open(&image, CMD_ARGV[0], (CMD_ARGC >= 3) ? CMD_ARGV[2] : NULL); if (retval != ERROR_OK) - { return retval; - } image_size = 0x0; retval = ERROR_OK; fastload_num = image.num_sections; - fastload = (struct FastLoad *)malloc(sizeof(struct FastLoad)*image.num_sections); - if (fastload == NULL) - { + fastload = malloc(sizeof(struct FastLoad)*image.num_sections); + if (fastload == NULL) { command_print(CMD_CTX, "out of memory"); image_close(&image); return ERROR_FAIL; } memset(fastload, 0, sizeof(struct FastLoad)*image.num_sections); - for (i = 0; i < image.num_sections; i++) - { + for (i = 0; i < image.num_sections; i++) { buffer = malloc(image.sections[i].size); - if (buffer == NULL) - { + if (buffer == NULL) { command_print(CMD_CTX, "error allocating buffer for section (%d bytes)", (int)(image.sections[i].size)); retval = ERROR_FAIL; break; } - if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK) - { + retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt); + if (retval != ERROR_OK) { free(buffer); break; } @@ -5385,30 +5509,24 @@ COMMAND_HANDLER(handle_fast_load_image_command) uint32_t offset = 0; uint32_t length = buf_cnt; - /* DANGER!!! beware of unsigned comparision here!!! */ - if ((image.sections[i].base_address + buf_cnt >= min_address)&& - (image.sections[i].base_address < max_address)) - { - if (image.sections[i].base_address < min_address) - { + if ((image.sections[i].base_address + buf_cnt >= min_address) && + (image.sections[i].base_address < max_address)) { + if (image.sections[i].base_address < min_address) { /* clip addresses below */ offset += min_address-image.sections[i].base_address; length -= offset; } if (image.sections[i].base_address + buf_cnt > max_address) - { length -= (image.sections[i].base_address + buf_cnt)-max_address; - } fastload[i].address = image.sections[i].base_address + offset; fastload[i].data = malloc(length); - if (fastload[i].data == NULL) - { + 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; @@ -5425,8 +5543,7 @@ COMMAND_HANDLER(handle_fast_load_image_command) free(buffer); } - if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) - { + if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK)) { command_print(CMD_CTX, "Loaded %" PRIu32 " bytes " "in %fs (%0.3f KiB/s)", image_size, duration_elapsed(&bench), duration_kbps(&bench, image_size)); @@ -5439,9 +5556,7 @@ COMMAND_HANDLER(handle_fast_load_image_command) image_close(&image); if (retval != ERROR_OK) - { free_fastload(); - } return retval; } @@ -5450,8 +5565,7 @@ COMMAND_HANDLER(handle_fast_load_command) { if (CMD_ARGC > 0) return ERROR_COMMAND_SYNTAX_ERROR; - if (fastload == NULL) - { + if (fastload == NULL) { LOG_ERROR("No image in memory"); return ERROR_FAIL; } @@ -5459,21 +5573,17 @@ COMMAND_HANDLER(handle_fast_load_command) int ms = timeval_ms(); int size = 0; int retval = ERROR_OK; - for (i = 0; i < fastload_num;i++) - { + for (i = 0; i < fastload_num; i++) { struct target *target = get_current_target(CMD_CTX); command_print(CMD_CTX, "Write to 0x%08x, length 0x%08x", (unsigned int)(fastload[i].address), (unsigned int)(fastload[i].length)); retval = target_write_buffer(target, fastload[i].address, fastload[i].length, fastload[i].data); if (retval != ERROR_OK) - { break; - } size += fastload[i].length; } - if (retval == ERROR_OK) - { + if (retval == ERROR_OK) { int after = timeval_ms(); command_print(CMD_CTX, "Loaded image %f kBytes/s", (float)(size/1024.0)/((float)(after-ms)/1000.0)); } @@ -5518,6 +5628,219 @@ COMMAND_HANDLER(handle_target_reset_nag) "performance"); } +COMMAND_HANDLER(handle_ps_command) +{ + struct target *target = get_current_target(CMD_CTX); + char *display; + if (target->state != TARGET_HALTED) { + LOG_INFO("target not halted !!"); + return ERROR_OK; + } + + if ((target->rtos) && (target->rtos->type) + && (target->rtos->type->ps_command)) { + display = target->rtos->type->ps_command(target); + command_print(CMD_CTX, "%s", display); + free(display); + return ERROR_OK; + } else { + LOG_INFO("failed"); + return ERROR_TARGET_FAILURE; + } +} + +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", @@ -5534,11 +5857,13 @@ static const struct command_registration target_exec_command_handlers[] = { .mode = COMMAND_EXEC, .help = "loads active fast load image to current target " "- mainly for profiling purposes", + .usage = "", }, { .name = "profile", .handler = handle_profile_command, .mode = COMMAND_EXEC, + .usage = "seconds filename [start end]", .help = "profiling samples the CPU PC", }, /** @todo don't register virt2phys() unless target supports it */ @@ -5553,9 +5878,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", @@ -5569,7 +5894,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]", }, { @@ -5577,7 +5902,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]", }, { @@ -5599,6 +5924,7 @@ static const struct command_registration target_exec_command_handlers[] = { .name = "soft_reset_halt", .handler = handle_soft_reset_halt_command, .mode = COMMAND_EXEC, + .usage = "", .help = "halt the target and do a soft reset", }, { @@ -5655,7 +5981,7 @@ static const struct command_registration target_exec_command_handlers[] = { .handler = handle_bp_command, .mode = COMMAND_EXEC, .help = "list or set hardware or software breakpoint", - .usage = "usage: bp
[] ['hw'|'hw_ctx']", + .usage = "
[] ['hw'|'hw_ctx']", }, { .name = "rbp", @@ -5727,15 +6053,32 @@ static const struct command_registration target_exec_command_handlers[] = { "enabled to improve performance. ", .usage = "['enable'|'disable']", }, + { + .name = "ps", + .handler = handle_ps_command, + .mode = COMMAND_EXEC, + .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 }; static int target_register_user_commands(struct command_context *cmd_ctx) { int retval = ERROR_OK; - if ((retval = target_request_register_commands(cmd_ctx)) != ERROR_OK) + retval = target_request_register_commands(cmd_ctx); + if (retval != ERROR_OK) return retval; - if ((retval = trace_register_commands(cmd_ctx)) != ERROR_OK) + retval = trace_register_commands(cmd_ctx); + if (retval != ERROR_OK) return retval;