Skip to content

Commit da66734

Browse files
committed
cortexr: Began overhauling cortexr_mem_write() to support writing memory properly as it requires ajump from the debug to system busses on Cortex-A and -R targets
1 parent 6df753f commit da66734

File tree

1 file changed

+40
-1
lines changed

1 file changed

+40
-1
lines changed

src/target/cortexr.c

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,15 +200,21 @@ static const uint16_t cortexr_spsr_encodings[5] = {
200200
/*
201201
* Instruction encodings for coprocessor load/store
202202
* LDC -> Load Coprocessor (DDI0406C §A8.8.56, pg393)
203+
* STC -> Store Corprocessor (DDI0406C §A8.8.119, pg663)
203204
*/
204205
#define ARM_LDC_INSN 0xec100000U
206+
#define ARM_STC_INSN 0xec000000U
205207
/*
206208
* Pre-encoded LDC/STC operands for getting data in and out of the core
207209
* The first is a LDC encoded to move [r0] to the debug DTR and then increment r0 by 4
208210
* (`LDC p14, c5, [r0], #+4`, Preincrement = 0, Unindexed = 1, Doublelength = 0, Writeback = 1)
209211
* The immediate is encoded shifted right by 2, and the reads are done 32 bits at a time.
212+
* The second is a STC encoded to move from the debug DTR to [r0] and then increment r0 by 4
213+
* (`STC p14, c5, [r0], #+4`, Preincrement = 0, Unindexed = 1, Doublelength = 0, Writeback = 1)
214+
* As with read, the immediate is encoded shifted right by 2 and writes are done 32 bits at a time.
210215
*/
211216
#define ARM_LDC_R0_POSTINC4_DTRTX_INSN (ARM_LDC_INSN | 0x00a05e01U)
217+
#define ARM_STC_DTRRX_R0_POSTINC4_INSN (ARM_STC_INSN | 0x00a05e01U)
212218

213219
/*
214220
* Instruction encodings for indirect loads and stores of data via the CPU
@@ -805,9 +811,42 @@ static void cortexr_mem_read(target_s *const target, void *const dest, const tar
805811
cortexr_mem_handle_fault(target, __func__, fault_status, fault_addr);
806812
}
807813

814+
/* Fast path for cortexr_mem_write(). Assumes the address to read data from is already loaded in r0. */
815+
static inline bool cortexr_mem_write_fast(target_s *const target, const uint32_t *const src, const size_t count)
816+
{
817+
/* Read each of the uint32_t's checking for failure */
818+
for (size_t offset = 0; offset < count; ++offset) {
819+
if (!cortexr_run_write_insn(target, ARM_STC_DTRRX_R0_POSTINC4_INSN, src[offset]))
820+
return false; /* Propagate failure if it happens */
821+
}
822+
return true; /* Signal success */
823+
}
824+
825+
/*
826+
* This writes memory by jumping from the debug unit bus to the system bus.
827+
* NB: This requires the core to be halted! Uses instruction launches on
828+
* the core and requires we're in debug mode to work. Trashes r0.
829+
*/
808830
static void cortexr_mem_write(target_s *const target, const target_addr_t dest, const void *const src, const size_t len)
809831
{
810-
adiv5_mem_write(cortex_ap(target), dest, src, len);
832+
cortexr_priv_s *const priv = (cortexr_priv_s *)target->priv;
833+
DEBUG_TARGET("%s: Writing %zu bytes @0x%" PRIx32 "\n", __func__, len, dest);
834+
/* Cache DFSR and DFAR in case we wind up triggering a data fault */
835+
const uint32_t fault_status = cortexr_coproc_read(target, CORTEXR_DFSR);
836+
const uint32_t fault_addr = cortexr_coproc_read(target, CORTEXR_DFAR);
837+
/* Clear any existing fault state */
838+
priv->core_status &= ~(CORTEXR_STATUS_DATA_FAULT | CORTEXR_STATUS_MMU_FAULT);
839+
840+
/* Move the start address into the core's r0 */
841+
cortexr_core_reg_write(target, 0U, dest);
842+
843+
/* If the address is 32-bit aligned and we're writing 32 bits at a time, use the fast path */
844+
if ((dest & 3U) == 0U && (len & 3U) == 0U)
845+
cortexr_mem_write_fast(target, (const uint32_t *)src, len >> 2U);
846+
else
847+
adiv5_mem_write(cortex_ap(target), dest, src, len);
848+
/* Deal with any data faults that occured */
849+
cortexr_mem_handle_fault(target, __func__, fault_status, fault_addr);
811850
}
812851

813852
static void cortexr_regs_read(target_s *const target, void *const data)

0 commit comments

Comments
 (0)