+ /* Handle asynchronous data faults. */
+ if (fault_dscr & DSCR_STICKY_ABORT_IMPRECISE) {
+ if (final_retval == ERROR_OK)
+ /* No other error has been recorded so far, so keep this one. */
+ final_retval = ERROR_TARGET_DATA_ABORT;
+ }
+
+ /* If the DCC is nonempty, clear it. */
+ if (dscr & DSCR_DTRTX_FULL_LATCHED) {
+ uint32_t dummy;
+ retval = mem_ap_read_atomic_u32(armv7a->debug_ap,
+ armv7a->debug_base + CPUDBG_DTRTX, &dummy);
+ if (final_retval == ERROR_OK)
+ final_retval = retval;
+ }
+ if (dscr & DSCR_DTRRX_FULL_LATCHED) {
+ retval = cortex_a_exec_opcode(target, ARMV4_5_MRC(14, 0, 1, 0, 5, 0), &dscr);
+ if (final_retval == ERROR_OK)
+ final_retval = retval;
+ }
+
+ /* Done. */
+ return final_retval;
+}
+
+static int cortex_a_read_cpu_memory_slow(struct target *target,
+ uint32_t size, uint32_t count, uint8_t *buffer, uint32_t *dscr)
+{
+ /* Reads count objects of size size into *buffer. Old value of DSCR must be
+ * in *dscr; updated to new value. This is slow because it works for
+ * non-word-sized objects and (maybe) unaligned accesses. If size == 4 and
+ * the address is aligned, cortex_a_read_cpu_memory_fast should be
+ * preferred.
+ * Preconditions:
+ * - Address is in R0.
+ * - R0 is marked dirty.
+ */
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+ struct arm *arm = &armv7a->arm;
+ int retval;
+
+ /* Mark register R1 as dirty, to use for transferring data. */
+ arm_reg_current(arm, 1)->dirty = true;
+
+ /* Switch to non-blocking mode if not already in that mode. */
+ retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, dscr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Go through the objects. */
+ while (count) {
+ /* Issue a load of the appropriate size to R1. */
+ uint32_t opcode, data;
+ if (size == 1)
+ opcode = ARMV4_5_LDRB_IP(1, 0);
+ else if (size == 2)
+ opcode = ARMV4_5_LDRH_IP(1, 0);
+ else
+ opcode = ARMV4_5_LDRW_IP(1, 0);
+ retval = cortex_a_exec_opcode(target, opcode, dscr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Issue a write of R1 to DTRTX. */
+ retval = cortex_a_exec_opcode(target, ARMV4_5_MCR(14, 0, 1, 0, 5, 0), dscr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Check for faults and return early. */
+ if (*dscr & (DSCR_STICKY_ABORT_PRECISE | DSCR_STICKY_ABORT_IMPRECISE))
+ return ERROR_OK; /* A data fault is not considered a system failure. */
+
+ /* Wait until DTRTX is full (according to ARMv7-A/-R architecture
+ * manual section C8.4.3, checking InstrCmpl_l is not sufficient; one
+ * must also check TXfull_l). Most of the time this will be free
+ * because TXfull_l will be set immediately and cached in dscr. */
+ retval = cortex_a_wait_dscr_bits(target, DSCR_DTRTX_FULL_LATCHED,
+ DSCR_DTRTX_FULL_LATCHED, dscr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Read the value transferred to DTRTX into the buffer. */
+ retval = mem_ap_read_atomic_u32(armv7a->debug_ap,
+ armv7a->debug_base + CPUDBG_DTRTX, &data);
+ if (retval != ERROR_OK)
+ return retval;
+ if (size == 1)
+ *buffer = (uint8_t) data;
+ else if (size == 2)
+ target_buffer_set_u16(target, buffer, (uint16_t) data);
+ else
+ target_buffer_set_u32(target, buffer, data);
+
+ /* Advance. */
+ buffer += size;
+ --count;
+ }
+
+ return ERROR_OK;
+}
+
+static int cortex_a_read_cpu_memory_fast(struct target *target,
+ uint32_t count, uint8_t *buffer, uint32_t *dscr)
+{
+ /* Reads count objects of size 4 into *buffer. Old value of DSCR must be in
+ * *dscr; updated to new value. This is fast but only works for word-sized
+ * objects at aligned addresses.
+ * Preconditions:
+ * - Address is in R0 and must be a multiple of 4.
+ * - R0 is marked dirty.
+ */
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+ uint32_t u32;
+ int retval;
+
+ /* Switch to non-blocking mode if not already in that mode. */
+ retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, dscr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Issue the LDC instruction via a write to ITR. */
+ retval = cortex_a_exec_opcode(target, ARMV4_5_LDC(0, 1, 0, 1, 14, 5, 0, 4), dscr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ count--;
+
+ if (count > 0) {
+ /* Switch to fast mode if not already in that mode. */
+ retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_FAST_MODE, dscr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Latch LDC instruction. */
+ retval = mem_ap_write_atomic_u32(armv7a->debug_ap,
+ armv7a->debug_base + CPUDBG_ITR, ARMV4_5_LDC(0, 1, 0, 1, 14, 5, 0, 4));
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Read the value transferred to DTRTX into the buffer. Due to fast
+ * mode rules, this blocks until the instruction finishes executing and
+ * then reissues the read instruction to read the next word from
+ * memory. The last read of DTRTX in this call reads the second-to-last
+ * word from memory and issues the read instruction for the last word.
+ */
+ retval = mem_ap_read_buf_noincr(armv7a->debug_ap, buffer,
+ 4, count, armv7a->debug_base + CPUDBG_DTRTX);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Advance. */
+ buffer += count * 4;
+ }
+
+ /* Wait for last issued instruction to complete. */
+ retval = cortex_a_wait_instrcmpl(target, dscr, false);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Switch to non-blocking mode if not already in that mode. */
+ retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, dscr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Check for faults and return early. */
+ if (*dscr & (DSCR_STICKY_ABORT_PRECISE | DSCR_STICKY_ABORT_IMPRECISE))
+ return ERROR_OK; /* A data fault is not considered a system failure. */
+
+ /* Wait until DTRTX is full (according to ARMv7-A/-R architecture manual
+ * section C8.4.3, checking InstrCmpl_l is not sufficient; one must also
+ * check TXfull_l). Most of the time this will be free because TXfull_l
+ * will be set immediately and cached in dscr. */
+ retval = cortex_a_wait_dscr_bits(target, DSCR_DTRTX_FULL_LATCHED,
+ DSCR_DTRTX_FULL_LATCHED, dscr);
+ if (retval != ERROR_OK)
+ return retval;
+
+ /* Read the value transferred to DTRTX into the buffer. This is the last
+ * word. */
+ retval = mem_ap_read_atomic_u32(armv7a->debug_ap,
+ armv7a->debug_base + CPUDBG_DTRTX, &u32);
+ if (retval != ERROR_OK)
+ return retval;
+ target_buffer_set_u32(target, buffer, u32);
+
+ return ERROR_OK;