+ uint8_t *buffer;
+ size_t buf_cnt;
+ uint32_t image_size;
+ int i;
+ int retval;
+ uint32_t checksum = 0;
+ uint32_t mem_checksum = 0;
+
+ struct image image;
+
+ struct target *target = get_current_target(CMD_CTX);
+
+ if (CMD_ARGC < 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ if (!target) {
+ LOG_ERROR("no target selected");
+ return ERROR_FAIL;
+ }
+
+ struct duration bench;
+ duration_start(&bench);
+
+ if (CMD_ARGC >= 2) {
+ target_addr_t addr;
+ COMMAND_PARSE_ADDRESS(CMD_ARGV[1], addr);
+ image.base_address = addr;
+ image.base_address_set = 1;
+ } else {
+ image.base_address_set = 0;
+ image.base_address = 0x0;
+ }
+
+ image.start_address_set = 0;
+
+ 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++) {
+ buffer = malloc(image.sections[i].size);
+ if (buffer == NULL) {
+ command_print(CMD_CTX,
+ "error allocating buffer for section (%d bytes)",
+ (int)(image.sections[i].size));
+ break;
+ }
+ retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt);
+ if (retval != ERROR_OK) {
+ free(buffer);
+ break;
+ }
+
+ if (verify >= IMAGE_VERIFY) {
+ /* calculate checksum of image */
+ retval = image_calculate_checksum(buffer, buf_cnt, &checksum);
+ 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) {
+ free(buffer);
+ break;
+ }
+ if ((checksum != mem_checksum) && (verify == IMAGE_CHECKSUM_ONLY)) {
+ LOG_ERROR("checksum mismatch");
+ free(buffer);
+ retval = ERROR_FAIL;
+ goto done;
+ }
+ if (checksum != mem_checksum) {
+ /* failed crc checksum, fall back to a binary compare */
+ uint8_t *data;
+
+ if (diffs == 0)
+ LOG_ERROR("checksum mismatch - attempting binary compare");
+
+ data = malloc(buf_cnt);
+
+ /* Can we use 32bit word accesses? */
+ int size = 1;
+ int count = buf_cnt;
+ 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) {
+ uint32_t 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) {
+ command_print(CMD_CTX, "More than 128 errors, the rest are not printed.");
+ free(data);
+ free(buffer);
+ goto done;
+ }
+ }
+ keep_alive();
+ }
+ }
+ free(data);
+ }
+ } else {
+ command_print(CMD_CTX, "address " TARGET_ADDR_FMT " length 0x%08zx",
+ image.sections[i].base_address,
+ buf_cnt);
+ }
+
+ free(buffer);
+ 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)) {
+ command_print(CMD_CTX, "verified %" PRIu32 " bytes "
+ "in %fs (%0.3f KiB/s)", image_size,
+ duration_elapsed(&bench), duration_kbps(&bench, image_size));
+ }
+
+ image_close(&image);
+
+ return retval;
+}
+
+COMMAND_HANDLER(handle_verify_image_checksum_command)
+{
+ return CALL_COMMAND_HANDLER(handle_verify_image_command_internal, IMAGE_CHECKSUM_ONLY);
+}
+
+COMMAND_HANDLER(handle_verify_image_command)
+{
+ return CALL_COMMAND_HANDLER(handle_verify_image_command_internal, IMAGE_VERIFY);
+}
+
+COMMAND_HANDLER(handle_test_image_command)
+{
+ return CALL_COMMAND_HANDLER(handle_verify_image_command_internal, IMAGE_TEST);
+}
+
+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,
+ breakpoint->length, 16);
+ command_print(cmd_ctx, "IVA breakpoint: " TARGET_ADDR_FMT ", 0x%x, %i, 0x%s",
+ breakpoint->address,
+ breakpoint->length,
+ breakpoint->set, buf);
+ free(buf);
+ } 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)) {
+ command_print(cmd_ctx, "Hybrid breakpoint(IVA): " TARGET_ADDR_FMT ", 0x%x, %i",
+ breakpoint->address,
+ breakpoint->length, breakpoint->set);
+ command_print(cmd_ctx, "\t|--->linked with ContextID: 0x%8.8" PRIx32,
+ breakpoint->asid);
+ } else
+ command_print(cmd_ctx, "Breakpoint(IVA): " TARGET_ADDR_FMT ", 0x%x, %i",
+ breakpoint->address,
+ breakpoint->length, breakpoint->set);
+ }
+
+ breakpoint = breakpoint->next;
+ }
+ return ERROR_OK;
+}
+
+static int handle_bp_command_set(struct command_context *cmd_ctx,
+ target_addr_t addr, uint32_t asid, uint32_t length, int hw)
+{
+ struct target *target = get_current_target(cmd_ctx);
+ int retval;
+
+ if (asid == 0) {
+ retval = breakpoint_add(target, addr, length, hw);
+ if (ERROR_OK == retval)
+ command_print(cmd_ctx, "breakpoint set at " TARGET_ADDR_FMT "", addr);
+ else {
+ LOG_ERROR("Failure setting breakpoint, the same address(IVA) is already used");
+ return retval;
+ }
+ } else if (addr == 0) {
+ if (target->type->add_context_breakpoint == NULL) {
+ LOG_WARNING("Context breakpoint not available");
+ return ERROR_OK;
+ }
+ retval = context_breakpoint_add(target, asid, length, hw);
+ if (ERROR_OK == retval)
+ command_print(cmd_ctx, "Context breakpoint set at 0x%8.8" PRIx32 "", asid);
+ else {
+ LOG_ERROR("Failure setting breakpoint, the same address(CONTEXTID) is already used");
+ return retval;
+ }
+ } else {
+ if (target->type->add_hybrid_breakpoint == NULL) {
+ LOG_WARNING("Hybrid breakpoint not available");
+ return ERROR_OK;
+ }
+ retval = hybrid_breakpoint_add(target, addr, asid, length, hw);
+ if (ERROR_OK == retval)
+ command_print(cmd_ctx, "Hybrid breakpoint set at 0x%8.8" PRIx32 "", asid);
+ else {
+ LOG_ERROR("Failure setting breakpoint, the same address is already used");
+ return retval;
+ }
+ }
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_bp_command)
+{
+ target_addr_t addr;
+ uint32_t asid;
+ uint32_t length;
+ int hw = BKPT_SOFT;
+
+ switch (CMD_ARGC) {
+ case 0:
+ return handle_bp_command_list(CMD_CTX);
+
+ case 2:
+ asid = 0;
+ COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length);
+ return handle_bp_command_set(CMD_CTX, addr, asid, length, hw);
+
+ case 3:
+ if (strcmp(CMD_ARGV[2], "hw") == 0) {
+ hw = BKPT_HARD;
+ COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length);
+ asid = 0;
+ return handle_bp_command_set(CMD_CTX, addr, asid, length, hw);
+ } else if (strcmp(CMD_ARGV[2], "hw_ctx") == 0) {
+ hw = BKPT_HARD;
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], asid);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length);
+ addr = 0;
+ return handle_bp_command_set(CMD_CTX, addr, asid, length, hw);
+ }
+ /* fallthrough */
+ case 4:
+ hw = BKPT_HARD;
+ COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], asid);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], length);
+ return handle_bp_command_set(CMD_CTX, addr, asid, length, hw);
+
+ default:
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+}
+
+COMMAND_HANDLER(handle_rbp_command)
+{
+ if (CMD_ARGC != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ target_addr_t addr;
+ COMMAND_PARSE_ADDRESS(CMD_ARGV[0], addr);
+
+ struct target *target = get_current_target(CMD_CTX);
+ breakpoint_remove(target, addr);
+
+ return ERROR_OK;
+}
+
+COMMAND_HANDLER(handle_wp_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+
+ if (CMD_ARGC == 0) {
+ struct watchpoint *watchpoint = target->watchpoints;
+
+ while (watchpoint) {
+ command_print(CMD_CTX, "address: " TARGET_ADDR_FMT
+ ", len: 0x%8.8" PRIx32
+ ", r/w/a: %i, value: 0x%8.8" PRIx32
+ ", mask: 0x%8.8" PRIx32,
+ watchpoint->address,
+ watchpoint->length,
+ (int)watchpoint->rw,
+ watchpoint->value,
+ watchpoint->mask);
+ watchpoint = watchpoint->next;
+ }
+ return ERROR_OK;
+ }
+
+ enum watchpoint_rw type = WPT_ACCESS;
+ uint32_t addr = 0;
+ uint32_t length = 0;
+ uint32_t data_value = 0x0;
+ uint32_t data_mask = 0xffffffff;
+
+ switch (CMD_ARGC) {
+ case 5:
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], data_mask);
+ /* fall through */
+ case 4:
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], data_value);
+ /* fall through */
+ case 3:
+ switch (CMD_ARGV[2][0]) {
+ case 'r':
+ type = WPT_READ;
+ break;
+ case 'w':
+ type = WPT_WRITE;
+ break;
+ case 'a':
+ type = WPT_ACCESS;
+ break;
+ default:
+ LOG_ERROR("invalid watchpoint mode ('%c')", CMD_ARGV[2][0]);
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+ /* fall through */
+ case 2:
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], length);
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr);
+ break;
+
+ default:
+ return ERROR_COMMAND_SYNTAX_ERROR;
+ }
+
+ int retval = watchpoint_add(target, addr, length, type,
+ data_value, data_mask);
+ if (ERROR_OK != retval)
+ LOG_ERROR("Failure setting watchpoints");
+
+ return retval;
+}
+
+COMMAND_HANDLER(handle_rwp_command)
+{
+ if (CMD_ARGC != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ uint32_t addr;
+ COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], addr);
+
+ struct target *target = get_current_target(CMD_CTX);
+ watchpoint_remove(target, addr);
+
+ return ERROR_OK;
+}
+
+/**
+ * Translate a virtual address to a physical address.
+ *
+ * The low-level target implementation must have logged a detailed error
+ * which is forwarded to telnet/GDB session.
+ */
+COMMAND_HANDLER(handle_virt2phys_command)
+{
+ if (CMD_ARGC != 1)
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ target_addr_t va;
+ COMMAND_PARSE_ADDRESS(CMD_ARGV[0], va);
+ target_addr_t pa;
+
+ struct target *target = get_current_target(CMD_CTX);
+ int retval = target->type->virt2phys(target, va, &pa);
+ if (retval == ERROR_OK)
+ command_print(CMD_CTX, "Physical address " TARGET_ADDR_FMT "", pa);
+
+ return retval;
+}
+
+static void writeData(FILE *f, const void *data, size_t len)
+{
+ size_t written = fwrite(data, 1, len, f);
+ if (written != len)
+ LOG_ERROR("failed to write %zu bytes: %s", len, strerror(errno));
+}
+
+static void writeLong(FILE *f, int l, struct target *target)
+{
+ uint8_t val[4];
+
+ target_buffer_set_u32(target, val, l);
+ writeData(f, val, 4);
+}
+
+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 write_gmon(uint32_t *samples, uint32_t sampleNum, const char *filename, bool with_range,
+ uint32_t start_address, uint32_t end_address, struct target *target, uint32_t duration_ms)
+{
+ uint32_t i;
+ FILE *f = fopen(filename, "w");
+ if (f == NULL)
+ return;
+ writeString(f, "gmon");
+ writeLong(f, 0x00000001, target); /* Version */
+ writeLong(f, 0, target); /* padding */
+ writeLong(f, 0, target); /* padding */
+ writeLong(f, 0, target); /* padding */
+
+ uint8_t zero = 0; /* GMON_TAG_TIME_HIST */
+ writeData(f, &zero, 1);
+
+ /* figure out bucket size */
+ uint32_t min;
+ 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;
+ assert(addressSpace >= 2);
+
+ /* 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) * numBuckets);
+ for (i = 0; i < sampleNum; i++) {
+ uint32_t address = samples[i];
+
+ if ((address < min) || (max <= address))
+ continue;
+
+ long long a = address - min;
+ long long b = 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, target); /* low_pc */
+ writeLong(f, max, target); /* high_pc */
+ writeLong(f, numBuckets, target); /* # of buckets */
+ float sample_rate = sampleNum / (duration_ms / 1000.0);
+ writeLong(f, sample_rate, target);
+ writeString(f, "seconds");
+ for (i = 0; i < (15-strlen("seconds")); i++)
+ writeData(f, &zero, 1);
+ writeString(f, "s");
+
+ /*append binary memory gmon.out profile_hist_data (profile_hist_data + profile_hist_hdr.hist_size) */
+
+ 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;
+ }
+ free(buckets);
+ writeData(f, data, numBuckets * 2);
+ free(data);
+ } else
+ free(buckets);
+
+ fclose(f);
+}
+
+/* profiling samples the CPU PC as quickly as OpenOCD is able,
+ * which will be used as a random sampling of PC */
+COMMAND_HANDLER(handle_profile_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+
+ if ((CMD_ARGC != 2) && (CMD_ARGC != 4))
+ return ERROR_COMMAND_SYNTAX_ERROR;
+
+ 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;
+ }
+
+ uint64_t timestart_ms = timeval_ms();
+ /**
+ * 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;
+ }
+ uint32_t duration_ms = timeval_ms() - timestart_ms;
+
+ assert(num_of_samples <= MAX_PROFILE_SAMPLE_NUM);
+
+ retval = target_poll(target);
+ if (retval != ERROR_OK) {
+ free(samples);
+ return retval;
+ }
+ if (target->state == TARGET_RUNNING) {
+ retval = target_halt(target);
+ if (retval != ERROR_OK) {
+ free(samples);
+ return retval;
+ }
+ }
+
+ retval = target_poll(target);
+ if (retval != ERROR_OK) {
+ free(samples);
+ return retval;
+ }
+
+ 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, target, duration_ms);
+ 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)
+{
+ char *namebuf;
+ Jim_Obj *nameObjPtr, *valObjPtr;
+ int result;
+
+ namebuf = alloc_printf("%s(%d)", varname, idx);
+ if (!namebuf)
+ return JIM_ERR;
+
+ nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
+ valObjPtr = Jim_NewIntObj(interp, val);
+ if (!nameObjPtr || !valObjPtr) {
+ free(namebuf);
+ return JIM_ERR;
+ }
+
+ Jim_IncrRefCount(nameObjPtr);
+ Jim_IncrRefCount(valObjPtr);
+ result = Jim_SetVariable(interp, nameObjPtr, valObjPtr);
+ Jim_DecrRefCount(interp, nameObjPtr);
+ Jim_DecrRefCount(interp, valObjPtr);
+ free(namebuf);
+ /* printf("%s(%d) <= 0%08x\n", varname, idx, val); */
+ return result;
+}
+
+static int jim_mem2array(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct command_context *context;
+ struct target *target;
+
+ context = current_command_context(interp);
+ assert(context != NULL);
+
+ target = get_current_target(context);
+ if (target == NULL) {
+ LOG_ERROR("mem2array: no current target");
+ return JIM_ERR;
+ }
+
+ 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)
+{
+ long l;
+ uint32_t width;
+ int len;
+ uint32_t addr;
+ uint32_t count;
+ uint32_t v;
+ const char *varname;
+ const char *phys;
+ bool is_phys;
+ int n, e, retval;
+ uint32_t i;
+
+ /* argv[1] = name of array to receive the data
+ * argv[2] = desired width
+ * argv[3] = memory address
+ * argv[4] = count of times to read
+ */
+
+ if (argc < 4 || argc > 5) {
+ Jim_WrongNumArgs(interp, 0, argv, "varname width addr nelems [phys]");
+ return JIM_ERR;
+ }
+ varname = Jim_GetString(argv[0], &len);
+ /* given "foo" get space for worse case "foo(%d)" .. add 20 */
+
+ e = Jim_GetLong(interp, argv[1], &l);
+ width = l;
+ if (e != JIM_OK)
+ return e;
+
+ e = Jim_GetLong(interp, argv[2], &l);
+ addr = l;
+ if (e != JIM_OK)
+ return e;
+ e = Jim_GetLong(interp, argv[3], &l);
+ len = l;
+ if (e != JIM_OK)
+ return e;
+ is_phys = false;
+ if (argc > 4) {
+ phys = Jim_GetString(argv[4], &n);
+ if (!strncmp(phys, "phys", n))
+ is_phys = true;
+ else
+ return JIM_ERR;
+ }
+ switch (width) {
+ case 8:
+ width = 1;
+ break;
+ case 16:
+ width = 2;
+ break;
+ case 32:
+ width = 4;
+ break;
+ default:
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ 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), "mem2array: zero width read?", NULL);
+ return JIM_ERR;
+ }
+ if ((addr + (len * width)) < addr) {
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: 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), "mem2array: absurd > 64K item request", NULL);
+ return JIM_ERR;
+ }
+
+ if ((width == 1) ||
+ ((width == 2) && ((addr & 1) == 0)) ||
+ ((width == 4) && ((addr & 3) == 0))) {
+ /* all is well */
+ } else {
+ char buf[100];
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ sprintf(buf, "mem2array address: 0x%08" PRIx32 " is not aligned for %" PRId32 " byte reads",
+ addr,
+ width);
+ Jim_AppendStrings(interp, Jim_GetResult(interp), buf, NULL);
+ return JIM_ERR;
+ }
+
+ /* Transfer loop */
+
+ /* index counter */
+ n = 0;
+
+ size_t buffersize = 4096;
+ uint8_t *buffer = malloc(buffersize);
+ if (buffer == NULL)
+ return JIM_ERR;
+
+ /* assume ok */
+ e = JIM_OK;
+ while (len) {
+ /* Slurp... in buffer size chunks */
+
+ count = len; /* in objects.. */
+ if (count > (buffersize / width))
+ count = (buffersize / width);
+
+ if (is_phys)
+ retval = target_read_phys_memory(target, addr, width, count, buffer);
+ else
+ retval = target_read_memory(target, addr, width, count, buffer);
+ if (retval != ERROR_OK) {
+ /* BOO !*/
+ LOG_ERROR("mem2array: Read @ 0x%08" PRIx32 ", w=%" PRId32 ", cnt=%" PRId32 ", failed",
+ addr,
+ width,
+ count);
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "mem2array: cannot read memory", NULL);
+ e = JIM_ERR;
+ break;
+ } else {
+ v = 0; /* shut up gcc */
+ for (i = 0; i < count ; i++, n++) {
+ switch (width) {
+ case 4:
+ v = target_buffer_get_u32(target, &buffer[i*width]);
+ break;
+ case 2:
+ v = target_buffer_get_u16(target, &buffer[i*width]);
+ break;
+ case 1:
+ v = buffer[i] & 0x0ff;
+ break;
+ }
+ new_int_array_element(interp, varname, n, v);
+ }
+ len -= count;
+ addr += count * width;
+ }
+ }
+
+ free(buffer);
+
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+
+ return e;
+}
+
+static int get_int_array_element(Jim_Interp *interp, const char *varname, int idx, uint32_t *val)
+{
+ char *namebuf;
+ Jim_Obj *nameObjPtr, *valObjPtr;
+ int result;
+ long l;
+
+ namebuf = alloc_printf("%s(%d)", varname, idx);
+ if (!namebuf)
+ return JIM_ERR;
+
+ nameObjPtr = Jim_NewStringObj(interp, namebuf, -1);
+ if (!nameObjPtr) {
+ free(namebuf);
+ return JIM_ERR;
+ }
+
+ Jim_IncrRefCount(nameObjPtr);
+ valObjPtr = Jim_GetVariable(interp, nameObjPtr, JIM_ERRMSG);
+ Jim_DecrRefCount(interp, nameObjPtr);
+ free(namebuf);
+ if (valObjPtr == NULL)
+ return JIM_ERR;
+
+ result = Jim_GetLong(interp, valObjPtr, &l);
+ /* printf("%s(%d) => 0%08x\n", varname, idx, val); */
+ *val = l;
+ return result;
+}
+
+static int jim_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
+{
+ struct command_context *context;
+ struct target *target;
+
+ context = current_command_context(interp);
+ assert(context != NULL);
+
+ target = get_current_target(context);
+ if (target == NULL) {
+ LOG_ERROR("array2mem: no current target");
+ return JIM_ERR;
+ }
+
+ return target_array2mem(interp, target, argc-1, argv + 1);
+}
+
+static int target_array2mem(Jim_Interp *interp, struct target *target,
+ int argc, Jim_Obj *const *argv)
+{
+ long l;
+ uint32_t width;
+ int len;
+ uint32_t addr;
+ uint32_t count;
+ uint32_t v;
+ const char *varname;
+ const char *phys;
+ bool is_phys;
+ int n, e, retval;
+ uint32_t i;
+
+ /* argv[1] = name of array to get the data
+ * argv[2] = desired width
+ * argv[3] = memory address
+ * argv[4] = count to write
+ */
+ if (argc < 4 || argc > 5) {
+ Jim_WrongNumArgs(interp, 0, argv, "varname width addr nelems [phys]");
+ return JIM_ERR;
+ }
+ varname = Jim_GetString(argv[0], &len);
+ /* given "foo" get space for worse case "foo(%d)" .. add 20 */
+
+ e = Jim_GetLong(interp, argv[1], &l);
+ width = l;
+ if (e != JIM_OK)
+ return e;
+
+ e = Jim_GetLong(interp, argv[2], &l);
+ addr = l;
+ if (e != JIM_OK)
+ return e;
+ e = Jim_GetLong(interp, argv[3], &l);
+ len = l;
+ if (e != JIM_OK)
+ return e;
+ is_phys = false;
+ if (argc > 4) {
+ phys = Jim_GetString(argv[4], &n);
+ if (!strncmp(phys, "phys", n))
+ is_phys = true;
+ else
+ return JIM_ERR;
+ }
+ switch (width) {
+ case 8:
+ width = 1;
+ break;
+ case 16:
+ width = 2;
+ break;
+ case 32:
+ width = 4;
+ break;
+ default:
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ 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);
+ 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);
+ 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);
+ return JIM_ERR;
+ }
+
+ if ((width == 1) ||
+ ((width == 2) && ((addr & 1) == 0)) ||
+ ((width == 4) && ((addr & 3) == 0))) {
+ /* all is well */
+ } else {
+ char buf[100];
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ sprintf(buf, "array2mem address: 0x%08" PRIx32 " is not aligned for %" PRId32 " byte reads",
+ addr,
+ width);
+ Jim_AppendStrings(interp, Jim_GetResult(interp), buf, NULL);
+ return JIM_ERR;
+ }
+
+ /* Transfer loop */
+
+ /* index counter */
+ n = 0;
+ /* assume ok */
+ e = JIM_OK;
+
+ size_t buffersize = 4096;
+ uint8_t *buffer = malloc(buffersize);
+ if (buffer == NULL)
+ return JIM_ERR;
+
+ while (len) {
+ /* Slurp... in buffer size chunks */
+
+ count = len; /* in objects.. */
+ if (count > (buffersize / width))
+ count = (buffersize / width);
+
+ v = 0; /* shut up gcc */
+ 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);
+ break;
+ case 2:
+ target_buffer_set_u16(target, &buffer[i * width], v);
+ break;
+ case 1:
+ buffer[i] = v & 0x0ff;
+ break;
+ }
+ }
+ len -= count;
+
+ if (is_phys)
+ retval = target_write_phys_memory(target, addr, width, count, buffer);
+ else
+ retval = target_write_memory(target, addr, width, count, buffer);
+ if (retval != ERROR_OK) {
+ /* BOO !*/
+ LOG_ERROR("array2mem: Write @ 0x%08" PRIx32 ", w=%" PRId32 ", cnt=%" PRId32 ", failed",
+ addr,
+ width,
+ count);
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+ Jim_AppendStrings(interp, Jim_GetResult(interp), "array2mem: cannot read memory", NULL);
+ e = JIM_ERR;
+ break;
+ }
+ addr += count * width;
+ }
+
+ free(buffer);
+
+ Jim_SetResult(interp, Jim_NewEmptyStringObj(interp));
+
+ return e;
+}
+
+/* FIX? should we propagate errors here rather than printing them
+ * and continuing?
+ */
+void target_handle_event(struct target *target, enum target_event e)
+{
+ struct target_event_action *teap;
+
+ for (teap = target->event_action; teap != NULL; teap = teap->next) {
+ if (teap->event == e) {
+ LOG_DEBUG("target(%d): %s (%s) event: %d (%s) action: %s",
+ target->target_number,
+ target_name(target),
+ target_type_name(target),
+ e,
+ Jim_Nvp_value2name_simple(nvp_target_event, e)->name,
+ Jim_GetString(teap->body, NULL));
+
+ /* Override current target by the target an event
+ * is issued from (lot of scripts need it).
+ * Return back to previous override as soon
+ * as the handler processing is done */
+ struct command_context *cmd_ctx = current_command_context(teap->interp);
+ struct target *saved_target_override = cmd_ctx->current_target_override;
+ cmd_ctx->current_target_override = target;
+
+ 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));
+ }
+
+ cmd_ctx->current_target_override = saved_target_override;
+ }
+ }
+}
+
+/**
+ * Returns true only if the target has a handler for the specified event.
+ */
+bool target_has_event_action(struct target *target, enum target_event event)
+{
+ struct target_event_action *teap;
+
+ for (teap = target->event_action; teap != NULL; teap = teap->next) {
+ if (teap->event == event)
+ return true;
+ }
+ return false;
+}
+
+enum target_cfg_param {
+ TCFG_TYPE,
+ TCFG_EVENT,
+ TCFG_WORK_AREA_VIRT,
+ TCFG_WORK_AREA_PHYS,
+ TCFG_WORK_AREA_SIZE,
+ TCFG_WORK_AREA_BACKUP,
+ TCFG_ENDIAN,
+ TCFG_COREID,
+ TCFG_CHAIN_POSITION,
+ TCFG_DBGBASE,
+ TCFG_RTOS,
+ TCFG_DEFER_EXAMINE,
+ TCFG_GDB_PORT,
+};
+
+static Jim_Nvp nvp_config_opts[] = {
+ { .name = "-type", .value = TCFG_TYPE },
+ { .name = "-event", .value = TCFG_EVENT },
+ { .name = "-work-area-virt", .value = TCFG_WORK_AREA_VIRT },
+ { .name = "-work-area-phys", .value = TCFG_WORK_AREA_PHYS },
+ { .name = "-work-area-size", .value = TCFG_WORK_AREA_SIZE },
+ { .name = "-work-area-backup", .value = TCFG_WORK_AREA_BACKUP },
+ { .name = "-endian" , .value = TCFG_ENDIAN },
+ { .name = "-coreid", .value = TCFG_COREID },
+ { .name = "-chain-position", .value = TCFG_CHAIN_POSITION },
+ { .name = "-dbgbase", .value = TCFG_DBGBASE },
+ { .name = "-rtos", .value = TCFG_RTOS },
+ { .name = "-defer-examine", .value = TCFG_DEFER_EXAMINE },
+ { .name = "-gdb-port", .value = TCFG_GDB_PORT },
+ { .name = NULL, .value = -1 }
+};
+
+static int target_configure(Jim_GetOptInfo *goi, struct target *target)
+{
+ Jim_Nvp *n;
+ Jim_Obj *o;
+ jim_wide w;