X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Ftarget%2Faarch64.c;h=fc6bd6b3012dd24d2de0942c9901a4e6e611cca9;hp=df1e49c21c03263349669fd9cca8046e9f8f2508;hb=HEAD;hpb=cad39b73904dfe8f5270603aa54a628e59f507d3 diff --git a/src/target/aarch64.c b/src/target/aarch64.c index df1e49c21c..6a70b2ddf8 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -1,20 +1,8 @@ +// SPDX-License-Identifier: GPL-2.0-or-later + /*************************************************************************** * Copyright (C) 2015 by David Ung * * * - * 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., * - * * ***************************************************************************/ #ifdef HAVE_CONFIG_H @@ -23,11 +11,17 @@ #include "breakpoints.h" #include "aarch64.h" +#include "a64_disassembler.h" #include "register.h" #include "target_request.h" #include "target_type.h" #include "armv8_opcodes.h" #include "armv8_cache.h" +#include "arm_coresight.h" +#include "arm_semihosting.h" +#include "jtag/interface.h" +#include "smp.h" +#include #include enum restart_mode { @@ -62,9 +56,6 @@ static int aarch64_virt2phys(struct target *target, static int aarch64_read_cpu_memory(struct target *target, uint64_t address, uint32_t size, uint32_t count, uint8_t *buffer); -#define foreach_smp_target(pos, head) \ - for (pos = head; (pos != NULL); pos = pos->next) - static int aarch64_restore_system_control_reg(struct target *target) { enum arm_mode target_mode = ARM_MODE_ANY; @@ -99,18 +90,23 @@ static int aarch64_restore_system_control_reg(struct target *target) case ARM_MODE_ABT: case ARM_MODE_FIQ: case ARM_MODE_IRQ: + case ARM_MODE_HYP: + case ARM_MODE_UND: + case ARM_MODE_SYS: + case ARM_MODE_MON: instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0); break; default: - LOG_INFO("cannot read system control register in this mode"); + LOG_ERROR("cannot read system control register in this mode: (%s : 0x%x)", + armv8_mode_name(armv8->arm.core_mode), armv8->arm.core_mode); return ERROR_FAIL; } if (target_mode != ARM_MODE_ANY) armv8_dpm_modeswitch(&armv8->dpm, target_mode); - retval = armv8->dpm.instr_write_data_r0(&armv8->dpm, instr, aarch64->system_control_reg); + retval = armv8->dpm.instr_write_data_r0_64(&armv8->dpm, instr, aarch64->system_control_reg); if (retval != ERROR_OK) return retval; @@ -129,6 +125,7 @@ static int aarch64_mmu_modify(struct target *target, int enable) struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; int retval = ERROR_OK; + enum arm_mode target_mode = ARM_MODE_ANY; uint32_t instr = 0; if (enable) { @@ -154,6 +151,8 @@ static int aarch64_mmu_modify(struct target *target, int enable) switch (armv8->arm.core_mode) { case ARMV8_64_EL0T: + target_mode = ARMV8_64_EL1H; + /* fall through */ case ARMV8_64_EL1T: case ARMV8_64_EL1H: instr = ARMV8_MSR_GP(SYSTEM_SCTLR_EL1, 0); @@ -171,16 +170,26 @@ static int aarch64_mmu_modify(struct target *target, int enable) case ARM_MODE_ABT: case ARM_MODE_FIQ: case ARM_MODE_IRQ: + case ARM_MODE_HYP: + case ARM_MODE_UND: + case ARM_MODE_SYS: + case ARM_MODE_MON: instr = ARMV4_5_MCR(15, 0, 0, 1, 0, 0); break; default: - LOG_DEBUG("unknown cpu state 0x%" PRIx32, armv8->arm.core_mode); + LOG_DEBUG("unknown cpu state 0x%x", armv8->arm.core_mode); break; } + if (target_mode != ARM_MODE_ANY) + armv8_dpm_modeswitch(&armv8->dpm, target_mode); - retval = armv8->dpm.instr_write_data_r0(&armv8->dpm, instr, + retval = armv8->dpm.instr_write_data_r0_64(&armv8->dpm, instr, aarch64->system_control_reg_curr); + + if (target_mode != ARM_MODE_ANY) + armv8_dpm_modeswitch(&armv8->dpm, ARM_MODE_ANY); + return retval; } @@ -237,7 +246,7 @@ static int aarch64_init_debug_access(struct target *target) /* Write to memory mapped registers directly with no cache or mmu handling */ static int aarch64_dap_write_memap_register_u32(struct target *target, - uint32_t address, + target_addr_t address, uint32_t value) { int retval; @@ -315,15 +324,14 @@ static int aarch64_wait_halt_one(struct target *target) static int aarch64_prepare_halt_smp(struct target *target, bool exc_target, struct target **p_first) { int retval = ERROR_OK; - struct target_list *head = target->head; + struct target_list *head; struct target *first = NULL; LOG_DEBUG("target %s exc %i", target_name(target), exc_target); - while (head != NULL) { + foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; struct armv8_common *armv8 = target_to_armv8(curr); - head = head->next; if (exc_target && curr == target) continue; @@ -344,7 +352,7 @@ static int aarch64_prepare_halt_smp(struct target *target, bool exc_target, stru LOG_DEBUG("target %s prepared", target_name(curr)); - if (first == NULL) + if (!first) first = curr; } @@ -412,7 +420,7 @@ static int aarch64_halt_smp(struct target *target, bool exc_target) struct target_list *head; struct target *curr; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { int halted; curr = head->target; @@ -462,7 +470,7 @@ static int update_halt_gdb(struct target *target, enum target_debug_reason debug } /* poll all targets in the group, but skip the target that serves GDB */ - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { curr = head->target; /* skip calling context */ if (curr == target) @@ -473,7 +481,7 @@ static int update_halt_gdb(struct target *target, enum target_debug_reason debug if (curr->state == TARGET_HALTED) continue; /* remember the gdb_service->target */ - if (curr->gdb_service != NULL) + if (curr->gdb_service) gdb_target = curr->gdb_service->target; /* skip it */ if (curr == gdb_target) @@ -486,7 +494,7 @@ static int update_halt_gdb(struct target *target, enum target_debug_reason debug } /* after all targets were updated, poll the gdb serving target */ - if (gdb_target != NULL && gdb_target != target) + if (gdb_target && gdb_target != target) aarch64_poll(gdb_target); return ERROR_OK; @@ -522,6 +530,9 @@ static int aarch64_poll(struct target *target) if (target->smp) update_halt_gdb(target, debug_reason); + if (arm_semihosting(target, &retval) != 0) + return retval; + switch (prev_target_state) { case TARGET_RUNNING: case TARGET_UNKNOWN: @@ -543,6 +554,9 @@ static int aarch64_poll(struct target *target) static int aarch64_halt(struct target *target) { + struct armv8_common *armv8 = target_to_armv8(target); + armv8->last_run_control_op = ARMV8_RUNCONTROL_HALT; + if (target->smp) return aarch64_halt_smp(target, false); @@ -577,7 +591,7 @@ static int aarch64_restore_one(struct target *target, int current, resume_pc &= 0xFFFFFFFC; break; case ARM_STATE_AARCH64: - resume_pc &= 0xFFFFFFFFFFFFFFFC; + resume_pc &= 0xFFFFFFFFFFFFFFFCULL; break; case ARM_STATE_THUMB: case ARM_STATE_THUMB_EE: @@ -592,8 +606,8 @@ static int aarch64_restore_one(struct target *target, int current, } LOG_DEBUG("resume pc = 0x%016" PRIx64, resume_pc); buf_set_u64(arm->pc->value, 0, 64, resume_pc); - arm->pc->dirty = 1; - arm->pc->valid = 1; + arm->pc->dirty = true; + arm->pc->valid = true; /* called it now before restoring context because it uses cpu * register r0 for restoring system control register */ @@ -721,7 +735,7 @@ static int aarch64_prep_restart_smp(struct target *target, int handle_breakpoint struct target *first = NULL; uint64_t address; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { struct target *curr = head->target; /* skip calling target */ @@ -741,7 +755,7 @@ static int aarch64_prep_restart_smp(struct target *target, int handle_breakpoint break; } /* remember the first valid target in the group */ - if (first == NULL) + if (!first) first = curr; } @@ -764,7 +778,7 @@ static int aarch64_step_restart_smp(struct target *target) if (retval != ERROR_OK) return retval; - if (first != NULL) + if (first) retval = aarch64_do_restart_one(first, RESTART_LAZY); if (retval != ERROR_OK) { LOG_DEBUG("error restarting target %s", target_name(first)); @@ -776,7 +790,7 @@ static int aarch64_step_restart_smp(struct target *target) struct target *curr = target; bool all_resumed = true; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { uint32_t prsr; int resumed; @@ -831,8 +845,13 @@ static int aarch64_resume(struct target *target, int current, int retval = 0; uint64_t addr = address; - if (target->state != TARGET_HALTED) + struct armv8_common *armv8 = target_to_armv8(target); + armv8->last_run_control_op = ARMV8_RUNCONTROL_RESUME; + + if (target->state != TARGET_HALTED) { + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; + } /* * If this target is part of a SMP group, prepare the others @@ -861,7 +880,7 @@ static int aarch64_resume(struct target *target, int current, struct target_list *head; bool all_resumed = true; - foreach_smp_target(head, target->head) { + foreach_smp_target(head, target->smp_targets) { uint32_t prsr; int resumed; @@ -964,25 +983,26 @@ static int aarch64_debug_entry(struct target *target) /* Examine debug reason */ armv8_dpm_report_dscr(dpm, dscr); - /* save address of instruction that triggered the watchpoint? */ + /* save the memory address that triggered the watchpoint */ if (target->debug_reason == DBG_REASON_WATCHPOINT) { uint32_t tmp; - uint64_t wfar = 0; retval = mem_ap_read_atomic_u32(armv8->debug_ap, - armv8->debug_base + CPUV8_DBG_WFAR1, - &tmp); + armv8->debug_base + CPUV8_DBG_EDWAR0, &tmp); if (retval != ERROR_OK) return retval; - wfar = tmp; - wfar = (wfar << 32); - retval = mem_ap_read_atomic_u32(armv8->debug_ap, - armv8->debug_base + CPUV8_DBG_WFAR0, - &tmp); - if (retval != ERROR_OK) - return retval; - wfar |= tmp; - armv8_dpm_report_wfar(&armv8->dpm, wfar); + target_addr_t edwar = tmp; + + /* EDWAR[63:32] has unknown content in aarch32 state */ + if (core_state == ARM_STATE_AARCH64) { + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_EDWAR1, &tmp); + if (retval != ERROR_OK) + return retval; + edwar |= ((target_addr_t)tmp) << 32; + } + + armv8->dpm.wp_addr = edwar; } retval = armv8_dpm_read_current_registers(&armv8->dpm); @@ -1022,34 +1042,42 @@ static int aarch64_post_debug_entry(struct target *target) case ARM_MODE_ABT: case ARM_MODE_FIQ: case ARM_MODE_IRQ: + case ARM_MODE_HYP: + case ARM_MODE_UND: + case ARM_MODE_SYS: + case ARM_MODE_MON: instr = ARMV4_5_MRC(15, 0, 0, 1, 0, 0); break; default: - LOG_INFO("cannot read system control register in this mode"); + LOG_ERROR("cannot read system control register in this mode: (%s : 0x%x)", + armv8_mode_name(armv8->arm.core_mode), armv8->arm.core_mode); return ERROR_FAIL; } if (target_mode != ARM_MODE_ANY) armv8_dpm_modeswitch(&armv8->dpm, target_mode); - retval = armv8->dpm.instr_read_data_r0(&armv8->dpm, instr, &aarch64->system_control_reg); + retval = armv8->dpm.instr_read_data_r0_64(&armv8->dpm, instr, &aarch64->system_control_reg); if (retval != ERROR_OK) return retval; if (target_mode != ARM_MODE_ANY) armv8_dpm_modeswitch(&armv8->dpm, ARM_MODE_ANY); - LOG_DEBUG("System_register: %8.8" PRIx32, aarch64->system_control_reg); + LOG_DEBUG("System_register: %8.8" PRIx64, aarch64->system_control_reg); aarch64->system_control_reg_curr = aarch64->system_control_reg; if (armv8->armv8_mmu.armv8_cache.info == -1) { armv8_identify_cache(armv8); armv8_read_mpidr(armv8); } - - armv8->armv8_mmu.mmu_enabled = + if (armv8->is_armv8r) { + armv8->armv8_mmu.mmu_enabled = 0; + } else { + armv8->armv8_mmu.mmu_enabled = (aarch64->system_control_reg & 0x1U) ? 1 : 0; + } armv8->armv8_mmu.armv8_cache.d_u_cache_enabled = (aarch64->system_control_reg & 0x4U) ? 1 : 0; armv8->armv8_mmu.armv8_cache.i_cache_enabled = @@ -1066,11 +1094,14 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres struct armv8_common *armv8 = target_to_armv8(target); struct aarch64_common *aarch64 = target_to_aarch64(target); int saved_retval = ERROR_OK; + int poll_retval; int retval; uint32_t edecr; + armv8->last_run_control_op = ARMV8_RUNCONTROL_STEP; + if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1146,6 +1177,8 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres if (retval == ERROR_TARGET_TIMEOUT) saved_retval = aarch64_halt_one(target, HALT_SYNC); + poll_retval = aarch64_poll(target); + /* restore EDECR */ retval = mem_ap_write_atomic_u32(armv8->debug_ap, armv8->debug_base + CPUV8_DBG_EDECR, edecr); @@ -1162,7 +1195,10 @@ static int aarch64_step(struct target *target, int current, target_addr_t addres if (saved_retval != ERROR_OK) return saved_retval; - return aarch64_poll(target); + if (poll_retval != ERROR_OK) + return poll_retval; + + return ERROR_OK; } static int aarch64_restore_context(struct target *target, bool bpwp) @@ -1203,7 +1239,7 @@ static int aarch64_set_breakpoint(struct target *target, struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *brp_list = aarch64->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return ERROR_OK; } @@ -1216,7 +1252,7 @@ static int aarch64_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) @@ -1224,23 +1260,23 @@ static int aarch64_set_breakpoint(struct target *target, | (byte_addr_select << 5) | (3 << 1) | 1; brp_list[brp_i].used = 1; - brp_list[brp_i].value = breakpoint->address & 0xFFFFFFFFFFFFFFFC; + brp_list[brp_i].value = breakpoint->address & 0xFFFFFFFFFFFFFFFCULL; brp_list[brp_i].control = control; bpt_value = brp_list[brp_i].value; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].BRPn, + + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].brpn, (uint32_t)(bpt_value & 0xFFFFFFFF)); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_i].BRPn, + + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_i].brpn, (uint32_t)(bpt_value >> 32)); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].BRPn, + + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; @@ -1249,35 +1285,58 @@ static int aarch64_set_breakpoint(struct target *target, brp_list[brp_i].value); } else if (breakpoint->type == BKPT_SOFT) { + uint32_t opcode; uint8_t code[4]; - buf_set_u32(code, 0, 32, armv8_opcode(armv8, ARMV8_OPC_HLT)); + if (armv8_dpm_get_core_state(&armv8->dpm) == ARM_STATE_AARCH64) { + opcode = ARMV8_HLT(11); + + if (breakpoint->length != 4) + LOG_ERROR("bug: breakpoint length should be 4 in AArch64 mode"); + } else { + /** + * core_state is ARM_STATE_ARM + * in that case the opcode depends on breakpoint length: + * - if length == 4 => A32 opcode + * - if length == 2 => T32 opcode + * - if length == 3 => T32 opcode (refer to gdb doc : ARM-Breakpoint-Kinds) + * in that case the length should be changed from 3 to 4 bytes + **/ + opcode = (breakpoint->length == 4) ? ARMV8_HLT_A1(11) : + (uint32_t) (ARMV8_HLT_T1(11) | ARMV8_HLT_T1(11) << 16); + + if (breakpoint->length == 3) + breakpoint->length = 4; + } + + buf_set_u32(code, 0, 32, opcode); + retval = target_read_memory(target, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; armv8_cache_d_inner_flush_virt(armv8, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); retval = target_write_memory(target, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length, 1, code); if (retval != ERROR_OK) return retval; armv8_cache_d_inner_flush_virt(armv8, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); armv8_cache_i_inner_inval_virt(armv8, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); - breakpoint->set = 0x11; /* Any nice value but 0 */ + breakpoint->is_set = true; } /* Ensure that halting debug mode is enable */ @@ -1301,7 +1360,7 @@ static int aarch64_set_context_breakpoint(struct target *target, struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *brp_list = aarch64->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return retval; } @@ -1315,7 +1374,7 @@ static int aarch64_set_context_breakpoint(struct target *target, return ERROR_FAIL; } - breakpoint->set = brp_i + 1; + breakpoint_hw_set(breakpoint, brp_i); control = ((matchmode & 0x7) << 20) | (1 << 13) | (byte_addr_select << 5) @@ -1324,12 +1383,12 @@ static int aarch64_set_context_breakpoint(struct target *target, brp_list[brp_i].value = (breakpoint->asid); brp_list[brp_i].control = control; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].BRPn, + + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].brpn, brp_list[brp_i].value); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].BRPn, + + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; @@ -1345,16 +1404,16 @@ static int aarch64_set_hybrid_breakpoint(struct target *target, struct breakpoin 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 aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *brp_list = aarch64->brp_list; - if (breakpoint->set) { + if (breakpoint->is_set) { LOG_WARNING("breakpoint already set"); return retval; } @@ -1363,7 +1422,7 @@ static int aarch64_set_hybrid_breakpoint(struct target *target, struct breakpoin (brp_list[brp_1].type != BRP_CONTEXT)) && (brp_1 < aarch64->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 >= aarch64->brp_num) { LOG_ERROR("ERROR Can not find free Breakpoint Register Pair"); return ERROR_FAIL; @@ -1373,53 +1432,53 @@ static int aarch64_set_hybrid_breakpoint(struct target *target, struct breakpoin (brp_list[brp_2].type != BRP_NORMAL)) && (brp_2 < aarch64->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 >= aarch64->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].value = (breakpoint->asid); - brp_list[brp_1].control = control_CTX; + brp_list[brp_1].control = control_ctx; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_1].BRPn, + + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_1].brpn, brp_list[brp_1].value); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_1].BRPn, + + CPUV8_DBG_BCR_BASE + 16 * 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) | (1 << 13) - | (IVA_byte_addr_select << 5) + | (iva_byte_addr_select << 5) | (3 << 1) | 1; brp_list[brp_2].used = 1; - brp_list[brp_2].value = breakpoint->address & 0xFFFFFFFFFFFFFFFC; - brp_list[brp_2].control = control_IVA; + brp_list[brp_2].value = breakpoint->address & 0xFFFFFFFFFFFFFFFCULL; + brp_list[brp_2].control = control_iva; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_2].BRPn, + + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_2].brpn, brp_list[brp_2].value & 0xFFFFFFFF); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_2].BRPn, + + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_2].brpn, brp_list[brp_2].value >> 32); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_2].BRPn, + + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_2].brpn, brp_list[brp_2].control); if (retval != ERROR_OK) return retval; @@ -1434,16 +1493,16 @@ static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *br struct armv8_common *armv8 = &aarch64->armv8_common; struct aarch64_brp *brp_list = aarch64->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 >= aarch64->brp_num)) { + int brp_i = breakpoint->number; + int brp_j = breakpoint->linked_brp; + if (brp_i >= aarch64->brp_num) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } @@ -1453,17 +1512,17 @@ static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *br brp_list[brp_i].value = 0; brp_list[brp_i].control = 0; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].BRPn, + + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].BRPn, + + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].brpn, (uint32_t)brp_list[brp_i].value); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_i].BRPn, + + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_i].brpn, (uint32_t)brp_list[brp_i].value); if (retval != ERROR_OK) return retval; @@ -1477,28 +1536,28 @@ static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *br brp_list[brp_j].value = 0; brp_list[brp_j].control = 0; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_j].BRPn, + + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_j].brpn, brp_list[brp_j].control); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_j].BRPn, + + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_j].brpn, (uint32_t)brp_list[brp_j].value); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_j].BRPn, + + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_j].brpn, (uint32_t)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 >= aarch64->brp_num)) { + int brp_i = breakpoint->number; + if (brp_i >= aarch64->brp_num) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; } @@ -1508,54 +1567,54 @@ static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *br brp_list[brp_i].value = 0; brp_list[brp_i].control = 0; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].BRPn, + + CPUV8_DBG_BCR_BASE + 16 * brp_list[brp_i].brpn, brp_list[brp_i].control); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].BRPn, + + CPUV8_DBG_BVR_BASE + 16 * brp_list[brp_i].brpn, brp_list[brp_i].value); if (retval != ERROR_OK) return retval; retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base - + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_i].BRPn, + + CPUV8_DBG_BVR_BASE + 4 + 16 * brp_list[brp_i].brpn, (uint32_t)brp_list[brp_i].value); if (retval != ERROR_OK) return retval; - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } } else { /* restore original instruction (kept in target endianness) */ armv8_cache_d_inner_flush_virt(armv8, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); if (breakpoint->length == 4) { retval = target_write_memory(target, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, 4, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } else { retval = target_write_memory(target, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, 2, 1, breakpoint->orig_instr); if (retval != ERROR_OK) return retval; } armv8_cache_d_inner_flush_virt(armv8, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); armv8_cache_i_inner_inval_virt(armv8, - breakpoint->address & 0xFFFFFFFFFFFFFFFE, + breakpoint->address & 0xFFFFFFFFFFFFFFFEULL, breakpoint->length); } - breakpoint->set = 0; + breakpoint->is_set = false; return ERROR_OK; } @@ -1608,7 +1667,6 @@ static int aarch64_add_hybrid_breakpoint(struct target *target, return aarch64_set_hybrid_breakpoint(target, breakpoint); /* ??? */ } - static int aarch64_remove_breakpoint(struct target *target, struct breakpoint *breakpoint) { struct aarch64_common *aarch64 = target_to_aarch64(target); @@ -1621,7 +1679,7 @@ static int aarch64_remove_breakpoint(struct target *target, struct breakpoint *b } #endif - if (breakpoint->set) { + if (breakpoint->is_set) { aarch64_unset_breakpoint(target, breakpoint); if (breakpoint->type == BKPT_HARD) aarch64->brp_num_available++; @@ -1630,33 +1688,302 @@ static int aarch64_remove_breakpoint(struct target *target, struct breakpoint *b return ERROR_OK; } +/* Setup hardware Watchpoint Register Pair */ +static int aarch64_set_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + int retval; + int wp_i = 0; + uint32_t control, offset, length; + struct aarch64_common *aarch64 = target_to_aarch64(target); + struct armv8_common *armv8 = &aarch64->armv8_common; + struct aarch64_brp *wp_list = aarch64->wp_list; + + if (watchpoint->is_set) { + LOG_WARNING("watchpoint already set"); + return ERROR_OK; + } + + while (wp_list[wp_i].used && (wp_i < aarch64->wp_num)) + wp_i++; + if (wp_i >= aarch64->wp_num) { + LOG_ERROR("ERROR Can not find free Watchpoint Register Pair"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + control = (1 << 0) /* enable */ + | (3 << 1) /* both user and privileged access */ + | (1 << 13); /* higher mode control */ + + switch (watchpoint->rw) { + case WPT_READ: + control |= 1 << 3; + break; + case WPT_WRITE: + control |= 2 << 3; + break; + case WPT_ACCESS: + control |= 3 << 3; + break; + } + + /* Match up to 8 bytes. */ + offset = watchpoint->address & 7; + length = watchpoint->length; + if (offset + length > sizeof(uint64_t)) { + length = sizeof(uint64_t) - offset; + LOG_WARNING("Adjust watchpoint match inside 8-byte boundary"); + } + for (; length > 0; offset++, length--) + control |= (1 << offset) << 5; + + wp_list[wp_i].value = watchpoint->address & 0xFFFFFFFFFFFFFFF8ULL; + wp_list[wp_i].control = control; + + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_WVR_BASE + 16 * wp_list[wp_i].brpn, + (uint32_t)(wp_list[wp_i].value & 0xFFFFFFFF)); + if (retval != ERROR_OK) + return retval; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_WVR_BASE + 4 + 16 * wp_list[wp_i].brpn, + (uint32_t)(wp_list[wp_i].value >> 32)); + if (retval != ERROR_OK) + return retval; + + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_WCR_BASE + 16 * wp_list[wp_i].brpn, + control); + if (retval != ERROR_OK) + return retval; + LOG_DEBUG("wp %i control 0x%0" PRIx32 " value 0x%" TARGET_PRIxADDR, wp_i, + wp_list[wp_i].control, wp_list[wp_i].value); + + /* Ensure that halting debug mode is enable */ + retval = aarch64_set_dscr_bits(target, DSCR_HDE, DSCR_HDE); + if (retval != ERROR_OK) { + LOG_DEBUG("Failed to set DSCR.HDE"); + return retval; + } + + wp_list[wp_i].used = 1; + watchpoint_set(watchpoint, wp_i); + + return ERROR_OK; +} + +/* Clear hardware Watchpoint Register Pair */ +static int aarch64_unset_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + int retval; + struct aarch64_common *aarch64 = target_to_aarch64(target); + struct armv8_common *armv8 = &aarch64->armv8_common; + struct aarch64_brp *wp_list = aarch64->wp_list; + + if (!watchpoint->is_set) { + LOG_WARNING("watchpoint not set"); + return ERROR_OK; + } + + int wp_i = watchpoint->number; + if (wp_i >= aarch64->wp_num) { + LOG_DEBUG("Invalid WP number in watchpoint"); + return ERROR_OK; + } + LOG_DEBUG("rwp %i control 0x%0" PRIx32 " value 0x%0" PRIx64, wp_i, + wp_list[wp_i].control, wp_list[wp_i].value); + wp_list[wp_i].used = 0; + wp_list[wp_i].value = 0; + wp_list[wp_i].control = 0; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_WCR_BASE + 16 * wp_list[wp_i].brpn, + wp_list[wp_i].control); + if (retval != ERROR_OK) + return retval; + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_WVR_BASE + 16 * wp_list[wp_i].brpn, + wp_list[wp_i].value); + if (retval != ERROR_OK) + return retval; + + retval = aarch64_dap_write_memap_register_u32(target, armv8->debug_base + + CPUV8_DBG_WVR_BASE + 4 + 16 * wp_list[wp_i].brpn, + (uint32_t)wp_list[wp_i].value); + if (retval != ERROR_OK) + return retval; + watchpoint->is_set = false; + + return ERROR_OK; +} + +static int aarch64_add_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + int retval; + struct aarch64_common *aarch64 = target_to_aarch64(target); + + if (aarch64->wp_num_available < 1) { + LOG_INFO("no hardware watchpoint available"); + return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; + } + + retval = aarch64_set_watchpoint(target, watchpoint); + if (retval == ERROR_OK) + aarch64->wp_num_available--; + + return retval; +} + +static int aarch64_remove_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + struct aarch64_common *aarch64 = target_to_aarch64(target); + + if (watchpoint->is_set) { + aarch64_unset_watchpoint(target, watchpoint); + aarch64->wp_num_available++; + } + + return ERROR_OK; +} + +/** + * find out which watchpoint hits + * get exception address and compare the address to watchpoints + */ +static int aarch64_hit_watchpoint(struct target *target, + struct watchpoint **hit_watchpoint) +{ + if (target->debug_reason != DBG_REASON_WATCHPOINT) + return ERROR_FAIL; + + struct armv8_common *armv8 = target_to_armv8(target); + + target_addr_t exception_address; + struct watchpoint *wp; + + exception_address = armv8->dpm.wp_addr; + + if (exception_address == 0xFFFFFFFF) + return ERROR_FAIL; + + for (wp = target->watchpoints; wp; wp = wp->next) + if (exception_address >= wp->address && exception_address < (wp->address + wp->length)) { + *hit_watchpoint = wp; + return ERROR_OK; + } + + return ERROR_FAIL; +} + /* * Cortex-A8 Reset functions */ +static int aarch64_enable_reset_catch(struct target *target, bool enable) +{ + struct armv8_common *armv8 = target_to_armv8(target); + uint32_t edecr; + int retval; + + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_EDECR, &edecr); + LOG_DEBUG("EDECR = 0x%08" PRIx32 ", enable=%d", edecr, enable); + if (retval != ERROR_OK) + return retval; + + if (enable) + edecr |= ECR_RCE; + else + edecr &= ~ECR_RCE; + + return mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_EDECR, edecr); +} + +static int aarch64_clear_reset_catch(struct target *target) +{ + struct armv8_common *armv8 = target_to_armv8(target); + uint32_t edesr; + int retval; + bool was_triggered; + + /* check if Reset Catch debug event triggered as expected */ + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_EDESR, &edesr); + if (retval != ERROR_OK) + return retval; + + was_triggered = !!(edesr & ESR_RC); + LOG_DEBUG("Reset Catch debug event %s", + was_triggered ? "triggered" : "NOT triggered!"); + + if (was_triggered) { + /* clear pending Reset Catch debug event */ + edesr &= ~ESR_RC; + retval = mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_EDESR, edesr); + if (retval != ERROR_OK) + return retval; + } + + return ERROR_OK; +} + static int aarch64_assert_reset(struct target *target) { struct armv8_common *armv8 = target_to_armv8(target); + enum reset_types reset_config = jtag_get_reset_config(); + int retval; LOG_DEBUG(" "); - /* FIXME when halt is requested, make it work somehow... */ - /* Issue some kind of warm reset. */ if (target_has_event_action(target, TARGET_EVENT_RESET_ASSERT)) target_handle_event(target, TARGET_EVENT_RESET_ASSERT); - else if (jtag_get_reset_config() & RESET_HAS_SRST) { + else if (reset_config & RESET_HAS_SRST) { + bool srst_asserted = false; + + if (target->reset_halt && !(reset_config & RESET_SRST_PULLS_TRST)) { + if (target_was_examined(target)) { + + if (reset_config & RESET_SRST_NO_GATING) { + /* + * SRST needs to be asserted *before* Reset Catch + * debug event can be set up. + */ + adapter_assert_reset(); + srst_asserted = true; + } + + /* make sure to clear all sticky errors */ + mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DRCR, DRCR_CSE); + + /* set up Reset Catch debug event to halt the CPU after reset */ + retval = aarch64_enable_reset_catch(target, true); + if (retval != ERROR_OK) + LOG_WARNING("%s: Error enabling Reset Catch debug event; the CPU will not halt immediately after reset!", + target_name(target)); + } else { + LOG_WARNING("%s: Target not examined, will not halt immediately after reset!", + target_name(target)); + } + } + /* REVISIT handle "pulls" cases, if there's * hardware that needs them to work. */ - jtag_add_reset(0, 1); + if (!srst_asserted) + adapter_assert_reset(); } else { LOG_ERROR("%s: how to reset?", target_name(target)); return ERROR_FAIL; } /* registers are now invalid */ - if (target_was_examined(target)) { + if (armv8->arm.core_cache) { register_cache_invalidate(armv8->arm.core_cache); register_cache_invalidate(armv8->arm.core_cache->next); } @@ -1673,26 +2000,46 @@ static int aarch64_deassert_reset(struct target *target) LOG_DEBUG(" "); /* be certain SRST is off */ - jtag_add_reset(0, 0); + adapter_deassert_reset(); if (!target_was_examined(target)) return ERROR_OK; + retval = aarch64_init_debug_access(target); + if (retval != ERROR_OK) + return retval; + retval = aarch64_poll(target); if (retval != ERROR_OK) return retval; if (target->reset_halt) { + /* clear pending Reset Catch debug event */ + retval = aarch64_clear_reset_catch(target); + if (retval != ERROR_OK) + LOG_WARNING("%s: Clearing Reset Catch debug event failed", + target_name(target)); + + /* disable Reset Catch debug event */ + retval = aarch64_enable_reset_catch(target, false); + if (retval != ERROR_OK) + LOG_WARNING("%s: Disabling Reset Catch debug event failed", + target_name(target)); + 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 = aarch64_halt_one(target, HALT_LAZY); + if (retval != ERROR_OK) + return retval; + } else { + target->state = TARGET_UNKNOWN; + } } } - return aarch64_init_debug_access(target); + return ERROR_OK; } static int aarch64_write_cpu_memory_slow(struct target *target, @@ -1703,6 +2050,11 @@ static int aarch64_write_cpu_memory_slow(struct target *target, struct arm *arm = &armv8->arm; int retval; + if (size > 4 && arm->core_state != ARM_STATE_AARCH64) { + LOG_ERROR("memory write sizes greater than 4 bytes is only supported for AArch64 state"); + return ERROR_FAIL; + } + armv8_reg_current(arm, 1)->dirty = true; /* change DCC to normal mode if necessary */ @@ -1715,22 +2067,32 @@ static int aarch64_write_cpu_memory_slow(struct target *target, } while (count) { - uint32_t data, opcode; + uint32_t opcode; + uint64_t data; - /* write the data to store into DTRRX */ + /* write the data to store into DTRRX (and DTRTX for 64-bit) */ if (size == 1) data = *buffer; else if (size == 2) data = target_buffer_get_u16(target, buffer); - else + else if (size == 4) data = target_buffer_get_u32(target, buffer); + else + data = target_buffer_get_u64(target, buffer); + retval = mem_ap_write_atomic_u32(armv8->debug_ap, - armv8->debug_base + CPUV8_DBG_DTRRX, data); + armv8->debug_base + CPUV8_DBG_DTRRX, (uint32_t)data); + if (retval == ERROR_OK && size > 4) + retval = mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DTRTX, (uint32_t)(data >> 32)); if (retval != ERROR_OK) return retval; if (arm->core_state == ARM_STATE_AARCH64) - retval = dpm->instr_execute(dpm, ARMV8_MRS(SYSTEM_DBG_DTRRX_EL0, 1)); + if (size <= 4) + retval = dpm->instr_execute(dpm, ARMV8_MRS(SYSTEM_DBG_DTRRX_EL0, 1)); + else + retval = dpm->instr_execute(dpm, ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0, 1)); else retval = dpm->instr_execute(dpm, ARMV4_5_MRC(14, 0, 1, 0, 5, 0)); if (retval != ERROR_OK) @@ -1740,8 +2102,11 @@ static int aarch64_write_cpu_memory_slow(struct target *target, opcode = armv8_opcode(armv8, ARMV8_OPC_STRB_IP); else if (size == 2) opcode = armv8_opcode(armv8, ARMV8_OPC_STRH_IP); - else + else if (size == 4) opcode = armv8_opcode(armv8, ARMV8_OPC_STRW_IP); + else + opcode = armv8_opcode(armv8, ARMV8_OPC_STRD_IP); + retval = dpm->instr_execute(dpm, opcode); if (retval != ERROR_OK) return retval; @@ -1799,7 +2164,7 @@ static int aarch64_write_cpu_memory(struct target *target, uint32_t dscr; if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -1882,6 +2247,11 @@ static int aarch64_read_cpu_memory_slow(struct target *target, struct arm *arm = &armv8->arm; int retval; + if (size > 4 && arm->core_state != ARM_STATE_AARCH64) { + LOG_ERROR("memory read sizes greater than 4 bytes is only supported for AArch64 state"); + return ERROR_FAIL; + } + armv8_reg_current(arm, 1)->dirty = true; /* change DCC to normal mode (if necessary) */ @@ -1894,36 +2264,56 @@ static int aarch64_read_cpu_memory_slow(struct target *target, } while (count) { - uint32_t opcode, data; + uint32_t opcode; + uint32_t lower; + uint32_t higher; + uint64_t data; if (size == 1) opcode = armv8_opcode(armv8, ARMV8_OPC_LDRB_IP); else if (size == 2) opcode = armv8_opcode(armv8, ARMV8_OPC_LDRH_IP); - else + else if (size == 4) opcode = armv8_opcode(armv8, ARMV8_OPC_LDRW_IP); + else + opcode = armv8_opcode(armv8, ARMV8_OPC_LDRD_IP); + retval = dpm->instr_execute(dpm, opcode); if (retval != ERROR_OK) return retval; if (arm->core_state == ARM_STATE_AARCH64) - retval = dpm->instr_execute(dpm, ARMV8_MSR_GP(SYSTEM_DBG_DTRTX_EL0, 1)); + if (size <= 4) + retval = dpm->instr_execute(dpm, ARMV8_MSR_GP(SYSTEM_DBG_DTRTX_EL0, 1)); + else + retval = dpm->instr_execute(dpm, ARMV8_MSR_GP(SYSTEM_DBG_DBGDTR_EL0, 1)); else retval = dpm->instr_execute(dpm, ARMV4_5_MCR(14, 0, 1, 0, 5, 0)); if (retval != ERROR_OK) return retval; retval = mem_ap_read_atomic_u32(armv8->debug_ap, - armv8->debug_base + CPUV8_DBG_DTRTX, &data); + armv8->debug_base + CPUV8_DBG_DTRTX, &lower); + if (retval == ERROR_OK) { + if (size > 4) + retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + CPUV8_DBG_DTRRX, &higher); + else + higher = 0; + } if (retval != ERROR_OK) return retval; + data = (uint64_t)lower | (uint64_t)higher << 32; + if (size == 1) *buffer = (uint8_t)data; else if (size == 2) target_buffer_set_u16(target, buffer, (uint16_t)data); + else if (size == 4) + target_buffer_set_u32(target, buffer, (uint32_t)data); else - target_buffer_set_u32(target, buffer, data); + target_buffer_set_u64(target, buffer, data); /* Advance */ buffer += size; @@ -2017,7 +2407,7 @@ static int aarch64_read_cpu_memory(struct target *target, address, size, count); if (target->state != TARGET_HALTED) { - LOG_WARNING("target not halted"); + LOG_TARGET_ERROR(target, "not halted"); return ERROR_TARGET_NOT_HALTED; } @@ -2203,7 +2593,7 @@ static int aarch64_examine_first(struct target *target) struct aarch64_common *aarch64 = target_to_aarch64(target); struct armv8_common *armv8 = &aarch64->armv8_common; struct adiv5_dap *swjdp = armv8->arm.dap; - struct aarch64_private_config *pc; + struct aarch64_private_config *pc = target->private_config; int i; int retval = ERROR_OK; uint64_t debug, ttypr; @@ -2211,11 +2601,24 @@ static int aarch64_examine_first(struct target *target) uint32_t tmp0, tmp1, tmp2, tmp3; debug = ttypr = cpuid = 0; - /* Search for the APB-AB - it is needed for access to debug registers */ - retval = dap_find_ap(swjdp, AP_TYPE_APB_AP, &armv8->debug_ap); - if (retval != ERROR_OK) { - LOG_ERROR("Could not find APB-AP for debug access"); - return retval; + if (!pc) + return ERROR_FAIL; + + if (!armv8->debug_ap) { + if (pc->adiv5_config.ap_num == DP_APSEL_INVALID) { + /* Search for the APB-AB */ + retval = dap_find_get_ap(swjdp, AP_TYPE_APB_AP, &armv8->debug_ap); + if (retval != ERROR_OK) { + LOG_ERROR("Could not find APB-AP for debug access"); + return retval; + } + } else { + armv8->debug_ap = dap_get_ap(swjdp, pc->adiv5_config.ap_num); + if (!armv8->debug_ap) { + LOG_ERROR("Cannot get AP"); + return ERROR_FAIL; + } + } } retval = mem_ap_init(armv8->debug_ap); @@ -2227,20 +2630,13 @@ static int aarch64_examine_first(struct target *target) armv8->debug_ap->memaccess_tck = 10; if (!target->dbgbase_set) { - uint32_t dbgbase; - /* Get ROM Table base */ - uint32_t apid; - int32_t coreidx = target->coreid; - retval = dap_get_debugbase(armv8->debug_ap, &dbgbase, &apid); + /* Lookup Processor DAP */ + retval = dap_lookup_cs_component(armv8->debug_ap, ARM_CS_C9_DEVTYPE_CORE_DEBUG, + &armv8->debug_base, target->coreid); if (retval != ERROR_OK) return retval; - /* Lookup 0x15 -- Processor DAP */ - retval = dap_lookup_cs_component(armv8->debug_ap, dbgbase, 0x15, - &armv8->debug_base, &coreidx); - if (retval != ERROR_OK) - return retval; - LOG_DEBUG("Detected core %" PRId32 " dbgbase: %08" PRIx32 - " apid: %08" PRIx32, coreidx, armv8->debug_base, apid); + LOG_DEBUG("Detected core %" PRId32 " dbgbase: " TARGET_ADDR_FMT, + target->coreid, armv8->debug_base); } else armv8->debug_base = target->dbgbase; @@ -2290,12 +2686,10 @@ static int aarch64_examine_first(struct target *target) LOG_DEBUG("ttypr = 0x%08" PRIx64, ttypr); LOG_DEBUG("debug = 0x%08" PRIx64, debug); - if (target->private_config == NULL) - return ERROR_FAIL; - - pc = (struct aarch64_private_config *)target->private_config; - if (pc->cti == NULL) + if (!pc->cti) { + LOG_TARGET_ERROR(target, "CTI not specified"); return ERROR_FAIL; + } armv8->cti = pc->cti; @@ -2316,10 +2710,23 @@ static int aarch64_examine_first(struct target *target) aarch64->brp_list[i].type = BRP_CONTEXT; aarch64->brp_list[i].value = 0; aarch64->brp_list[i].control = 0; - aarch64->brp_list[i].BRPn = i; + aarch64->brp_list[i].brpn = i; + } + + /* Setup Watchpoint Register Pairs */ + aarch64->wp_num = (uint32_t)((debug >> 20) & 0x0F) + 1; + aarch64->wp_num_available = aarch64->wp_num; + aarch64->wp_list = calloc(aarch64->wp_num, sizeof(struct aarch64_brp)); + for (i = 0; i < aarch64->wp_num; i++) { + aarch64->wp_list[i].used = 0; + aarch64->wp_list[i].type = BRP_NORMAL; + aarch64->wp_list[i].value = 0; + aarch64->wp_list[i].control = 0; + aarch64->wp_list[i].brpn = i; } - LOG_DEBUG("Configured %i hw breakpoints", aarch64->brp_num); + LOG_DEBUG("Configured %i hw breakpoints, %i watchpoints", + aarch64->brp_num, aarch64->wp_num); target->state = TARGET_UNKNOWN; target->debug_reason = DBG_REASON_NOTHALTED; @@ -2340,6 +2747,9 @@ static int aarch64_examine(struct target *target) if (retval == ERROR_OK) retval = aarch64_init_debug_access(target); + if (retval == ERROR_OK) + retval = aarch64_poll(target); + return retval; } @@ -2351,6 +2761,7 @@ static int aarch64_init_target(struct command_context *cmd_ctx, struct target *target) { /* examine_first() does a bunch of this */ + arm_semihosting_init(target); return ERROR_OK; } @@ -2370,19 +2781,47 @@ static int aarch64_init_arch_info(struct target *target, armv8->armv8_mmu.read_physical_memory = aarch64_read_phys_memory; armv8_init_arch_info(target, armv8); - target_register_timer_callback(aarch64_handle_target_request, 1, 1, target); + target_register_timer_callback(aarch64_handle_target_request, 1, + TARGET_TIMER_TYPE_PERIODIC, target); return ERROR_OK; } +static int armv8r_target_create(struct target *target, Jim_Interp *interp) +{ + struct aarch64_private_config *pc = target->private_config; + struct aarch64_common *aarch64; + + if (adiv5_verify_config(&pc->adiv5_config) != ERROR_OK) + return ERROR_FAIL; + + aarch64 = calloc(1, sizeof(struct aarch64_common)); + if (!aarch64) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + aarch64->armv8_common.is_armv8r = true; + + return aarch64_init_arch_info(target, aarch64, pc->adiv5_config.dap); +} + static int aarch64_target_create(struct target *target, Jim_Interp *interp) { struct aarch64_private_config *pc = target->private_config; - struct aarch64_common *aarch64 = calloc(1, sizeof(struct aarch64_common)); + struct aarch64_common *aarch64; if (adiv5_verify_config(&pc->adiv5_config) != ERROR_OK) return ERROR_FAIL; + aarch64 = calloc(1, sizeof(struct aarch64_common)); + if (!aarch64) { + LOG_ERROR("Out of memory"); + return ERROR_FAIL; + } + + aarch64->armv8_common.is_armv8r = false; + return aarch64_init_arch_info(target, aarch64, pc->adiv5_config.dap); } @@ -2392,6 +2831,9 @@ static void aarch64_deinit_target(struct target *target) struct armv8_common *armv8 = &aarch64->armv8_common; struct arm_dpm *dpm = &armv8->dpm; + if (armv8->debug_ap) + dap_put_ap(armv8->debug_ap); + armv8_free_reg_cache(target); free(aarch64->brp_list); free(dpm->dbp); @@ -2402,12 +2844,16 @@ static void aarch64_deinit_target(struct target *target) static int aarch64_mmu(struct target *target, int *enabled) { + struct aarch64_common *aarch64 = target_to_aarch64(target); + struct armv8_common *armv8 = &aarch64->armv8_common; if (target->state != TARGET_HALTED) { - LOG_ERROR("%s: target %s not halted", __func__, target_name(target)); - return ERROR_TARGET_INVALID; + LOG_TARGET_ERROR(target, "not halted"); + return ERROR_TARGET_NOT_HALTED; } - - *enabled = target_to_aarch64(target)->armv8_common.armv8_mmu.mmu_enabled; + if (armv8->is_armv8r) + *enabled = 0; + else + *enabled = target_to_aarch64(target)->armv8_common.armv8_mmu.mmu_enabled; return ERROR_OK; } @@ -2424,20 +2870,21 @@ enum aarch64_cfg_param { CFG_CTI, }; -static const Jim_Nvp nvp_config_opts[] = { +static const struct jim_nvp nvp_config_opts[] = { { .name = "-cti", .value = CFG_CTI }, { .name = NULL, .value = -1 } }; -static int aarch64_jim_configure(struct target *target, Jim_GetOptInfo *goi) +static int aarch64_jim_configure(struct target *target, struct jim_getopt_info *goi) { struct aarch64_private_config *pc; - Jim_Nvp *n; + struct jim_nvp *n; int e; pc = (struct aarch64_private_config *)target->private_config; - if (pc == NULL) { + if (!pc) { pc = calloc(1, sizeof(struct aarch64_private_config)); + pc->adiv5_config.ap_num = DP_APSEL_INVALID; target->private_config = pc; } @@ -2445,10 +2892,10 @@ static int aarch64_jim_configure(struct target *target, Jim_GetOptInfo *goi) * Call adiv5_jim_configure() to parse the common DAP options * It will return JIM_CONTINUE if it didn't find any known * options, JIM_OK if it correctly parsed the topmost option - * and JIM_ERR if an error occured during parameter evaluation. + * and JIM_ERR if an error occurred during parameter evaluation. * For JIM_CONTINUE, we check our own params. */ - e = adiv5_jim_configure(target, goi); + e = adiv5_jim_configure_ext(target, goi, &pc->adiv5_config, ADI_CONFIGURE_DAP_COMPULSORY); if (e != JIM_CONTINUE) return e; @@ -2457,12 +2904,12 @@ static int aarch64_jim_configure(struct target *target, Jim_GetOptInfo *goi) Jim_SetEmptyResult(goi->interp); /* check first if topmost item is for us */ - e = Jim_Nvp_name2value_obj(goi->interp, nvp_config_opts, + e = jim_nvp_name2value_obj(goi->interp, nvp_config_opts, goi->argv[0], &n); if (e != JIM_OK) return JIM_CONTINUE; - e = Jim_GetOpt_Obj(goi, NULL); + e = jim_getopt_obj(goi, NULL); if (e != JIM_OK) return e; @@ -2471,11 +2918,11 @@ static int aarch64_jim_configure(struct target *target, Jim_GetOptInfo *goi) if (goi->isconfigure) { Jim_Obj *o_cti; struct arm_cti *cti; - e = Jim_GetOpt_Obj(goi, &o_cti); + e = jim_getopt_obj(goi, &o_cti); if (e != JIM_OK) return e; cti = cti_instance_by_jim_obj(goi->interp, o_cti); - if (cti == NULL) { + if (!cti) { Jim_SetResultString(goi->interp, "CTI name invalid!", -1); return JIM_ERR; } @@ -2488,7 +2935,7 @@ static int aarch64_jim_configure(struct target *target, Jim_GetOptInfo *goi) return JIM_ERR; } - if (pc == NULL || pc->cti == NULL) { + if (!pc || !pc->cti) { Jim_SetResultString(goi->interp, "CTI not configured", -1); return JIM_ERR; } @@ -2510,11 +2957,10 @@ COMMAND_HANDLER(aarch64_handle_cache_info_command) struct target *target = get_current_target(CMD_CTX); struct armv8_common *armv8 = target_to_armv8(target); - return armv8_handle_cache_info_command(CMD_CTX, + return armv8_handle_cache_info_command(CMD, &armv8->armv8_mmu.armv8_cache); } - COMMAND_HANDLER(aarch64_handle_dbginit_command) { struct target *target = get_current_target(CMD_CTX); @@ -2525,41 +2971,38 @@ COMMAND_HANDLER(aarch64_handle_dbginit_command) return aarch64_init_debug_access(target); } -COMMAND_HANDLER(aarch64_handle_smp_off_command) + +COMMAND_HANDLER(aarch64_handle_disassemble_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; + + if (!target) { + LOG_ERROR("No target selected"); + return ERROR_FAIL; } - return ERROR_OK; -} -COMMAND_HANDLER(aarch64_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; - } + struct aarch64_common *aarch64 = target_to_aarch64(target); + + if (aarch64->common_magic != AARCH64_COMMON_MAGIC) { + command_print(CMD, "current target isn't an AArch64"); + return ERROR_FAIL; } - return ERROR_OK; + + int count = 1; + target_addr_t address; + + switch (CMD_ARGC) { + case 2: + COMMAND_PARSE_NUMBER(int, CMD_ARGV[1], count); + /* FALL THROUGH */ + case 1: + COMMAND_PARSE_ADDRESS(CMD_ARGV[0], address); + break; + default: + return ERROR_COMMAND_SYNTAX_ERROR; + } + + return a64_disassemble(CMD, target, address, count); } COMMAND_HANDLER(aarch64_mask_interrupts_command) @@ -2567,16 +3010,16 @@ COMMAND_HANDLER(aarch64_mask_interrupts_command) struct target *target = get_current_target(CMD_CTX); struct aarch64_common *aarch64 = target_to_aarch64(target); - static const Jim_Nvp nvp_maskisr_modes[] = { + static const struct nvp nvp_maskisr_modes[] = { { .name = "off", .value = AARCH64_ISRMASK_OFF }, { .name = "on", .value = AARCH64_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; } @@ -2584,147 +3027,113 @@ COMMAND_HANDLER(aarch64_mask_interrupts_command) aarch64->isrmasking_mode = n->value; } - n = Jim_Nvp_value2name_simple(nvp_maskisr_modes, aarch64->isrmasking_mode); - command_print(CMD_CTX, "aarch64 interrupt mask %s", n->name); + n = nvp_value2name(nvp_maskisr_modes, aarch64->isrmasking_mode); + command_print(CMD, "aarch64 interrupt mask %s", n->name); return ERROR_OK; } -static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv) +COMMAND_HANDLER(aarch64_mcrmrc_command) { - struct command_context *context; - struct target *target; - struct arm *arm; - int retval; bool is_mcr = false; - int arg_cnt = 0; + unsigned int arg_cnt = 5; - if (Jim_CompareStringImmediate(interp, argv[0], "mcr")) { + if (!strcmp(CMD_NAME, "mcr")) { is_mcr = true; - arg_cnt = 7; - } else { arg_cnt = 6; } - context = current_command_context(interp); - assert(context != NULL); + if (arg_cnt != CMD_ARGC) + return ERROR_COMMAND_SYNTAX_ERROR; - target = get_current_target(context); - if (target == NULL) { - LOG_ERROR("%s: no current target", __func__); - return JIM_ERR; + struct target *target = get_current_target(CMD_CTX); + if (!target) { + command_print(CMD, "no current target"); + return ERROR_FAIL; } if (!target_was_examined(target)) { - LOG_ERROR("%s: not yet examined", target_name(target)); - return JIM_ERR; + command_print(CMD, "%s: not yet examined", target_name(target)); + return ERROR_TARGET_NOT_EXAMINED; } - arm = target_to_arm(target); + struct arm *arm = target_to_arm(target); if (!is_arm(arm)) { - LOG_ERROR("%s: not an ARM", target_name(target)); - return JIM_ERR; + command_print(CMD, "%s: not an ARM", target_name(target)); + return ERROR_FAIL; } - if (target->state != TARGET_HALTED) + if (target->state != TARGET_HALTED) { + command_print(CMD, "Error: [%s] not halted", target_name(target)); return ERROR_TARGET_NOT_HALTED; - - if (arm->core_state == ARM_STATE_AARCH64) { - LOG_ERROR("%s: not 32-bit arm target", target_name(target)); - return JIM_ERR; } - if (argc != arg_cnt) { - LOG_ERROR("%s: wrong number of arguments", __func__); - return JIM_ERR; + if (arm->core_state == ARM_STATE_AARCH64) { + command_print(CMD, "%s: not 32-bit arm target", target_name(target)); + return ERROR_FAIL; } int cpnum; uint32_t op1; uint32_t op2; - uint32_t CRn; - uint32_t CRm; + uint32_t crn; + uint32_t crm; uint32_t value; - long l; /* NOTE: parameter sequence matches ARM instruction set usage: * MCR pNUM, op1, rX, CRn, CRm, op2 ; write CP from rX * MRC pNUM, op1, rX, CRn, CRm, op2 ; read CP into rX * The "rX" is necessarily omitted; it uses Tcl mechanisms. */ - retval = Jim_GetLong(interp, argv[1], &l); - if (retval != JIM_OK) - return retval; - if (l & ~0xf) { - LOG_ERROR("%s: %s %d out of range", __func__, - "coprocessor", (int) l); - return JIM_ERR; + COMMAND_PARSE_NUMBER(int, CMD_ARGV[0], cpnum); + if (cpnum & ~0xf) { + command_print(CMD, "coprocessor %d out of range", cpnum); + return ERROR_COMMAND_ARGUMENT_INVALID; } - cpnum = l; - retval = Jim_GetLong(interp, argv[2], &l); - if (retval != JIM_OK) - return retval; - if (l & ~0x7) { - LOG_ERROR("%s: %s %d out of range", __func__, - "op1", (int) l); - return JIM_ERR; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], op1); + if (op1 & ~0x7) { + command_print(CMD, "op1 %d out of range", op1); + return ERROR_COMMAND_ARGUMENT_INVALID; } - op1 = l; - retval = Jim_GetLong(interp, argv[3], &l); - if (retval != JIM_OK) - return retval; - if (l & ~0xf) { - LOG_ERROR("%s: %s %d out of range", __func__, - "CRn", (int) l); - return JIM_ERR; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], crn); + if (crn & ~0xf) { + command_print(CMD, "CRn %d out of range", crn); + return ERROR_COMMAND_ARGUMENT_INVALID; } - CRn = l; - retval = Jim_GetLong(interp, argv[4], &l); - if (retval != JIM_OK) - return retval; - if (l & ~0xf) { - LOG_ERROR("%s: %s %d out of range", __func__, - "CRm", (int) l); - return JIM_ERR; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], crm); + if (crm & ~0xf) { + command_print(CMD, "CRm %d out of range", crm); + return ERROR_COMMAND_ARGUMENT_INVALID; } - CRm = l; - retval = Jim_GetLong(interp, argv[5], &l); - if (retval != JIM_OK) - return retval; - if (l & ~0x7) { - LOG_ERROR("%s: %s %d out of range", __func__, - "op2", (int) l); - return JIM_ERR; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[4], op2); + if (op2 & ~0x7) { + command_print(CMD, "op2 %d out of range", op2); + return ERROR_COMMAND_ARGUMENT_INVALID; } - op2 = l; - - value = 0; - if (is_mcr == true) { - retval = Jim_GetLong(interp, argv[6], &l); - if (retval != JIM_OK) - return retval; - value = l; + if (is_mcr) { + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[5], value); /* NOTE: parameters reordered! */ - /* ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2) */ - retval = arm->mcr(target, cpnum, op1, op2, CRn, CRm, value); + /* ARMV4_5_MCR(cpnum, op1, 0, crn, crm, op2) */ + int retval = arm->mcr(target, cpnum, op1, op2, crn, crm, value); if (retval != ERROR_OK) - return JIM_ERR; + return retval; } else { + value = 0; /* NOTE: parameters reordered! */ - /* ARMV4_5_MRC(cpnum, op1, 0, CRn, CRm, op2) */ - retval = arm->mrc(target, cpnum, op1, op2, CRn, CRm, &value); + /* ARMV4_5_MRC(cpnum, op1, 0, crn, crm, op2) */ + int retval = arm->mrc(target, cpnum, op1, op2, crn, crm, &value); if (retval != ERROR_OK) - return JIM_ERR; + return retval; - Jim_SetResult(interp, Jim_NewIntObj(interp, value)); + command_print(CMD, "0x%" PRIx32, value); } - return JIM_OK; + return ERROR_OK; } static const struct command_registration aarch64_exec_command_handlers[] = { @@ -2742,18 +3151,12 @@ static const struct command_registration aarch64_exec_command_handlers[] = { .help = "Initialize core debug", .usage = "", }, - { .name = "smp_off", - .handler = aarch64_handle_smp_off_command, - .mode = COMMAND_EXEC, - .help = "Stop smp handling", - .usage = "", - }, { - .name = "smp_on", - .handler = aarch64_handle_smp_on_command, + .name = "disassemble", + .handler = aarch64_handle_disassemble_command, .mode = COMMAND_EXEC, - .help = "Restart smp handling", - .usage = "", + .help = "Disassemble instructions", + .usage = "address [count]", }, { .name = "maskisr", @@ -2765,23 +3168,33 @@ static const struct command_registration aarch64_exec_command_handlers[] = { { .name = "mcr", .mode = COMMAND_EXEC, - .jim_handler = jim_mcrmrc, + .handler = aarch64_mcrmrc_command, .help = "write coprocessor register", .usage = "cpnum op1 CRn CRm op2 value", }, { .name = "mrc", .mode = COMMAND_EXEC, - .jim_handler = jim_mcrmrc, + .handler = aarch64_mcrmrc_command, .help = "read coprocessor register", .usage = "cpnum op1 CRn CRm op2", }, + { + .chain = smp_command_handlers, + }, COMMAND_REGISTRATION_DONE }; static const struct command_registration aarch64_command_handlers[] = { + { + .name = "arm", + .mode = COMMAND_ANY, + .help = "ARM Command Group", + .usage = "", + .chain = semihosting_common_handlers + }, { .chain = armv8_command_handlers, }, @@ -2809,6 +3222,7 @@ struct target_type aarch64_target = { .deassert_reset = aarch64_deassert_reset, /* REVISIT allow exporting VFP3 registers ... */ + .get_gdb_arch = armv8_get_gdb_arch, .get_gdb_reg_list = armv8_get_gdb_reg_list, .read_memory = aarch64_read_memory, @@ -2818,8 +3232,9 @@ struct target_type aarch64_target = { .add_context_breakpoint = aarch64_add_context_breakpoint, .add_hybrid_breakpoint = aarch64_add_hybrid_breakpoint, .remove_breakpoint = aarch64_remove_breakpoint, - .add_watchpoint = NULL, - .remove_watchpoint = NULL, + .add_watchpoint = aarch64_add_watchpoint, + .remove_watchpoint = aarch64_remove_watchpoint, + .hit_watchpoint = aarch64_hit_watchpoint, .commands = aarch64_command_handlers, .target_create = aarch64_target_create, @@ -2833,3 +3248,39 @@ struct target_type aarch64_target = { .mmu = aarch64_mmu, .virt2phys = aarch64_virt2phys, }; + +struct target_type armv8r_target = { + .name = "armv8r", + + .poll = aarch64_poll, + .arch_state = armv8_arch_state, + + .halt = aarch64_halt, + .resume = aarch64_resume, + .step = aarch64_step, + + .assert_reset = aarch64_assert_reset, + .deassert_reset = aarch64_deassert_reset, + + /* REVISIT allow exporting VFP3 registers ... */ + .get_gdb_arch = armv8_get_gdb_arch, + .get_gdb_reg_list = armv8_get_gdb_reg_list, + + .read_memory = aarch64_read_phys_memory, + .write_memory = aarch64_write_phys_memory, + + .add_breakpoint = aarch64_add_breakpoint, + .add_context_breakpoint = aarch64_add_context_breakpoint, + .add_hybrid_breakpoint = aarch64_add_hybrid_breakpoint, + .remove_breakpoint = aarch64_remove_breakpoint, + .add_watchpoint = aarch64_add_watchpoint, + .remove_watchpoint = aarch64_remove_watchpoint, + .hit_watchpoint = aarch64_hit_watchpoint, + + .commands = aarch64_command_handlers, + .target_create = armv8r_target_create, + .target_jim_configure = aarch64_jim_configure, + .init_target = aarch64_init_target, + .deinit_target = aarch64_deinit_target, + .examine = aarch64_examine, +};