X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Ftarget%2Fcortex_a.c;h=4aae5e4731fff2dfb25edd478446b58f9310c136;hp=5fd8731885d1bf8d3c73388c61fca607b133b26a;hb=766d6114fea0c2748ed281db866588f975d2ba83;hpb=cd440bd32a120a9b4c2d703d3d16dd52f16edab2 diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 5fd8731885..4aae5e4731 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -18,7 +18,7 @@ * michel.jaouen@stericsson.com : smp minimum support * * * * Copyright (C) Broadcom 2012 * - * ehunter@broadcom.com : Cortex R4 support * + * ehunter@broadcom.com : Cortex-R4 support * * * * Copyright (C) 2013 Kamal Dasu * * kdasu.kdev@gmail.com * @@ -34,9 +34,7 @@ * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * - * along with this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * + * along with this program. If not, see . * * * * Cortex-A8(tm) TRM, ARM DDI 0344H * * Cortex-A9(tm) TRM, ARM DDI 0407F * @@ -55,6 +53,8 @@ #include "target_request.h" #include "target_type.h" #include "arm_opcodes.h" +#include "arm_semihosting.h" +#include "transport/transport.h" #include static int cortex_a_poll(struct target *target); @@ -73,9 +73,10 @@ static int cortex_a_dap_read_coreregister_u32(struct target *target, static int cortex_a_dap_write_coreregister_u32(struct target *target, uint32_t value, int regnum); static int cortex_a_mmu(struct target *target, int *enabled); +static int cortex_a_mmu_modify(struct target *target, int enable); static int cortex_a_virt2phys(struct target *target, - uint32_t virt, uint32_t *phys); -static int cortex_a_read_apb_ab_memory(struct target *target, + target_addr_t virt, target_addr_t *phys); +static int cortex_a_read_cpu_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer); @@ -97,33 +98,64 @@ static int cortex_a_restore_cp15_control_reg(struct target *target) return retval; } -/* check address before cortex_a_apb read write access with mmu on - * remove apb predictible data abort */ -static int cortex_a_check_address(struct target *target, uint32_t address) +/* + * Set up ARM core for memory access. + * If !phys_access, switch to SVC mode and make sure MMU is on + * If phys_access, switch off mmu + */ +static int cortex_a_prep_memaccess(struct target *target, int phys_access) { struct armv7a_common *armv7a = target_to_armv7a(target); struct cortex_a_common *cortex_a = target_to_cortex_a(target); - uint32_t os_border = armv7a->armv7a_mmu.os_border; - if ((address < os_border) && - (armv7a->arm.core_mode == ARM_MODE_SVC)) { - LOG_ERROR("%" PRIx32 " access in userspace and target in supervisor", address); - return ERROR_FAIL; - } - if ((address >= os_border) && - (cortex_a->curr_mode != ARM_MODE_SVC)) { + int mmu_enabled = 0; + + if (phys_access == 0) { dpm_modeswitch(&armv7a->dpm, ARM_MODE_SVC); - cortex_a->curr_mode = ARM_MODE_SVC; - LOG_INFO("%" PRIx32 " access in kernel space and target not in supervisor", - address); - return ERROR_OK; + cortex_a_mmu(target, &mmu_enabled); + if (mmu_enabled) + cortex_a_mmu_modify(target, 1); + if (cortex_a->dacrfixup_mode == CORTEX_A_DACRFIXUP_ON) { + /* overwrite DACR to all-manager */ + armv7a->arm.mcr(target, 15, + 0, 0, 3, 0, + 0xFFFFFFFF); + } + } else { + cortex_a_mmu(target, &mmu_enabled); + if (mmu_enabled) + cortex_a_mmu_modify(target, 0); } - if ((address < os_border) && - (cortex_a->curr_mode == ARM_MODE_SVC)) { + return ERROR_OK; +} + +/* + * Restore ARM core after memory access. + * If !phys_access, switch to previous mode + * If phys_access, restore MMU setting + */ +static int cortex_a_post_memaccess(struct target *target, int phys_access) +{ + struct armv7a_common *armv7a = target_to_armv7a(target); + struct cortex_a_common *cortex_a = target_to_cortex_a(target); + + if (phys_access == 0) { + if (cortex_a->dacrfixup_mode == CORTEX_A_DACRFIXUP_ON) { + /* restore */ + armv7a->arm.mcr(target, 15, + 0, 0, 3, 0, + cortex_a->cp15_dacr_reg); + } dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY); - cortex_a->curr_mode = ARM_MODE_ANY; + } else { + int mmu_enabled = 0; + cortex_a_mmu(target, &mmu_enabled); + if (mmu_enabled) + cortex_a_mmu_modify(target, 1); } return ERROR_OK; } + + /* modify cp15_control_reg in order to enable or disable mmu for : * - virt2phys address conversion * - read or write memory in phys or virt address */ @@ -132,62 +164,35 @@ static int cortex_a_mmu_modify(struct target *target, int enable) struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = target_to_armv7a(target); int retval = ERROR_OK; + int need_write = 0; + if (enable) { /* if mmu enabled at target stop and mmu not enable */ if (!(cortex_a->cp15_control_reg & 0x1U)) { LOG_ERROR("trying to enable mmu on target stopped with mmu disable"); return ERROR_FAIL; } - if (!(cortex_a->cp15_control_reg_curr & 0x1U)) { + if ((cortex_a->cp15_control_reg_curr & 0x1U) == 0) { cortex_a->cp15_control_reg_curr |= 0x1U; - retval = armv7a->arm.mcr(target, 15, - 0, 0, /* op1, op2 */ - 1, 0, /* CRn, CRm */ - cortex_a->cp15_control_reg_curr); + need_write = 1; } } else { - if ((cortex_a->cp15_control_reg_curr & 0x1U)) { - if (cortex_a->cp15_control_reg_curr & 0x4U) { - /* data cache is active */ - cortex_a->cp15_control_reg_curr &= ~0x4U; - /* flush data cache armv7 function to be called */ - if (armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache) - armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache(target); - } + if ((cortex_a->cp15_control_reg_curr & 0x1U) == 0x1U) { cortex_a->cp15_control_reg_curr &= ~0x1U; - retval = armv7a->arm.mcr(target, 15, - 0, 0, /* op1, op2 */ - 1, 0, /* CRn, CRm */ - cortex_a->cp15_control_reg_curr); + need_write = 1; } } - return retval; -} - -/* - * Cortex-A Basic debug access, very low level assumes state is saved - */ -static int cortex_a8_init_debug_access(struct target *target) -{ - struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; - int retval; - LOG_DEBUG(" "); + if (need_write) { + LOG_DEBUG("%s, writing cp15 ctrl: %" PRIx32, + enable ? "enable mmu" : "disable mmu", + cortex_a->cp15_control_reg_curr); - /* Unlocking the debug registers for modification - * The debugport might be uninitialised so try twice */ - retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, - armv7a->debug_base + CPUDBG_LOCKACCESS, 0xC5ACCE55); - if (retval != ERROR_OK) { - /* try again */ - retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, - armv7a->debug_base + CPUDBG_LOCKACCESS, 0xC5ACCE55); - if (retval == ERROR_OK) - LOG_USER( - "Locking debug access failed on first, but succeeded on second try."); + retval = armv7a->arm.mcr(target, 15, + 0, 0, /* op1, op2 */ + 1, 0, /* CRn, CRm */ + cortex_a->cp15_control_reg_curr); } - return retval; } @@ -197,49 +202,28 @@ static int cortex_a8_init_debug_access(struct target *target) static int cortex_a_init_debug_access(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; int retval; - uint32_t dbg_osreg; - uint32_t cortex_part_num; - struct cortex_a_common *cortex_a = target_to_cortex_a(target); - - LOG_DEBUG(" "); - cortex_part_num = (cortex_a->cpuid & CORTEX_A_MIDR_PARTNUM_MASK) >> - CORTEX_A_MIDR_PARTNUM_SHIFT; - - switch (cortex_part_num) { - case CORTEX_A7_PARTNUM: - case CORTEX_A15_PARTNUM: - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, - armv7a->debug_base + CPUDBG_OSLSR, - &dbg_osreg); - if (retval != ERROR_OK) - return retval; - LOG_DEBUG("DBGOSLSR 0x%" PRIx32, dbg_osreg); - - if (dbg_osreg & CPUDBG_OSLAR_LK_MASK) - /* Unlocking the DEBUG OS registers for modification */ - retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, - armv7a->debug_base + CPUDBG_OSLAR, - 0); - break; + /* lock memory-mapped access to debug registers to prevent + * software interference */ + retval = mem_ap_write_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_LOCKACCESS, 0); + if (retval != ERROR_OK) + return retval; - case CORTEX_A5_PARTNUM: - case CORTEX_A8_PARTNUM: - case CORTEX_A9_PARTNUM: - default: - retval = cortex_a8_init_debug_access(target); - } + /* Disable cacheline fills and force cache write-through in debug state */ + retval = mem_ap_write_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_DSCCR, 0); + if (retval != ERROR_OK) + return retval; + /* Disable TLB lookup and refill/eviction in debug state */ + retval = mem_ap_write_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_DSMCR, 0); if (retval != ERROR_OK) return retval; - /* Clear Sticky Power Down status Bit in PRSR to enable access to - the registers in the Core Power Domain */ - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, - armv7a->debug_base + CPUDBG_PRSR, &dbg_osreg); - LOG_DEBUG("target->coreid %" PRId32 " DBGPRSR 0x%" PRIx32, target->coreid, dbg_osreg); + retval = dap_run(armv7a->debug_ap->dap); if (retval != ERROR_OK) return retval; @@ -257,11 +241,10 @@ static int cortex_a_wait_instrcmpl(struct target *target, uint32_t *dscr, bool f * Writes final value of DSCR into *dscr. Pass force to force always * reading DSCR at least once. */ struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; - long long then = timeval_ms(); + int64_t then = timeval_ms(); while ((*dscr & DSCR_INSTR_COMP) == 0 || force) { force = false; - int retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + int retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr); if (retval != ERROR_OK) { LOG_ERROR("Could not read DSCR register"); @@ -286,7 +269,6 @@ static int cortex_a_exec_opcode(struct target *target, uint32_t dscr; int retval; struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; dscr = dscr_p ? *dscr_p : 0; @@ -297,14 +279,14 @@ static int cortex_a_exec_opcode(struct target *target, if (retval != ERROR_OK) return retval; - retval = mem_ap_sel_write_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_write_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_ITR, opcode); if (retval != ERROR_OK) return retval; - long long then = timeval_ms(); + int64_t then = timeval_ms(); do { - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) { LOG_ERROR("Could not read DSCR register"); @@ -331,7 +313,6 @@ static int cortex_a_read_regs_through_mem(struct target *target, uint32_t addres { int retval = ERROR_OK; struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; retval = cortex_a_dap_read_coreregister_u32(target, regfile, 0); if (retval != ERROR_OK) @@ -343,7 +324,7 @@ static int cortex_a_read_regs_through_mem(struct target *target, uint32_t addres if (retval != ERROR_OK) return retval; - retval = mem_ap_sel_read_buf(swjdp, armv7a->memory_ap, + retval = mem_ap_read_buf(armv7a->memory_ap, (uint8_t *)(®file[1]), 4, 15, address); return retval; @@ -356,7 +337,6 @@ static int cortex_a_dap_read_coreregister_u32(struct target *target, uint8_t reg = regnum&0xFF; uint32_t dscr = 0; struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; if (reg > 17) return retval; @@ -393,9 +373,9 @@ static int cortex_a_dap_read_coreregister_u32(struct target *target, } /* Wait for DTRRXfull then read DTRRTX */ - long long then = timeval_ms(); + int64_t then = timeval_ms(); while ((dscr & DSCR_DTR_TX_FULL) == 0) { - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; @@ -405,7 +385,7 @@ static int cortex_a_dap_read_coreregister_u32(struct target *target, } } - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRTX, value); LOG_DEBUG("read DCC 0x%08" PRIx32, *value); @@ -419,12 +399,11 @@ static int cortex_a_dap_write_coreregister_u32(struct target *target, uint8_t Rd = regnum&0xFF; uint32_t dscr; struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; LOG_DEBUG("register %i, value 0x%08" PRIx32, regnum, value); /* Check that DCCRX is not full */ - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; @@ -442,7 +421,7 @@ static int cortex_a_dap_write_coreregister_u32(struct target *target, /* Write DTRRX ... sets DSCR.DTRRXfull but exec_opcode() won't care */ LOG_DEBUG("write DCC 0x%08" PRIx32, value); - retval = mem_ap_sel_write_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_write_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRRX, value); if (retval != ERROR_OK) return retval; @@ -498,9 +477,8 @@ static int cortex_a_dap_write_memap_register_u32(struct target *target, { int retval; struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; - retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, address, value); + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, address, value); return retval; } @@ -524,14 +502,13 @@ static inline struct cortex_a_common *dpm_to_a(struct arm_dpm *dpm) static int cortex_a_write_dcc(struct cortex_a_common *a, uint32_t data) { LOG_DEBUG("write DCC 0x%08" PRIx32, data); - return mem_ap_sel_write_u32(a->armv7a_common.arm.dap, - a->armv7a_common.debug_ap, a->armv7a_common.debug_base + CPUDBG_DTRRX, data); + return mem_ap_write_u32(a->armv7a_common.debug_ap, + a->armv7a_common.debug_base + CPUDBG_DTRRX, data); } static int cortex_a_read_dcc(struct cortex_a_common *a, uint32_t *data, uint32_t *dscr_p) { - struct adiv5_dap *swjdp = a->armv7a_common.arm.dap; uint32_t dscr = DSCR_INSTR_COMP; int retval; @@ -539,9 +516,9 @@ static int cortex_a_read_dcc(struct cortex_a_common *a, uint32_t *data, dscr = *dscr_p; /* Wait for DTRRXfull */ - long long then = timeval_ms(); + int64_t then = timeval_ms(); while ((dscr & DSCR_DTR_TX_FULL) == 0) { - retval = mem_ap_sel_read_atomic_u32(swjdp, a->armv7a_common.debug_ap, + retval = mem_ap_read_atomic_u32(a->armv7a_common.debug_ap, a->armv7a_common.debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) @@ -552,7 +529,7 @@ static int cortex_a_read_dcc(struct cortex_a_common *a, uint32_t *data, } } - retval = mem_ap_sel_read_atomic_u32(swjdp, a->armv7a_common.debug_ap, + retval = mem_ap_read_atomic_u32(a->armv7a_common.debug_ap, a->armv7a_common.debug_base + CPUDBG_DTRTX, data); if (retval != ERROR_OK) return retval; @@ -567,14 +544,13 @@ static int cortex_a_read_dcc(struct cortex_a_common *a, uint32_t *data, static int cortex_a_dpm_prepare(struct arm_dpm *dpm) { struct cortex_a_common *a = dpm_to_a(dpm); - struct adiv5_dap *swjdp = a->armv7a_common.arm.dap; uint32_t dscr; int retval; /* set up invariant: INSTR_COMP is set after ever DPM operation */ - long long then = timeval_ms(); + int64_t then = timeval_ms(); for (;; ) { - retval = mem_ap_sel_read_atomic_u32(swjdp, a->armv7a_common.debug_ap, + retval = mem_ap_read_atomic_u32(a->armv7a_common.debug_ap, a->armv7a_common.debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) @@ -820,7 +796,8 @@ static int cortex_a_halt_smp(struct target *target) head = target->head; while (head != (struct target_list *)NULL) { curr = head->target; - if ((curr != target) && (curr->state != TARGET_HALTED)) + if ((curr != target) && (curr->state != TARGET_HALTED) + && target_was_examined(curr)) retval += cortex_a_halt(curr); head = head->next; } @@ -848,7 +825,6 @@ static int cortex_a_poll(struct target *target) uint32_t dscr; struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = &cortex_a->armv7a_common; - struct adiv5_dap *swjdp = armv7a->arm.dap; enum target_state prev_target_state = target->state; /* toggle to another core is done by gdb as follow */ /* maint packet J core_id */ @@ -862,7 +838,7 @@ static int cortex_a_poll(struct target *target) target_call_event_callbacks(target, TARGET_EVENT_HALTED); return retval; } - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; @@ -884,6 +860,10 @@ static int cortex_a_poll(struct target *target) if (retval != ERROR_OK) return retval; } + + if (arm_semihosting(target, &retval) != 0) + return retval; + target_call_event_callbacks(target, TARGET_EVENT_HALTED); } @@ -903,12 +883,8 @@ static int cortex_a_poll(struct target *target) TARGET_EVENT_DEBUG_HALTED); } } - } else if (DSCR_RUN_MODE(dscr) == DSCR_CORE_RESTARTED) + } else target->state = TARGET_RUNNING; - else { - LOG_DEBUG("Unknown target state dscr = 0x%08" PRIx32, dscr); - target->state = TARGET_UNKNOWN; - } return retval; } @@ -918,13 +894,12 @@ static int cortex_a_halt(struct target *target) int retval = ERROR_OK; uint32_t dscr; struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; /* * Tell the core to be halted by writing DRCR with 0x1 * and then wait for the core to be halted. */ - retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DRCR, DRCR_HALT); if (retval != ERROR_OK) return retval; @@ -932,19 +907,19 @@ static int cortex_a_halt(struct target *target) /* * enter halting debug mode */ - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; - retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr | DSCR_HALT_DBG_MODE); if (retval != ERROR_OK) return retval; - long long then = timeval_ms(); + int64_t then = timeval_ms(); for (;; ) { - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; @@ -962,7 +937,7 @@ static int cortex_a_halt(struct target *target) } static int cortex_a_internal_restore(struct target *target, int current, - uint32_t *address, int handle_breakpoints, int debug_execution) + target_addr_t *address, int handle_breakpoints, int debug_execution) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; @@ -1017,11 +992,15 @@ static int cortex_a_internal_restore(struct target *target, int current, case ARM_STATE_JAZELLE: LOG_ERROR("How do I resume into Jazelle state??"); return ERROR_FAIL; + case ARM_STATE_AARCH64: + LOG_ERROR("Shoudn't be in AARCH64 state"); + return ERROR_FAIL; } LOG_DEBUG("resume pc = 0x%08" PRIx32, resume_pc); buf_set_u32(arm->pc->value, 0, 32, resume_pc); arm->pc->dirty = 1; arm->pc->valid = 1; + /* restore dpm_mode at system halt */ dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY); /* called it now before restoring context because it uses cpu @@ -1059,7 +1038,6 @@ static int cortex_a_internal_restart(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; - struct adiv5_dap *swjdp = arm->dap; int retval; uint32_t dscr; /* @@ -1070,7 +1048,7 @@ static int cortex_a_internal_restart(struct target *target) * disable IRQs by default, with optional override... */ - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; @@ -1078,20 +1056,20 @@ static int cortex_a_internal_restart(struct target *target) if ((dscr & DSCR_INSTR_COMP) == 0) LOG_ERROR("DSCR InstrCompl must be set before leaving debug!"); - retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr & ~DSCR_ITR_EN); if (retval != ERROR_OK) return retval; - retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DRCR, DRCR_RESTART | DRCR_CLEAR_EXCEPTIONS); if (retval != ERROR_OK) return retval; - long long then = timeval_ms(); + int64_t then = timeval_ms(); for (;; ) { - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; @@ -1117,11 +1095,12 @@ static int cortex_a_restore_smp(struct target *target, int handle_breakpoints) int retval = 0; struct target_list *head; struct target *curr; - uint32_t address; + target_addr_t address; head = target->head; while (head != (struct target_list *)NULL) { curr = head->target; - if ((curr != target) && (curr->state != TARGET_RUNNING)) { + if ((curr != target) && (curr->state != TARGET_RUNNING) + && target_was_examined(curr)) { /* resume current address , not in step mode */ retval += cortex_a_internal_restore(curr, 1, &address, handle_breakpoints, 0); @@ -1134,7 +1113,7 @@ static int cortex_a_restore_smp(struct target *target, int handle_breakpoints) } static int cortex_a_resume(struct target *target, int current, - uint32_t address, int handle_breakpoints, int debug_execution) + target_addr_t address, int handle_breakpoints, int debug_execution) { int retval = 0; /* dummy resume for smp toggle in order to reduce gdb impact */ @@ -1158,11 +1137,11 @@ static int cortex_a_resume(struct target *target, int current, if (!debug_execution) { target->state = TARGET_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_RESUMED); - LOG_DEBUG("target resumed at 0x%" PRIx32, address); + LOG_DEBUG("target resumed at " TARGET_ADDR_FMT, address); } else { target->state = TARGET_DEBUG_RUNNING; target_call_event_callbacks(target, TARGET_EVENT_DEBUG_RESUMED); - LOG_DEBUG("target debug resumed at 0x%" PRIx32, address); + LOG_DEBUG("target debug resumed at " TARGET_ADDR_FMT, address); } return ERROR_OK; @@ -1171,19 +1150,18 @@ static int cortex_a_resume(struct target *target, int current, static int cortex_a_debug_entry(struct target *target) { int i; - uint32_t regfile[16], cpsr, dscr; + uint32_t regfile[16], cpsr, spsr, dscr; int retval = ERROR_OK; struct working_area *regfile_working_area = NULL; struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = target_to_armv7a(target); struct arm *arm = &armv7a->arm; - struct adiv5_dap *swjdp = armv7a->arm.dap; struct reg *reg; LOG_DEBUG("dscr = 0x%08" PRIx32, cortex_a->cpudbg_dscr); /* REVISIT surely we should not re-read DSCR !! */ - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; @@ -1195,7 +1173,7 @@ static int cortex_a_debug_entry(struct target *target) /* Enable the ITR execution once we are in debug mode */ dscr |= DSCR_ITR_EN; - retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr); if (retval != ERROR_OK) return retval; @@ -1207,7 +1185,7 @@ static int cortex_a_debug_entry(struct target *target) if (target->debug_reason == DBG_REASON_WATCHPOINT) { uint32_t wfar; - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_WFAR, &wfar); if (retval != ERROR_OK) @@ -1221,6 +1199,7 @@ static int cortex_a_debug_entry(struct target *target) if (cortex_a->fast_reg_read) target_alloc_working_area(target, 64, ®file_working_area); + /* First load register acessible through core debug port*/ if (!regfile_working_area) retval = arm_dpm_read_current_registers(&armv7a->dpm); @@ -1265,6 +1244,19 @@ static int cortex_a_debug_entry(struct target *target) reg->dirty = reg->valid; } + if (arm->spsr) { + /* read Saved PSR */ + retval = cortex_a_dap_read_coreregister_u32(target, &spsr, 17); + /* store current spsr */ + if (retval != ERROR_OK) + return retval; + + reg = arm->spsr; + buf_set_u32(reg->value, 0, 32, spsr); + reg->valid = 1; + reg->dirty = 0; + } + #if 0 /* TODO, Move this */ uint32_t cp15_control_register, cp15_cacr, cp15_nacr; @@ -1305,7 +1297,10 @@ static int cortex_a_post_debug_entry(struct target *target) LOG_DEBUG("cp15_control_reg: %8.8" PRIx32, cortex_a->cp15_control_reg); cortex_a->cp15_control_reg_curr = cortex_a->cp15_control_reg; - if (armv7a->armv7a_mmu.armv7a_cache.ctype == -1) + if (!armv7a->is_armv7r) + armv7a_read_ttbcr(target); + + if (armv7a->armv7a_mmu.armv7a_cache.info == -1) armv7a_identify_cache(target); if (armv7a->is_armv7r) { @@ -1320,17 +1315,26 @@ static int cortex_a_post_debug_entry(struct target *target) (cortex_a->cp15_control_reg & 0x1000U) ? 1 : 0; cortex_a->curr_mode = armv7a->arm.core_mode; + /* switch to SVC mode to read DACR */ + dpm_modeswitch(&armv7a->dpm, ARM_MODE_SVC); + armv7a->arm.mrc(target, 15, + 0, 0, 3, 0, + &cortex_a->cp15_dacr_reg); + + LOG_DEBUG("cp15_dacr_reg: %8.8" PRIx32, + cortex_a->cp15_dacr_reg); + + dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY); return ERROR_OK; } int cortex_a_set_dscr_bits(struct target *target, unsigned long bit_mask, unsigned long value) { struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; uint32_t dscr; /* Read DSCR */ - int retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + int retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (ERROR_OK != retval) return retval; @@ -1341,12 +1345,12 @@ int cortex_a_set_dscr_bits(struct target *target, unsigned long bit_mask, unsign dscr |= value & bit_mask; /* write new DSCR */ - retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr); return retval; } -static int cortex_a_step(struct target *target, int current, uint32_t address, +static int cortex_a_step(struct target *target, int current, target_addr_t address, int handle_breakpoints) { struct cortex_a_common *cortex_a = target_to_cortex_a(target); @@ -1403,7 +1407,7 @@ static int cortex_a_step(struct target *target, int current, uint32_t address, if (retval != ERROR_OK) return retval; - long long then = timeval_ms(); + int64_t then = timeval_ms(); while (target->state != TARGET_HALTED) { retval = cortex_a_poll(target); if (retval != ERROR_OK) @@ -1499,21 +1503,47 @@ static int cortex_a_set_breakpoint(struct target *target, brp_list[brp_i].value); } else if (breakpoint->type == BKPT_SOFT) { uint8_t code[4]; + /* length == 2: Thumb breakpoint */ if (breakpoint->length == 2) buf_set_u32(code, 0, 32, ARMV5_T_BKPT(0x11)); else + /* length == 3: Thumb-2 breakpoint, actual encoding is + * a regular Thumb BKPT instruction but we replace a + * 32bit Thumb-2 instruction, so fix-up the breakpoint + * length + */ + if (breakpoint->length == 3) { + buf_set_u32(code, 0, 32, ARMV5_T_BKPT(0x11)); + breakpoint->length = 4; + } else + /* length == 4, normal ARM breakpoint */ buf_set_u32(code, 0, 32, ARMV5_BKPT(0x11)); + retval = target_read_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; + + /* make sure data cache is cleaned & invalidated down to PoC */ + if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled) { + armv7a_cache_flush_virt(target, breakpoint->address, + breakpoint->length); + } + retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, breakpoint->length, 1, code); if (retval != ERROR_OK) return retval; + + /* update i-cache at breakpoint location */ + armv7a_l1_d_cache_inval_virt(target, breakpoint->address, + breakpoint->length); + armv7a_l1_i_cache_inval_virt(target, breakpoint->address, + breakpoint->length); + breakpoint->set = 0x11; /* Any nice value but 0 */ } @@ -1733,6 +1763,13 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *b return ERROR_OK; } } else { + + /* make sure data cache is cleaned & invalidated down to PoC */ + if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled) { + armv7a_cache_flush_virt(target, breakpoint->address, + breakpoint->length); + } + /* restore original instruction (kept in target endianness) */ if (breakpoint->length == 4) { retval = target_write_memory(target, @@ -1747,6 +1784,12 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *b if (retval != ERROR_OK) return retval; } + + /* update i-cache at breakpoint location */ + armv7a_l1_d_cache_inval_virt(target, breakpoint->address, + breakpoint->length); + armv7a_l1_i_cache_inval_virt(target, breakpoint->address, + breakpoint->length); } breakpoint->set = 0; @@ -1836,6 +1879,8 @@ static int cortex_a_assert_reset(struct target *target) /* FIXME when halt is requested, make it work somehow... */ + /* This function can be called in "target not examined" state */ + /* Issue some kind of warm reset. */ if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) target_handle_event(target, TARGET_EVENT_RESET_ASSERT); @@ -1843,14 +1888,23 @@ static int cortex_a_assert_reset(struct target *target) /* REVISIT handle "pulls" cases, if there's * hardware that needs them to work. */ - jtag_add_reset(0, 1); + + /* + * FIXME: fix reset when transport is SWD. This is a temporary + * work-around for release v0.10 that is not intended to stay! + */ + if (transport_is_swd() || + (target->reset_halt && (jtag_get_reset_config() & RESET_SRST_NO_GATING))) + jtag_add_reset(0, 1); + } else { LOG_ERROR("%s: how to reset?", target_name(target)); return ERROR_FAIL; } /* registers are now invalid */ - register_cache_invalidate(armv7a->arm.core_cache); + if (target_was_examined(target)) + register_cache_invalidate(armv7a->arm.core_cache); target->state = TARGET_RESET; @@ -1866,17 +1920,22 @@ static int cortex_a_deassert_reset(struct target *target) /* be certain SRST is off */ jtag_add_reset(0, 0); - retval = cortex_a_poll(target); - if (retval != ERROR_OK) - return retval; + if (target_was_examined(target)) { + retval = cortex_a_poll(target); + if (retval != ERROR_OK) + return retval; + } if (target->reset_halt) { if (target->state != TARGET_HALTED) { LOG_WARNING("%s: ran after reset and before halt ...", target_name(target)); - retval = target_halt(target); - if (retval != ERROR_OK) - return retval; + if (target_was_examined(target)) { + retval = target_halt(target); + if (retval != ERROR_OK) + return retval; + } else + target->state = TARGET_UNKNOWN; } } @@ -1895,8 +1954,8 @@ static int cortex_a_set_dcc_mode(struct target *target, uint32_t mode, uint32_t uint32_t new_dscr = (*dscr & ~DSCR_EXT_DCC_MASK) | mode; if (new_dscr != *dscr) { struct armv7a_common *armv7a = target_to_armv7a(target); - int retval = mem_ap_sel_write_atomic_u32(armv7a->arm.dap, - armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, new_dscr); + int retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_DSCR, new_dscr); if (retval == ERROR_OK) *dscr = new_dscr; return retval; @@ -1910,12 +1969,11 @@ static int cortex_a_wait_dscr_bits(struct target *target, uint32_t mask, { /* Waits until the specified bit(s) of DSCR take on a specified value. */ struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; - long long then = timeval_ms(); + int64_t then = timeval_ms(); int retval; while ((*dscr & mask) != value) { - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr); if (retval != ERROR_OK) return retval; @@ -1932,7 +1990,6 @@ static int cortex_a_read_copro(struct target *target, uint32_t opcode, { int retval; struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; /* Move from coprocessor to R0. */ retval = cortex_a_exec_opcode(target, opcode, dscr); @@ -1954,7 +2011,7 @@ static int cortex_a_read_copro(struct target *target, uint32_t opcode, return retval; /* Read the value transferred to DTRTX. */ - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRTX, data); if (retval != ERROR_OK) return retval; @@ -1987,10 +2044,9 @@ static int cortex_a_write_copro(struct target *target, uint32_t opcode, { int retval; struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; /* Write the value into DTRRX. */ - retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRRX, data); if (retval != ERROR_OK) return retval; @@ -2059,20 +2115,19 @@ static int cortex_a_dfsr_to_error_code(uint32_t dfsr) } } -static int cortex_a_write_apb_ab_memory_slow(struct target *target, +static int cortex_a_write_cpu_memory_slow(struct target *target, uint32_t size, uint32_t count, const uint8_t *buffer, uint32_t *dscr) { /* Writes count objects of size size from *buffer. Old value of DSCR must * be in *dscr; updated to new value. This is slow because it works for * non-word-sized objects and (maybe) unaligned accesses. If size == 4 and - * the address is aligned, cortex_a_write_apb_ab_memory_fast should be + * the address is aligned, cortex_a_write_cpu_memory_fast should be * preferred. * Preconditions: * - Address is in R0. * - R0 is marked dirty. */ struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; struct arm *arm = &armv7a->arm; int retval; @@ -2094,7 +2149,7 @@ static int cortex_a_write_apb_ab_memory_slow(struct target *target, data = target_buffer_get_u16(target, buffer); else data = target_buffer_get_u32(target, buffer); - retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRRX, data); if (retval != ERROR_OK) return retval; @@ -2135,7 +2190,7 @@ static int cortex_a_write_apb_ab_memory_slow(struct target *target, return ERROR_OK; } -static int cortex_a_write_apb_ab_memory_fast(struct target *target, +static int cortex_a_write_cpu_memory_fast(struct target *target, uint32_t count, const uint8_t *buffer, uint32_t *dscr) { /* Writes count objects of size 4 from *buffer. Old value of DSCR must be @@ -2146,7 +2201,6 @@ static int cortex_a_write_apb_ab_memory_fast(struct target *target, * - R0 is marked dirty. */ struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; int retval; /* Switch to fast mode if not already in that mode. */ @@ -2155,28 +2209,27 @@ static int cortex_a_write_apb_ab_memory_fast(struct target *target, return retval; /* Latch STC instruction. */ - retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_ITR, ARMV4_5_STC(0, 1, 0, 1, 14, 5, 0, 4)); if (retval != ERROR_OK) return retval; /* Transfer all the data and issue all the instructions. */ - return mem_ap_sel_write_buf_noincr(swjdp, armv7a->debug_ap, buffer, + return mem_ap_write_buf_noincr(armv7a->debug_ap, buffer, 4, count, armv7a->debug_base + CPUDBG_DTRRX); } -static int cortex_a_write_apb_ab_memory(struct target *target, +static int cortex_a_write_cpu_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { - /* Write memory through APB-AP. */ + /* Write memory through the CPU. */ int retval, final_retval; struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; struct arm *arm = &armv7a->arm; uint32_t dscr, orig_dfar, orig_dfsr, fault_dscr, fault_dfar, fault_dfsr; - LOG_DEBUG("Writing APB-AP memory address 0x%" PRIx32 " size %" PRIu32 " count %" PRIu32, + LOG_DEBUG("Writing CPU memory address 0x%" PRIx32 " size %" PRIu32 " count %" PRIu32, address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); @@ -2187,13 +2240,13 @@ static int cortex_a_write_apb_ab_memory(struct target *target, return ERROR_OK; /* Clear any abort. */ - retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DRCR, DRCR_CLEAR_EXCEPTIONS); if (retval != ERROR_OK) return retval; /* Read DSCR. */ - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; @@ -2212,7 +2265,7 @@ static int cortex_a_write_apb_ab_memory(struct target *target, goto out; /* Get the memory address into R0. */ - retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRRX, address); if (retval != ERROR_OK) goto out; @@ -2222,10 +2275,10 @@ static int cortex_a_write_apb_ab_memory(struct target *target, if (size == 4 && (address % 4) == 0) { /* We are doing a word-aligned transfer, so use fast mode. */ - retval = cortex_a_write_apb_ab_memory_fast(target, count, buffer, &dscr); + retval = cortex_a_write_cpu_memory_fast(target, count, buffer, &dscr); } else { /* Use slow path. */ - retval = cortex_a_write_apb_ab_memory_slow(target, size, count, buffer, &dscr); + retval = cortex_a_write_cpu_memory_slow(target, size, count, buffer, &dscr); } out: @@ -2244,7 +2297,7 @@ out: /* Wait until DTRRX is empty (according to ARMv7-A/-R architecture manual * section C8.4.3, checking InstrCmpl_l is not sufficient; one must also * check RXfull_l). Most of the time this will be free because RXfull_l - * will be cleared immediately and cached in dscr. However, don’t do this + * will be cleared immediately and cached in dscr. However, don't do this * if there is fault, because then the instruction might not have completed * successfully. */ if (!(dscr & DSCR_STICKY_ABORT_PRECISE)) { @@ -2256,7 +2309,7 @@ out: /* If there were any sticky abort flags, clear them. */ if (dscr & (DSCR_STICKY_ABORT_PRECISE | DSCR_STICKY_ABORT_IMPRECISE)) { fault_dscr = dscr; - mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, + mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DRCR, DRCR_CLEAR_EXCEPTIONS); dscr &= ~(DSCR_STICKY_ABORT_PRECISE | DSCR_STICKY_ABORT_IMPRECISE); } else { @@ -2290,7 +2343,7 @@ out: /* If the DCC is nonempty, clear it. */ if (dscr & DSCR_DTRTX_FULL_LATCHED) { uint32_t dummy; - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRTX, &dummy); if (final_retval == ERROR_OK) final_retval = retval; @@ -2305,20 +2358,19 @@ out: return final_retval; } -static int cortex_a_read_apb_ab_memory_slow(struct target *target, +static int cortex_a_read_cpu_memory_slow(struct target *target, uint32_t size, uint32_t count, uint8_t *buffer, uint32_t *dscr) { /* Reads count objects of size size into *buffer. Old value of DSCR must be * in *dscr; updated to new value. This is slow because it works for * non-word-sized objects and (maybe) unaligned accesses. If size == 4 and - * the address is aligned, cortex_a_read_apb_ab_memory_fast should be + * the address is aligned, cortex_a_read_cpu_memory_fast should be * preferred. * Preconditions: * - Address is in R0. * - R0 is marked dirty. */ struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; struct arm *arm = &armv7a->arm; int retval; @@ -2363,7 +2415,7 @@ static int cortex_a_read_apb_ab_memory_slow(struct target *target, return retval; /* Read the value transferred to DTRTX into the buffer. */ - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRTX, &data); if (retval != ERROR_OK) return retval; @@ -2382,7 +2434,7 @@ static int cortex_a_read_apb_ab_memory_slow(struct target *target, return ERROR_OK; } -static int cortex_a_read_apb_ab_memory_fast(struct target *target, +static int cortex_a_read_cpu_memory_fast(struct target *target, uint32_t count, uint8_t *buffer, uint32_t *dscr) { /* Reads count objects of size 4 into *buffer. Old value of DSCR must be in @@ -2393,8 +2445,7 @@ static int cortex_a_read_apb_ab_memory_fast(struct target *target, * - R0 is marked dirty. */ struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; - uint32_t new_dscr, u32; + uint32_t u32; int retval; /* Switch to non-blocking mode if not already in that mode. */ @@ -2402,19 +2453,24 @@ static int cortex_a_read_apb_ab_memory_fast(struct target *target, if (retval != ERROR_OK) return retval; - if (count > 1) { - /* Consecutively issue the LDC instruction via a write to ITR and - * change to fast mode, in a single bulk copy since DSCR == ITR + 4. - * The instruction is issued into the core before the mode switch. */ - uint8_t command[8]; - target_buffer_set_u32(target, command, ARMV4_5_LDC(0, 1, 0, 1, 14, 5, 0, 4)); - new_dscr = (*dscr & ~DSCR_EXT_DCC_MASK) | DSCR_EXT_DCC_FAST_MODE; - target_buffer_set_u32(target, command + 4, new_dscr); - retval = mem_ap_sel_write_buf(swjdp, armv7a->debug_ap, command, 4, 2, - armv7a->debug_base + CPUDBG_ITR); + /* Issue the LDC instruction via a write to ITR. */ + retval = cortex_a_exec_opcode(target, ARMV4_5_LDC(0, 1, 0, 1, 14, 5, 0, 4), dscr); + if (retval != ERROR_OK) + return retval; + + count--; + + if (count > 0) { + /* Switch to fast mode if not already in that mode. */ + retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_FAST_MODE, dscr); + if (retval != ERROR_OK) + return retval; + + /* Latch LDC instruction. */ + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_ITR, ARMV4_5_LDC(0, 1, 0, 1, 14, 5, 0, 4)); if (retval != ERROR_OK) return retval; - *dscr = new_dscr; /* Read the value transferred to DTRTX into the buffer. Due to fast * mode rules, this blocks until the instruction finishes executing and @@ -2422,27 +2478,22 @@ static int cortex_a_read_apb_ab_memory_fast(struct target *target, * memory. The last read of DTRTX in this call reads the second-to-last * word from memory and issues the read instruction for the last word. */ - retval = mem_ap_sel_read_buf_noincr(swjdp, armv7a->debug_ap, buffer, - 4, count - 1, armv7a->debug_base + CPUDBG_DTRTX); + retval = mem_ap_read_buf_noincr(armv7a->debug_ap, buffer, + 4, count, armv7a->debug_base + CPUDBG_DTRTX); if (retval != ERROR_OK) return retval; /* Advance. */ - buffer += (count - 1) * 4; - } else { - /* Issue the LDC instruction via a write to ITR. */ - retval = cortex_a_exec_opcode(target, ARMV4_5_LDC(0, 1, 0, 1, 14, 5, 0, 4), dscr); - if (retval != ERROR_OK) - return retval; + buffer += count * 4; } - /* Switch to non-blocking mode if not already in that mode. */ - retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, dscr); + /* Wait for last issued instruction to complete. */ + retval = cortex_a_wait_instrcmpl(target, dscr, false); if (retval != ERROR_OK) return retval; - /* Wait for last issued instruction to complete. */ - retval = cortex_a_wait_instrcmpl(target, dscr, false); + /* Switch to non-blocking mode if not already in that mode. */ + retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, dscr); if (retval != ERROR_OK) return retval; @@ -2461,7 +2512,7 @@ static int cortex_a_read_apb_ab_memory_fast(struct target *target, /* Read the value transferred to DTRTX into the buffer. This is the last * word. */ - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRTX, &u32); if (retval != ERROR_OK) return retval; @@ -2470,18 +2521,17 @@ static int cortex_a_read_apb_ab_memory_fast(struct target *target, return ERROR_OK; } -static int cortex_a_read_apb_ab_memory(struct target *target, +static int cortex_a_read_cpu_memory(struct target *target, uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer) { - /* Read memory through APB-AP. */ + /* Read memory through the CPU. */ int retval, final_retval; struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; struct arm *arm = &armv7a->arm; uint32_t dscr, orig_dfar, orig_dfsr, fault_dscr, fault_dfar, fault_dfsr; - LOG_DEBUG("Reading APB-AP memory address 0x%" PRIx32 " size %" PRIu32 " count %" PRIu32, + LOG_DEBUG("Reading CPU memory address 0x%" PRIx32 " size %" PRIu32 " count %" PRIu32, address, size, count); if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); @@ -2492,13 +2542,13 @@ static int cortex_a_read_apb_ab_memory(struct target *target, return ERROR_OK; /* Clear any abort. */ - retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DRCR, DRCR_CLEAR_EXCEPTIONS); if (retval != ERROR_OK) return retval; /* Read DSCR */ - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); if (retval != ERROR_OK) return retval; @@ -2517,7 +2567,7 @@ static int cortex_a_read_apb_ab_memory(struct target *target, goto out; /* Get the memory address into R0. */ - retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRRX, address); if (retval != ERROR_OK) goto out; @@ -2527,10 +2577,10 @@ static int cortex_a_read_apb_ab_memory(struct target *target, if (size == 4 && (address % 4) == 0) { /* We are doing a word-aligned transfer, so use fast mode. */ - retval = cortex_a_read_apb_ab_memory_fast(target, count, buffer, &dscr); + retval = cortex_a_read_cpu_memory_fast(target, count, buffer, &dscr); } else { /* Use slow path. */ - retval = cortex_a_read_apb_ab_memory_slow(target, size, count, buffer, &dscr); + retval = cortex_a_read_cpu_memory_slow(target, size, count, buffer, &dscr); } out: @@ -2549,7 +2599,7 @@ out: /* If there were any sticky abort flags, clear them. */ if (dscr & (DSCR_STICKY_ABORT_PRECISE | DSCR_STICKY_ABORT_IMPRECISE)) { fault_dscr = dscr; - mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, + mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DRCR, DRCR_CLEAR_EXCEPTIONS); dscr &= ~(DSCR_STICKY_ABORT_PRECISE | DSCR_STICKY_ABORT_IMPRECISE); } else { @@ -2583,7 +2633,7 @@ out: /* If the DCC is nonempty, clear it. */ if (dscr & DSCR_DTRTX_FULL_LATCHED) { uint32_t dummy; - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRTX, &dummy); if (final_retval == ERROR_OK) final_retval = retval; @@ -2602,81 +2652,68 @@ out: /* * Cortex-A Memory access * - * This is same Cortex M3 but we must also use the correct + * This is same Cortex-M3 but we must also use the correct * ap number for every access. */ static int cortex_a_read_phys_memory(struct target *target, - uint32_t address, uint32_t size, + target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { struct armv7a_common *armv7a = target_to_armv7a(target); - int retval = ERROR_COMMAND_SYNTAX_ERROR; + struct adiv5_dap *swjdp = armv7a->arm.dap; + uint8_t apsel = swjdp->apsel; + int retval; - LOG_DEBUG("Reading memory at real address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, + if (!count || !buffer) + return ERROR_COMMAND_SYNTAX_ERROR; + + LOG_DEBUG("Reading memory at real address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32, address, size, count); - if (count && buffer) { - /* read memory through APB-AP */ - if (!armv7a->is_armv7r) { - /* disable mmu */ - retval = cortex_a_mmu_modify(target, 0); - if (retval != ERROR_OK) - return retval; - } - retval = cortex_a_read_apb_ab_memory(target, address, size, count, buffer); - } + if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap->ap_num)) + return mem_ap_read_buf(armv7a->memory_ap, buffer, size, count, address); + + /* read memory through the CPU */ + cortex_a_prep_memaccess(target, 1); + retval = cortex_a_read_cpu_memory(target, address, size, count, buffer); + cortex_a_post_memaccess(target, 1); + return retval; } -static int cortex_a_read_memory(struct target *target, uint32_t address, +static int cortex_a_read_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { - int mmu_enabled = 0; int retval; - struct armv7a_common *armv7a = target_to_armv7a(target); /* cortex_a handles unaligned memory access */ - LOG_DEBUG("Reading memory at address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address, - size, count); + LOG_DEBUG("Reading memory at address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32, + address, size, count); - /* determine if MMU was enabled on target stop */ - if (!armv7a->is_armv7r) { - retval = cortex_a_mmu(target, &mmu_enabled); - if (retval != ERROR_OK) - return retval; - } - - if (mmu_enabled) { - retval = cortex_a_check_address(target, address); - if (retval != ERROR_OK) - return retval; - /* enable MMU as we could have disabled it for phys access */ - retval = cortex_a_mmu_modify(target, 1); - if (retval != ERROR_OK) - return retval; - } - retval = cortex_a_read_apb_ab_memory(target, address, size, count, buffer); + cortex_a_prep_memaccess(target, 0); + retval = cortex_a_read_cpu_memory(target, address, size, count, buffer); + cortex_a_post_memaccess(target, 0); return retval; } -static int cortex_a_read_memory_ahb(struct target *target, uint32_t address, +static int cortex_a_read_memory_ahb(struct target *target, target_addr_t address, uint32_t size, uint32_t count, uint8_t *buffer) { int mmu_enabled = 0; - uint32_t virt, phys; + target_addr_t virt, phys; int retval; struct armv7a_common *armv7a = target_to_armv7a(target); struct adiv5_dap *swjdp = armv7a->arm.dap; uint8_t apsel = swjdp->apsel; - if (!armv7a->memory_ap_available || (apsel != armv7a->memory_ap)) + if (!armv7a->memory_ap_available || (apsel != armv7a->memory_ap->ap_num)) return target_read_memory(target, address, size, count, buffer); /* cortex_a handles unaligned memory access */ - LOG_DEBUG("Reading memory at address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address, - size, count); + LOG_DEBUG("Reading memory at address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32, + address, size, count); /* determine if MMU was enabled on target stop */ if (!armv7a->is_armv7r) { @@ -2691,7 +2728,8 @@ static int cortex_a_read_memory_ahb(struct target *target, uint32_t address, if (retval != ERROR_OK) return retval; - LOG_DEBUG("Reading at virtual address. Translating v:0x%" PRIx32 " to r:0x%" PRIx32, + LOG_DEBUG("Reading at virtual address. " + "Translating v:" TARGET_ADDR_FMT " to r:" TARGET_ADDR_FMT, virt, phys); address = phys; } @@ -2699,84 +2737,71 @@ static int cortex_a_read_memory_ahb(struct target *target, uint32_t address, if (!count || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; - retval = mem_ap_sel_read_buf(swjdp, armv7a->memory_ap, buffer, size, count, address); + retval = mem_ap_read_buf(armv7a->memory_ap, buffer, size, count, address); return retval; } static int cortex_a_write_phys_memory(struct target *target, - uint32_t address, uint32_t size, + target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { struct armv7a_common *armv7a = target_to_armv7a(target); - int retval = ERROR_COMMAND_SYNTAX_ERROR; + struct adiv5_dap *swjdp = armv7a->arm.dap; + uint8_t apsel = swjdp->apsel; + int retval; - LOG_DEBUG("Writing memory to real address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address, - size, count); + if (!count || !buffer) + return ERROR_COMMAND_SYNTAX_ERROR; - if (count && buffer) { - /* write memory through APB-AP */ - if (!armv7a->is_armv7r) { - retval = cortex_a_mmu_modify(target, 0); - if (retval != ERROR_OK) - return retval; - } - return cortex_a_write_apb_ab_memory(target, address, size, count, buffer); - } + LOG_DEBUG("Writing memory to real address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32, + address, size, count); + + if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap->ap_num)) + return mem_ap_write_buf(armv7a->memory_ap, buffer, size, count, address); + + /* write memory through the CPU */ + cortex_a_prep_memaccess(target, 1); + retval = cortex_a_write_cpu_memory(target, address, size, count, buffer); + cortex_a_post_memaccess(target, 1); return retval; } -static int cortex_a_write_memory(struct target *target, uint32_t address, +static int cortex_a_write_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { - int mmu_enabled = 0; int retval; - struct armv7a_common *armv7a = target_to_armv7a(target); /* cortex_a handles unaligned memory access */ - LOG_DEBUG("Writing memory at address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address, - size, count); - - /* determine if MMU was enabled on target stop */ - if (!armv7a->is_armv7r) { - retval = cortex_a_mmu(target, &mmu_enabled); - if (retval != ERROR_OK) - return retval; - } - - if (mmu_enabled) { - retval = cortex_a_check_address(target, address); - if (retval != ERROR_OK) - return retval; - /* enable MMU as we could have disabled it for phys access */ - retval = cortex_a_mmu_modify(target, 1); - if (retval != ERROR_OK) - return retval; - } - retval = cortex_a_write_apb_ab_memory(target, address, size, count, buffer); + LOG_DEBUG("Writing memory at address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32, + address, size, count); + /* memory writes bypass the caches, must flush before writing */ armv7a_cache_auto_flush_on_write(target, address, size * count); + cortex_a_prep_memaccess(target, 0); + retval = cortex_a_write_cpu_memory(target, address, size, count, buffer); + cortex_a_post_memaccess(target, 0); return retval; } -static int cortex_a_write_memory_ahb(struct target *target, uint32_t address, +static int cortex_a_write_memory_ahb(struct target *target, target_addr_t address, uint32_t size, uint32_t count, const uint8_t *buffer) { int mmu_enabled = 0; - uint32_t virt, phys; + target_addr_t virt, phys; int retval; struct armv7a_common *armv7a = target_to_armv7a(target); struct adiv5_dap *swjdp = armv7a->arm.dap; uint8_t apsel = swjdp->apsel; - if (!armv7a->memory_ap_available || (apsel != armv7a->memory_ap)) + if (!armv7a->memory_ap_available || (apsel != armv7a->memory_ap->ap_num)) return target_write_memory(target, address, size, count, buffer); /* cortex_a handles unaligned memory access */ - LOG_DEBUG("Writing memory at address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address, - size, count); + LOG_DEBUG("Writing memory at address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32, + address, size, count); /* determine if MMU was enabled on target stop */ if (!armv7a->is_armv7r) { @@ -2791,7 +2816,8 @@ static int cortex_a_write_memory_ahb(struct target *target, uint32_t address, if (retval != ERROR_OK) return retval; - LOG_DEBUG("Writing to virtual address. Translating v:0x%" PRIx32 " to r:0x%" PRIx32, + LOG_DEBUG("Writing to virtual address. " + "Translating v:" TARGET_ADDR_FMT " to r:" TARGET_ADDR_FMT, virt, phys); address = phys; @@ -2800,12 +2826,12 @@ static int cortex_a_write_memory_ahb(struct target *target, uint32_t address, if (!count || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; - retval = mem_ap_sel_write_buf(swjdp, armv7a->memory_ap, buffer, size, count, address); + retval = mem_ap_write_buf(armv7a->memory_ap, buffer, size, count, address); return retval; } -static int cortex_a_read_buffer(struct target *target, uint32_t address, +static int cortex_a_read_buffer(struct target *target, target_addr_t address, uint32_t count, uint8_t *buffer) { uint32_t size; @@ -2839,7 +2865,7 @@ static int cortex_a_read_buffer(struct target *target, uint32_t address, return ERROR_OK; } -static int cortex_a_write_buffer(struct target *target, uint32_t address, +static int cortex_a_write_buffer(struct target *target, target_addr_t address, uint32_t count, const uint8_t *buffer) { uint32_t size; @@ -2877,7 +2903,6 @@ static int cortex_a_handle_target_request(void *priv) { struct target *target = priv; struct armv7a_common *armv7a = target_to_armv7a(target); - struct adiv5_dap *swjdp = armv7a->arm.dap; int retval; if (!target_was_examined(target)) @@ -2888,18 +2913,23 @@ static int cortex_a_handle_target_request(void *priv) if (target->state == TARGET_RUNNING) { uint32_t request; uint32_t dscr; - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); /* check if we have data */ + int64_t then = timeval_ms(); while ((dscr & DSCR_DTR_TX_FULL) && (retval == ERROR_OK)) { - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRTX, &request); if (retval == ERROR_OK) { target_request(target, request); - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); } + if (timeval_ms() > then + 1000) { + LOG_ERROR("Timeout waiting for dtr tx full"); + return ERROR_FAIL; + } } } @@ -2915,33 +2945,40 @@ static int cortex_a_examine_first(struct target *target) struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct adiv5_dap *swjdp = armv7a->arm.dap; + int i; int retval = ERROR_OK; - uint32_t didr, ctypr, ttypr, cpuid, dbg_osreg; - - /* We do one extra read to ensure DAP is configured, - * we call ahbap_debugport_init(swjdp) instead - */ - retval = ahbap_debugport_init(swjdp); - if (retval != ERROR_OK) - return retval; + uint32_t didr, cpuid, dbg_osreg; - /* Search for the APB-AB - it is needed for access to debug registers */ + /* Search for the APB-AP - it is needed for access to debug registers */ retval = dap_find_ap(swjdp, AP_TYPE_APB_AP, &armv7a->debug_ap); if (retval != ERROR_OK) { LOG_ERROR("Could not find APB-AP for debug access"); return retval; } - /* Search for the AHB-AB */ - retval = dap_find_ap(swjdp, AP_TYPE_AHB_AP, &armv7a->memory_ap); + + retval = mem_ap_init(armv7a->debug_ap); if (retval != ERROR_OK) { - /* AHB-AP not found - use APB-AP */ - LOG_DEBUG("Could not find AHB-AP - using APB-AP for memory access"); - armv7a->memory_ap_available = false; - } else { - armv7a->memory_ap_available = true; + LOG_ERROR("Could not initialize the APB-AP"); + return retval; } + armv7a->debug_ap->memaccess_tck = 80; + + /* Search for the AHB-AB. + * REVISIT: We should search for AXI-AP as well and make sure the AP's MEMTYPE says it + * can access system memory. */ + armv7a->memory_ap_available = false; + retval = dap_find_ap(swjdp, AP_TYPE_AHB_AP, &armv7a->memory_ap); + if (retval == ERROR_OK) { + retval = mem_ap_init(armv7a->memory_ap); + if (retval == ERROR_OK) + armv7a->memory_ap_available = true; + } + if (retval != ERROR_OK) { + /* AHB-AP not found or unavailable - use the CPU */ + LOG_DEBUG("No AHB-AP available for memory access"); + } if (!target->dbgbase_set) { uint32_t dbgbase; @@ -2950,11 +2987,11 @@ static int cortex_a_examine_first(struct target *target) int32_t coreidx = target->coreid; LOG_DEBUG("%s's dbgbase is not set, trying to detect using the ROM table", target->cmd_name); - retval = dap_get_debugbase(swjdp, 1, &dbgbase, &apid); + retval = dap_get_debugbase(armv7a->debug_ap, &dbgbase, &apid); if (retval != ERROR_OK) return retval; /* Lookup 0x15 -- Processor DAP */ - retval = dap_lookup_cs_component(swjdp, 1, dbgbase, 0x15, + retval = dap_lookup_cs_component(armv7a->debug_ap, dbgbase, 0x15, &armv7a->debug_base, &coreidx); if (retval != ERROR_OK) { LOG_ERROR("Can't detect %s's dbgbase from the ROM table; you need to specify it explicitly.", @@ -2962,84 +2999,74 @@ static int cortex_a_examine_first(struct target *target) return retval; } LOG_DEBUG("Detected core %" PRId32 " dbgbase: %08" PRIx32, - coreidx, armv7a->debug_base); + target->coreid, armv7a->debug_base); } else armv7a->debug_base = target->dbgbase; - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, - armv7a->debug_base + CPUDBG_CPUID, &cpuid); - if (retval != ERROR_OK) - return retval; - - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, - armv7a->debug_base + CPUDBG_CPUID, &cpuid); - if (retval != ERROR_OK) { - LOG_DEBUG("Examine %s failed", "CPUID"); - return retval; - } - - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, - armv7a->debug_base + CPUDBG_CTYPR, &ctypr); - if (retval != ERROR_OK) { - LOG_DEBUG("Examine %s failed", "CTYPR"); - return retval; - } - - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, - armv7a->debug_base + CPUDBG_TTYPR, &ttypr); + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_DIDR, &didr); if (retval != ERROR_OK) { - LOG_DEBUG("Examine %s failed", "TTYPR"); + LOG_DEBUG("Examine %s failed", "DIDR"); return retval; } - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, - armv7a->debug_base + CPUDBG_DIDR, &didr); + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_CPUID, &cpuid); if (retval != ERROR_OK) { - LOG_DEBUG("Examine %s failed", "DIDR"); + LOG_DEBUG("Examine %s failed", "CPUID"); return retval; } - LOG_DEBUG("cpuid = 0x%08" PRIx32, cpuid); - LOG_DEBUG("ctypr = 0x%08" PRIx32, ctypr); - LOG_DEBUG("ttypr = 0x%08" PRIx32, ttypr); LOG_DEBUG("didr = 0x%08" PRIx32, didr); + LOG_DEBUG("cpuid = 0x%08" PRIx32, cpuid); - cortex_a->cpuid = cpuid; - cortex_a->ctypr = ctypr; - cortex_a->ttypr = ttypr; cortex_a->didr = didr; + cortex_a->cpuid = cpuid; - /* Unlocking the debug registers */ - if ((cpuid & CORTEX_A_MIDR_PARTNUM_MASK) >> CORTEX_A_MIDR_PARTNUM_SHIFT == - CORTEX_A15_PARTNUM) { - - retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, - armv7a->debug_base + CPUDBG_OSLAR, - 0); - - if (retval != ERROR_OK) - return retval; + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_PRSR, &dbg_osreg); + if (retval != ERROR_OK) + return retval; + LOG_DEBUG("target->coreid %" PRId32 " DBGPRSR 0x%" PRIx32, target->coreid, dbg_osreg); + if ((dbg_osreg & PRSR_POWERUP_STATUS) == 0) { + LOG_ERROR("target->coreid %" PRId32 " powered down!", target->coreid); + target->state = TARGET_UNKNOWN; /* TARGET_NO_POWER? */ + return ERROR_TARGET_INIT_FAILED; } - /* Unlocking the debug registers */ - if ((cpuid & CORTEX_A_MIDR_PARTNUM_MASK) >> CORTEX_A_MIDR_PARTNUM_SHIFT == - CORTEX_A7_PARTNUM) { - - retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap, - armv7a->debug_base + CPUDBG_OSLAR, - 0); - - if (retval != ERROR_OK) - return retval; - } - retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap, - armv7a->debug_base + CPUDBG_PRSR, &dbg_osreg); + if (dbg_osreg & PRSR_STICKY_RESET_STATUS) + LOG_DEBUG("target->coreid %" PRId32 " was reset!", target->coreid); + /* Read DBGOSLSR and check if OSLK is implemented */ + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_OSLSR, &dbg_osreg); if (retval != ERROR_OK) return retval; + LOG_DEBUG("target->coreid %" PRId32 " DBGOSLSR 0x%" PRIx32, target->coreid, dbg_osreg); - LOG_DEBUG("target->coreid %" PRId32 " DBGPRSR 0x%" PRIx32, target->coreid, dbg_osreg); + /* check if OS Lock is implemented */ + if ((dbg_osreg & OSLSR_OSLM) == OSLSR_OSLM0 || (dbg_osreg & OSLSR_OSLM) == OSLSR_OSLM1) { + /* check if OS Lock is set */ + if (dbg_osreg & OSLSR_OSLK) { + LOG_DEBUG("target->coreid %" PRId32 " OSLock set! Trying to unlock", target->coreid); + + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_OSLAR, + 0); + if (retval == ERROR_OK) + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_OSLSR, &dbg_osreg); + + /* if we fail to access the register or cannot reset the OSLK bit, bail out */ + if (retval != ERROR_OK || (dbg_osreg & OSLSR_OSLK) != 0) { + LOG_ERROR("target->coreid %" PRId32 " OSLock sticky, core not powered?", + target->coreid); + target->state = TARGET_UNKNOWN; /* TARGET_NO_POWER? */ + return ERROR_TARGET_INIT_FAILED; + } + } + } armv7a->arm.core_type = ARM_MODE_MON; @@ -3070,6 +3097,9 @@ static int cortex_a_examine_first(struct target *target) LOG_DEBUG("Configured %i hw breakpoints", cortex_a->brp_num); + /* select debug_ap as default */ + swjdp->apsel = armv7a->debug_ap->ap_num; + target_set_examined(target); return ERROR_OK; } @@ -3096,37 +3126,18 @@ static int cortex_a_init_target(struct command_context *cmd_ctx, struct target *target) { /* examine_first() does a bunch of this */ + arm_semihosting_init(target); return ERROR_OK; } static int cortex_a_init_arch_info(struct target *target, - struct cortex_a_common *cortex_a, struct jtag_tap *tap) + struct cortex_a_common *cortex_a, struct adiv5_dap *dap) { struct armv7a_common *armv7a = &cortex_a->armv7a_common; - struct adiv5_dap *dap = &armv7a->dap; - - armv7a->arm.dap = dap; /* Setup struct cortex_a_common */ cortex_a->common_magic = CORTEX_A_COMMON_MAGIC; - /* tap has no dap initialized */ - if (!tap->dap) { - armv7a->arm.dap = dap; - /* Setup struct cortex_a_common */ - - /* prepare JTAG information for the new target */ - cortex_a->jtag_info.tap = tap; - cortex_a->jtag_info.scann_size = 4; - - /* Leave (only) generic DAP stuff for debugport_init() */ - dap->jtag_info = &cortex_a->jtag_info; - - /* Number of bits for tar autoincrement, impl. dep. at least 10 */ - dap->tar_autoincr_block = (1 << 10); - dap->memaccess_tck = 80; - tap->dap = dap; - } else - armv7a->arm.dap = tap->dap; + armv7a->arm.dap = dap; cortex_a->fast_reg_read = 0; @@ -3152,19 +3163,34 @@ static int cortex_a_init_arch_info(struct target *target, static int cortex_a_target_create(struct target *target, Jim_Interp *interp) { struct cortex_a_common *cortex_a = calloc(1, sizeof(struct cortex_a_common)); + cortex_a->common_magic = CORTEX_A_COMMON_MAGIC; + struct adiv5_private_config *pc; + + if (target->private_config == NULL) + return ERROR_FAIL; + + pc = (struct adiv5_private_config *)target->private_config; cortex_a->armv7a_common.is_armv7r = false; - return cortex_a_init_arch_info(target, cortex_a, target->tap); + cortex_a->armv7a_common.arm.arm_vfp_version = ARM_VFP_V3; + + return cortex_a_init_arch_info(target, cortex_a, pc->dap); } static int cortex_r4_target_create(struct target *target, Jim_Interp *interp) { struct cortex_a_common *cortex_a = calloc(1, sizeof(struct cortex_a_common)); + cortex_a->common_magic = CORTEX_A_COMMON_MAGIC; + struct adiv5_private_config *pc; + + pc = (struct adiv5_private_config *)target->private_config; + if (adiv5_verify_config(pc) != ERROR_OK) + return ERROR_FAIL; cortex_a->armv7a_common.is_armv7r = true; - return cortex_a_init_arch_info(target, cortex_a, target->tap); + return cortex_a_init_arch_info(target, cortex_a, pc->dap); } static void cortex_a_deinit_target(struct target *target) @@ -3175,28 +3201,49 @@ static void cortex_a_deinit_target(struct target *target) free(cortex_a->brp_list); free(dpm->dbp); free(dpm->dwp); + free(target->private_config); free(cortex_a); } static int cortex_a_mmu(struct target *target, int *enabled) { + struct armv7a_common *armv7a = target_to_armv7a(target); + if (target->state != TARGET_HALTED) { LOG_ERROR("%s: target not halted", __func__); return ERROR_TARGET_INVALID; } - *enabled = target_to_cortex_a(target)->armv7a_common.armv7a_mmu.mmu_enabled; + if (armv7a->is_armv7r) + *enabled = 0; + else + *enabled = target_to_cortex_a(target)->armv7a_common.armv7a_mmu.mmu_enabled; + return ERROR_OK; } static int cortex_a_virt2phys(struct target *target, - uint32_t virt, uint32_t *phys) + target_addr_t virt, target_addr_t *phys) { int retval = ERROR_FAIL; struct armv7a_common *armv7a = target_to_armv7a(target); struct adiv5_dap *swjdp = armv7a->arm.dap; uint8_t apsel = swjdp->apsel; - if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap)) { + int mmu_enabled = 0; + + /* + * If the MMU was not enabled at debug entry, there is no + * way of knowing if there was ever a valid configuration + * for it and thus it's not safe to enable it. In this case, + * just return the virtual address as physical. + */ + cortex_a_mmu(target, &mmu_enabled); + if (!mmu_enabled) { + *phys = virt; + return ERROR_OK; + } + + if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap->ap_num)) { uint32_t ret; retval = armv7a_mmu_translate_va(target, virt, &ret); @@ -3208,7 +3255,8 @@ static int cortex_a_virt2phys(struct target *target, retval = cortex_a_mmu_modify(target, 1); if (retval != ERROR_OK) goto done; - retval = armv7a_mmu_translate_va_pa(target, virt, phys, 1); + retval = armv7a_mmu_translate_va_pa(target, (uint32_t)virt, + (uint32_t *)phys, 1); } done: return retval; @@ -3304,17 +3352,14 @@ COMMAND_HANDLER(handle_cortex_a_mask_interrupts_command) }; const Jim_Nvp *n; - if (target->state != TARGET_HALTED) { - command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME); - return ERROR_OK; - } - if (CMD_ARGC > 0) { n = Jim_Nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]); - if (n->name == NULL) + if (n->name == NULL) { + LOG_ERROR("Unknown parameter: %s - should be off or on", CMD_ARGV[0]); return ERROR_COMMAND_SYNTAX_ERROR; - cortex_a->isrmasking_mode = n->value; + } + cortex_a->isrmasking_mode = n->value; } n = Jim_Nvp_value2name_simple(nvp_maskisr_modes, cortex_a->isrmasking_mode); @@ -3323,6 +3368,32 @@ COMMAND_HANDLER(handle_cortex_a_mask_interrupts_command) return ERROR_OK; } +COMMAND_HANDLER(handle_cortex_a_dacrfixup_command) +{ + struct target *target = get_current_target(CMD_CTX); + struct cortex_a_common *cortex_a = target_to_cortex_a(target); + + static const Jim_Nvp nvp_dacrfixup_modes[] = { + { .name = "off", .value = CORTEX_A_DACRFIXUP_OFF }, + { .name = "on", .value = CORTEX_A_DACRFIXUP_ON }, + { .name = NULL, .value = -1 }, + }; + const Jim_Nvp *n; + + if (CMD_ARGC > 0) { + n = Jim_Nvp_name2value_simple(nvp_dacrfixup_modes, CMD_ARGV[0]); + if (n->name == NULL) + return ERROR_COMMAND_SYNTAX_ERROR; + cortex_a->dacrfixup_mode = n->value; + + } + + n = Jim_Nvp_value2name_simple(nvp_dacrfixup_modes, cortex_a->dacrfixup_mode); + command_print(CMD_CTX, "cortex_a domain access control fixup %s", n->name); + + return ERROR_OK; +} + static const struct command_registration cortex_a_exec_command_handlers[] = { { .name = "cache_info", @@ -3360,11 +3431,18 @@ static const struct command_registration cortex_a_exec_command_handlers[] = { { .name = "maskisr", .handler = handle_cortex_a_mask_interrupts_command, - .mode = COMMAND_EXEC, + .mode = COMMAND_ANY, .help = "mask cortex_a interrupts", .usage = "['on'|'off']", }, - + { + .name = "dacrfixup", + .handler = handle_cortex_a_dacrfixup_command, + .mode = COMMAND_ANY, + .help = "set domain access control (DACR) to all-manager " + "on memory access", + .usage = "['on'|'off']", + }, COMMAND_REGISTRATION_DONE }; @@ -3422,6 +3500,7 @@ struct target_type cortexa_target = { .commands = cortex_a_command_handlers, .target_create = cortex_a_target_create, + .target_jim_configure = adiv5_jim_configure, .init_target = cortex_a_init_target, .examine = cortex_a_examine, .deinit_target = cortex_a_deinit_target, @@ -3433,13 +3512,6 @@ struct target_type cortexa_target = { }; static const struct command_registration cortex_r4_exec_command_handlers[] = { - { - .name = "cache_info", - .handler = cortex_a_handle_cache_info_command, - .mode = COMMAND_EXEC, - .help = "display information about target caches", - .usage = "", - }, { .name = "dbginit", .handler = cortex_a_handle_dbginit_command, @@ -3461,9 +3533,6 @@ static const struct command_registration cortex_r4_command_handlers[] = { { .chain = arm_command_handlers, }, - { - .chain = armv7a_command_handlers, - }, { .name = "cortex_r4", .mode = COMMAND_ANY, @@ -3490,8 +3559,8 @@ struct target_type cortexr4_target = { /* REVISIT allow exporting VFP3 registers ... */ .get_gdb_reg_list = arm_get_gdb_reg_list, - .read_memory = cortex_a_read_memory, - .write_memory = cortex_a_write_memory, + .read_memory = cortex_a_read_phys_memory, + .write_memory = cortex_a_write_phys_memory, .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, @@ -3507,6 +3576,7 @@ struct target_type cortexr4_target = { .commands = cortex_r4_command_handlers, .target_create = cortex_r4_target_create, + .target_jim_configure = adiv5_jim_configure, .init_target = cortex_a_init_target, .examine = cortex_a_examine, .deinit_target = cortex_a_deinit_target,