static int cortex_a_dap_write_coreregister_u32(struct target *target,
uint32_t value, int regnum);
static int cortex_a_mmu(struct target *target, int *enabled);
+static int cortex_a_mmu_modify(struct target *target, int enable);
static int cortex_a_virt2phys(struct target *target,
uint32_t virt, uint32_t *phys);
static int cortex_a_read_apb_ab_memory(struct target *target,
return retval;
}
-/* check address before cortex_a_apb read write access with mmu on
- * remove apb predictible data abort */
-static int cortex_a_check_address(struct target *target, uint32_t address)
+/*
+ * Set up ARM core for memory access.
+ * If !phys_access, switch to SVC mode and make sure MMU is on
+ * If phys_access, switch off mmu
+ */
+static int cortex_a_prep_memaccess(struct target *target, int phys_access)
{
struct armv7a_common *armv7a = target_to_armv7a(target);
- struct cortex_a_common *cortex_a = target_to_cortex_a(target);
- uint32_t os_border = armv7a->armv7a_mmu.os_border;
- if ((address < os_border) &&
- (armv7a->arm.core_mode == ARM_MODE_SVC)) {
- LOG_ERROR("%" PRIx32 " access in userspace and target in supervisor", address);
- return ERROR_FAIL;
- }
- if ((address >= os_border) &&
- (cortex_a->curr_mode != ARM_MODE_SVC)) {
+ int mmu_enabled = 0;
+
+ if (phys_access == 0) {
dpm_modeswitch(&armv7a->dpm, ARM_MODE_SVC);
- cortex_a->curr_mode = ARM_MODE_SVC;
- LOG_INFO("%" PRIx32 " access in kernel space and target not in supervisor",
- address);
- return ERROR_OK;
+ cortex_a_mmu(target, &mmu_enabled);
+ if (mmu_enabled)
+ cortex_a_mmu_modify(target, 1);
+ } else {
+ cortex_a_mmu(target, &mmu_enabled);
+ if (mmu_enabled)
+ cortex_a_mmu_modify(target, 0);
}
- if ((address < os_border) &&
- (cortex_a->curr_mode == ARM_MODE_SVC)) {
+ return ERROR_OK;
+}
+
+/*
+ * Restore ARM core after memory access.
+ * If !phys_access, switch to previous mode
+ * If phys_access, restore MMU setting
+ */
+static int cortex_a_post_memaccess(struct target *target, int phys_access)
+{
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+
+ if (phys_access == 0) {
dpm_modeswitch(&armv7a->dpm, ARM_MODE_ANY);
- cortex_a->curr_mode = ARM_MODE_ANY;
+ } else {
+ int mmu_enabled = 0;
+ cortex_a_mmu(target, &mmu_enabled);
+ if (mmu_enabled)
+ cortex_a_mmu_modify(target, 1);
}
return ERROR_OK;
}
+
+
/* modify cp15_control_reg in order to enable or disable mmu for :
* - virt2phys address conversion
* - read or write memory in phys or virt address */
struct cortex_a_common *cortex_a = target_to_cortex_a(target);
struct armv7a_common *armv7a = target_to_armv7a(target);
int retval = ERROR_OK;
+ int need_write = 0;
+
if (enable) {
/* if mmu enabled at target stop and mmu not enable */
if (!(cortex_a->cp15_control_reg & 0x1U)) {
LOG_ERROR("trying to enable mmu on target stopped with mmu disable");
return ERROR_FAIL;
}
- if (!(cortex_a->cp15_control_reg_curr & 0x1U)) {
+ if ((cortex_a->cp15_control_reg_curr & 0x1U) == 0) {
cortex_a->cp15_control_reg_curr |= 0x1U;
- retval = armv7a->arm.mcr(target, 15,
- 0, 0, /* op1, op2 */
- 1, 0, /* CRn, CRm */
- cortex_a->cp15_control_reg_curr);
+ need_write = 1;
}
} else {
- if ((cortex_a->cp15_control_reg_curr & 0x1U)) {
- if (cortex_a->cp15_control_reg_curr & 0x4U) {
- /* data cache is active */
- cortex_a->cp15_control_reg_curr &= ~0x4U;
- /* flush data cache armv7 function to be called */
- if (armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache)
- armv7a->armv7a_mmu.armv7a_cache.flush_all_data_cache(target);
- }
+ if ((cortex_a->cp15_control_reg_curr & 0x1U) == 0x1U) {
cortex_a->cp15_control_reg_curr &= ~0x1U;
- retval = armv7a->arm.mcr(target, 15,
- 0, 0, /* op1, op2 */
- 1, 0, /* CRn, CRm */
- cortex_a->cp15_control_reg_curr);
+ need_write = 1;
}
}
+
+ if (need_write) {
+ LOG_DEBUG("%s, writing cp15 ctrl: %" PRIx32,
+ enable ? "enable mmu" : "disable mmu",
+ cortex_a->cp15_control_reg_curr);
+
+ retval = armv7a->arm.mcr(target, 15,
+ 0, 0, /* op1, op2 */
+ 1, 0, /* CRn, CRm */
+ cortex_a->cp15_control_reg_curr);
+ }
return retval;
}
*/
struct armv7a_common *armv7a = target_to_armv7a(target);
struct adiv5_dap *swjdp = armv7a->arm.dap;
- uint32_t new_dscr, u32;
+ uint32_t u32;
int retval;
/* Switch to non-blocking mode if not already in that mode. */
if (retval != ERROR_OK)
return retval;
- if (count > 1) {
- /* Consecutively issue the LDC instruction via a write to ITR and
- * change to fast mode, in a single bulk copy since DSCR == ITR + 4.
- * The instruction is issued into the core before the mode switch. */
- uint8_t command[8];
- target_buffer_set_u32(target, command, ARMV4_5_LDC(0, 1, 0, 1, 14, 5, 0, 4));
- new_dscr = (*dscr & ~DSCR_EXT_DCC_MASK) | DSCR_EXT_DCC_FAST_MODE;
- target_buffer_set_u32(target, command + 4, new_dscr);
- retval = mem_ap_sel_write_buf(swjdp, armv7a->debug_ap, command, 4, 2,
- armv7a->debug_base + CPUDBG_ITR);
+ /* 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_sel_write_atomic_u32(swjdp, 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;
- *dscr = new_dscr;
/* Read the value transferred to DTRTX into the buffer. Due to fast
* mode rules, this blocks until the instruction finishes executing and
* word from memory and issues the read instruction for the last word.
*/
retval = mem_ap_sel_read_buf_noincr(swjdp, armv7a->debug_ap, buffer,
- 4, count - 1, armv7a->debug_base + CPUDBG_DTRTX);
+ 4, count, armv7a->debug_base + CPUDBG_DTRTX);
if (retval != ERROR_OK)
return retval;
/* Advance. */
- buffer += (count - 1) * 4;
- } else {
- /* 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;
+ buffer += count * 4;
}
- /* Switch to non-blocking mode if not already in that mode. */
- retval = cortex_a_set_dcc_mode(target, DSCR_EXT_DCC_NON_BLOCKING, dscr);
+ /* Wait for last issued instruction to complete. */
+ retval = cortex_a_wait_instrcmpl(target, dscr, false);
if (retval != ERROR_OK)
return retval;
- /* Wait for last issued instruction to complete. */
- retval = cortex_a_wait_instrcmpl(target, dscr, false);
+ /* 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;
uint32_t address, uint32_t size,
uint32_t count, uint8_t *buffer)
{
- struct armv7a_common *armv7a = target_to_armv7a(target);
int retval = ERROR_COMMAND_SYNTAX_ERROR;
LOG_DEBUG("Reading memory at real address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32,
if (count && buffer) {
/* read memory through APB-AP */
- if (!armv7a->is_armv7r) {
- /* disable mmu */
- retval = cortex_a_mmu_modify(target, 0);
- if (retval != ERROR_OK)
- return retval;
- }
+ cortex_a_prep_memaccess(target, 1);
retval = cortex_a_read_apb_ab_memory(target, address, size, count, buffer);
+ cortex_a_post_memaccess(target, 1);
}
return retval;
}
static int cortex_a_read_memory(struct target *target, uint32_t address,
uint32_t size, uint32_t count, uint8_t *buffer)
{
- int mmu_enabled = 0;
int retval;
- struct armv7a_common *armv7a = target_to_armv7a(target);
/* cortex_a handles unaligned memory access */
LOG_DEBUG("Reading memory at address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address,
size, count);
- /* determine if MMU was enabled on target stop */
- if (!armv7a->is_armv7r) {
- retval = cortex_a_mmu(target, &mmu_enabled);
- if (retval != ERROR_OK)
- return retval;
- }
-
- if (mmu_enabled) {
- retval = cortex_a_check_address(target, address);
- if (retval != ERROR_OK)
- return retval;
- /* enable MMU as we could have disabled it for phys access */
- retval = cortex_a_mmu_modify(target, 1);
- if (retval != ERROR_OK)
- return retval;
- }
+ cortex_a_prep_memaccess(target, 0);
retval = cortex_a_read_apb_ab_memory(target, address, size, count, buffer);
+ cortex_a_post_memaccess(target, 0);
return retval;
}
uint32_t address, uint32_t size,
uint32_t count, const uint8_t *buffer)
{
- struct armv7a_common *armv7a = target_to_armv7a(target);
int retval = ERROR_COMMAND_SYNTAX_ERROR;
LOG_DEBUG("Writing memory to real address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address,
if (count && buffer) {
/* write memory through APB-AP */
- if (!armv7a->is_armv7r) {
- retval = cortex_a_mmu_modify(target, 0);
- if (retval != ERROR_OK)
- return retval;
- }
- return cortex_a_write_apb_ab_memory(target, address, size, count, buffer);
+ cortex_a_prep_memaccess(target, 1);
+ retval = cortex_a_write_apb_ab_memory(target, address, size, count, buffer);
+ cortex_a_post_memaccess(target, 1);
}
return retval;
static int cortex_a_write_memory(struct target *target, uint32_t address,
uint32_t size, uint32_t count, const uint8_t *buffer)
{
- int mmu_enabled = 0;
int retval;
- struct armv7a_common *armv7a = target_to_armv7a(target);
/* cortex_a handles unaligned memory access */
LOG_DEBUG("Writing memory at address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address,
size, count);
- /* determine if MMU was enabled on target stop */
- if (!armv7a->is_armv7r) {
- retval = cortex_a_mmu(target, &mmu_enabled);
- if (retval != ERROR_OK)
- return retval;
- }
-
- if (mmu_enabled) {
- retval = cortex_a_check_address(target, address);
- if (retval != ERROR_OK)
- return retval;
- /* enable MMU as we could have disabled it for phys access */
- retval = cortex_a_mmu_modify(target, 1);
- if (retval != ERROR_OK)
- return retval;
- }
-
/* memory writes bypass the caches, must flush before writing */
armv7a_cache_auto_flush_on_write(target, address, size * count);
+ cortex_a_prep_memaccess(target, 0);
retval = cortex_a_write_apb_ab_memory(target, address, size, count, buffer);
-
+ cortex_a_post_memaccess(target, 0);
return retval;
}
/* We do one extra read to ensure DAP is configured,
* we call ahbap_debugport_init(swjdp) instead
*/
- retval = ahbap_debugport_init(swjdp);
+ retval = ahbap_debugport_init(swjdp, 0);
if (retval != ERROR_OK)
return retval;
return retval;
}
LOG_DEBUG("Detected core %" PRId32 " dbgbase: %08" PRIx32,
- coreidx, armv7a->debug_base);
+ target->coreid, armv7a->debug_base);
} else
armv7a->debug_base = target->dbgbase;
struct cortex_a_common *cortex_a, struct jtag_tap *tap)
{
struct armv7a_common *armv7a = &cortex_a->armv7a_common;
- struct adiv5_dap *dap = &armv7a->dap;
-
- armv7a->arm.dap = dap;
/* Setup struct cortex_a_common */
cortex_a->common_magic = CORTEX_A_COMMON_MAGIC;
+
/* tap has no dap initialized */
if (!tap->dap) {
- armv7a->arm.dap = dap;
- /* Setup struct cortex_a_common */
+ tap->dap = dap_init();
/* prepare JTAG information for the new target */
cortex_a->jtag_info.tap = tap;
cortex_a->jtag_info.scann_size = 4;
/* Leave (only) generic DAP stuff for debugport_init() */
- dap->jtag_info = &cortex_a->jtag_info;
+ tap->dap->jtag_info = &cortex_a->jtag_info;
+ }
- /* Number of bits for tar autoincrement, impl. dep. at least 10 */
- dap->tar_autoincr_block = (1 << 10);
- dap->memaccess_tck = 80;
- tap->dap = dap;
- } else
- armv7a->arm.dap = tap->dap;
+ tap->dap->ap[dap_ap_get_select(tap->dap)].memaccess_tck = 80;
+ armv7a->arm.dap = tap->dap;
cortex_a->fast_reg_read = 0;
static int cortex_a_mmu(struct target *target, int *enabled)
{
+ struct armv7a_common *armv7a = target_to_armv7a(target);
+
if (target->state != TARGET_HALTED) {
LOG_ERROR("%s: target not halted", __func__);
return ERROR_TARGET_INVALID;
}
- *enabled = target_to_cortex_a(target)->armv7a_common.armv7a_mmu.mmu_enabled;
+ if (armv7a->is_armv7r)
+ *enabled = 0;
+ else
+ *enabled = target_to_cortex_a(target)->armv7a_common.armv7a_mmu.mmu_enabled;
+
return ERROR_OK;
}