X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Ftarget%2Fcortex_a8.c;h=b006e81a64df7f91547fce2a4020b70d2042c083;hb=bf3abc48f008e0a0c0e42b943481872599463af6;hp=d02fee9e17affa30f904c726d8a4913e9b59d9dc;hpb=71cde5e359f273585880ea8986709b950ba85b08;p=openocd.git diff --git a/src/target/cortex_a8.c b/src/target/cortex_a8.c index d02fee9e17..b006e81a64 100644 --- a/src/target/cortex_a8.c +++ b/src/target/cortex_a8.c @@ -237,7 +237,7 @@ static int cortex_a8_dap_read_coreregister_u32(struct target *target, struct armv7a_common *armv7a = target_to_armv7a(target); struct swjdp_common *swjdp = &armv7a->swjdp_info; - if (reg > 16) + if (reg > 17) return retval; if (reg < 15) @@ -251,10 +251,12 @@ static int cortex_a8_dap_read_coreregister_u32(struct target *target, cortex_a8_exec_opcode(target, 0xE1A0000F); cortex_a8_exec_opcode(target, ARMV4_5_MCR(14, 0, 0, 0, 5, 0)); } - else if (reg == 16) + else { - /* "MRS r0, CPSR"; then move r0 to DCCTX */ - cortex_a8_exec_opcode(target, ARMV4_5_MRS(0, 0)); + /* "MRS r0, CPSR" or "MRS r0, SPSR" + * then move r0 to DCCTX + */ + cortex_a8_exec_opcode(target, ARMV4_5_MRS(0, reg & 1)); cortex_a8_exec_opcode(target, ARMV4_5_MCR(14, 0, 0, 0, 5, 0)); } @@ -268,11 +270,13 @@ static int cortex_a8_dap_read_coreregister_u32(struct target *target, retval = mem_ap_read_atomic_u32(swjdp, armv7a->debug_base + CPUDBG_DTRTX, value); + LOG_DEBUG("read DCC 0x%08" PRIx32, *value); return retval; } -static int cortex_a8_dap_write_coreregister_u32(struct target *target, uint32_t value, int regnum) +static int cortex_a8_dap_write_coreregister_u32(struct target *target, + uint32_t value, int regnum) { int retval = ERROR_OK; uint8_t Rd = regnum&0xFF; @@ -292,29 +296,39 @@ static int cortex_a8_dap_write_coreregister_u32(struct target *target, uint32_t cortex_a8_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0)); } - if (Rd > 16) + if (Rd > 17) return retval; /* Write to DCCRX */ + LOG_DEBUG("write DCC 0x%08" PRIx32, value); retval = mem_ap_write_u32(swjdp, armv7a->debug_base + CPUDBG_DTRRX, value); if (Rd < 15) { - /* DCCRX to Rd, MCR p14, 0, Rd, c0, c5, 0, 0xEE000E15 */ + /* DCCRX to Rn, "MCR p14, 0, Rn, c0, c5, 0", 0xEE00nE15 */ cortex_a8_exec_opcode(target, ARMV4_5_MRC(14, 0, Rd, 0, 5, 0)); } else if (Rd == 15) { + /* DCCRX to R0, "MCR p14, 0, R0, c0, c5, 0", 0xEE000E15 + * then "mov r15, r0" + */ cortex_a8_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0)); cortex_a8_exec_opcode(target, 0xE1A0F000); } - else if (Rd == 16) + else { + /* DCCRX to R0, "MCR p14, 0, R0, c0, c5, 0", 0xEE000E15 + * then "MSR CPSR_cxsf, r0" or "MSR SPSR_cxsf, r0" (all fields) + */ cortex_a8_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0)); - cortex_a8_exec_opcode(target, ARMV4_5_MSR_GP(0, 0xF, 0)); - /* Execute a PrefetchFlush instruction through the ITR. */ - cortex_a8_exec_opcode(target, ARMV4_5_MCR(15, 0, 0, 7, 5, 4)); + cortex_a8_exec_opcode(target, ARMV4_5_MSR_GP(0, 0xF, Rd & 1)); + + /* "Prefetch flush" after modifying execution status in CPSR */ + if (Rd == 16) + cortex_a8_exec_opcode(target, + ARMV4_5_MCR(15, 0, 0, 7, 5, 4)); } return retval; @@ -443,7 +457,7 @@ static int cortex_a8_resume(struct target *target, int current, uint32_t address, int handle_breakpoints, int debug_execution) { struct armv7a_common *armv7a = target_to_armv7a(target); - struct armv4_5_common_s *armv4_5 = &armv7a->armv4_5_common; + struct arm *armv4_5 = &armv7a->armv4_5_common; struct swjdp_common *swjdp = &armv7a->swjdp_info; // struct breakpoint *breakpoint = NULL; @@ -482,8 +496,7 @@ static int cortex_a8_resume(struct target *target, int current, /* current = 1: continue on current pc, otherwise continue at
*/ resume_pc = buf_get_u32( - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, - armv4_5->core_mode, 15).value, + armv4_5->core_cache->reg_list[15].value, 0, 32); if (!current) resume_pc = address; @@ -508,16 +521,13 @@ static int cortex_a8_resume(struct target *target, int current, return ERROR_FAIL; } LOG_DEBUG("resume pc = 0x%08" PRIx32, resume_pc); - buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, - armv4_5->core_mode, 15).value, + buf_set_u32(armv4_5->core_cache->reg_list[15].value, 0, 32, resume_pc); - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, - armv4_5->core_mode, 15).dirty = 1; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, - armv4_5->core_mode, 15).valid = 1; + armv4_5->core_cache->reg_list[15].dirty = 1; + armv4_5->core_cache->reg_list[15].valid = 1; cortex_a8_restore_context(target); -// arm7_9_restore_context(target); TODO Context is currently NOT Properly restored + #if 0 /* the front-end may request us not to handle breakpoints */ if (handle_breakpoints) @@ -573,7 +583,7 @@ static int cortex_a8_debug_entry(struct target *target) struct working_area *regfile_working_area = NULL; struct cortex_a8_common *cortex_a8 = target_to_cortex_a8(target); struct armv7a_common *armv7a = target_to_armv7a(target); - struct armv4_5_common_s *armv4_5 = &armv7a->armv4_5_common; + struct arm *armv4_5 = &armv7a->armv4_5_common; struct swjdp_common *swjdp = &armv7a->swjdp_info; struct reg *reg; @@ -634,41 +644,12 @@ static int cortex_a8_debug_entry(struct target *target) dap_ap_select(swjdp, swjdp_debugap); LOG_DEBUG("cpsr: %8.8" PRIx32, cpsr); - armv4_5->core_mode = cpsr & 0x1F; - - i = (cpsr >> 5) & 1; /* T */ - i |= (cpsr >> 23) & 1; /* J << 1 */ - switch (i) { - case 0: /* J = 0, T = 0 */ - armv4_5->core_state = ARMV4_5_STATE_ARM; - break; - case 1: /* J = 0, T = 1 */ - armv4_5->core_state = ARMV4_5_STATE_THUMB; - break; - case 2: /* J = 1, T = 0 */ - LOG_WARNING("Jazelle state -- not handled"); - armv4_5->core_state = ARMV4_5_STATE_JAZELLE; - break; - case 3: /* J = 1, T = 1 */ - /* ThumbEE is very much like Thumb, but some of the - * instructions are different. Single stepping and - * breakpoints need updating... - */ - LOG_WARNING("ThumbEE -- incomplete support"); - armv4_5->core_state = ARM_STATE_THUMB_EE; - break; - } + arm_set_cpsr(armv4_5, cpsr); /* update cache */ - reg = armv4_5->core_cache->reg_list + ARMV4_5_CPSR; - buf_set_u32(reg->value, 0, 32, cpsr); - reg->valid = 1; - reg->dirty = 0; - for (i = 0; i <= ARM_PC; i++) { - reg = &ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, - armv4_5->core_mode, i); + reg = arm_reg_current(armv4_5, i); buf_set_u32(reg->value, 0, 32, regfile[i]); reg->valid = 1; @@ -686,13 +667,10 @@ static int cortex_a8_debug_entry(struct target *target) // ARM state regfile[ARM_PC] -= 8; } - buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, - armv4_5->core_mode, ARM_PC).value, - 0, 32, regfile[ARM_PC]); - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 0) - .dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, - armv4_5->core_mode, 0).valid; + reg = armv4_5->core_cache->reg_list + 15; + buf_set_u32(reg->value, 0, 32, regfile[ARM_PC]); + reg->dirty = reg->valid; ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 15) .dirty = ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5->core_mode, 15).valid; @@ -757,7 +735,7 @@ static int cortex_a8_step(struct target *target, int current, uint32_t address, int handle_breakpoints) { struct armv7a_common *armv7a = target_to_armv7a(target); - struct armv4_5_common_s *armv4_5 = &armv7a->armv4_5_common; + struct arm *armv4_5 = &armv7a->armv4_5_common; struct breakpoint *breakpoint = NULL; struct breakpoint stepbreakpoint; @@ -836,30 +814,84 @@ static int cortex_a8_step(struct target *target, int current, uint32_t address, static int cortex_a8_restore_context(struct target *target) { - int i; uint32_t value; struct armv7a_common *armv7a = target_to_armv7a(target); - struct armv4_5_common_s *armv4_5 = &armv7a->armv4_5_common; + struct reg_cache *cache = armv7a->armv4_5_common.core_cache; + unsigned max = cache->num_regs; + struct reg *r; + bool flushed, flush_cpsr = false; LOG_DEBUG(" "); if (armv7a->pre_restore_context) armv7a->pre_restore_context(target); - for (i = 15; i >= 0; i--) - { - if (ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, - armv4_5->core_mode, i).dirty) - { - value = buf_get_u32(ARMV4_5_CORE_REG_MODE( - armv4_5->core_cache, - armv4_5->core_mode, i).value, - 0, 32); + /* Flush all dirty registers from the cache, one mode at a time so + * that we write CPSR as little as possible. Save CPSR and R0 for + * last; they're used to change modes and write other registers. + * + * REVISIT be smarter: save eventual mode for last loop, don't + * need to write CPSR an extra time. + */ + do { + enum armv4_5_mode mode = ARMV4_5_MODE_ANY; + unsigned i; + + flushed = false; + + /* write dirty non-{R0,CPSR} registers sharing the same mode */ + for (i = max - 1, r = cache->reg_list + 1; i > 0; i--, r++) { + struct arm_reg *reg; + + if (!r->dirty || r == armv7a->armv4_5_common.cpsr) + continue; + reg = r->arch_info; + /* TODO Check return values */ - cortex_a8_dap_write_coreregister_u32(target, value, i); + + /* Pick a mode and update CPSR; else ignore this + * register if it's for a different mode than what + * we're handling on this pass. + * + * REVISIT don't distinguish SYS and USR modes. + * + * FIXME if we restore from FIQ mode, R8..R12 will + * get wrongly flushed onto FIQ shadows... + */ + if (mode == ARMV4_5_MODE_ANY) { + mode = reg->mode; + if (mode != ARMV4_5_MODE_ANY) { + cortex_a8_dap_write_coreregister_u32( + target, mode, 16); + flush_cpsr = true; + } + } else if (mode != reg->mode) + continue; + + /* Write this register */ + value = buf_get_u32(r->value, 0, 32); + cortex_a8_dap_write_coreregister_u32(target, value, + (reg->num == 16) ? 17 : reg->num); + r->dirty = false; + flushed = true; } + + } while (flushed); + + /* now flush CPSR if needed ... */ + r = armv7a->armv4_5_common.cpsr; + if (flush_cpsr || r->dirty) { + value = buf_get_u32(r->value, 0, 32); + cortex_a8_dap_write_coreregister_u32(target, value, 16); + r->dirty = false; } + /* ... and R0 always (it was dirtied when we saved context) */ + r = cache->reg_list + 0; + value = buf_get_u32(r->value, 0, 32); + cortex_a8_dap_write_coreregister_u32(target, value, 0); + r->dirty = false; + if (armv7a->post_restore_context) armv7a->post_restore_context(target); @@ -875,7 +907,7 @@ static int cortex_a8_load_core_reg_u32(struct target *target, int num, armv4_5_mode_t mode, uint32_t * value) { int retval; - struct armv4_5_common_s *armv4_5 = target_to_armv4_5(target); + struct arm *armv4_5 = target_to_armv4_5(target); if ((num <= ARM_CPSR)) { @@ -913,7 +945,7 @@ static int cortex_a8_store_core_reg_u32(struct target *target, int num, { int retval; // uint32_t reg; - struct armv4_5_common_s *armv4_5 = target_to_armv4_5(target); + struct arm *armv4_5 = target_to_armv4_5(target); #ifdef ARMV7_GDB_HACKS /* If the LR register is being modified, make sure it will put us @@ -950,48 +982,118 @@ static int cortex_a8_store_core_reg_u32(struct target *target, int num, #endif -static int cortex_a8_read_core_reg(struct target *target, int num, - enum armv4_5_mode mode) +static int cortex_a8_write_core_reg(struct target *target, struct reg *r, + int num, enum armv4_5_mode mode, uint32_t value); + +static int cortex_a8_read_core_reg(struct target *target, struct reg *r, + int num, enum armv4_5_mode mode) { uint32_t value; int retval; - struct armv4_5_common_s *armv4_5 = target_to_armv4_5(target); + struct arm *armv4_5 = target_to_armv4_5(target); + struct reg *cpsr_r = NULL; + uint32_t cpsr = 0; + unsigned cookie = num; - /* FIXME cortex may not be in "mode" ... */ - - cortex_a8_dap_read_coreregister_u32(target, &value, num); + /* avoid some needless mode changes + * FIXME move some of these to shared ARM code... + */ + if (mode != armv4_5->core_mode) { + if ((armv4_5->core_mode == ARMV4_5_MODE_SYS) + && (mode == ARMV4_5_MODE_USR)) + mode = ARMV4_5_MODE_ANY; + else if ((mode != ARMV4_5_MODE_FIQ) && (num <= 12)) + mode = ARMV4_5_MODE_ANY; + + if (mode != ARMV4_5_MODE_ANY) { + cpsr_r = armv4_5->cpsr; + cpsr = buf_get_u32(cpsr_r->value, 0, 32); + cortex_a8_write_core_reg(target, cpsr_r, + 16, ARMV4_5_MODE_ANY, mode); + } + } - if ((retval = jtag_execute_queue()) != ERROR_OK) - { - return retval; + if (num == 16) { + switch (mode) { + case ARMV4_5_MODE_USR: + case ARMV4_5_MODE_SYS: + case ARMV4_5_MODE_ANY: + /* CPSR */ + break; + default: + /* SPSR */ + cookie++; + break; + } } - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, mode, num).valid = 1; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, mode, num).dirty = 0; - buf_set_u32(ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, - mode, num).value, 0, 32, value); + cortex_a8_dap_read_coreregister_u32(target, &value, cookie); + retval = jtag_execute_queue(); + if (retval == ERROR_OK) { + r->valid = 1; + r->dirty = 0; + buf_set_u32(r->value, 0, 32, value); + } - return ERROR_OK; + if (cpsr_r) + cortex_a8_write_core_reg(target, cpsr_r, + 16, ARMV4_5_MODE_ANY, cpsr); + return retval; } -static int cortex_a8_write_core_reg(struct target *target, int num, - enum armv4_5_mode mode, uint32_t value) +static int cortex_a8_write_core_reg(struct target *target, struct reg *r, + int num, enum armv4_5_mode mode, uint32_t value) { int retval; - struct armv4_5_common_s *armv4_5 = target_to_armv4_5(target); + struct arm *armv4_5 = target_to_armv4_5(target); + struct reg *cpsr_r = NULL; + uint32_t cpsr = 0; + unsigned cookie = num; - /* FIXME cortex may not be in "mode" ... */ + /* avoid some needless mode changes + * FIXME move some of these to shared ARM code... + */ + if (mode != armv4_5->core_mode) { + if ((armv4_5->core_mode == ARMV4_5_MODE_SYS) + && (mode == ARMV4_5_MODE_USR)) + mode = ARMV4_5_MODE_ANY; + else if ((mode != ARMV4_5_MODE_FIQ) && (num <= 12)) + mode = ARMV4_5_MODE_ANY; + + if (mode != ARMV4_5_MODE_ANY) { + cpsr_r = armv4_5->cpsr; + cpsr = buf_get_u32(cpsr_r->value, 0, 32); + cortex_a8_write_core_reg(target, cpsr_r, + 16, ARMV4_5_MODE_ANY, mode); + } + } - cortex_a8_dap_write_coreregister_u32(target, value, num); - if ((retval = jtag_execute_queue()) != ERROR_OK) - { - return retval; + + if (num == 16) { + switch (mode) { + case ARMV4_5_MODE_USR: + case ARMV4_5_MODE_SYS: + case ARMV4_5_MODE_ANY: + /* CPSR */ + break; + default: + /* SPSR */ + cookie++; + break; + } } - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, mode, num).valid = 1; - ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, mode, num).dirty = 0; + cortex_a8_dap_write_coreregister_u32(target, value, cookie); + if ((retval = jtag_execute_queue()) == ERROR_OK) { + buf_set_u32(r->value, 0, 32, value); + r->valid = 1; + r->dirty = 0; + } - return ERROR_OK; + if (cpsr_r) + cortex_a8_write_core_reg(target, cpsr_r, + 16, ARMV4_5_MODE_ANY, cpsr); + return retval; } @@ -1474,12 +1576,11 @@ static int cortex_a8_examine(struct target *target) static void cortex_a8_build_reg_cache(struct target *target) { struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); - struct armv4_5_common_s *armv4_5 = target_to_armv4_5(target); + struct arm *armv4_5 = target_to_armv4_5(target); armv4_5->core_type = ARM_MODE_MON; (*cache_p) = armv4_5_build_reg_cache(target, armv4_5); - armv4_5->core_cache = (*cache_p); }