#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 <helper/time_support.h>
case ARM_MODE_ABT:
case ARM_MODE_FIQ:
case ARM_MODE_IRQ:
+ case ARM_MODE_HYP:
case ARM_MODE_SYS:
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;
}
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) {
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);
case ARM_MODE_ABT:
case ARM_MODE_FIQ:
case ARM_MODE_IRQ:
+ case ARM_MODE_HYP:
case ARM_MODE_SYS:
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,
aarch64->system_control_reg_curr);
+
+ if (target_mode != ARM_MODE_ANY)
+ armv8_dpm_modeswitch(&armv8->dpm, ARM_MODE_ANY);
+
return retval;
}
/* 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;
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;
LOG_DEBUG("target %s prepared", target_name(curr));
- if (first == NULL)
+ if (!first)
first = curr;
}
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)
}
/* 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;
break;
}
/* remember the first valid target in the group */
- if (first == NULL)
+ if (!first)
first = curr;
}
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));
/* 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);
case ARM_MODE_ABT:
case ARM_MODE_FIQ:
case ARM_MODE_IRQ:
+ case ARM_MODE_HYP:
case ARM_MODE_SYS:
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 (saved_retval != ERROR_OK)
return saved_retval;
- return aarch64_poll(target);
+ return ERROR_OK;
}
static int aarch64_restore_context(struct target *target, bool bpwp)
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;
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->length, 1,
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;
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;
(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;
(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;
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;
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;
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;
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;
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);
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.
*/
- jtag_add_reset(0, 1);
+ if (!srst_asserted)
+ adapter_assert_reset();
} else {
LOG_ERROR("%s: how to reset?", target_name(target));
return ERROR_FAIL;
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_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,
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;
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);
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;
retval = dap_get_debugbase(armv8->debug_ap, &dbgbase, &apid);
if (retval != ERROR_OK)
return retval;
- /* Lookup 0x15 -- Processor DAP */
- retval = dap_lookup_cs_component(armv8->debug_ap, dbgbase, 0x15,
+ /* Lookup Processor DAP */
+ retval = dap_lookup_cs_component(armv8->debug_ap, dbgbase, ARM_CS_C9_DEVTYPE_CORE_DEBUG,
&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;
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;
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;
return ERROR_FAIL;
aarch64 = calloc(1, sizeof(struct aarch64_common));
- if (aarch64 == NULL) {
+ if (!aarch64) {
LOG_ERROR("Out of memory");
return ERROR_FAIL;
}
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;
}
* 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.
+ *
+ * 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;
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;
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;
}
return JIM_ERR;
}
- if (pc == NULL || pc->cti == NULL) {
+ if (!pc || !pc->cti) {
Jim_SetResultString(goi->interp, "CTI not configured", -1);
return JIM_ERR;
}
&armv8->armv8_mmu.armv8_cache);
}
-
COMMAND_HANDLER(aarch64_handle_dbginit_command)
{
struct target *target = get_current_target(CMD_CTX);
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;
}
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;
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;
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 {
}
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;
}
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;
"CRn", (int) l);
return JIM_ERR;
}
- CRn = l;
+ crn = l;
retval = Jim_GetLong(interp, argv[4], &l);
if (retval != JIM_OK)
"CRm", (int) l);
return JIM_ERR;
}
- CRm = l;
+ crm = l;
retval = Jim_GetLong(interp, argv[5], &l);
if (retval != JIM_OK)
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;
.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,
COMMAND_REGISTRATION_DONE
};
+extern const struct command_registration semihosting_common_handlers[];
+
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,
},
.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,