+ if (size == 4 && (address % 4) == 0) {
+ /* We are doing a word-aligned transfer, so use fast mode. */
+ retval = cortex_a_write_cpu_memory_fast(target, count, buffer, &dscr);
+ } else {
+ /* Use slow path. */
+ retval = cortex_a_write_cpu_memory_slow(target, size, count, buffer, &dscr);
+ }
+
+out:
+ final_retval = 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 (final_retval == ERROR_OK)
+ final_retval = retval;
+
+ /* Wait for last issued instruction to complete. */
+ retval = cortex_a_wait_instrcmpl(target, &dscr, true);
+ if (final_retval == ERROR_OK)
+ final_retval = retval;
+
+ /* Wait until DTRRX is empty (according to ARMv7-A/-R architecture manual
+ * section C8.4.3, checking InstrCmpl_l is not sufficient; one must also
+ * check RXfull_l). Most of the time this will be free because RXfull_l
+ * will be cleared immediately and cached in dscr. However, don't do this
+ * if there is fault, because then the instruction might not have completed
+ * successfully. */
+ if (!(dscr & DSCR_STICKY_ABORT_PRECISE)) {
+ retval = cortex_a_wait_dscr_bits(target, DSCR_DTRRX_FULL_LATCHED, 0, &dscr);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
+ /* If there were any sticky abort flags, clear them. */
+ if (dscr & (DSCR_STICKY_ABORT_PRECISE | DSCR_STICKY_ABORT_IMPRECISE)) {
+ fault_dscr = dscr;
+ mem_ap_write_atomic_u32(armv7a->debug_ap,
+ armv7a->debug_base + CPUDBG_DRCR, DRCR_CLEAR_EXCEPTIONS);
+ dscr &= ~(DSCR_STICKY_ABORT_PRECISE | DSCR_STICKY_ABORT_IMPRECISE);
+ } else {
+ fault_dscr = 0;
+ }
+
+ /* Handle synchronous data faults. */
+ if (fault_dscr & DSCR_STICKY_ABORT_PRECISE) {
+ if (final_retval == ERROR_OK) {
+ /* Final return value will reflect cause of fault. */
+ retval = cortex_a_read_dfar_dfsr(target, &fault_dfar, &fault_dfsr, &dscr);
+ if (retval == ERROR_OK) {
+ LOG_ERROR("data abort at 0x%08" PRIx32 ", dfsr = 0x%08" PRIx32, fault_dfar, fault_dfsr);
+ final_retval = cortex_a_dfsr_to_error_code(fault_dfsr);
+ } else
+ final_retval = retval;
+ }
+ /* Fault destroyed DFAR/DFSR; restore them. */
+ retval = cortex_a_write_dfar_dfsr(target, orig_dfar, orig_dfsr, &dscr);
+ if (retval != ERROR_OK)
+ LOG_ERROR("error restoring dfar/dfsr - dscr = 0x%08" PRIx32, dscr);
+ }
+
+ /* 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.