+
+ /* 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;
+ }
+
+ if (retval == ERROR_OK) {
+ /* check if algorithm set rp = 0 after fifo writer loop finished */
+ retval = target_read_u32(target, rp_addr, &rp);
+ if (retval == ERROR_OK && rp == 0) {
+ LOG_ERROR("flash write algorithm aborted by target");
+ retval = ERROR_FLASH_OPERATION_FAILED;
+ }
+ }
+
+ return retval;
+}
+
+int target_read_memory(struct target *target,
+ target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer)
+{
+ if (!target_was_examined(target)) {
+ LOG_ERROR("Target not examined yet");
+ return ERROR_FAIL;
+ }
+ if (!target->type->read_memory) {
+ LOG_ERROR("Target %s doesn't support read_memory", target_name(target));
+ return ERROR_FAIL;
+ }
+ return target->type->read_memory(target, address, size, count, buffer);
+}
+
+int target_read_phys_memory(struct target *target,
+ target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer)
+{
+ if (!target_was_examined(target)) {
+ LOG_ERROR("Target not examined yet");
+ return ERROR_FAIL;
+ }
+ if (!target->type->read_phys_memory) {
+ LOG_ERROR("Target %s doesn't support read_phys_memory", target_name(target));
+ return ERROR_FAIL;
+ }
+ return target->type->read_phys_memory(target, address, size, count, buffer);
+}
+
+int target_write_memory(struct target *target,
+ target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer)
+{
+ if (!target_was_examined(target)) {
+ LOG_ERROR("Target not examined yet");
+ return ERROR_FAIL;
+ }
+ if (!target->type->write_memory) {
+ LOG_ERROR("Target %s doesn't support write_memory", target_name(target));
+ return ERROR_FAIL;
+ }
+ return target->type->write_memory(target, address, size, count, buffer);
+}
+
+int target_write_phys_memory(struct target *target,
+ target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer)
+{
+ if (!target_was_examined(target)) {
+ LOG_ERROR("Target not examined yet");
+ return ERROR_FAIL;
+ }
+ if (!target->type->write_phys_memory) {
+ LOG_ERROR("Target %s doesn't support write_phys_memory", target_name(target));
+ return ERROR_FAIL;
+ }
+ return target->type->write_phys_memory(target, address, size, count, buffer);
+}
+
+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 (add breakpoint)", target_name(target));
+ return ERROR_TARGET_NOT_HALTED;
+ }
+ return target->type->add_breakpoint(target, breakpoint);
+}
+
+int target_add_context_breakpoint(struct target *target,
+ struct breakpoint *breakpoint)
+{
+ if (target->state != TARGET_HALTED) {
+ LOG_WARNING("target %s is not halted (add context breakpoint)", target_name(target));
+ return ERROR_TARGET_NOT_HALTED;
+ }
+ return target->type->add_context_breakpoint(target, breakpoint);
+}
+
+int target_add_hybrid_breakpoint(struct target *target,
+ struct breakpoint *breakpoint)
+{
+ if (target->state != TARGET_HALTED) {
+ LOG_WARNING("target %s is not halted (add hybrid breakpoint)", target_name(target));
+ return ERROR_TARGET_NOT_HALTED;
+ }
+ return target->type->add_hybrid_breakpoint(target, breakpoint);
+}
+
+int target_remove_breakpoint(struct target *target,
+ struct breakpoint *breakpoint)
+{
+ return target->type->remove_breakpoint(target, breakpoint);
+}
+
+int target_add_watchpoint(struct target *target,
+ struct watchpoint *watchpoint)
+{
+ if (target->state != TARGET_HALTED) {
+ LOG_WARNING("target %s is not halted (add watchpoint)", target_name(target));
+ return ERROR_TARGET_NOT_HALTED;
+ }
+ return target->type->add_watchpoint(target, watchpoint);
+}
+int target_remove_watchpoint(struct target *target,
+ struct watchpoint *watchpoint)
+{
+ return target->type->remove_watchpoint(target, watchpoint);
+}
+int target_hit_watchpoint(struct target *target,
+ struct watchpoint **hit_watchpoint)
+{
+ if (target->state != TARGET_HALTED) {
+ LOG_WARNING("target %s is not halted (hit watchpoint)", target->cmd_name);
+ return ERROR_TARGET_NOT_HALTED;
+ }
+
+ if (target->type->hit_watchpoint == NULL) {
+ /* For backward compatible, if hit_watchpoint is not implemented,
+ * return ERROR_FAIL such that gdb_server will not take the nonsense
+ * information. */
+ return ERROR_FAIL;
+ }
+
+ return target->type->hit_watchpoint(target, hit_watchpoint);
+}
+
+int target_get_gdb_reg_list(struct target *target,
+ struct reg **reg_list[], int *reg_list_size,
+ enum target_register_class reg_class)
+{
+ return target->type->get_gdb_reg_list(target, reg_list, reg_list_size, reg_class);
+}
+
+bool target_supports_gdb_connection(struct target *target)
+{
+ /*
+ * based on current code, we can simply exclude all the targets that
+ * don't provide get_gdb_reg_list; this could change with new targets.
+ */
+ return !!target->type->get_gdb_reg_list;
+}
+
+int target_step(struct target *target,
+ int current, target_addr_t address, int handle_breakpoints)
+{
+ 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 (gdb fileio)", 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 (gdb fileio end)", 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 (profiling)", target->cmd_name);
+ return ERROR_TARGET_NOT_HALTED;
+ }
+ return target->type->profiling(target, samples, max_num_samples,
+ num_samples, seconds);
+}
+
+/**
+ * Reset the @c examined flag for the given target.
+ * Pure paranoia -- targets are zeroed on allocation.
+ */
+static void target_reset_examined(struct target *target)
+{
+ target->examined = false;
+}
+
+static int handle_target(void *priv);
+
+static int target_init_one(struct command_context *cmd_ctx,
+ struct target *target)
+{
+ target_reset_examined(target);
+
+ struct target_type *type = target->type;
+ if (type->examine == NULL)
+ type->examine = default_examine;
+
+ 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) {
+ LOG_ERROR("target '%s' init failed", target_name(target));
+ return retval;
+ }
+
+ /* 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->virt2phys == NULL) {