X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Ftarget%2Fcortex_a.c;h=bf65544f51afa133d33a458ccd51c4adcbc5c6d4;hp=f9ffccd08a4144bd0fb45b2feb6653aa6730632d;hb=HEAD;hpb=b0698501b0e789091e9f9f1427b32af304888769 diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index f9ffccd08a..2de77c9602 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -1,3 +1,5 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2005 by Dominic Rath * * Dominic.Rath@gmx.de * @@ -18,25 +20,13 @@ * 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 * * * - * This program is free software; you can redistribute it and/or modify * - * it under the terms of the GNU General Public License as published by * - * the Free Software Foundation; either version 2 of the License, or * - * (at your option) any later version. * - * * - * This program is distributed in the hope that it will be useful, * - * but WITHOUT ANY WARRANTY; without even the implied warranty of * - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * - * 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. * + * Copyright (C) 2016 Chengyu Zheng * + * chengyu.zheng@polimi.it : watchpoint support * * * * Cortex-A8(tm) TRM, ARM DDI 0344H * * Cortex-A9(tm) TRM, ARM DDI 0407F * @@ -52,9 +42,17 @@ #include "breakpoints.h" #include "cortex_a.h" #include "register.h" +#include "armv7a_mmu.h" #include "target_request.h" #include "target_type.h" +#include "arm_coresight.h" #include "arm_opcodes.h" +#include "arm_semihosting.h" +#include "jtag/interface.h" +#include "transport/transport.h" +#include "smp.h" +#include +#include #include static int cortex_a_poll(struct target *target); @@ -68,17 +66,25 @@ static int cortex_a_set_hybrid_breakpoint(struct target *target, struct breakpoint *breakpoint); static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *breakpoint); -static int cortex_a_dap_read_coreregister_u32(struct target *target, - uint32_t *value, int regnum); -static int cortex_a_dap_write_coreregister_u32(struct target *target, - uint32_t value, int regnum); +static int cortex_a_wait_dscr_bits(struct target *target, uint32_t mask, + uint32_t value, uint32_t *dscr); 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); +static unsigned int ilog2(unsigned int x) +{ + unsigned int y = 0; + x /= 2; + while (x) { + ++y; + x /= 2; + } + return y; +} /* restore cp15_control_reg at resume */ static int cortex_a_restore_cp15_control_reg(struct target *target) @@ -110,7 +116,7 @@ static int cortex_a_prep_memaccess(struct target *target, int phys_access) int mmu_enabled = 0; if (phys_access == 0) { - dpm_modeswitch(&armv7a->dpm, ARM_MODE_SVC); + arm_dpm_modeswitch(&armv7a->dpm, ARM_MODE_SVC); cortex_a_mmu(target, &mmu_enabled); if (mmu_enabled) cortex_a_mmu_modify(target, 1); @@ -145,7 +151,7 @@ static int cortex_a_post_memaccess(struct target *target, int phys_access) 0, 0, 3, 0, cortex_a->cp15_dacr_reg); } - dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY); + arm_dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY); } else { int mmu_enabled = 0; cortex_a_mmu(target, &mmu_enabled); @@ -196,99 +202,52 @@ static int cortex_a_mmu_modify(struct target *target, int enable) 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); - int retval; - - LOG_DEBUG(" "); - - /* Unlocking the debug registers for modification - * The debugport might be uninitialised so try twice */ - retval = mem_ap_write_atomic_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_LOCKACCESS, 0xC5ACCE55); - if (retval != ERROR_OK) { - /* try again */ - retval = mem_ap_write_atomic_u32(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."); - } - - return retval; -} - /* * Cortex-A Basic debug access, very low level assumes state is saved */ static int cortex_a_init_debug_access(struct target *target) { struct armv7a_common *armv7a = target_to_armv7a(target); + uint32_t dscr; 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_read_atomic_u32(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_write_atomic_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_OSLAR, - 0); - break; - - case CORTEX_A5_PARTNUM: - case CORTEX_A8_PARTNUM: - case CORTEX_A9_PARTNUM: - default: - retval = cortex_a8_init_debug_access(target); - } - - 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_read_atomic_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_PRSR, &dbg_osreg); - LOG_DEBUG("target->coreid %" PRId32 " DBGPRSR 0x%" PRIx32, target->coreid, dbg_osreg); + /* 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; /* Disable cacheline fills and force cache write-through in debug state */ - retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + 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_atomic_u32(armv7a->debug_ap, + retval = mem_ap_write_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSMCR, 0); if (retval != ERROR_OK) return retval; + retval = dap_run(armv7a->debug_ap->dap); + if (retval != ERROR_OK) + return retval; + /* Enabling of instruction execution in debug mode is done in debug_entry code */ /* Resync breakpoint registers */ + /* Enable halt for breakpoint, watchpoint and vector catch */ + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_DSCR, &dscr); + if (retval != ERROR_OK) + return retval; + 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; + /* Since this is likely called from init or reset, update target state information*/ return cortex_a_poll(target); } @@ -299,21 +258,21 @@ 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); - int64_t then = timeval_ms(); - while ((*dscr & DSCR_INSTR_COMP) == 0 || force) { - force = false; - int retval = mem_ap_read_atomic_u32(armv7a->debug_ap, + int retval; + + if (force) { + 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"); return retval; } - if (timeval_ms() > then + 1000) { - LOG_ERROR("Timeout waiting for InstrCompl=1"); - return ERROR_FAIL; - } } - return ERROR_OK; + + retval = cortex_a_wait_dscr_bits(target, DSCR_INSTR_COMP, DSCR_INSTR_COMP, dscr); + if (retval != ERROR_OK) + LOG_ERROR("Error waiting for InstrCompl=1"); + return retval; } /* To reduce needless round-trips, pass in a pointer to the current @@ -342,201 +301,15 @@ static int cortex_a_exec_opcode(struct target *target, if (retval != ERROR_OK) return retval; - int64_t then = timeval_ms(); - do { - 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"); - return retval; - } - if (timeval_ms() > then + 1000) { - LOG_ERROR("Timeout waiting for cortex_a_exec_opcode"); - return ERROR_FAIL; - } - } while ((dscr & DSCR_INSTR_COMP) == 0); /* Wait for InstrCompl bit to be set */ - - if (dscr_p) - *dscr_p = dscr; - - return retval; -} - -/************************************************************************** -Read core register with very few exec_opcode, fast but needs work_area. -This can cause problems with MMU active. -**************************************************************************/ -static int cortex_a_read_regs_through_mem(struct target *target, uint32_t address, - uint32_t *regfile) -{ - int retval = ERROR_OK; - struct armv7a_common *armv7a = target_to_armv7a(target); - - retval = cortex_a_dap_read_coreregister_u32(target, regfile, 0); - if (retval != ERROR_OK) - return retval; - retval = cortex_a_dap_write_coreregister_u32(target, address, 0); - if (retval != ERROR_OK) - return retval; - retval = cortex_a_exec_opcode(target, ARMV4_5_STMIA(0, 0xFFFE, 0, 0), NULL); - if (retval != ERROR_OK) - return retval; - - retval = mem_ap_read_buf(armv7a->memory_ap, - (uint8_t *)(®file[1]), 4, 15, address); - - return retval; -} - -static int cortex_a_dap_read_coreregister_u32(struct target *target, - uint32_t *value, int regnum) -{ - int retval = ERROR_OK; - uint8_t reg = regnum&0xFF; - uint32_t dscr = 0; - struct armv7a_common *armv7a = target_to_armv7a(target); - - if (reg > 17) - return retval; - - if (reg < 15) { - /* Rn to DCCTX, "MCR p14, 0, Rn, c0, c5, 0" 0xEE00nE15 */ - retval = cortex_a_exec_opcode(target, - ARMV4_5_MCR(14, 0, reg, 0, 5, 0), - &dscr); - if (retval != ERROR_OK) - return retval; - } else if (reg == 15) { - /* "MOV r0, r15"; then move r0 to DCCTX */ - retval = cortex_a_exec_opcode(target, 0xE1A0000F, &dscr); - if (retval != ERROR_OK) - return retval; - retval = cortex_a_exec_opcode(target, - ARMV4_5_MCR(14, 0, 0, 0, 5, 0), - &dscr); - if (retval != ERROR_OK) - return retval; - } else { - /* "MRS r0, CPSR" or "MRS r0, SPSR" - * then move r0 to DCCTX - */ - retval = cortex_a_exec_opcode(target, ARMV4_5_MRS(0, reg & 1), &dscr); - if (retval != ERROR_OK) - return retval; - retval = cortex_a_exec_opcode(target, - ARMV4_5_MCR(14, 0, 0, 0, 5, 0), - &dscr); - if (retval != ERROR_OK) - return retval; - } - - /* Wait for DTRRXfull then read DTRRTX */ - int64_t then = timeval_ms(); - while ((dscr & DSCR_DTR_TX_FULL) == 0) { - retval = mem_ap_read_atomic_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_DSCR, &dscr); - if (retval != ERROR_OK) - return retval; - if (timeval_ms() > then + 1000) { - LOG_ERROR("Timeout waiting for cortex_a_exec_opcode"); - return ERROR_FAIL; - } - } - - retval = mem_ap_read_atomic_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_DTRTX, value); - LOG_DEBUG("read DCC 0x%08" PRIx32, *value); - - return retval; -} - -static int cortex_a_dap_write_coreregister_u32(struct target *target, - uint32_t value, int regnum) -{ - int retval = ERROR_OK; - uint8_t Rd = regnum&0xFF; - uint32_t dscr; - struct armv7a_common *armv7a = target_to_armv7a(target); - - LOG_DEBUG("register %i, value 0x%08" PRIx32, regnum, value); - - /* Check that DCCRX is not full */ - retval = mem_ap_read_atomic_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_DSCR, &dscr); - if (retval != ERROR_OK) + /* Wait for InstrCompl bit to be set */ + retval = cortex_a_wait_instrcmpl(target, &dscr, true); + if (retval != ERROR_OK) { + LOG_ERROR("Error waiting for cortex_a_exec_opcode"); return retval; - if (dscr & DSCR_DTR_RX_FULL) { - LOG_ERROR("DSCR_DTR_RX_FULL, dscr 0x%08" PRIx32, dscr); - /* Clear DCCRX with MRC(p14, 0, Rd, c0, c5, 0), opcode 0xEE100E15 */ - retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), - &dscr); - if (retval != ERROR_OK) - return retval; } - if (Rd > 17) - return retval; - - /* Write DTRRX ... sets DSCR.DTRRXfull but exec_opcode() won't care */ - LOG_DEBUG("write DCC 0x%08" PRIx32, value); - retval = mem_ap_write_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_DTRRX, value); - if (retval != ERROR_OK) - return retval; - - if (Rd < 15) { - /* DCCRX to Rn, "MRC p14, 0, Rn, c0, c5, 0", 0xEE10nE15 */ - retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, Rd, 0, 5, 0), - &dscr); - - if (retval != ERROR_OK) - return retval; - } else if (Rd == 15) { - /* DCCRX to R0, "MRC p14, 0, R0, c0, c5, 0", 0xEE100E15 - * then "mov r15, r0" - */ - retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), - &dscr); - if (retval != ERROR_OK) - return retval; - retval = cortex_a_exec_opcode(target, 0xE1A0F000, &dscr); - if (retval != ERROR_OK) - return retval; - } else { - /* DCCRX to R0, "MRC p14, 0, R0, c0, c5, 0", 0xEE100E15 - * then "MSR CPSR_cxsf, r0" or "MSR SPSR_cxsf, r0" (all fields) - */ - retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), - &dscr); - if (retval != ERROR_OK) - return retval; - retval = cortex_a_exec_opcode(target, ARMV4_5_MSR_GP(0, 0xF, Rd & 1), - &dscr); - if (retval != ERROR_OK) - return retval; - - /* "Prefetch flush" after modifying execution status in CPSR */ - if (Rd == 16) { - retval = cortex_a_exec_opcode(target, - ARMV4_5_MCR(15, 0, 0, 7, 5, 4), - &dscr); - if (retval != ERROR_OK) - return retval; - } - } - - return retval; -} - -/* Write to memory mapped registers directly with no cache or mmu handling */ -static int cortex_a_dap_write_memap_register_u32(struct target *target, - uint32_t address, - uint32_t value) -{ - int retval; - struct armv7a_common *armv7a = target_to_armv7a(target); - - retval = mem_ap_write_atomic_u32(armv7a->debug_ap, address, value); + if (dscr_p) + *dscr_p = dscr; return retval; } @@ -574,17 +347,11 @@ static int cortex_a_read_dcc(struct cortex_a_common *a, uint32_t *data, dscr = *dscr_p; /* Wait for DTRRXfull */ - int64_t then = timeval_ms(); - while ((dscr & DSCR_DTR_TX_FULL) == 0) { - retval = mem_ap_read_atomic_u32(a->armv7a_common.debug_ap, - a->armv7a_common.debug_base + CPUDBG_DSCR, - &dscr); - if (retval != ERROR_OK) - return retval; - if (timeval_ms() > then + 1000) { - LOG_ERROR("Timeout waiting for read dcc"); - return ERROR_FAIL; - } + retval = cortex_a_wait_dscr_bits(a->armv7a_common.arm.target, + DSCR_DTR_TX_FULL, DSCR_DTR_TX_FULL, &dscr); + if (retval != ERROR_OK) { + LOG_ERROR("Error waiting for read dcc"); + return retval; } retval = mem_ap_read_atomic_u32(a->armv7a_common.debug_ap, @@ -606,19 +373,10 @@ static int cortex_a_dpm_prepare(struct arm_dpm *dpm) int retval; /* set up invariant: INSTR_COMP is set after ever DPM operation */ - int64_t then = timeval_ms(); - for (;; ) { - retval = mem_ap_read_atomic_u32(a->armv7a_common.debug_ap, - a->armv7a_common.debug_base + CPUDBG_DSCR, - &dscr); - if (retval != ERROR_OK) - return retval; - if ((dscr & DSCR_INSTR_COMP) != 0) - break; - if (timeval_ms() > then + 1000) { - LOG_ERROR("Timeout waiting for dpm prepare"); - return ERROR_FAIL; - } + retval = cortex_a_wait_instrcmpl(dpm->arm->target, &dscr, true); + if (retval != ERROR_OK) { + LOG_ERROR("Error waiting for dpm prepare"); + return retval; } /* this "should never happen" ... */ @@ -659,22 +417,35 @@ static int cortex_a_instr_write_data_dcc(struct arm_dpm *dpm, &dscr); } -static int cortex_a_instr_write_data_r0(struct arm_dpm *dpm, - uint32_t opcode, uint32_t data) +static int cortex_a_instr_write_data_rt_dcc(struct arm_dpm *dpm, + uint8_t rt, uint32_t data) { struct cortex_a_common *a = dpm_to_a(dpm); uint32_t dscr = DSCR_INSTR_COMP; int retval; + if (rt > 15) + return ERROR_TARGET_INVALID; + retval = cortex_a_write_dcc(a, data); if (retval != ERROR_OK) return retval; - /* DCCRX to R0, "MCR p14, 0, R0, c0, c5, 0", 0xEE000E15 */ - retval = cortex_a_exec_opcode( + /* DCCRX to Rt, "MCR p14, 0, R0, c0, c5, 0", 0xEE000E15 */ + return cortex_a_exec_opcode( a->armv7a_common.arm.target, - ARMV4_5_MRC(14, 0, 0, 0, 5, 0), + ARMV4_5_MRC(14, 0, rt, 0, 5, 0), &dscr); +} + +static int cortex_a_instr_write_data_r0(struct arm_dpm *dpm, + uint32_t opcode, uint32_t data) +{ + struct cortex_a_common *a = dpm_to_a(dpm); + uint32_t dscr = DSCR_INSTR_COMP; + int retval; + + retval = cortex_a_instr_write_data_rt_dcc(dpm, 0, data); if (retval != ERROR_OK) return retval; @@ -687,6 +458,28 @@ static int cortex_a_instr_write_data_r0(struct arm_dpm *dpm, return retval; } +static int cortex_a_instr_write_data_r0_r1(struct arm_dpm *dpm, + uint32_t opcode, uint64_t data) +{ + struct cortex_a_common *a = dpm_to_a(dpm); + uint32_t dscr = DSCR_INSTR_COMP; + int retval; + + retval = cortex_a_instr_write_data_rt_dcc(dpm, 0, data & 0xffffffffULL); + if (retval != ERROR_OK) + return retval; + + retval = cortex_a_instr_write_data_rt_dcc(dpm, 1, data >> 32); + if (retval != ERROR_OK) + return retval; + + /* then the opcode, taking data from R0, R1 */ + retval = cortex_a_exec_opcode(a->armv7a_common.arm.target, + opcode, + &dscr); + return retval; +} + static int cortex_a_instr_cpsr_sync(struct arm_dpm *dpm) { struct target *target = dpm->arm->target; @@ -716,6 +509,25 @@ static int cortex_a_instr_read_data_dcc(struct arm_dpm *dpm, return cortex_a_read_dcc(a, data, &dscr); } +static int cortex_a_instr_read_data_rt_dcc(struct arm_dpm *dpm, + uint8_t rt, uint32_t *data) +{ + struct cortex_a_common *a = dpm_to_a(dpm); + uint32_t dscr = DSCR_INSTR_COMP; + int retval; + + if (rt > 15) + return ERROR_TARGET_INVALID; + + retval = cortex_a_exec_opcode( + a->armv7a_common.arm.target, + ARMV4_5_MCR(14, 0, rt, 0, 5, 0), + &dscr); + if (retval != ERROR_OK) + return retval; + + return cortex_a_read_dcc(a, data, &dscr); +} static int cortex_a_instr_read_data_r0(struct arm_dpm *dpm, uint32_t opcode, uint32_t *data) @@ -733,14 +545,30 @@ static int cortex_a_instr_read_data_r0(struct arm_dpm *dpm, return retval; /* write R0 to DCC */ - retval = cortex_a_exec_opcode( - a->armv7a_common.arm.target, - ARMV4_5_MCR(14, 0, 0, 0, 5, 0), - &dscr); + return cortex_a_instr_read_data_rt_dcc(dpm, 0, data); +} + +static int cortex_a_instr_read_data_r0_r1(struct arm_dpm *dpm, + uint32_t opcode, uint64_t *data) +{ + uint32_t lo, hi; + int retval; + + /* the opcode, writing data to RO, R1 */ + retval = cortex_a_instr_read_data_r0(dpm, opcode, &lo); if (retval != ERROR_OK) return retval; - return cortex_a_read_dcc(a, data, &dscr); + *data = lo; + + /* write R1 to DCC */ + retval = cortex_a_instr_read_data_rt_dcc(dpm, 1, &hi); + if (retval != ERROR_OK) + return retval; + + *data |= (uint64_t)hi << 32; + + return retval; } static int cortex_a_bpwp_enable(struct arm_dpm *dpm, unsigned index_t, @@ -770,11 +598,11 @@ static int cortex_a_bpwp_enable(struct arm_dpm *dpm, unsigned index_t, LOG_DEBUG("A: bpwp enable, vr %08x cr %08x", (unsigned) vr, (unsigned) cr); - retval = cortex_a_dap_write_memap_register_u32(dpm->arm->target, + retval = mem_ap_write_atomic_u32(a->armv7a_common.debug_ap, vr, addr); if (retval != ERROR_OK) return retval; - retval = cortex_a_dap_write_memap_register_u32(dpm->arm->target, + retval = mem_ap_write_atomic_u32(a->armv7a_common.debug_ap, cr, control); return retval; } @@ -800,7 +628,7 @@ static int cortex_a_bpwp_disable(struct arm_dpm *dpm, unsigned index_t) LOG_DEBUG("A: bpwp disable, cr %08x", (unsigned) cr); /* clear control register */ - return cortex_a_dap_write_memap_register_u32(dpm->arm->target, cr, 0); + return mem_ap_write_atomic_u32(a->armv7a_common.debug_ap, cr, 0); } static int cortex_a_dpm_setup(struct cortex_a_common *a, uint32_t didr) @@ -816,10 +644,12 @@ static int cortex_a_dpm_setup(struct cortex_a_common *a, uint32_t didr) dpm->instr_write_data_dcc = cortex_a_instr_write_data_dcc; dpm->instr_write_data_r0 = cortex_a_instr_write_data_r0; + dpm->instr_write_data_r0_r1 = cortex_a_instr_write_data_r0_r1; dpm->instr_cpsr_sync = cortex_a_instr_cpsr_sync; dpm->instr_read_data_dcc = cortex_a_instr_read_data_dcc; dpm->instr_read_data_r0 = cortex_a_instr_read_data_r0; + dpm->instr_read_data_r0_r1 = cortex_a_instr_read_data_r0_r1; dpm->bpwp_enable = cortex_a_bpwp_enable; dpm->bpwp_disable = cortex_a_bpwp_disable; @@ -833,14 +663,11 @@ static int cortex_a_dpm_setup(struct cortex_a_common *a, uint32_t didr) static struct target *get_cortex_a(struct target *target, int32_t coreid) { struct target_list *head; - struct target *curr; - head = target->head; - while (head != (struct target_list *)NULL) { - curr = head->target; + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; if ((curr->coreid == coreid) && (curr->state == TARGET_HALTED)) return curr; - head = head->next; } return target; } @@ -850,25 +677,55 @@ static int cortex_a_halt_smp(struct target *target) { int retval = 0; struct target_list *head; - struct target *curr; - head = target->head; - while (head != (struct target_list *)NULL) { - curr = head->target; - if ((curr != target) && (curr->state != TARGET_HALTED)) + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + if ((curr != target) && (curr->state != TARGET_HALTED) + && target_was_examined(curr)) retval += cortex_a_halt(curr); - head = head->next; } return retval; } static int update_halt_gdb(struct target *target) { + struct target *gdb_target = NULL; + struct target_list *head; + struct target *curr; int retval = 0; + if (target->gdb_service && target->gdb_service->core[0] == -1) { target->gdb_service->target = target; target->gdb_service->core[0] = target->coreid; retval += cortex_a_halt_smp(target); } + + if (target->gdb_service) + gdb_target = target->gdb_service->target; + + foreach_smp_target(head, target->smp_targets) { + curr = head->target; + /* skip calling context */ + if (curr == target) + continue; + if (!target_was_examined(curr)) + continue; + /* skip targets that were already halted */ + if (curr->state == TARGET_HALTED) + continue; + /* Skip gdb_target; it alerts GDB so has to be polled as last one */ + if (curr == gdb_target) + continue; + + /* avoid recursion in cortex_a_poll() */ + curr->smp = 0; + cortex_a_poll(curr); + curr->smp = 1; + } + + /* after all targets were updated, poll the gdb serving target */ + if (gdb_target && gdb_target != target) + cortex_a_poll(gdb_target); return retval; } @@ -889,7 +746,7 @@ static int cortex_a_poll(struct target *target) /* the next polling trigger an halt event sent to gdb */ if ((target->state == TARGET_HALTED) && (target->smp) && (target->gdb_service) && - (target->gdb_service->target == NULL)) { + (!target->gdb_service->target)) { target->gdb_service->target = get_cortex_a(target, target->gdb_service->core[1]); target_call_event_callbacks(target, TARGET_EVENT_HALTED); @@ -906,49 +763,36 @@ static int cortex_a_poll(struct target *target) /* We have a halting debug event */ LOG_DEBUG("Target halted"); target->state = TARGET_HALTED; - if ((prev_target_state == TARGET_RUNNING) - || (prev_target_state == TARGET_UNKNOWN) - || (prev_target_state == TARGET_RESET)) { - retval = cortex_a_debug_entry(target); + + retval = cortex_a_debug_entry(target); + if (retval != ERROR_OK) + return retval; + + if (target->smp) { + retval = update_halt_gdb(target); if (retval != ERROR_OK) return retval; - if (target->smp) { - retval = update_halt_gdb(target); - if (retval != ERROR_OK) - return retval; - } - target_call_event_callbacks(target, - TARGET_EVENT_HALTED); } - if (prev_target_state == TARGET_DEBUG_RUNNING) { - LOG_DEBUG(" "); - retval = cortex_a_debug_entry(target); - if (retval != ERROR_OK) + if (prev_target_state == TARGET_DEBUG_RUNNING) { + target_call_event_callbacks(target, TARGET_EVENT_DEBUG_HALTED); + } else { /* prev_target_state is RUNNING, UNKNOWN or RESET */ + if (arm_semihosting(target, &retval) != 0) return retval; - if (target->smp) { - retval = update_halt_gdb(target); - if (retval != ERROR_OK) - return retval; - } target_call_event_callbacks(target, - TARGET_EVENT_DEBUG_HALTED); + TARGET_EVENT_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; } static int cortex_a_halt(struct target *target) { - int retval = ERROR_OK; + int retval; uint32_t dscr; struct armv7a_common *armv7a = target_to_armv7a(target); @@ -961,31 +805,12 @@ static int cortex_a_halt(struct target *target) if (retval != ERROR_OK) return retval; - /* - * enter halting debug mode - */ - retval = mem_ap_read_atomic_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_DSCR, &dscr); - if (retval != ERROR_OK) - return retval; - - retval = mem_ap_write_atomic_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_DSCR, dscr | DSCR_HALT_DBG_MODE); - if (retval != ERROR_OK) + dscr = 0; /* force read of dscr */ + retval = cortex_a_wait_dscr_bits(target, DSCR_CORE_HALTED, + DSCR_CORE_HALTED, &dscr); + if (retval != ERROR_OK) { + LOG_ERROR("Error waiting for halt"); return retval; - - int64_t then = timeval_ms(); - for (;; ) { - retval = mem_ap_read_atomic_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_DSCR, &dscr); - if (retval != ERROR_OK) - return retval; - if ((dscr & DSCR_CORE_HALTED) != 0) - break; - if (timeval_ms() > then + 1000) { - LOG_ERROR("Timeout waiting for halt"); - return ERROR_FAIL; - } } target->debug_reason = DBG_REASON_DBGRQ; @@ -994,7 +819,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; @@ -1013,15 +838,15 @@ static int cortex_a_internal_restore(struct target *target, int current, * C_MASKINTS in parallel with disabled interrupts can cause * local faults to not be taken. */ buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_PRIMASK].value, 0, 32, 1); - armv7m->core_cache->reg_list[ARMV7M_PRIMASK].dirty = 1; - armv7m->core_cache->reg_list[ARMV7M_PRIMASK].valid = 1; + armv7m->core_cache->reg_list[ARMV7M_PRIMASK].dirty = true; + armv7m->core_cache->reg_list[ARMV7M_PRIMASK].valid = true; /* Make sure we are in Thumb mode */ - buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_xPSR].value, 0, 32, - buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_xPSR].value, 0, + buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_XPSR].value, 0, 32, + buf_get_u32(armv7m->core_cache->reg_list[ARMV7M_XPSR].value, 0, 32) | (1 << 24)); - armv7m->core_cache->reg_list[ARMV7M_xPSR].dirty = 1; - armv7m->core_cache->reg_list[ARMV7M_xPSR].valid = 1; + armv7m->core_cache->reg_list[ARMV7M_XPSR].dirty = true; + armv7m->core_cache->reg_list[ARMV7M_XPSR].valid = true; } #endif @@ -1049,14 +874,17 @@ 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("Shouldn'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; + arm->pc->dirty = true; + arm->pc->valid = true; /* restore dpm_mode at system halt */ - dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY); + arm_dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY); /* called it now before restoring context because it uses cpu * register r0 for restoring cp15 control register */ retval = cortex_a_restore_cp15_control_reg(target); @@ -1121,18 +949,12 @@ static int cortex_a_internal_restart(struct target *target) if (retval != ERROR_OK) return retval; - int64_t then = timeval_ms(); - for (;; ) { - retval = mem_ap_read_atomic_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_DSCR, &dscr); - if (retval != ERROR_OK) - return retval; - if ((dscr & DSCR_CORE_RESTARTED) != 0) - break; - if (timeval_ms() > then + 1000) { - LOG_ERROR("Timeout waiting for resume"); - return ERROR_FAIL; - } + dscr = 0; /* force read of dscr */ + retval = cortex_a_wait_dscr_bits(target, DSCR_CORE_RESTARTED, + DSCR_CORE_RESTARTED, &dscr); + if (retval != ERROR_OK) { + LOG_ERROR("Error waiting for resume"); + return retval; } target->debug_reason = DBG_REASON_NOTHALTED; @@ -1148,25 +970,23 @@ 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; - head = target->head; - while (head != (struct target_list *)NULL) { - curr = head->target; - if ((curr != target) && (curr->state != TARGET_RUNNING)) { + target_addr_t address; + + foreach_smp_target(head, target->smp_targets) { + struct target *curr = head->target; + 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); retval += cortex_a_internal_restart(curr); } - head = head->next; - } return retval; } 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 */ @@ -1190,11 +1010,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; @@ -1202,14 +1022,11 @@ 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 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 reg *reg; LOG_DEBUG("dscr = 0x%08" PRIx32, cortex_a->cpudbg_dscr); @@ -1246,54 +1063,16 @@ static int cortex_a_debug_entry(struct target *target) arm_dpm_report_wfar(&armv7a->dpm, wfar); } - /* REVISIT fast_reg_read is never set ... */ - - /* Examine target state and mode */ - 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); - else { - retval = cortex_a_read_regs_through_mem(target, - regfile_working_area->address, regfile); - - target_free_working_area(target, regfile_working_area); - if (retval != ERROR_OK) - return retval; + /* First load register accessible through core debug port */ + retval = arm_dpm_read_current_registers(&armv7a->dpm); + if (retval != ERROR_OK) + return retval; - /* read Current PSR */ - retval = cortex_a_dap_read_coreregister_u32(target, &cpsr, 16); - /* store current cpsr */ + if (arm->spsr) { + /* read SPSR */ + retval = arm_dpm_read_reg(&armv7a->dpm, arm->spsr, 17); if (retval != ERROR_OK) return retval; - - LOG_DEBUG("cpsr: %8.8" PRIx32, cpsr); - - arm_set_cpsr(arm, cpsr); - - /* update cache */ - for (i = 0; i <= ARM_PC; i++) { - reg = arm_reg_current(arm, i); - - buf_set_u32(reg->value, 0, 32, regfile[i]); - reg->valid = 1; - reg->dirty = 0; - } - - /* Fixup PC Resume Address */ - if (cpsr & (1 << 5)) { - /* T bit set for Thumb or ThumbEE state */ - regfile[ARM_PC] -= 4; - } else { - /* ARM state */ - regfile[ARM_PC] -= 8; - } - - reg = arm->pc; - buf_set_u32(reg->value, 0, 32, regfile[ARM_PC]); - reg->dirty = reg->valid; } #if 0 @@ -1336,6 +1115,9 @@ 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->is_armv7r) + armv7a_read_ttbcr(target); + if (armv7a->armv7a_mmu.armv7a_cache.info == -1) armv7a_identify_cache(target); @@ -1352,7 +1134,7 @@ static int cortex_a_post_debug_entry(struct target *target) cortex_a->curr_mode = armv7a->arm.core_mode; /* switch to SVC mode to read DACR */ - dpm_modeswitch(&armv7a->dpm, ARM_MODE_SVC); + arm_dpm_modeswitch(&armv7a->dpm, ARM_MODE_SVC); armv7a->arm.mrc(target, 15, 0, 0, 3, 0, &cortex_a->cp15_dacr_reg); @@ -1360,11 +1142,12 @@ static int cortex_a_post_debug_entry(struct target *target) LOG_DEBUG("cp15_dacr_reg: %8.8" PRIx32, cortex_a->cp15_dacr_reg); - dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY); + arm_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) +static int cortex_a_set_dscr_bits(struct target *target, + unsigned long bit_mask, unsigned long value) { struct armv7a_common *armv7a = target_to_armv7a(target); uint32_t dscr; @@ -1372,7 +1155,7 @@ int cortex_a_set_dscr_bits(struct target *target, unsigned long bit_mask, unsign /* Read DSCR */ int retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, &dscr); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; /* clear bitfield */ @@ -1386,7 +1169,7 @@ int cortex_a_set_dscr_bits(struct target *target, unsigned long bit_mask, unsign 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); @@ -1398,7 +1181,7 @@ static int cortex_a_step(struct target *target, int current, uint32_t address, int retval; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1422,15 +1205,16 @@ static int cortex_a_step(struct target *target, int current, uint32_t address, /* Setup single step breakpoint */ stepbreakpoint.address = address; + stepbreakpoint.asid = 0; stepbreakpoint.length = (arm->core_state == ARM_STATE_THUMB) ? 2 : 4; stepbreakpoint.type = BKPT_HARD; - stepbreakpoint.set = 0; + stepbreakpoint.is_set = false; /* Disable interrupts during single step if requested */ if (cortex_a->isrmasking_mode == CORTEX_A_ISRMASK_ON) { retval = cortex_a_set_dscr_bits(target, DSCR_INT_DIS, DSCR_INT_DIS); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; } @@ -1448,6 +1232,8 @@ static int cortex_a_step(struct target *target, int current, uint32_t address, retval = cortex_a_poll(target); if (retval != ERROR_OK) return retval; + if (target->state == TARGET_HALTED) + break; if (timeval_ms() > then + 1000) { LOG_ERROR("timeout waiting for target halt"); return ERROR_FAIL; @@ -1459,7 +1245,7 @@ static int cortex_a_step(struct target *target, int current, uint32_t address, /* Re-enable interrupts if they were disabled */ if (cortex_a->isrmasking_mode == CORTEX_A_ISRMASK_ON) { retval = cortex_a_set_dscr_bits(target, DSCR_INT_DIS, 0); - if (ERROR_OK != retval) + if (retval != ERROR_OK) return retval; } @@ -1503,7 +1289,7 @@ static int cortex_a_set_breakpoint(struct target *target, struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_brp *brp_list = cortex_a->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } @@ -1515,22 +1301,22 @@ static int cortex_a_set_breakpoint(struct target *target, LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } - breakpoint->set = brp_i + 1; + breakpoint_hw_set(breakpoint, brp_i); if (breakpoint->length == 2) byte_addr_select = (3 << (breakpoint->address & 0x02)); control = ((matchmode & 0x7) << 20) | (byte_addr_select << 5) | (3 << 1) | 1; - brp_list[brp_i].used = 1; + brp_list[brp_i].used = true; brp_list[brp_i].value = (breakpoint->address & 0xFFFFFFFC); brp_list[brp_i].control = control; - retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].BRPn, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].value); if (retval != ERROR_OK) return retval; - retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].BRPn, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; @@ -1539,10 +1325,22 @@ 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, @@ -1551,10 +1349,8 @@ static int cortex_a_set_breakpoint(struct target *target, 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, + armv7a_cache_flush_virt(target, breakpoint->address, breakpoint->length); - } retval = target_write_memory(target, breakpoint->address & 0xFFFFFFFE, @@ -1568,7 +1364,7 @@ static int cortex_a_set_breakpoint(struct target *target, armv7a_l1_i_cache_inval_virt(target, breakpoint->address, breakpoint->length); - breakpoint->set = 0x11; /* Any nice value but 0 */ + breakpoint->is_set = true; } return ERROR_OK; @@ -1585,7 +1381,7 @@ static int cortex_a_set_context_breakpoint(struct target *target, struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_brp *brp_list = cortex_a->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return retval; } @@ -1599,20 +1395,20 @@ static int cortex_a_set_context_breakpoint(struct target *target, return ERROR_FAIL; } - breakpoint->set = brp_i + 1; + breakpoint_hw_set(breakpoint, brp_i); control = ((matchmode & 0x7) << 20) | (byte_addr_select << 5) | (3 << 1) | 1; - brp_list[brp_i].used = 1; + brp_list[brp_i].used = true; brp_list[brp_i].value = (breakpoint->asid); brp_list[brp_i].control = control; - retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].BRPn, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].value); if (retval != ERROR_OK) return retval; - retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].BRPn, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; @@ -1628,16 +1424,16 @@ static int cortex_a_set_hybrid_breakpoint(struct target *target, struct breakpoi int retval = ERROR_FAIL; int brp_1 = 0; /* holds the contextID pair */ int brp_2 = 0; /* holds the IVA pair */ - uint32_t control_CTX, control_IVA; - uint8_t CTX_byte_addr_select = 0x0F; - uint8_t IVA_byte_addr_select = 0x0F; - uint8_t CTX_machmode = 0x03; - uint8_t IVA_machmode = 0x01; + uint32_t control_ctx, control_iva; + uint8_t ctx_byte_addr_select = 0x0F; + uint8_t iva_byte_addr_select = 0x0F; + uint8_t ctx_machmode = 0x03; + uint8_t iva_machmode = 0x01; struct cortex_a_common *cortex_a = target_to_cortex_a(target); struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_brp *brp_list = cortex_a->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return retval; } @@ -1646,7 +1442,7 @@ static int cortex_a_set_hybrid_breakpoint(struct target *target, struct breakpoi (brp_list[brp_1].type != BRP_CONTEXT)) && (brp_1 < cortex_a->brp_num)) brp_1++; - printf("brp(CTX) found num: %d\n", brp_1); + LOG_DEBUG("brp(CTX) found num: %d", brp_1); if (brp_1 >= cortex_a->brp_num) { LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_FAIL; @@ -1656,47 +1452,47 @@ static int cortex_a_set_hybrid_breakpoint(struct target *target, struct breakpoi (brp_list[brp_2].type != BRP_NORMAL)) && (brp_2 < cortex_a->brp_num)) brp_2++; - printf("brp(IVA) found num: %d\n", brp_2); + LOG_DEBUG("brp(IVA) found num: %d", brp_2); if (brp_2 >= cortex_a->brp_num) { LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_FAIL; } - breakpoint->set = brp_1 + 1; - breakpoint->linked_BRP = brp_2; - control_CTX = ((CTX_machmode & 0x7) << 20) + breakpoint_hw_set(breakpoint, brp_1); + breakpoint->linked_brp = brp_2; + control_ctx = ((ctx_machmode & 0x7) << 20) | (brp_2 << 16) | (0 << 14) - | (CTX_byte_addr_select << 5) + | (ctx_byte_addr_select << 5) | (3 << 1) | 1; - brp_list[brp_1].used = 1; + brp_list[brp_1].used = true; brp_list[brp_1].value = (breakpoint->asid); - brp_list[brp_1].control = control_CTX; - retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BVR_BASE + 4 * brp_list[brp_1].BRPn, + brp_list[brp_1].control = control_ctx; + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_BVR_BASE + 4 * brp_list[brp_1].brpn, brp_list[brp_1].value); if (retval != ERROR_OK) return retval; - retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BCR_BASE + 4 * brp_list[brp_1].BRPn, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_BCR_BASE + 4 * brp_list[brp_1].brpn, brp_list[brp_1].control); if (retval != ERROR_OK) return retval; - control_IVA = ((IVA_machmode & 0x7) << 20) + control_iva = ((iva_machmode & 0x7) << 20) | (brp_1 << 16) - | (IVA_byte_addr_select << 5) + | (iva_byte_addr_select << 5) | (3 << 1) | 1; - brp_list[brp_2].used = 1; + brp_list[brp_2].used = true; brp_list[brp_2].value = (breakpoint->address & 0xFFFFFFFC); - brp_list[brp_2].control = control_IVA; - retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BVR_BASE + 4 * brp_list[brp_2].BRPn, + brp_list[brp_2].control = control_iva; + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_BVR_BASE + 4 * brp_list[brp_2].brpn, brp_list[brp_2].value); if (retval != ERROR_OK) return retval; - retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BCR_BASE + 4 * brp_list[brp_2].BRPn, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_BCR_BASE + 4 * brp_list[brp_2].brpn, brp_list[brp_2].control); if (retval != ERROR_OK) return retval; @@ -1711,31 +1507,31 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *b struct armv7a_common *armv7a = &cortex_a->armv7a_common; struct cortex_a_brp *brp_list = cortex_a->brp_list; - if (!breakpoint->set) { + if (!breakpoint->is_set) { LOG_WARNING("breakpoint not set"); return ERROR_OK; } if (breakpoint->type == BKPT_HARD) { if ((breakpoint->address != 0) && (breakpoint->asid != 0)) { - int brp_i = breakpoint->set - 1; - int brp_j = breakpoint->linked_BRP; - if ((brp_i < 0) || (brp_i >= cortex_a->brp_num)) { + int brp_i = breakpoint->number; + int brp_j = breakpoint->linked_brp; + if (brp_i >= cortex_a->brp_num) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } LOG_DEBUG("rbp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, brp_i, brp_list[brp_i].control, brp_list[brp_i].value); - brp_list[brp_i].used = 0; + brp_list[brp_i].used = false; brp_list[brp_i].value = 0; brp_list[brp_i].control = 0; - retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].BRPn, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; - retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].BRPn, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].value); if (retval != ERROR_OK) return retval; @@ -1745,54 +1541,52 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *b } LOG_DEBUG("rbp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, brp_j, brp_list[brp_j].control, brp_list[brp_j].value); - brp_list[brp_j].used = 0; + brp_list[brp_j].used = false; brp_list[brp_j].value = 0; brp_list[brp_j].control = 0; - retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BCR_BASE + 4 * brp_list[brp_j].BRPn, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_BCR_BASE + 4 * brp_list[brp_j].brpn, brp_list[brp_j].control); if (retval != ERROR_OK) return retval; - retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BVR_BASE + 4 * brp_list[brp_j].BRPn, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_BVR_BASE + 4 * brp_list[brp_j].brpn, brp_list[brp_j].value); if (retval != ERROR_OK) return retval; - breakpoint->linked_BRP = 0; - breakpoint->set = 0; + breakpoint->linked_brp = 0; + breakpoint->is_set = false; return ERROR_OK; } else { - int brp_i = breakpoint->set - 1; - if ((brp_i < 0) || (brp_i >= cortex_a->brp_num)) { + int brp_i = breakpoint->number; + if (brp_i >= cortex_a->brp_num) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } LOG_DEBUG("rbp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, brp_i, brp_list[brp_i].control, brp_list[brp_i].value); - brp_list[brp_i].used = 0; + brp_list[brp_i].used = false; brp_list[brp_i].value = 0; brp_list[brp_i].control = 0; - retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].BRPn, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; - retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base - + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].BRPn, + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].value); if (retval != ERROR_OK) return retval; - breakpoint->set = 0; + breakpoint->is_set = false; 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, + armv7a_cache_flush_virt(target, breakpoint->address, breakpoint->length); - } /* restore original instruction (kept in target endianness) */ if (breakpoint->length == 4) { @@ -1815,7 +1609,7 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *b armv7a_l1_i_cache_inval_virt(target, breakpoint->address, breakpoint->length); } - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } @@ -1881,7 +1675,7 @@ static int cortex_a_remove_breakpoint(struct target *target, struct breakpoint * } #endif - if (breakpoint->set) { + if (breakpoint->is_set) { cortex_a_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) cortex_a->brp_num_available++; @@ -1891,6 +1685,200 @@ static int cortex_a_remove_breakpoint(struct target *target, struct breakpoint * return ERROR_OK; } +/** + * Sets a watchpoint for an Cortex-A target in one of the watchpoint units. It is + * considered a bug to call this function when there are no available watchpoint + * units. + * + * @param target Pointer to an Cortex-A target to set a watchpoint on + * @param watchpoint Pointer to the watchpoint to be set + * @return Error status if watchpoint set fails or the result of executing the + * JTAG queue + */ +static int cortex_a_set_watchpoint(struct target *target, struct watchpoint *watchpoint) +{ + int retval = ERROR_OK; + int wrp_i = 0; + uint32_t control; + uint32_t address; + uint8_t address_mask; + uint8_t byte_address_select; + uint8_t load_store_access_control = 0x3; + struct cortex_a_common *cortex_a = target_to_cortex_a(target); + struct armv7a_common *armv7a = &cortex_a->armv7a_common; + struct cortex_a_wrp *wrp_list = cortex_a->wrp_list; + + if (watchpoint->is_set) { + LOG_WARNING("watchpoint already set"); + return retval; + } + + /* check available context WRPs */ + while (wrp_list[wrp_i].used && (wrp_i < cortex_a->wrp_num)) + wrp_i++; + + if (wrp_i >= cortex_a->wrp_num) { + LOG_ERROR("ERROR Can not find free Watchpoint Register Pair"); + return ERROR_FAIL; + } + + if (watchpoint->length == 0 || watchpoint->length > 0x80000000U || + (watchpoint->length & (watchpoint->length - 1))) { + LOG_WARNING("watchpoint length must be a power of 2"); + return ERROR_FAIL; + } + + if (watchpoint->address & (watchpoint->length - 1)) { + LOG_WARNING("watchpoint address must be aligned at length"); + return ERROR_FAIL; + } + + /* FIXME: ARM DDI 0406C: address_mask is optional. What to do if it's missing? */ + /* handle wp length 1 and 2 through byte select */ + switch (watchpoint->length) { + case 1: + byte_address_select = BIT(watchpoint->address & 0x3); + address = watchpoint->address & ~0x3; + address_mask = 0; + break; + + case 2: + byte_address_select = 0x03 << (watchpoint->address & 0x2); + address = watchpoint->address & ~0x3; + address_mask = 0; + break; + + case 4: + byte_address_select = 0x0f; + address = watchpoint->address; + address_mask = 0; + break; + + default: + byte_address_select = 0xff; + address = watchpoint->address; + address_mask = ilog2(watchpoint->length); + break; + } + + watchpoint_set(watchpoint, wrp_i); + control = (address_mask << 24) | + (byte_address_select << 5) | + (load_store_access_control << 3) | + (0x3 << 1) | 1; + wrp_list[wrp_i].used = true; + wrp_list[wrp_i].value = address; + wrp_list[wrp_i].control = control; + + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_WVR_BASE + 4 * wrp_list[wrp_i].wrpn, + wrp_list[wrp_i].value); + if (retval != ERROR_OK) + return retval; + + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_WCR_BASE + 4 * wrp_list[wrp_i].wrpn, + wrp_list[wrp_i].control); + if (retval != ERROR_OK) + return retval; + + LOG_DEBUG("wp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, wrp_i, + wrp_list[wrp_i].control, + wrp_list[wrp_i].value); + + return ERROR_OK; +} + +/** + * Unset an existing watchpoint and clear the used watchpoint unit. + * + * @param target Pointer to the target to have the watchpoint removed + * @param watchpoint Pointer to the watchpoint to be removed + * @return Error status while trying to unset the watchpoint or the result of + * executing the JTAG queue + */ +static int cortex_a_unset_watchpoint(struct target *target, struct watchpoint *watchpoint) +{ + int retval; + struct cortex_a_common *cortex_a = target_to_cortex_a(target); + struct armv7a_common *armv7a = &cortex_a->armv7a_common; + struct cortex_a_wrp *wrp_list = cortex_a->wrp_list; + + if (!watchpoint->is_set) { + LOG_WARNING("watchpoint not set"); + return ERROR_OK; + } + + int wrp_i = watchpoint->number; + if (wrp_i >= cortex_a->wrp_num) { + LOG_DEBUG("Invalid WRP number in watchpoint"); + return ERROR_OK; + } + LOG_DEBUG("wrp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, wrp_i, + wrp_list[wrp_i].control, wrp_list[wrp_i].value); + wrp_list[wrp_i].used = false; + wrp_list[wrp_i].value = 0; + wrp_list[wrp_i].control = 0; + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_WCR_BASE + 4 * wrp_list[wrp_i].wrpn, + wrp_list[wrp_i].control); + if (retval != ERROR_OK) + return retval; + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_WVR_BASE + 4 * wrp_list[wrp_i].wrpn, + wrp_list[wrp_i].value); + if (retval != ERROR_OK) + return retval; + watchpoint->is_set = false; + + return ERROR_OK; +} + +/** + * Add a watchpoint to an Cortex-A target. If there are no watchpoint units + * available, an error response is returned. + * + * @param target Pointer to the Cortex-A target to add a watchpoint to + * @param watchpoint Pointer to the watchpoint to be added + * @return Error status while trying to add the watchpoint + */ +static int cortex_a_add_watchpoint(struct target *target, struct watchpoint *watchpoint) +{ + struct cortex_a_common *cortex_a = target_to_cortex_a(target); + + if (cortex_a->wrp_num_available < 1) { + LOG_INFO("no hardware watchpoint available"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + int retval = cortex_a_set_watchpoint(target, watchpoint); + if (retval != ERROR_OK) + return retval; + + cortex_a->wrp_num_available--; + return ERROR_OK; +} + +/** + * Remove a watchpoint from an Cortex-A target. The watchpoint will be unset and + * the used watchpoint unit will be reopened. + * + * @param target Pointer to the target to remove a watchpoint from + * @param watchpoint Pointer to the watchpoint to be removed + * @return Result of trying to unset the watchpoint + */ +static int cortex_a_remove_watchpoint(struct target *target, struct watchpoint *watchpoint) +{ + struct cortex_a_common *cortex_a = target_to_cortex_a(target); + + if (watchpoint->is_set) { + cortex_a->wrp_num_available++; + cortex_a_unset_watchpoint(target, watchpoint); + } + return ERROR_OK; +} + + /* * Cortex-A Reset functions */ @@ -1912,16 +1900,23 @@ static int cortex_a_assert_reset(struct target *target) /* REVISIT handle "pulls" cases, if there's * hardware that needs them to work. */ - if (target->reset_halt) - if (jtag_get_reset_config() & RESET_SRST_NO_GATING) - jtag_add_reset(0, 1); + + /* + * FIXME: fix reset when transport is not JTAG. This is a temporary + * work-around for release v0.10 that is not intended to stay! + */ + if (!transport_is_jtag() || + (target->reset_halt && (jtag_get_reset_config() & RESET_SRST_NO_GATING))) + adapter_assert_reset(); + } 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 (armv7a->arm.core_cache) + register_cache_invalidate(armv7a->arm.core_cache); target->state = TARGET_RESET; @@ -1930,24 +1925,31 @@ static int cortex_a_assert_reset(struct target *target) static int cortex_a_deassert_reset(struct target *target) { + struct armv7a_common *armv7a = target_to_armv7a(target); int retval; LOG_DEBUG(" "); /* be certain SRST is off */ - jtag_add_reset(0, 0); + adapter_deassert_reset(); - 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 = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_DRCR, DRCR_HALT); + if (retval != ERROR_OK) + return retval; + } else + target->state = TARGET_UNKNOWN; } } @@ -1981,14 +1983,22 @@ 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); - int64_t then = timeval_ms(); + int64_t then; int retval; - while ((*dscr & mask) != value) { + if ((*dscr & mask) == value) + return ERROR_OK; + + then = timeval_ms(); + while (1) { retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DSCR, dscr); - if (retval != ERROR_OK) + if (retval != ERROR_OK) { + LOG_ERROR("Could not read DSCR register"); return retval; + } + if ((*dscr & mask) == value) + break; if (timeval_ms() > then + 1000) { LOG_ERROR("timeout waiting for DSCR bit change"); return ERROR_FAIL; @@ -2127,13 +2137,14 @@ 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 + * non-word-sized objects. Avoid unaligned accesses as they do not work + * on memory address space without "Normal" attribute. If size == 4 and + * the address is aligned, cortex_a_write_cpu_memory_fast should be * preferred. * Preconditions: * - Address is in R0. @@ -2202,7 +2213,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 @@ -2231,20 +2242,20 @@ static int cortex_a_write_apb_ab_memory_fast(struct target *target, 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 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"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2266,7 +2277,7 @@ static int cortex_a_write_apb_ab_memory(struct target *target, /* 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) - goto out; + return retval; /* Mark R0 as dirty. */ arm_reg_current(arm, 0)->dirty = true; @@ -2274,26 +2285,40 @@ static int cortex_a_write_apb_ab_memory(struct target *target, /* Read DFAR and DFSR, as they will be modified in the event of a fault. */ retval = cortex_a_read_dfar_dfsr(target, &orig_dfar, &orig_dfsr, &dscr); if (retval != ERROR_OK) - goto out; + return retval; /* Get the memory address into R0. */ retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRRX, address); if (retval != ERROR_OK) - goto out; + return retval; retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), &dscr); if (retval != ERROR_OK) - goto out; + return retval; 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); + /* Use slow path. Adjust size for aligned accesses */ + switch (address % 4) { + case 1: + case 3: + count *= size; + size = 1; + break; + case 2: + if (size == 4) { + count *= 2; + size = 2; + } + case 0: + default: + break; + } + retval = cortex_a_write_cpu_memory_slow(target, size, count, buffer, &dscr); } -out: final_retval = retval; /* Switch to non-blocking mode if not already in that mode. */ @@ -2370,13 +2395,14 @@ 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 + * non-word-sized objects. Avoid unaligned accesses as they do not work + * on memory address space without "Normal" attribute. If size == 4 and + * the address is aligned, cortex_a_read_cpu_memory_fast should be * preferred. * Preconditions: * - Address is in R0. @@ -2446,7 +2472,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 @@ -2533,20 +2559,20 @@ 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 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"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2568,7 +2594,7 @@ static int cortex_a_read_apb_ab_memory(struct target *target, /* 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) - goto out; + return retval; /* Mark R0 as dirty. */ arm_reg_current(arm, 0)->dirty = true; @@ -2576,26 +2602,41 @@ static int cortex_a_read_apb_ab_memory(struct target *target, /* Read DFAR and DFSR, as they will be modified in the event of a fault. */ retval = cortex_a_read_dfar_dfsr(target, &orig_dfar, &orig_dfsr, &dscr); if (retval != ERROR_OK) - goto out; + return retval; /* Get the memory address into R0. */ retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_DTRRX, address); if (retval != ERROR_OK) - goto out; + return retval; retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 0, 0, 5, 0), &dscr); if (retval != ERROR_OK) - goto out; + return retval; 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); + /* Use slow path. Adjust size for aligned accesses */ + switch (address % 4) { + case 1: + case 3: + count *= size; + size = 1; + break; + case 2: + if (size == 4) { + count *= 2; + size = 2; + } + break; + case 0: + default: + break; + } + retval = cortex_a_read_cpu_memory_slow(target, size, count, buffer, &dscr); } -out: final_retval = retval; /* Switch to non-blocking mode if not already in that mode. */ @@ -2664,184 +2705,82 @@ 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); - struct adiv5_dap *swjdp = armv7a->arm.dap; - uint8_t apsel = swjdp->apsel; int retval; if (!count || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; - LOG_DEBUG("Reading memory at real address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, + LOG_DEBUG("Reading memory at real address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32, address, size, count); - 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 APB-AP */ + /* read memory through the CPU */ cortex_a_prep_memaccess(target, 1); - retval = cortex_a_read_apb_ab_memory(target, address, size, count, buffer); + 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 retval; /* 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 %" PRIu32 "; count %" PRIu32, + address, size, count); cortex_a_prep_memaccess(target, 0); - retval = cortex_a_read_apb_ab_memory(target, address, size, count, buffer); + 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, - uint32_t size, uint32_t count, uint8_t *buffer) -{ - int mmu_enabled = 0; - uint32_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->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); - - /* 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) { - virt = address; - retval = cortex_a_virt2phys(target, virt, &phys); - if (retval != ERROR_OK) - return retval; - - LOG_DEBUG("Reading at virtual address. Translating v:0x%" PRIx32 " to r:0x%" PRIx32, - virt, phys); - address = phys; - } - - if (!count || !buffer) - return ERROR_COMMAND_SYNTAX_ERROR; - - 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); - struct adiv5_dap *swjdp = armv7a->arm.dap; - uint8_t apsel = swjdp->apsel; int retval; if (!count || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; - LOG_DEBUG("Writing memory to real address 0x%" PRIx32 "; 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); + LOG_DEBUG("Writing memory to real address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32, + address, size, count); - /* write memory through APB-AP */ + /* write memory through the CPU */ cortex_a_prep_memaccess(target, 1); - retval = cortex_a_write_apb_ab_memory(target, address, size, count, buffer); + 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 retval; /* cortex_a handles unaligned memory access */ - LOG_DEBUG("Writing memory at address 0x%" PRIx32 "; 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); + LOG_DEBUG("Writing memory at address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32, + address, size, count); cortex_a_prep_memaccess(target, 0); - retval = cortex_a_write_apb_ab_memory(target, address, size, count, buffer); + 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, - uint32_t size, uint32_t count, const uint8_t *buffer) -{ - int mmu_enabled = 0; - uint32_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->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); - - /* 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) { - virt = address; - retval = cortex_a_virt2phys(target, virt, &phys); - if (retval != ERROR_OK) - return retval; - - LOG_DEBUG("Writing to virtual address. Translating v:0x%" PRIx32 " to r:0x%" PRIx32, - virt, - phys); - address = phys; - } - - if (!count || !buffer) - return ERROR_COMMAND_SYNTAX_ERROR; - - 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; @@ -2850,7 +2789,7 @@ static int cortex_a_read_buffer(struct target *target, uint32_t address, * will have something to do with the size we leave to it. */ for (size = 1; size < 4 && count >= size * 2 + (address & size); size *= 2) { if (address & size) { - int retval = cortex_a_read_memory_ahb(target, address, size, 1, buffer); + int retval = target_read_memory(target, address, size, 1, buffer); if (retval != ERROR_OK) return retval; address += size; @@ -2863,7 +2802,7 @@ static int cortex_a_read_buffer(struct target *target, uint32_t address, for (; size > 0; size /= 2) { uint32_t aligned = count - count % size; if (aligned > 0) { - int retval = cortex_a_read_memory_ahb(target, address, size, aligned / size, buffer); + int retval = target_read_memory(target, address, size, aligned / size, buffer); if (retval != ERROR_OK) return retval; address += aligned; @@ -2875,7 +2814,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; @@ -2884,7 +2823,7 @@ static int cortex_a_write_buffer(struct target *target, uint32_t address, * will have something to do with the size we leave to it. */ for (size = 1; size < 4 && count >= size * 2 + (address & size); size *= 2) { if (address & size) { - int retval = cortex_a_write_memory_ahb(target, address, size, 1, buffer); + int retval = target_write_memory(target, address, size, 1, buffer); if (retval != ERROR_OK) return retval; address += size; @@ -2897,7 +2836,7 @@ static int cortex_a_write_buffer(struct target *target, uint32_t address, for (; size > 0; size /= 2) { uint32_t aligned = count - count % size; if (aligned > 0) { - int retval = cortex_a_write_memory_ahb(target, address, size, aligned / size, buffer); + int retval = target_write_memory(target, address, size, aligned / size, buffer); if (retval != ERROR_OK) return retval; address += aligned; @@ -2955,21 +2894,27 @@ 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; + struct adiv5_private_config *pc = target->private_config; + int i; int retval = ERROR_OK; - uint32_t didr, ctypr, ttypr, cpuid, dbg_osreg; - - retval = dap_dp_init(swjdp); - if (retval != ERROR_OK) { - LOG_ERROR("Could not initialize the debug port"); - return retval; - } - - /* Search for the APB-AB - 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; + uint32_t didr, cpuid, dbg_osreg, dbg_idpfr1; + + if (!armv7a->debug_ap) { + if (pc->ap_num == DP_APSEL_INVALID) { + /* Search for the APB-AP - it is needed for access to debug registers */ + retval = dap_find_get_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; + } + } else { + armv7a->debug_ap = dap_get_ap(swjdp, pc->ap_num); + if (!armv7a->debug_ap) { + LOG_ERROR("Cannot get AP"); + return ERROR_FAIL; + } + } } retval = mem_ap_init(armv7a->debug_ap); @@ -2980,121 +2925,107 @@ static int cortex_a_examine_first(struct target *target) 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; - else - LOG_WARNING("Could not initialize AHB-AP for memory access - using APB-AP"); - } else { - /* AHB-AP not found - use APB-AP */ - LOG_DEBUG("Could not find AHB-AP - using APB-AP for memory access"); - } - if (!target->dbgbase_set) { - uint32_t dbgbase; - /* Get ROM Table base */ - uint32_t apid; - 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(armv7a->debug_ap, &dbgbase, &apid); - if (retval != ERROR_OK) - return retval; - /* Lookup 0x15 -- Processor DAP */ - retval = dap_lookup_cs_component(armv7a->debug_ap, dbgbase, 0x15, - &armv7a->debug_base, &coreidx); + /* Lookup Processor DAP */ + retval = dap_lookup_cs_component(armv7a->debug_ap, ARM_CS_C9_DEVTYPE_CORE_DEBUG, + &armv7a->debug_base, target->coreid); if (retval != ERROR_OK) { LOG_ERROR("Can't detect %s's dbgbase from the ROM table; you need to specify it explicitly.", target->cmd_name); return retval; } - LOG_DEBUG("Detected core %" PRId32 " dbgbase: %08" PRIx32, + LOG_DEBUG("Detected core %" PRId32 " dbgbase: " TARGET_ADDR_FMT, target->coreid, armv7a->debug_base); } else armv7a->debug_base = target->dbgbase; - retval = mem_ap_read_atomic_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_CPUID, &cpuid); - if (retval != ERROR_OK) - return retval; - - retval = mem_ap_read_atomic_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_CPUID, &cpuid); - if (retval != ERROR_OK) { - LOG_DEBUG("Examine %s failed", "CPUID"); - return retval; - } - - retval = mem_ap_read_atomic_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_CTYPR, &ctypr); - if (retval != ERROR_OK) { - LOG_DEBUG("Examine %s failed", "CTYPR"); - return retval; - } + if ((armv7a->debug_base & (1UL<<31)) == 0) + LOG_WARNING("Debug base address for target %s has bit 31 set to 0. Access to debug registers will likely fail!\n" + "Please fix the target configuration.", target_name(target)); retval = mem_ap_read_atomic_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_TTYPR, &ttypr); + 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_read_atomic_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_DIDR, &didr); + 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_read_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_PRSR, &dbg_osreg); + if (retval != ERROR_OK) + return retval; + LOG_TARGET_DEBUG(target, "DBGPRSR 0x%" PRIx32, dbg_osreg); - retval = mem_ap_write_atomic_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_OSLAR, - 0); + if ((dbg_osreg & PRSR_POWERUP_STATUS) == 0) { + LOG_TARGET_ERROR(target, "powered down!"); + target->state = TARGET_UNKNOWN; /* TARGET_NO_POWER? */ + return ERROR_TARGET_INIT_FAILED; + } - if (retval != ERROR_OK) - return retval; + if (dbg_osreg & PRSR_STICKY_RESET_STATUS) + LOG_TARGET_DEBUG(target, "was reset!"); - } - /* Unlocking the debug registers */ - if ((cpuid & CORTEX_A_MIDR_PARTNUM_MASK) >> CORTEX_A_MIDR_PARTNUM_SHIFT == - CORTEX_A7_PARTNUM) { + /* 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_TARGET_DEBUG(target, "DBGOSLSR 0x%" PRIx32, dbg_osreg); - retval = mem_ap_write_atomic_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_OSLAR, - 0); + /* 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_TARGET_DEBUG(target, "OSLock set! Trying to unlock"); - if (retval != ERROR_OK) - return retval; + 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_TARGET_ERROR(target, "OSLock sticky, core not powered?"); + target->state = TARGET_UNKNOWN; /* TARGET_NO_POWER? */ + return ERROR_TARGET_INIT_FAILED; + } + } } - retval = mem_ap_read_atomic_u32(armv7a->debug_ap, - armv7a->debug_base + CPUDBG_PRSR, &dbg_osreg); + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_ID_PFR1, &dbg_idpfr1); if (retval != ERROR_OK) return retval; - LOG_DEBUG("target->coreid %" PRId32 " DBGPRSR 0x%" PRIx32, target->coreid, dbg_osreg); - - armv7a->arm.core_type = ARM_MODE_MON; + if (dbg_idpfr1 & 0x000000f0) { + LOG_TARGET_DEBUG(target, "has security extensions"); + armv7a->arm.core_type = ARM_CORE_TYPE_SEC_EXT; + } + if (dbg_idpfr1 & 0x0000f000) { + LOG_TARGET_DEBUG(target, "has virtualization extensions"); + /* + * overwrite and simplify the checks. + * virtualization extensions require implementation of security extension + */ + armv7a->arm.core_type = ARM_CORE_TYPE_VIRT_EXT; + } /* Avoid recreating the registers cache */ if (!target_was_examined(target)) { @@ -3111,18 +3042,32 @@ static int cortex_a_examine_first(struct target *target) cortex_a->brp_list = calloc(cortex_a->brp_num, sizeof(struct cortex_a_brp)); /* cortex_a->brb_enabled = ????; */ for (i = 0; i < cortex_a->brp_num; i++) { - cortex_a->brp_list[i].used = 0; + cortex_a->brp_list[i].used = false; if (i < (cortex_a->brp_num-cortex_a->brp_num_context)) cortex_a->brp_list[i].type = BRP_NORMAL; else cortex_a->brp_list[i].type = BRP_CONTEXT; cortex_a->brp_list[i].value = 0; cortex_a->brp_list[i].control = 0; - cortex_a->brp_list[i].BRPn = i; + cortex_a->brp_list[i].brpn = i; } LOG_DEBUG("Configured %i hw breakpoints", cortex_a->brp_num); + /* Setup Watchpoint Register Pairs */ + cortex_a->wrp_num = ((didr >> 28) & 0x0F) + 1; + cortex_a->wrp_num_available = cortex_a->wrp_num; + free(cortex_a->wrp_list); + cortex_a->wrp_list = calloc(cortex_a->wrp_num, sizeof(struct cortex_a_wrp)); + for (i = 0; i < cortex_a->wrp_num; i++) { + cortex_a->wrp_list[i].used = false; + cortex_a->wrp_list[i].value = 0; + cortex_a->wrp_list[i].control = 0; + cortex_a->wrp_list[i].wrpn = i; + } + + LOG_DEBUG("Configured %i hw watchpoints", cortex_a->wrp_num); + /* select debug_ap as default */ swjdp->apsel = armv7a->debug_ap->ap_num; @@ -3152,28 +3097,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; /* Setup struct cortex_a_common */ cortex_a->common_magic = CORTEX_A_COMMON_MAGIC; - - /* tap has no dap initialized */ - if (!tap->dap) { - tap->dap = dap_init(); - - /* Leave (only) generic DAP stuff for debugport_init() */ - tap->dap->tap = tap; - } - - armv7a->arm.dap = tap->dap; - - cortex_a->fast_reg_read = 0; + armv7a->arm.dap = dap; /* register arch-specific functions */ armv7a->examine_debug_reason = NULL; @@ -3189,37 +3124,81 @@ static int cortex_a_init_arch_info(struct target *target, /* REVISIT v7a setup should be in a v7a-specific routine */ armv7a_init_arch_info(target, armv7a); - target_register_timer_callback(cortex_a_handle_target_request, 1, 1, target); + target_register_timer_callback(cortex_a_handle_target_request, 1, + TARGET_TIMER_TYPE_PERIODIC, target); return ERROR_OK; } 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)); + struct cortex_a_common *cortex_a; + struct adiv5_private_config *pc; + if (!target->private_config) + return ERROR_FAIL; + + pc = (struct adiv5_private_config *)target->private_config; + + cortex_a = calloc(1, sizeof(struct cortex_a_common)); + if (!cortex_a) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + cortex_a->common_magic = CORTEX_A_COMMON_MAGIC; cortex_a->armv7a_common.is_armv7r = false; + cortex_a->armv7a_common.arm.arm_vfp_version = ARM_VFP_V3; - return cortex_a_init_arch_info(target, cortex_a, target->tap); + 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)); + struct cortex_a_common *cortex_a; + 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 = calloc(1, sizeof(struct cortex_a_common)); + if (!cortex_a) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + cortex_a->common_magic = CORTEX_A_COMMON_MAGIC; 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) { struct cortex_a_common *cortex_a = target_to_cortex_a(target); - struct arm_dpm *dpm = &cortex_a->armv7a_common.dpm; + struct armv7a_common *armv7a = &cortex_a->armv7a_common; + struct arm_dpm *dpm = &armv7a->dpm; + uint32_t dscr; + int retval; + + if (target_was_examined(target)) { + /* Disable halt for breakpoint, watchpoint and vector catch */ + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_DSCR, &dscr); + if (retval == ERROR_OK) + mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_DSCR, + dscr & ~DSCR_HALT_DBG_MODE); + } + + if (armv7a->debug_ap) + dap_put_ap(armv7a->debug_ap); + free(cortex_a->wrp_list); free(cortex_a->brp_list); + arm_free_reg_cache(dpm->arm); free(dpm->dbp); free(dpm->dwp); + free(target->private_config); free(cortex_a); } @@ -3228,8 +3207,8 @@ 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; + LOG_TARGET_ERROR(target, "not halted"); + return ERROR_TARGET_NOT_HALTED; } if (armv7a->is_armv7r) @@ -3241,28 +3220,29 @@ static int cortex_a_mmu(struct target *target, int *enabled) } 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->ap_num)) { - uint32_t ret; - retval = armv7a_mmu_translate_va(target, - virt, &ret); - if (retval != ERROR_OK) - goto done; - *phys = ret; - } else {/* use this method if armv7a->memory_ap not selected - * mmu must be enable in order to get a correct translation */ - retval = cortex_a_mmu_modify(target, 1); - if (retval != ERROR_OK) - goto done; - retval = armv7a_mmu_translate_va_pa(target, virt, phys, 1); + int retval; + 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; } -done: - return retval; + + /* mmu must be enable in order to get a correct translation */ + retval = cortex_a_mmu_modify(target, 1); + if (retval != ERROR_OK) + return retval; + return armv7a_mmu_translate_va_pa(target, (uint32_t)virt, + phys, 1); } COMMAND_HANDLER(cortex_a_handle_cache_info_command) @@ -3270,7 +3250,7 @@ COMMAND_HANDLER(cortex_a_handle_cache_info_command) struct target *target = get_current_target(CMD_CTX); struct armv7a_common *armv7a = target_to_armv7a(target); - return armv7a_handle_cache_info_command(CMD_CTX, + return armv7a_handle_cache_info_command(CMD, &armv7a->armv7a_mmu.armv7a_cache); } @@ -3285,79 +3265,22 @@ COMMAND_HANDLER(cortex_a_handle_dbginit_command) return cortex_a_init_debug_access(target); } -COMMAND_HANDLER(cortex_a_handle_smp_off_command) -{ - struct target *target = get_current_target(CMD_CTX); - /* check target is an smp target */ - struct target_list *head; - struct target *curr; - head = target->head; - target->smp = 0; - if (head != (struct target_list *)NULL) { - while (head != (struct target_list *)NULL) { - curr = head->target; - curr->smp = 0; - head = head->next; - } - /* fixes the target display to the debugger */ - target->gdb_service->target = target; - } - return ERROR_OK; -} - -COMMAND_HANDLER(cortex_a_handle_smp_on_command) -{ - struct target *target = get_current_target(CMD_CTX); - struct target_list *head; - struct target *curr; - head = target->head; - if (head != (struct target_list *)NULL) { - target->smp = 1; - while (head != (struct target_list *)NULL) { - curr = head->target; - curr->smp = 1; - head = head->next; - } - } - return ERROR_OK; -} - -COMMAND_HANDLER(cortex_a_handle_smp_gdb_command) -{ - struct target *target = get_current_target(CMD_CTX); - int retval = ERROR_OK; - struct target_list *head; - head = target->head; - if (head != (struct target_list *)NULL) { - if (CMD_ARGC == 1) { - int coreid = 0; - COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], coreid); - if (ERROR_OK != retval) - return retval; - target->gdb_service->core[1] = coreid; - - } - command_print(CMD_CTX, "gdb coreid %" PRId32 " -> %" PRId32, target->gdb_service->core[0] - , target->gdb_service->core[1]); - } - return ERROR_OK; -} COMMAND_HANDLER(handle_cortex_a_mask_interrupts_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_maskisr_modes[] = { + static const struct nvp nvp_maskisr_modes[] = { { .name = "off", .value = CORTEX_A_ISRMASK_OFF }, { .name = "on", .value = CORTEX_A_ISRMASK_ON }, { .name = NULL, .value = -1 }, }; - const Jim_Nvp *n; + const struct nvp *n; if (CMD_ARGC > 0) { - n = Jim_Nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]); - if (n->name == NULL) { + n = nvp_name2value(nvp_maskisr_modes, CMD_ARGV[0]); + if (!n->name) { LOG_ERROR("Unknown parameter: %s - should be off or on", CMD_ARGV[0]); return ERROR_COMMAND_SYNTAX_ERROR; } @@ -3365,8 +3288,8 @@ COMMAND_HANDLER(handle_cortex_a_mask_interrupts_command) cortex_a->isrmasking_mode = n->value; } - n = Jim_Nvp_value2name_simple(nvp_maskisr_modes, cortex_a->isrmasking_mode); - command_print(CMD_CTX, "cortex_a interrupt mask %s", n->name); + n = nvp_value2name(nvp_maskisr_modes, cortex_a->isrmasking_mode); + command_print(CMD, "cortex_a interrupt mask %s", n->name); return ERROR_OK; } @@ -3376,23 +3299,23 @@ 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[] = { + static const struct 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; + const struct nvp *n; if (CMD_ARGC > 0) { - n = Jim_Nvp_name2value_simple(nvp_dacrfixup_modes, CMD_ARGV[0]); - if (n->name == NULL) + n = nvp_name2value(nvp_dacrfixup_modes, CMD_ARGV[0]); + if (!n->name) 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); + n = nvp_value2name(nvp_dacrfixup_modes, cortex_a->dacrfixup_mode); + command_print(CMD, "cortex_a domain access control fixup %s", n->name); return ERROR_OK; } @@ -3412,25 +3335,6 @@ static const struct command_registration cortex_a_exec_command_handlers[] = { .help = "Initialize core debug", .usage = "", }, - { .name = "smp_off", - .handler = cortex_a_handle_smp_off_command, - .mode = COMMAND_EXEC, - .help = "Stop smp handling", - .usage = "",}, - { - .name = "smp_on", - .handler = cortex_a_handle_smp_on_command, - .mode = COMMAND_EXEC, - .help = "Restart smp handling", - .usage = "", - }, - { - .name = "smp_gdb", - .handler = cortex_a_handle_smp_gdb_command, - .mode = COMMAND_EXEC, - .help = "display/fix current core played to gdb", - .usage = "", - }, { .name = "maskisr", .handler = handle_cortex_a_mask_interrupts_command, @@ -3441,11 +3345,17 @@ static const struct command_registration cortex_a_exec_command_handlers[] = { { .name = "dacrfixup", .handler = handle_cortex_a_dacrfixup_command, - .mode = COMMAND_EXEC, + .mode = COMMAND_ANY, .help = "set domain access control (DACR) to all-manager " "on memory access", .usage = "['on'|'off']", }, + { + .chain = armv7a_mmu_command_handlers, + }, + { + .chain = smp_command_handlers, + }, COMMAND_REGISTRATION_DONE }; @@ -3468,7 +3378,6 @@ static const struct command_registration cortex_a_command_handlers[] = { struct target_type cortexa_target = { .name = "cortex_a", - .deprecated_name = "cortex_a8", .poll = cortex_a_poll, .arch_state = armv7a_arch_state, @@ -3481,6 +3390,7 @@ struct target_type cortexa_target = { .deassert_reset = cortex_a_deassert_reset, /* REVISIT allow exporting VFP3 registers ... */ + .get_gdb_arch = arm_get_gdb_arch, .get_gdb_reg_list = arm_get_gdb_reg_list, .read_memory = cortex_a_read_memory, @@ -3498,11 +3408,12 @@ struct target_type cortexa_target = { .add_context_breakpoint = cortex_a_add_context_breakpoint, .add_hybrid_breakpoint = cortex_a_add_hybrid_breakpoint, .remove_breakpoint = cortex_a_remove_breakpoint, - .add_watchpoint = NULL, - .remove_watchpoint = NULL, + .add_watchpoint = cortex_a_add_watchpoint, + .remove_watchpoint = cortex_a_remove_watchpoint, .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, @@ -3514,13 +3425,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, @@ -3542,9 +3446,6 @@ static const struct command_registration cortex_r4_command_handlers[] = { { .chain = arm_command_handlers, }, - { - .chain = armv7a_command_handlers, - }, { .name = "cortex_r4", .mode = COMMAND_ANY, @@ -3569,10 +3470,11 @@ struct target_type cortexr4_target = { .deassert_reset = cortex_a_deassert_reset, /* REVISIT allow exporting VFP3 registers ... */ + .get_gdb_arch = arm_get_gdb_arch, .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, @@ -3583,11 +3485,12 @@ struct target_type cortexr4_target = { .add_context_breakpoint = cortex_a_add_context_breakpoint, .add_hybrid_breakpoint = cortex_a_add_hybrid_breakpoint, .remove_breakpoint = cortex_a_remove_breakpoint, - .add_watchpoint = NULL, - .remove_watchpoint = NULL, + .add_watchpoint = cortex_a_add_watchpoint, + .remove_watchpoint = cortex_a_remove_watchpoint, .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,