/** * Copies code to a working area. This will allocate room for the code plus the * additional amount requested if the working area pointer is null. * * @param target Pointer to the target to copy code to * @param code Pointer to the code area to be copied * @param code_size Size of the code being copied * @param additional Size of the additional area to be allocated in addition to * code * @param area Pointer to a pointer to a working area to copy code to * @return Success or failure of the operation */ static int arm_code_to_working_area(struct target *target, const uint32_t *code, unsigned code_size, unsigned additional, struct working_area **area) { uint8_t code_buf[code_size]; unsigned i; int retval; unsigned size = code_size + additional; /* REVISIT this assumes size doesn't ever change. * That's usually correct; but there are boards with * both large and small page chips, where it won't be... */ /* make sure we have a working area */ if (NULL == *area) { retval = target_alloc_working_area(target, size, area); if (retval != ERROR_OK) { LOG_DEBUG("%s: no %d byte buffer", __func__, (int) size); return ERROR_NAND_NO_BUFFER; } } /* buffer code in target endianness */ for (i = 0; i < code_size / 4; i++) target_buffer_set_u32(target, code_buf + i * 4, code[i]); /* copy code to work area */ retval = target_write_memory(target, (*area)->address, 4, code_size / 4, code_buf); return retval; }
/* Write byte at address */ static int arc_mem_write_block8(struct target *target, uint32_t addr, uint32_t count, void *buf) { struct arc32_common *arc32 = target_to_arc32(target); uint32_t i; LOG_DEBUG("Write 1-byte memory block: addr=0x%08" PRIx32 ", count=%" PRIu32, addr, count); /* We will read data from memory, so we need to flush D$. */ CHECK_RETVAL(arc32_dcache_flush(target)); uint32_t buffer_he; uint8_t buffer_te[sizeof(uint32_t)]; /* non-word writes are less common, than 4-byte writes, so I suppose we can * allowe ourselves to write this in a cycle, instead of calling arc_jtag * with count > 1. */ for(i = 0; i < count; i++) { /* See comment in arc_mem_write_block16 for details. Since it is a byte * there is not need to convert write buffer to target endianness, but * we still have to convert read buffer. */ CHECK_RETVAL(arc_jtag_read_memory(&arc32->jtag_info, (addr + i) & ~3, 1, &buffer_he, arc_mem_is_slow_memory(arc32, (addr + i) & ~3, 4, 1))); target_buffer_set_u32(target, buffer_te, buffer_he); memcpy(buffer_te + ((addr + i) & 3), (uint8_t*)buf + i, 1); buffer_he = target_buffer_get_u32(target, buffer_te); CHECK_RETVAL(arc_jtag_write_memory(&arc32->jtag_info, (addr + i) & ~3, 1, &buffer_he)); } /* Invalidate caches. */ CHECK_RETVAL(arc32_cache_invalidate(target)); return ERROR_OK; }
static int or1k_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { LOG_DEBUG("Adding breakpoint: addr %08x, len %d, type %d, set: %d, id: %d", breakpoint->address, breakpoint->length, breakpoint->type, breakpoint->set, breakpoint->unique_id); struct or1k_common *or1k = target_to_or1k(target); /* Only support SW breakpoints for now. */ if (breakpoint->type == BKPT_HARD) LOG_ERROR("HW breakpoints not supported for now. Doing SW breakpoint."); /* Read and save the instruction */ or1k_jtag_read_memory32(&or1k->jtag, breakpoint->address , 1, (uint32_t*)breakpoint->orig_instr); /* Sub in the OR1K trap instruction */ uint32_t or1k_trap_insn; /* set correct endianess */ target_buffer_set_u32(target, (uint8_t*)&or1k_trap_insn, OR1K_TRAP_INSTR); or1k_jtag_write_memory32(&or1k->jtag, breakpoint->address , 1, (uint32_t*)&or1k_trap_insn); /* invalidate instruction cache */ or1k_jtag_write_cpu(&or1k->jtag, OR1K_ICBIR_CPU_REG_ADD, 1, &breakpoint->address); return ERROR_OK; }
static int or1k_add_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct or1k_common *or1k = target_to_or1k(target); struct or1k_du *du_core = or1k_to_du(or1k); uint8_t data; LOG_DEBUG("Adding breakpoint: addr 0x%08" TARGET_PRIxADDR ", len %d, type %d, set: %d, id: %" PRId32, breakpoint->address, breakpoint->length, breakpoint->type, breakpoint->set, breakpoint->unique_id); /* Only support SW breakpoints for now. */ if (breakpoint->type == BKPT_HARD) LOG_ERROR("HW breakpoints not supported for now. Doing SW breakpoint."); /* Read and save the instruction */ int retval = du_core->or1k_jtag_read_memory(&or1k->jtag, breakpoint->address, 4, 1, &data); if (retval != ERROR_OK) { LOG_ERROR("Error while reading the instruction at 0x%08" TARGET_PRIxADDR, breakpoint->address); return retval; } if (breakpoint->orig_instr != NULL) free(breakpoint->orig_instr); breakpoint->orig_instr = malloc(breakpoint->length); memcpy(breakpoint->orig_instr, &data, breakpoint->length); /* Sub in the OR1K trap instruction */ uint8_t or1k_trap_insn[4]; target_buffer_set_u32(target, or1k_trap_insn, OR1K_TRAP_INSTR); retval = du_core->or1k_jtag_write_memory(&or1k->jtag, breakpoint->address, 4, 1, or1k_trap_insn); if (retval != ERROR_OK) { LOG_ERROR("Error while writing OR1K_TRAP_INSTR at 0x%08" TARGET_PRIxADDR, breakpoint->address); return retval; } /* invalidate instruction cache */ uint32_t addr = breakpoint->address; retval = du_core->or1k_jtag_write_cpu(&or1k->jtag, OR1K_ICBIR_CPU_REG_ADD, 1, &addr); if (retval != ERROR_OK) { LOG_ERROR("Error while invalidating the ICACHE"); return retval; } return ERROR_OK; }
static int lpc2000_iap_working_area_init(struct flash_bank *bank, struct working_area **iap_working_area) { struct target *target = bank->target; struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; if (target_alloc_working_area(target, IAP_CODE_LEN + lpc2000_info->iap_max_stack, iap_working_area) != ERROR_OK) { LOG_ERROR("no working area specified, can't write LPC2000 internal flash"); return ERROR_FLASH_OPERATION_FAILED; } uint8_t jump_gate[8]; /* write IAP code to working area */ switch (lpc2000_info->variant) { case lpc800: case lpc1100: case lpc1500: case lpc1700: case lpc4300: case lpc54100: case lpc_auto: target_buffer_set_u32(target, jump_gate, ARMV4_5_T_BX(12)); target_buffer_set_u32(target, jump_gate + 4, ARMV5_T_BKPT(0)); break; case lpc2000_v1: case lpc2000_v2: target_buffer_set_u32(target, jump_gate, ARMV4_5_BX(12)); target_buffer_set_u32(target, jump_gate + 4, ARMV4_5_B(0xfffffe, 0)); break; default: LOG_ERROR("BUG: unknown lpc2000_info->variant encountered"); exit(-1); } int retval = target_write_memory(target, (*iap_working_area)->address, 4, 2, jump_gate); if (retval != ERROR_OK) { LOG_ERROR("Write memory at address 0x%8.8" PRIx32 " failed (check work_area definition)", (*iap_working_area)->address); target_free_working_area(target, *iap_working_area); } return retval; }
/* Write half-word at half-word-aligned address */ static int arc_mem_write_block16(struct target *target, uint32_t addr, int count, void *buf) { struct arc32_common *arc32 = target_to_arc32(target); int retval = ERROR_OK; int i; LOG_DEBUG("Write memory (16bit): addr=0x%" PRIx32 ", count=%i", addr, count); /* Check arguments */ if (addr & 1u) return ERROR_TARGET_UNALIGNED_ACCESS; /* We will read data from memory, so we need to flush D$. */ retval = arc32_dcache_flush(target); if (ERROR_OK != retval) return retval; uint32_t buffer_he; uint8_t buffer_te[sizeof(uint32_t)]; uint8_t halfword_te[sizeof(uint16_t)]; /* non-word writes are less common, than 4-byte writes, so I suppose we can * allowe ourselves to write this in a cycle, instead of calling arc_jtag * with count > 1. */ for(i = 0; i < count; i++) { /* We can read only word at word-aligned address. Also *jtag_read_memory * functions return data in host endianness, so host endianness != * target endianness we have to convert data back to target endianness, * or bytes will be at the wrong places.So: * 1) read word * 2) convert to target endianness * 3) make changes * 4) convert back to host endianness * 5) write word back to target. */ retval = arc_jtag_read_memory(&arc32->jtag_info, (addr + i * sizeof(uint16_t)) & ~3u, 1, &buffer_he); target_buffer_set_u32(target, buffer_te, buffer_he); /* buf is in host endianness, convert to target */ target_buffer_set_u16(target, halfword_te, ((uint16_t *)buf)[i]); memcpy(buffer_te + ((addr + i * sizeof(uint16_t)) & 3u), halfword_te, sizeof(uint16_t)); buffer_he = target_buffer_get_u32(target, buffer_te); retval = arc_jtag_write_memory(&arc32->jtag_info, (addr + i * sizeof(uint16_t)) & ~3u, 1, &buffer_he); if (ERROR_OK != retval) return retval; } /* Invalidate caches. */ retval = arc32_cache_invalidate(target); return retval; }
/* Write byte at address */ static int arc_mem_write_block8(struct target *target, uint32_t addr, int count, void *buf) { struct arc32_common *arc32 = target_to_arc32(target); int retval = ERROR_OK; int i; /* We will read data from memory, so we need to flush D$. */ retval = arc32_dcache_flush(target); if (ERROR_OK != retval) return retval; uint32_t buffer_he; uint8_t buffer_te[sizeof(uint32_t)]; /* non-word writes are less common, than 4-byte writes, so I suppose we can * allowe ourselves to write this in a cycle, instead of calling arc_jtag * with count > 1. */ for(i = 0; i < count; i++) { /* See comment in arc_mem_write_block16 for details. Since it is a byte * there is not need to convert write buffer to target endianness, but * we still have to convert read buffer. */ retval = arc_jtag_read_memory(&arc32->jtag_info, (addr + i) & ~3, 1, &buffer_he); target_buffer_set_u32(target, buffer_te, buffer_he); memcpy(buffer_te + ((addr + i) & 3), (uint8_t*)buf + i, 1); buffer_he = target_buffer_get_u32(target, buffer_te); retval = arc_jtag_write_memory(&arc32->jtag_info, (addr + i) & ~3, 1, &buffer_he); if (ERROR_OK != retval) return retval; } /* Invalidate caches. */ retval = arc32_cache_invalidate(target); return retval; }
/* Reference: "XMC4500 Flash Protection.pptx" app note */ static int xmc4xxx_flash_protect(struct flash_bank *bank, int level, bool read_protect, int first, int last) { /* User configuration block buffers */ uint8_t ucp0_buf[8 * sizeof(uint32_t)] = {0}; uint32_t ucb_base = 0; uint32_t procon = 0; int res = ERROR_OK; uint32_t status = 0; bool proin = false; struct xmc4xxx_flash_bank *fb = bank->driver_priv; /* Read protect only works for user 0, make sure we don't try * to do something silly */ if (level != 0 && read_protect) { LOG_ERROR("Read protection is for user level 0 only!"); return ERROR_FAIL; } /* Check to see if protection is already installed for the * specified user level. If it is, the user configuration * block will need to be erased before we can continue */ /* Grab the flash status register*/ res = xmc4xxx_get_flash_status(bank, &status); if (res != ERROR_OK) return res; switch (level) { case 0: if ((status & FSR_RPROIN_MASK) || (status & FSR_WPROIN0_MASK)) proin = true; break; case 1: if (status & FSR_WPROIN1_MASK) proin = true; break; case 2: if (status & FSR_WPROIN2_MASK) proin = true; break; } if (proin) { LOG_ERROR("Flash protection is installed for user %d" " and must be removed before continuing", level); return ERROR_FAIL; } /* If this device has 12 flash sectors, protection for * sectors 10 & 11 are handled jointly. If we are trying to * write all sectors, we should decrement * last to ensure we don't write to a register bit that * doesn't exist*/ if ((bank->num_sectors == 12) && (last == 12)) last--; /* We need to fill out the procon register representation * that we will be writing to the device */ for (int i = first; i <= last; i++) procon |= 1 << i; /* If read protection is requested, set the appropriate bit * (we checked that this is allowed above) */ if (read_protect) procon |= PROCON_RPRO_MASK; LOG_DEBUG("Setting flash protection with procon:"); LOG_DEBUG("PROCON: %"PRIx32, procon); /* First we need to copy in the procon register to the buffer * we're going to attempt to write. This is written twice */ target_buffer_set_u32(bank->target, &ucp0_buf[0 * 4], procon); target_buffer_set_u32(bank->target, &ucp0_buf[2 * 4], procon); /* Now we must copy in both flash passwords. As with the * procon data, this must be written twice (4 total words * worth of data) */ target_buffer_set_u32(bank->target, &ucp0_buf[4 * 4], fb->pw1); target_buffer_set_u32(bank->target, &ucp0_buf[5 * 4], fb->pw2); target_buffer_set_u32(bank->target, &ucp0_buf[6 * 4], fb->pw1); target_buffer_set_u32(bank->target, &ucp0_buf[7 * 4], fb->pw2); /* Finally, (if requested) we copy in the confirmation * code so that the protection is permanent and will * require a password to undo. */ target_buffer_set_u32(bank->target, &ucp0_buf[0 * 4], FLASH_PROTECT_CONFIRMATION_CODE); target_buffer_set_u32(bank->target, &ucp0_buf[2 * 4], FLASH_PROTECT_CONFIRMATION_CODE); /* Now that the data is copied into place, we must write * these pages into flash */ /* The user configuration block base depends on what level of * protection we're trying to install, select the proper one */ switch (level) { case 0: ucb_base = UCB0_BASE; break; case 1: ucb_base = UCB1_BASE; break; case 2: ucb_base = UCB2_BASE; break; } /* Write the user config pages */ res = xmc4xxx_write_page(bank, ucp0_buf, ucb_base, true); if (res != ERROR_OK) { LOG_ERROR("Error writing user configuration block 0"); return res; } return ERROR_OK; }
/* call LPC1700/LPC2000 IAP function * uses 180 bytes working area * 0x0 to 0x7: jump gate (BX to thumb state, b -2 to wait) * 0x8 to 0x1f: command parameter table (1+5 words) * 0x20 to 0x33: command result table (1+4 words) * 0x34 to 0xb3: stack (only 128b needed) */ static int lpc2000_iap_call(struct flash_bank *bank, int code, uint32_t param_table[5], uint32_t result_table[4]) { int retval; struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; struct target *target = bank->target; struct mem_param mem_params[2]; struct reg_param reg_params[5]; struct arm_algorithm arm_algo; /* for LPC2000 */ struct armv7m_algorithm armv7m_info; /* for LPC1700 */ uint32_t status_code; uint32_t iap_entry_point = 0; /* to make compiler happier */ /* regrab previously allocated working_area, or allocate a new one */ if (!lpc2000_info->iap_working_area) { uint8_t jump_gate[8]; /* make sure we have a working area */ if (target_alloc_working_area(target, 180, &lpc2000_info->iap_working_area) != ERROR_OK) { LOG_ERROR("no working area specified, can't write LPC2000 internal flash"); return ERROR_FLASH_OPERATION_FAILED; } /* write IAP code to working area */ switch (lpc2000_info->variant) { case lpc1700: target_buffer_set_u32(target, jump_gate, ARMV4_5_T_BX(12)); target_buffer_set_u32(target, jump_gate + 4, ARMV5_T_BKPT(0)); break; case lpc2000_v1: case lpc2000_v2: target_buffer_set_u32(target, jump_gate, ARMV4_5_BX(12)); target_buffer_set_u32(target, jump_gate + 4, ARMV4_5_B(0xfffffe, 0)); break; default: LOG_ERROR("BUG: unknown lpc2000_info->variant encountered"); exit(-1); } retval = target_write_memory(target, lpc2000_info->iap_working_area->address, 4, 2, jump_gate); if (retval != ERROR_OK) { LOG_ERROR( "Write memory at address 0x%8.8" PRIx32 " failed (check work_area definition)", lpc2000_info->iap_working_area->address); return retval; } } switch (lpc2000_info->variant) { case lpc1700: armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARMV7M_MODE_ANY; iap_entry_point = 0x1fff1ff1; break; case lpc2000_v1: case lpc2000_v2: arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; iap_entry_point = 0x7ffffff1; break; default: LOG_ERROR("BUG: unknown lpc2000->variant encountered"); exit(-1); } /* command parameter table */ init_mem_param(&mem_params[0], lpc2000_info->iap_working_area->address + 8, 6 * 4, PARAM_OUT); target_buffer_set_u32(target, mem_params[0].value, code); target_buffer_set_u32(target, mem_params[0].value + 0x04, param_table[0]); target_buffer_set_u32(target, mem_params[0].value + 0x08, param_table[1]); target_buffer_set_u32(target, mem_params[0].value + 0x0c, param_table[2]); target_buffer_set_u32(target, mem_params[0].value + 0x10, param_table[3]); target_buffer_set_u32(target, mem_params[0].value + 0x14, param_table[4]); init_reg_param(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, lpc2000_info->iap_working_area->address + 0x08); /* command result table */ init_mem_param(&mem_params[1], lpc2000_info->iap_working_area->address + 0x20, 5 * 4, PARAM_IN); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, lpc2000_info->iap_working_area->address + 0x20); /* IAP entry point */ init_reg_param(®_params[2], "r12", 32, PARAM_OUT); buf_set_u32(reg_params[2].value, 0, 32, iap_entry_point); switch (lpc2000_info->variant) { case lpc1700: /* IAP stack */ init_reg_param(®_params[3], "sp", 32, PARAM_OUT); buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xb4); /* return address */ init_reg_param(®_params[4], "lr", 32, PARAM_OUT); buf_set_u32(reg_params[4].value, 0, 32, (lpc2000_info->iap_working_area->address + 0x04) | 1); /* bit0 of LR = 1 to return in Thumb mode */ target_run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, 0, 10000, &armv7m_info); break; case lpc2000_v1: case lpc2000_v2: /* IAP stack */ init_reg_param(®_params[3], "sp_svc", 32, PARAM_OUT); buf_set_u32(reg_params[3].value, 0, 32, lpc2000_info->iap_working_area->address + 0xb4); /* return address */ init_reg_param(®_params[4], "lr_svc", 32, PARAM_OUT); buf_set_u32(reg_params[4].value, 0, 32, lpc2000_info->iap_working_area->address + 0x04); target_run_algorithm(target, 2, mem_params, 5, reg_params, lpc2000_info->iap_working_area->address, lpc2000_info->iap_working_area->address + 0x4, 10000, &arm_algo); break; default: LOG_ERROR("BUG: unknown lpc2000->variant encountered"); exit(-1); } status_code = target_buffer_get_u32(target, mem_params[1].value); result_table[0] = target_buffer_get_u32(target, mem_params[1].value + 0x04); result_table[1] = target_buffer_get_u32(target, mem_params[1].value + 0x08); result_table[2] = target_buffer_get_u32(target, mem_params[1].value + 0x0c); result_table[3] = target_buffer_get_u32(target, mem_params[1].value + 0x10); LOG_DEBUG("IAP command = %i (0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ") completed with result = %8.8" PRIx32, code, param_table[0], param_table[1], param_table[2], param_table[3], param_table[4], status_code); destroy_mem_param(&mem_params[0]); destroy_mem_param(&mem_params[1]); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return status_code; }
static int lpc2000_iap_call(struct flash_bank *bank, struct working_area *iap_working_area, int code, uint32_t param_table[5], uint32_t result_table[4]) { struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; struct target *target = bank->target; struct arm_algorithm arm_algo; /* for LPC2000 */ struct armv7m_algorithm armv7m_info; /* for LPC1700 */ uint32_t iap_entry_point = 0; /* to make compiler happier */ switch (lpc2000_info->variant) { case lpc800: case lpc1100: case lpc1700: case lpc_auto: armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; iap_entry_point = 0x1fff1ff1; break; case lpc2000_v1: case lpc2000_v2: arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; iap_entry_point = 0x7ffffff1; break; case lpc4300: armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARM_MODE_THREAD; /* read out IAP entry point from ROM driver table at 0x10400100 */ target_read_u32(target, 0x10400100, &iap_entry_point); break; default: LOG_ERROR("BUG: unknown lpc2000->variant encountered"); exit(-1); } struct mem_param mem_params[2]; /* command parameter table */ init_mem_param(&mem_params[0], iap_working_area->address + 8, 6 * 4, PARAM_OUT); target_buffer_set_u32(target, mem_params[0].value, code); target_buffer_set_u32(target, mem_params[0].value + 0x04, param_table[0]); target_buffer_set_u32(target, mem_params[0].value + 0x08, param_table[1]); target_buffer_set_u32(target, mem_params[0].value + 0x0c, param_table[2]); target_buffer_set_u32(target, mem_params[0].value + 0x10, param_table[3]); target_buffer_set_u32(target, mem_params[0].value + 0x14, param_table[4]); struct reg_param reg_params[5]; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, iap_working_area->address + 0x08); /* command result table */ init_mem_param(&mem_params[1], iap_working_area->address + 0x20, 5 * 4, PARAM_IN); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, iap_working_area->address + 0x20); /* IAP entry point */ init_reg_param(®_params[2], "r12", 32, PARAM_OUT); buf_set_u32(reg_params[2].value, 0, 32, iap_entry_point); switch (lpc2000_info->variant) { case lpc800: case lpc1100: case lpc1700: case lpc4300: case lpc_auto: /* IAP stack */ init_reg_param(®_params[3], "sp", 32, PARAM_OUT); buf_set_u32(reg_params[3].value, 0, 32, iap_working_area->address + IAP_CODE_LEN + lpc2000_info->iap_max_stack); /* return address */ init_reg_param(®_params[4], "lr", 32, PARAM_OUT); buf_set_u32(reg_params[4].value, 0, 32, (iap_working_area->address + 0x04) | 1); /* bit0 of LR = 1 to return in Thumb mode */ target_run_algorithm(target, 2, mem_params, 5, reg_params, iap_working_area->address, 0, 10000, &armv7m_info); break; case lpc2000_v1: case lpc2000_v2: /* IAP stack */ init_reg_param(®_params[3], "sp_svc", 32, PARAM_OUT); buf_set_u32(reg_params[3].value, 0, 32, iap_working_area->address + IAP_CODE_LEN + lpc2000_info->iap_max_stack); /* return address */ init_reg_param(®_params[4], "lr_svc", 32, PARAM_OUT); buf_set_u32(reg_params[4].value, 0, 32, iap_working_area->address + 0x04); target_run_algorithm(target, 2, mem_params, 5, reg_params, iap_working_area->address, iap_working_area->address + 0x4, 10000, &arm_algo); break; default: LOG_ERROR("BUG: unknown lpc2000->variant encountered"); exit(-1); } int status_code = target_buffer_get_u32(target, mem_params[1].value); result_table[0] = target_buffer_get_u32(target, mem_params[1].value + 0x04); result_table[1] = target_buffer_get_u32(target, mem_params[1].value + 0x08); result_table[2] = target_buffer_get_u32(target, mem_params[1].value + 0x0c); result_table[3] = target_buffer_get_u32(target, mem_params[1].value + 0x10); LOG_DEBUG("IAP command = %i (0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ") completed with result = %8.8x", code, param_table[0], param_table[1], param_table[2], param_table[3], param_table[4], status_code); destroy_mem_param(&mem_params[0]); destroy_mem_param(&mem_params[1]); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return status_code; }