-/*
- * AARCH64 implementation of Debug Programmer's Model
- *
- * NOTE the invariant: these routines return with DSCR_ITE set,
- * so there's no need to poll for it before executing an instruction.
- *
- * NOTE that in several of these cases the "stall" mode might be useful.
- * It'd let us queue a few operations together... prepare/finish might
- * be the places to enable/disable that mode.
- */
-
-static inline struct aarch64_common *dpm_to_a8(struct arm_dpm *dpm)
-{
- return container_of(dpm, struct aarch64_common, armv8_common.dpm);
-}
-
-static int aarch64_write_dcc(struct armv8_common *armv8, uint32_t data)
-{
- LOG_DEBUG("write DCC 0x%08" PRIx32, data);
- return mem_ap_write_u32(armv8->debug_ap,
- armv8->debug_base + CPUV8_DBG_DTRRX, data);
-}
-
-static int aarch64_write_dcc_64(struct armv8_common *armv8, uint64_t data)
-{
- int ret;
- LOG_DEBUG("write DCC Low word0x%08" PRIx32, (unsigned)data);
- LOG_DEBUG("write DCC High word 0x%08" PRIx32, (unsigned)(data >> 32));
- ret = mem_ap_write_u32(armv8->debug_ap,
- armv8->debug_base + CPUV8_DBG_DTRRX, data);
- ret += mem_ap_write_u32(armv8->debug_ap,
- armv8->debug_base + CPUV8_DBG_DTRTX, data >> 32);
- return ret;
-}
-
-static int aarch64_read_dcc(struct armv8_common *armv8, uint32_t *data,
- uint32_t *dscr_p)
-{
- uint32_t dscr = DSCR_ITE;
- int retval;
-
- if (dscr_p)
- dscr = *dscr_p;
-
- /* Wait for DTRRXfull */
- long long then = timeval_ms();
- while ((dscr & DSCR_DTR_TX_FULL) == 0) {
- retval = mem_ap_read_atomic_u32(armv8->debug_ap,
- armv8->debug_base + CPUV8_DBG_DSCR,
- &dscr);
- if (retval != ERROR_OK)
- return retval;
- if (timeval_ms() > then + 1000) {
- LOG_ERROR("Timeout waiting for read dcc");
- return ERROR_FAIL;
- }
- }
-
- retval = mem_ap_read_atomic_u32(armv8->debug_ap,
- armv8->debug_base + CPUV8_DBG_DTRTX,
- data);
- if (retval != ERROR_OK)
- return retval;
- LOG_DEBUG("read DCC 0x%08" PRIx32, *data);
-
- if (dscr_p)
- *dscr_p = dscr;
-
- return retval;
-}
-
-static int aarch64_read_dcc_64(struct armv8_common *armv8, uint64_t *data,
- uint32_t *dscr_p)
-{
- uint32_t dscr = DSCR_ITE;
- uint32_t higher;
- int retval;
-
- if (dscr_p)
- dscr = *dscr_p;
-
- /* Wait for DTRRXfull */
- long long then = timeval_ms();
- while ((dscr & DSCR_DTR_TX_FULL) == 0) {
- retval = mem_ap_read_atomic_u32(armv8->debug_ap,
- armv8->debug_base + CPUV8_DBG_DSCR,
- &dscr);
- if (retval != ERROR_OK)
- return retval;
- if (timeval_ms() > then + 1000) {
- LOG_ERROR("Timeout waiting for read dcc");
- return ERROR_FAIL;
- }
- }
-
- retval = mem_ap_read_atomic_u32(armv8->debug_ap,
- armv8->debug_base + CPUV8_DBG_DTRTX,
- (uint32_t *)data);
- if (retval != ERROR_OK)
- return retval;
-
- retval = mem_ap_read_atomic_u32(armv8->debug_ap,
- armv8->debug_base + CPUV8_DBG_DTRRX,
- &higher);
- if (retval != ERROR_OK)
- return retval;
-
- *data = *(uint32_t *)data | (uint64_t)higher << 32;
- LOG_DEBUG("read DCC 0x%16.16" PRIx64, *data);
-
- if (dscr_p)
- *dscr_p = dscr;
-
- return retval;
-}
-
-static int aarch64_dpm_prepare(struct arm_dpm *dpm)
-{
- struct aarch64_common *a8 = dpm_to_a8(dpm);
- uint32_t dscr;
- int retval;
-
- /* set up invariant: INSTR_COMP is set after ever DPM operation */
- long long then = timeval_ms();
- for (;; ) {
- retval = mem_ap_read_atomic_u32(a8->armv8_common.debug_ap,
- a8->armv8_common.debug_base + CPUV8_DBG_DSCR,
- &dscr);
- if (retval != ERROR_OK)
- return retval;
- if ((dscr & DSCR_ITE) != 0)
- break;
- if (timeval_ms() > then + 1000) {
- LOG_ERROR("Timeout waiting for dpm prepare");
- return ERROR_FAIL;
- }
- }
-
- /* this "should never happen" ... */
- if (dscr & DSCR_DTR_RX_FULL) {
- LOG_ERROR("DSCR_DTR_RX_FULL, dscr 0x%08" PRIx32, dscr);
- /* Clear DCCRX */
- retval = mem_ap_read_u32(a8->armv8_common.debug_ap,
- a8->armv8_common.debug_base + CPUV8_DBG_DTRRX, &dscr);
- if (retval != ERROR_OK)
- return retval;
-
- /* Clear sticky error */
- retval = mem_ap_write_u32(a8->armv8_common.debug_ap,
- a8->armv8_common.debug_base + CPUV8_DBG_DRCR, DRCR_CSE);
- if (retval != ERROR_OK)
- return retval;
- }
-
- return retval;
-}
-
-static int aarch64_dpm_finish(struct arm_dpm *dpm)
-{
- /* REVISIT what could be done here? */
- return ERROR_OK;
-}
-
-static int aarch64_instr_execute(struct arm_dpm *dpm,
- uint32_t opcode)
-{
- struct aarch64_common *a8 = dpm_to_a8(dpm);
- uint32_t dscr = DSCR_ITE;
-
- return aarch64_exec_opcode(
- a8->armv8_common.arm.target,
- opcode,
- &dscr);
-}
-
-static int aarch64_instr_write_data_dcc(struct arm_dpm *dpm,
- uint32_t opcode, uint32_t data)
-{
- struct aarch64_common *a8 = dpm_to_a8(dpm);
- int retval;
- uint32_t dscr = DSCR_ITE;
-
- retval = aarch64_write_dcc(&a8->armv8_common, data);
- if (retval != ERROR_OK)
- return retval;
-
- return aarch64_exec_opcode(
- a8->armv8_common.arm.target,
- opcode,
- &dscr);
-}
-
-static int aarch64_instr_write_data_dcc_64(struct arm_dpm *dpm,
- uint32_t opcode, uint64_t data)
-{
- struct aarch64_common *a8 = dpm_to_a8(dpm);
- int retval;
- uint32_t dscr = DSCR_ITE;
-
- retval = aarch64_write_dcc_64(&a8->armv8_common, data);
- if (retval != ERROR_OK)
- return retval;
-
- return aarch64_exec_opcode(
- a8->armv8_common.arm.target,
- opcode,
- &dscr);
-}
-
-static int aarch64_instr_write_data_r0(struct arm_dpm *dpm,
- uint32_t opcode, uint32_t data)
-{
- struct aarch64_common *a8 = dpm_to_a8(dpm);
- uint32_t dscr = DSCR_ITE;
- int retval;
-
- retval = aarch64_write_dcc(&a8->armv8_common, data);
- if (retval != ERROR_OK)
- return retval;
-
- retval = aarch64_exec_opcode(
- a8->armv8_common.arm.target,
- ARMV8_MRS(SYSTEM_DBG_DTRRX_EL0, 0),
- &dscr);
- if (retval != ERROR_OK)
- return retval;
-
- /* then the opcode, taking data from R0 */
- retval = aarch64_exec_opcode(
- a8->armv8_common.arm.target,
- opcode,
- &dscr);
-
- return retval;
-}
-
-static int aarch64_instr_write_data_r0_64(struct arm_dpm *dpm,
- uint32_t opcode, uint64_t data)
-{
- struct aarch64_common *a8 = dpm_to_a8(dpm);
- uint32_t dscr = DSCR_ITE;
- int retval;
-
- retval = aarch64_write_dcc_64(&a8->armv8_common, data);
- if (retval != ERROR_OK)
- return retval;
-
- retval = aarch64_exec_opcode(
- a8->armv8_common.arm.target,
- ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0, 0),
- &dscr);
- if (retval != ERROR_OK)
- return retval;
-
- /* then the opcode, taking data from R0 */
- retval = aarch64_exec_opcode(
- a8->armv8_common.arm.target,
- opcode,
- &dscr);
-
- return retval;
-}
-
-static int aarch64_instr_cpsr_sync(struct arm_dpm *dpm)
-{
- struct target *target = dpm->arm->target;
- uint32_t dscr = DSCR_ITE;
-
- /* "Prefetch flush" after modifying execution status in CPSR */
- return aarch64_exec_opcode(target,
- DSB_SY,
- &dscr);
-}
-
-static int aarch64_instr_read_data_dcc(struct arm_dpm *dpm,
- uint32_t opcode, uint32_t *data)
-{
- struct aarch64_common *a8 = dpm_to_a8(dpm);
- int retval;
- uint32_t dscr = DSCR_ITE;
-
- /* the opcode, writing data to DCC */
- retval = aarch64_exec_opcode(
- a8->armv8_common.arm.target,
- opcode,
- &dscr);
- if (retval != ERROR_OK)
- return retval;
-
- return aarch64_read_dcc(&a8->armv8_common, data, &dscr);
-}
-
-static int aarch64_instr_read_data_dcc_64(struct arm_dpm *dpm,
- uint32_t opcode, uint64_t *data)
-{
- struct aarch64_common *a8 = dpm_to_a8(dpm);
- int retval;
- uint32_t dscr = DSCR_ITE;
-
- /* the opcode, writing data to DCC */
- retval = aarch64_exec_opcode(
- a8->armv8_common.arm.target,
- opcode,
- &dscr);
- if (retval != ERROR_OK)
- return retval;
-
- return aarch64_read_dcc_64(&a8->armv8_common, data, &dscr);
-}
-
-static int aarch64_instr_read_data_r0(struct arm_dpm *dpm,
- uint32_t opcode, uint32_t *data)
-{
- struct aarch64_common *a8 = dpm_to_a8(dpm);
- uint32_t dscr = DSCR_ITE;
- int retval;
-
- /* the opcode, writing data to R0 */
- retval = aarch64_exec_opcode(
- a8->armv8_common.arm.target,
- opcode,
- &dscr);
- if (retval != ERROR_OK)
- return retval;
-
- /* write R0 to DCC */
- retval = aarch64_exec_opcode(
- a8->armv8_common.arm.target,
- ARMV8_MSR_GP(SYSTEM_DBG_DTRTX_EL0, 0), /* msr dbgdtr_el0, x0 */
- &dscr);
- if (retval != ERROR_OK)
- return retval;
-
- return aarch64_read_dcc(&a8->armv8_common, data, &dscr);
-}
-
-static int aarch64_instr_read_data_r0_64(struct arm_dpm *dpm,
- uint32_t opcode, uint64_t *data)
-{
- struct aarch64_common *a8 = dpm_to_a8(dpm);
- uint32_t dscr = DSCR_ITE;
- int retval;
-
- /* the opcode, writing data to R0 */
- retval = aarch64_exec_opcode(
- a8->armv8_common.arm.target,
- opcode,
- &dscr);
- if (retval != ERROR_OK)
- return retval;
-
- /* write R0 to DCC */
- retval = aarch64_exec_opcode(
- a8->armv8_common.arm.target,
- ARMV8_MSR_GP(SYSTEM_DBG_DBGDTR_EL0, 0), /* msr dbgdtr_el0, x0 */
- &dscr);
- if (retval != ERROR_OK)
- return retval;
-
- return aarch64_read_dcc_64(&a8->armv8_common, data, &dscr);
-}
-
-static int aarch64_bpwp_enable(struct arm_dpm *dpm, unsigned index_t,
- uint32_t addr, uint32_t control)
-{
- struct aarch64_common *a8 = dpm_to_a8(dpm);
- uint32_t vr = a8->armv8_common.debug_base;
- uint32_t cr = a8->armv8_common.debug_base;
- int retval;
-
- switch (index_t) {
- case 0 ... 15: /* breakpoints */
- vr += CPUV8_DBG_BVR_BASE;
- cr += CPUV8_DBG_BCR_BASE;
- break;
- case 16 ... 31: /* watchpoints */
- vr += CPUV8_DBG_WVR_BASE;
- cr += CPUV8_DBG_WCR_BASE;
- index_t -= 16;
- break;
- default:
- return ERROR_FAIL;
- }
- vr += 16 * index_t;
- cr += 16 * index_t;
-
- LOG_DEBUG("A8: bpwp enable, vr %08x cr %08x",
- (unsigned) vr, (unsigned) cr);
-
- retval = aarch64_dap_write_memap_register_u32(dpm->arm->target,
- vr, addr);
- if (retval != ERROR_OK)
- return retval;
- retval = aarch64_dap_write_memap_register_u32(dpm->arm->target,
- cr, control);
- return retval;
-}
-
-static int aarch64_bpwp_disable(struct arm_dpm *dpm, unsigned index_t)
-{
- struct aarch64_common *a = dpm_to_a8(dpm);
- uint32_t cr;
-
- switch (index_t) {
- case 0 ... 15:
- cr = a->armv8_common.debug_base + CPUV8_DBG_BCR_BASE;
- break;
- case 16 ... 31:
- cr = a->armv8_common.debug_base + CPUV8_DBG_WCR_BASE;
- index_t -= 16;
- break;
- default:
- return ERROR_FAIL;
- }
- cr += 16 * index_t;
-
- LOG_DEBUG("A: bpwp disable, cr %08x", (unsigned) cr);
-
- /* clear control register */
- return aarch64_dap_write_memap_register_u32(dpm->arm->target, cr, 0);
-
-}
-