X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Ftarget%2Fcortex_a.c;h=b3a8a41d0b4eb39f23a014c7664e43e0cadfb7e5;hp=158de0b2476e98511ab97826c81bd69912058858;hb=HEAD;hpb=18f4ef0f5ef2306d95122af5cfb5e700e9f4767b diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 158de0b247..7fa0c4e8b7 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 * @@ -23,18 +25,8 @@ * 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, see . * + * 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 * @@ -53,10 +45,14 @@ #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); @@ -79,6 +75,16 @@ static int cortex_a_virt2phys(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); +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) @@ -424,22 +430,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; @@ -452,6 +471,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; @@ -481,6 +522,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) @@ -498,14 +558,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, @@ -581,10 +657,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; @@ -598,14 +676,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; } @@ -615,14 +690,12 @@ 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; + + 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; } @@ -643,7 +716,7 @@ static int update_halt_gdb(struct target *target) if (target->gdb_service) gdb_target = target->gdb_service->target; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { curr = head->target; /* skip calling context */ if (curr == target) @@ -664,7 +737,7 @@ static int update_halt_gdb(struct target *target) } /* after all targets were updated, poll the gdb serving target */ - if (gdb_target != NULL && gdb_target != target) + if (gdb_target && gdb_target != target) cortex_a_poll(gdb_target); return retval; } @@ -686,7 +759,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); @@ -782,11 +855,11 @@ static int cortex_a_internal_restore(struct target *target, int current, 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 = true; - armv7m->core_cache->reg_list[ARMV7M_xPSR].valid = true; + armv7m->core_cache->reg_list[ARMV7M_XPSR].dirty = true; + armv7m->core_cache->reg_list[ARMV7M_XPSR].valid = true; } #endif @@ -815,7 +888,7 @@ static int cortex_a_internal_restore(struct target *target, int current, LOG_ERROR("How do I resume into Jazelle state??"); return ERROR_FAIL; case ARM_STATE_AARCH64: - LOG_ERROR("Shoudn't be in AARCH64 state"); + LOG_ERROR("Shouldn't be in AARCH64 state"); return ERROR_FAIL; } LOG_DEBUG("resume pc = 0x%08" PRIx32, resume_pc); @@ -910,11 +983,10 @@ static int cortex_a_restore_smp(struct target *target, int handle_breakpoints) { int retval = 0; struct target_list *head; - struct target *curr; target_addr_t address; - 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 != target) && (curr->state != TARGET_RUNNING) && target_was_examined(curr)) { /* resume current address , not in step mode */ @@ -922,8 +994,6 @@ static int cortex_a_restore_smp(struct target *target, int handle_breakpoints) handle_breakpoints, 0); retval += cortex_a_internal_restart(curr); } - head = head->next; - } return retval; } @@ -1089,7 +1159,8 @@ static int cortex_a_post_debug_entry(struct target *target) 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; @@ -1097,7 +1168,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 */ @@ -1123,7 +1194,7 @@ static int cortex_a_step(struct target *target, int current, target_addr_t addre int retval; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1151,12 +1222,12 @@ static int cortex_a_step(struct target *target, int current, target_addr_t addre 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; } @@ -1187,7 +1258,7 @@ static int cortex_a_step(struct target *target, int current, target_addr_t addre /* 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; } @@ -1231,7 +1302,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; } @@ -1243,22 +1314,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, + + 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, + + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; @@ -1308,7 +1379,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; @@ -1325,7 +1396,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; } @@ -1339,20 +1410,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, + + 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, + + CPUDBG_BCR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; @@ -1368,16 +1439,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; } @@ -1386,7 +1457,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; @@ -1396,47 +1467,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; + 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, + + 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, + + 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; + 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, + + 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, + + CPUDBG_BCR_BASE + 4 * brp_list[brp_2].brpn, brp_list[brp_2].control); if (retval != ERROR_OK) return retval; @@ -1451,31 +1522,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, + + 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, + + CPUDBG_BVR_BASE + 4 * brp_list[brp_i].brpn, brp_list[brp_i].value); if (retval != ERROR_OK) return retval; @@ -1485,45 +1556,45 @@ 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, + + 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, + + 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, + + 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, + + 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 { @@ -1555,7 +1626,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; } @@ -1621,7 +1692,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++; @@ -1631,6 +1702,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 = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + + CPUDBG_WVR_BASE + 4 * wrp_list[wrp_i].wrpn, + wrp_list[wrp_i].value); + if (retval != ERROR_OK) + return retval; + + retval = cortex_a_dap_write_memap_register_u32(target, 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 = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base + + CPUDBG_WCR_BASE + 4 * wrp_list[wrp_i].wrpn, + wrp_list[wrp_i].control); + if (retval != ERROR_OK) + return retval; + retval = cortex_a_dap_write_memap_register_u32(target, 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 */ @@ -1654,12 +1919,12 @@ static int cortex_a_assert_reset(struct target *target) */ /* - * FIXME: fix reset when transport is SWD. This is a temporary + * 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_swd() || + if (!transport_is_jtag() || (target->reset_halt && (jtag_get_reset_config() & RESET_SRST_NO_GATING))) - jtag_add_reset(0, 1); + adapter_assert_reset(); } else { LOG_ERROR("%s: how to reset?", target_name(target)); @@ -1677,12 +1942,13 @@ 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(); if (target_was_examined(target)) { retval = cortex_a_poll(target); @@ -1695,7 +1961,8 @@ static int cortex_a_deassert_reset(struct target *target) LOG_WARNING("%s: ran after reset and before halt ...", target_name(target)); if (target_was_examined(target)) { - retval = target_halt(target); + retval = mem_ap_write_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_DRCR, DRCR_HALT); if (retval != ERROR_OK) return retval; } else @@ -1892,7 +2159,8 @@ static int cortex_a_write_cpu_memory_slow(struct target *target, { /* 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 + * 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: @@ -2004,7 +2272,7 @@ static int cortex_a_write_cpu_memory(struct target *target, 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; } @@ -2026,7 +2294,7 @@ static int cortex_a_write_cpu_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; @@ -2034,26 +2302,40 @@ static int cortex_a_write_cpu_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_cpu_memory_fast(target, count, buffer, &dscr); } else { - /* Use slow path. */ + /* 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. */ @@ -2135,7 +2417,8 @@ static int cortex_a_read_cpu_memory_slow(struct target *target, { /* 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 + * 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: @@ -2306,7 +2589,7 @@ static int cortex_a_read_cpu_memory(struct target *target, 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; } @@ -2328,7 +2611,7 @@ static int cortex_a_read_cpu_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; @@ -2336,26 +2619,41 @@ static int cortex_a_read_cpu_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_cpu_memory_fast(target, count, buffer, &dscr); } else { - /* Use slow path. */ + /* 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. */ @@ -2437,7 +2735,7 @@ static int cortex_a_read_phys_memory(struct target *target, if (!count || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; - LOG_DEBUG("Reading memory at real address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32, + LOG_DEBUG("Reading memory at real address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32, address, size, count); /* read memory through the CPU */ @@ -2454,7 +2752,7 @@ static int cortex_a_read_memory(struct target *target, target_addr_t address, int retval; /* cortex_a handles unaligned memory access */ - LOG_DEBUG("Reading memory at address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32, + LOG_DEBUG("Reading memory at address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32, address, size, count); cortex_a_prep_memaccess(target, 0); @@ -2473,7 +2771,7 @@ static int cortex_a_write_phys_memory(struct target *target, if (!count || !buffer) return ERROR_COMMAND_SYNTAX_ERROR; - LOG_DEBUG("Writing memory to real address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32, + LOG_DEBUG("Writing memory to real address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32, address, size, count); /* write memory through the CPU */ @@ -2490,7 +2788,7 @@ static int cortex_a_write_memory(struct target *target, target_addr_t address, int retval; /* cortex_a handles unaligned memory access */ - LOG_DEBUG("Writing memory at address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32, + LOG_DEBUG("Writing memory at address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32, address, size, count); /* memory writes bypass the caches, must flush before writing */ @@ -2616,16 +2914,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, cpuid, dbg_osreg; - - /* Search for the APB-AP - it is needed for access to debug registers */ - retval = dap_find_ap(swjdp, AP_TYPE_APB_AP, &armv7a->debug_ap); - if (retval != ERROR_OK) { - LOG_ERROR("Could not find APB-AP for debug access"); - return retval; + 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); @@ -2637,28 +2946,25 @@ static int cortex_a_examine_first(struct target *target) armv7a->debug_ap->memaccess_tck = 80; 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; + 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_DIDR, &didr); if (retval != ERROR_OK) { @@ -2683,29 +2989,29 @@ static int cortex_a_examine_first(struct target *target) armv7a->debug_base + CPUDBG_PRSR, &dbg_osreg); if (retval != ERROR_OK) return retval; - LOG_DEBUG("target->coreid %" PRId32 " DBGPRSR 0x%" PRIx32, target->coreid, dbg_osreg); + LOG_TARGET_DEBUG(target, "DBGPRSR 0x%" PRIx32, dbg_osreg); if ((dbg_osreg & PRSR_POWERUP_STATUS) == 0) { - LOG_ERROR("target->coreid %" PRId32 " powered down!", target->coreid); + LOG_TARGET_ERROR(target, "powered down!"); target->state = TARGET_UNKNOWN; /* TARGET_NO_POWER? */ return ERROR_TARGET_INIT_FAILED; } if (dbg_osreg & PRSR_STICKY_RESET_STATUS) - LOG_DEBUG("target->coreid %" PRId32 " was reset!", target->coreid); + LOG_TARGET_DEBUG(target, "was reset!"); /* Read DBGOSLSR and check if OSLK is implemented */ retval = mem_ap_read_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_OSLSR, &dbg_osreg); if (retval != ERROR_OK) return retval; - LOG_DEBUG("target->coreid %" PRId32 " DBGOSLSR 0x%" PRIx32, target->coreid, dbg_osreg); + LOG_TARGET_DEBUG(target, "DBGOSLSR 0x%" PRIx32, dbg_osreg); /* check if OS Lock is implemented */ if ((dbg_osreg & OSLSR_OSLM) == OSLSR_OSLM0 || (dbg_osreg & OSLSR_OSLM) == OSLSR_OSLM1) { /* check if OS Lock is set */ if (dbg_osreg & OSLSR_OSLK) { - LOG_DEBUG("target->coreid %" PRId32 " OSLock set! Trying to unlock", target->coreid); + LOG_TARGET_DEBUG(target, "OSLock set! Trying to unlock"); retval = mem_ap_write_atomic_u32(armv7a->debug_ap, armv7a->debug_base + CPUDBG_OSLAR, @@ -2716,15 +3022,30 @@ static int cortex_a_examine_first(struct target *target) /* if we fail to access the register or cannot reset the OSLK bit, bail out */ if (retval != ERROR_OK || (dbg_osreg & OSLSR_OSLK) != 0) { - LOG_ERROR("target->coreid %" PRId32 " OSLock sticky, core not powered?", - target->coreid); + LOG_TARGET_ERROR(target, "OSLock sticky, core not powered?"); target->state = TARGET_UNKNOWN; /* TARGET_NO_POWER? */ return ERROR_TARGET_INIT_FAILED; } } } - armv7a->arm.core_type = ARM_MODE_MON; + retval = mem_ap_read_atomic_u32(armv7a->debug_ap, + armv7a->debug_base + CPUDBG_ID_PFR1, &dbg_idpfr1); + if (retval != ERROR_OK) + return retval; + + 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)) { @@ -2741,18 +3062,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; @@ -2820,13 +3155,13 @@ static int cortex_a_target_create(struct target *target, Jim_Interp *interp) struct cortex_a_common *cortex_a; struct adiv5_private_config *pc; - if (target->private_config == NULL) + 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 == NULL) { + if (!cortex_a) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } @@ -2847,7 +3182,7 @@ static int cortex_r4_target_create(struct target *target, Jim_Interp *interp) return ERROR_FAIL; cortex_a = calloc(1, sizeof(struct cortex_a_common)); - if (cortex_a == NULL) { + if (!cortex_a) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } @@ -2875,7 +3210,12 @@ static void cortex_a_deinit_target(struct target *target) 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); @@ -2887,8 +3227,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) @@ -2951,16 +3291,16 @@ 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; } @@ -2968,7 +3308,7 @@ 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); + n = nvp_value2name(nvp_maskisr_modes, cortex_a->isrmasking_mode); command_print(CMD, "cortex_a interrupt mask %s", n->name); return ERROR_OK; @@ -2979,22 +3319,22 @@ 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); + 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; @@ -3058,7 +3398,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, @@ -3089,8 +3428,8 @@ 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, @@ -3166,8 +3505,8 @@ 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,