X-Git-Url: https://git.gag.com/?a=blobdiff_plain;f=src%2Ftarget%2Faarch64.c;h=70e727cf9d42334a2d304ceeba4607446ca800f5;hb=cdb6ea4f9ff6f61dc4eeadab4dd3edd5d49ab88e;hp=e6b1cc0076c54568fb15c1b911690d4f0517b172;hpb=480ba8ca88e3f12bb60498b35de5fc4b74d0511d;p=fw%2Fopenocd diff --git a/src/target/aarch64.c b/src/target/aarch64.c index e6b1cc007..70e727cf9 100644 --- a/src/target/aarch64.c +++ b/src/target/aarch64.c @@ -23,6 +23,7 @@ #include "breakpoints.h" #include "aarch64.h" +#include "a64_disassembler.h" #include "register.h" #include "target_request.h" #include "target_type.h" @@ -105,7 +106,7 @@ static int aarch64_restore_system_control_reg(struct target *target) break; default: - LOG_ERROR("cannot read system control register in this mode: (%s : 0x%" PRIx32 ")", + 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; } @@ -132,6 +133,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) { @@ -157,6 +159,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); @@ -180,12 +184,18 @@ static int aarch64_mmu_modify(struct target *target, int enable) 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, aarch64->system_control_reg_curr); + + if (target_mode != ARM_MODE_ANY) + armv8_dpm_modeswitch(&armv8->dpm, ARM_MODE_ANY); + return retval; } @@ -242,7 +252,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; @@ -325,7 +335,7 @@ static int aarch64_prepare_halt_smp(struct target *target, bool exc_target, stru LOG_DEBUG("target %s exc %i", target_name(target), exc_target); - while (head != NULL) { + while (head) { struct target *curr = head->target; struct armv8_common *armv8 = target_to_armv8(curr); head = head->next; @@ -349,7 +359,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; } @@ -478,7 +488,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) @@ -491,7 +501,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; @@ -752,7 +762,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; } @@ -775,7 +785,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)); @@ -978,25 +988,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); @@ -1042,7 +1053,7 @@ static int aarch64_post_debug_entry(struct target *target) break; default: - LOG_ERROR("cannot read system control register in this mode: (%s : 0x%" PRIx32 ")", + 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; } @@ -1248,18 +1259,18 @@ static int aarch64_set_breakpoint(struct target *target, 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; @@ -1366,12 +1377,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; @@ -1387,11 +1398,11 @@ 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; @@ -1405,7 +1416,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; @@ -1415,53 +1426,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->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].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; @@ -1484,7 +1495,7 @@ static int aarch64_unset_breakpoint(struct target *target, struct breakpoint *br if (breakpoint->type == BKPT_HARD) { if ((breakpoint->address != 0) && (breakpoint->asid != 0)) { int brp_i = breakpoint->set - 1; - int brp_j = breakpoint->linked_BRP; + int brp_j = breakpoint->linked_brp; if ((brp_i < 0) || (brp_i >= aarch64->brp_num)) { LOG_DEBUG("Invalid BRP number in breakpoint"); return ERROR_OK; @@ -1495,17 +1506,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; @@ -1519,22 +1530,22 @@ 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->linked_brp = 0; breakpoint->set = 0; return ERROR_OK; @@ -1550,18 +1561,18 @@ 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; @@ -1650,7 +1661,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); @@ -1672,26 +1682,295 @@ 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->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 = wp_i + 1; + + return ERROR_OK; +} + +/* Clear hardware Watchpoint Register Pair */ +static int aarch64_unset_watchpoint(struct target *target, + struct watchpoint *watchpoint) +{ + int retval, wp_i; + 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->set) { + LOG_WARNING("watchpoint not set"); + return ERROR_OK; + } + + wp_i = watchpoint->set - 1; + if ((wp_i < 0) || (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->set = 0; + + 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->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 + */ +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) { + 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. */ - adapter_assert_reset(); + if (!srst_asserted) + adapter_assert_reset(); } else { LOG_ERROR("%s: how to reset?", target_name(target)); return ERROR_FAIL; @@ -1720,23 +1999,37 @@ static int aarch64_deassert_reset(struct target *target) if (!target_was_examined(target)) return ERROR_OK; - retval = aarch64_poll(target); + retval = aarch64_init_debug_access(target); if (retval != ERROR_OK) return retval; - retval = aarch64_init_debug_access(target); + 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; } } - return retval; + return ERROR_OK; } static int aarch64_write_cpu_memory_slow(struct target *target, @@ -2247,7 +2540,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; @@ -2255,11 +2548,18 @@ 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 (pc->adiv5_config.ap_num == DP_APSEL_INVALID) { + /* Search for the APB-AB */ + 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; + } + } else { + armv8->debug_ap = dap_ap(swjdp, pc->adiv5_config.ap_num); } retval = mem_ap_init(armv8->debug_ap); @@ -2271,7 +2571,7 @@ static int aarch64_examine_first(struct target *target) armv8->debug_ap->memaccess_tck = 10; if (!target->dbgbase_set) { - uint32_t dbgbase; + target_addr_t dbgbase; /* Get ROM Table base */ uint32_t apid; int32_t coreidx = target->coreid; @@ -2283,7 +2583,7 @@ static int aarch64_examine_first(struct target *target) &armv8->debug_base, &coreidx); if (retval != ERROR_OK) return retval; - LOG_DEBUG("Detected core %" PRId32 " dbgbase: %08" PRIx32 + LOG_DEBUG("Detected core %" PRId32 " dbgbase: " TARGET_ADDR_FMT " apid: %08" PRIx32, coreidx, armv8->debug_base, apid); } else armv8->debug_base = target->dbgbase; @@ -2334,11 +2634,7 @@ 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) return ERROR_FAIL; armv8->cti = pc->cti; @@ -2360,10 +2656,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; } - LOG_DEBUG("Configured %i hw breakpoints", aarch64->brp_num); + /* 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, %i watchpoints", + aarch64->brp_num, aarch64->wp_num); target->state = TARGET_UNKNOWN; target->debug_reason = DBG_REASON_NOTHALTED; @@ -2430,7 +2739,7 @@ static int aarch64_target_create(struct target *target, Jim_Interp *interp) return ERROR_FAIL; aarch64 = calloc(1, sizeof(struct aarch64_common)); - if (aarch64 == NULL) { + if (!aarch64) { LOG_ERROR("Out of memory"); return ERROR_FAIL; } @@ -2476,20 +2785,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; } @@ -2499,8 +2809,13 @@ static int aarch64_jim_configure(struct target *target, Jim_GetOptInfo *goi) * options, JIM_OK if it correctly parsed the topmost option * and JIM_ERR if an error occurred during parameter evaluation. * For JIM_CONTINUE, we check our own params. + * + * adiv5_jim_configure() assumes 'private_config' to point to + * 'struct adiv5_private_config'. Override 'private_config'! */ + target->private_config = &pc->adiv5_config; e = adiv5_jim_configure(target, goi); + target->private_config = pc; if (e != JIM_CONTINUE) return e; @@ -2509,12 +2824,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; @@ -2523,11 +2838,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; } @@ -2540,7 +2855,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; } @@ -2566,7 +2881,6 @@ COMMAND_HANDLER(aarch64_handle_cache_info_command) &armv8->armv8_mmu.armv8_cache); } - COMMAND_HANDLER(aarch64_handle_dbginit_command) { struct target *target = get_current_target(CMD_CTX); @@ -2578,21 +2892,54 @@ COMMAND_HANDLER(aarch64_handle_dbginit_command) return aarch64_init_debug_access(target); } +COMMAND_HANDLER(aarch64_handle_disassemble_command) +{ + struct target *target = get_current_target(CMD_CTX); + + if (!target) { + LOG_ERROR("No target selected"); + return ERROR_FAIL; + } + + 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; + } + + 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) { 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 jim_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 jim_nvp *n; if (CMD_ARGC > 0) { - n = Jim_Nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]); - if (n->name == NULL) { + n = jim_nvp_name2value_simple(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; } @@ -2600,7 +2947,7 @@ COMMAND_HANDLER(aarch64_mask_interrupts_command) aarch64->isrmasking_mode = n->value; } - n = Jim_Nvp_value2name_simple(nvp_maskisr_modes, aarch64->isrmasking_mode); + n = jim_nvp_value2name_simple(nvp_maskisr_modes, aarch64->isrmasking_mode); command_print(CMD, "aarch64 interrupt mask %s", n->name); return ERROR_OK; @@ -2608,6 +2955,7 @@ COMMAND_HANDLER(aarch64_mask_interrupts_command) static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { + struct command *c = jim_to_command(interp); struct command_context *context; struct target *target; struct arm *arm; @@ -2615,7 +2963,7 @@ static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv) bool is_mcr = false; int arg_cnt = 0; - if (Jim_CompareStringImmediate(interp, argv[0], "mcr")) { + if (!strcmp(c->name, "mcr")) { is_mcr = true; arg_cnt = 7; } else { @@ -2623,10 +2971,10 @@ static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv) } context = current_command_context(interp); - assert(context != NULL); + assert(context); target = get_current_target(context); - if (target == NULL) { + if (!target) { LOG_ERROR("%s: no current target", __func__); return JIM_ERR; } @@ -2657,8 +3005,8 @@ static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv) 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; @@ -2695,7 +3043,7 @@ static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv) "CRn", (int) l); return JIM_ERR; } - CRn = l; + crn = l; retval = Jim_GetLong(interp, argv[4], &l); if (retval != JIM_OK) @@ -2705,7 +3053,7 @@ static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv) "CRm", (int) l); return JIM_ERR; } - CRm = l; + crm = l; retval = Jim_GetLong(interp, argv[5], &l); if (retval != JIM_OK) @@ -2726,14 +3074,14 @@ static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv) value = l; /* 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) */ + retval = arm->mcr(target, cpnum, op1, op2, crn, crm, value); if (retval != ERROR_OK) return JIM_ERR; } else { /* 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) */ + retval = arm->mrc(target, cpnum, op1, op2, crn, crm, &value); if (retval != ERROR_OK) return JIM_ERR; @@ -2758,6 +3106,13 @@ static const struct command_registration aarch64_exec_command_handlers[] = { .help = "Initialize core debug", .usage = "", }, + { + .name = "disassemble", + .handler = aarch64_handle_disassemble_command, + .mode = COMMAND_EXEC, + .help = "Disassemble instructions", + .usage = "address [count]", + }, { .name = "maskisr", .handler = aarch64_mask_interrupts_command, @@ -2834,8 +3189,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,