void arm9tdmi_change_to_arm(target_t *target, u32 *r0, u32 *pc) { int retval = ERROR_OK; /* get pointers to arch-specific information */ armv4_5_common_t *armv4_5 = target->arch_info; arm7_9_common_t *arm7_9 = armv4_5->arch_info; arm_jtag_t *jtag_info = &arm7_9->jtag_info; /* save r0 before using it and put system in ARM state * to allow common handling of ARM and THUMB debugging */ /* fetch STR r0, [r0] */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); /* STR r0, [r0] in Memory */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, r0, 0); /* MOV r0, r15 fetched, STR in Decode */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); /* nothing fetched, STR r0, [r0] in Memory */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, pc, 0); /* use pc-relative LDR to clear r0[1:0] (for switch to ARM mode) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), 0, NULL, 0); /* LDR in Decode */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); /* LDR in Execute */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); /* LDR in Memory (to account for interlock) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); /* fetch BX */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), 0, NULL, 0); /* NOP fetched, BX in Decode, MOV in Execute */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); /* NOP fetched, BX in Execute (1) */ arm9tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, 0, NULL, 0); if((retval = jtag_execute_queue()) != ERROR_OK) { return; } /* fix program counter: * MOV r0, r15 was the 5th instruction (+8) * reading PC in Thumb state gives address of instruction + 4 */ *pc -= 0xc; }
static void arm7tdmi_change_to_arm(struct target *target, uint32_t *r0, uint32_t *pc) { struct arm7_9_common *arm7_9 = target_to_arm7_9(target); struct arm_jtag *jtag_info = &arm7_9->jtag_info; /* save r0 before using it and put system in ARM state * to allow common handling of ARM and THUMB debugging */ /* fetch STR r0, [r0] */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); /* nothing fetched, STR r0, [r0] in Execute (2) */ arm7tdmi_clock_data_in(jtag_info, r0); /* MOV r0, r15 fetched, STR in Decode */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_MOV(0, 15), NULL, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_STR(0, 0), NULL, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); /* nothing fetched, STR r0, [r0] in Execute (2) */ arm7tdmi_clock_data_in(jtag_info, pc); /* use pc-relative LDR to clear r0[1:0] (for switch to ARM mode) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_LDR_PCREL(0), NULL, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); /* nothing fetched, data for LDR r0, [PC, #0] */ arm7tdmi_clock_out(jtag_info, 0x0, NULL, 0); /* nothing fetched, data from previous cycle is written to register */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); /* fetch BX */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_BX(0), NULL, 0); /* NOP fetched, BX in Decode, MOV in Execute */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); /* NOP fetched, BX in Execute (1) */ arm7tdmi_clock_out(jtag_info, ARMV4_5_T_NOP, NULL, 0); jtag_execute_queue(); /* fix program counter: * MOV r0, r15 was the 4th instruction (+6) * reading PC in Thumb state gives address of instruction + 4 */ *pc -= 0xa; }
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; }
/* 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; }