arm_debug: Support multiple APs per DAP and remove DAP from armv7* structs
[openocd.git] / src / target / cortex_a.c
index 3f00511c22ffa88993c16d9c4f87fda8442cbbe8..45a877d36783b0b785bc871fc3edd2502bf34dbd 100644 (file)
@@ -73,6 +73,7 @@ static int cortex_a_dap_read_coreregister_u32(struct target *target,
 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,
@@ -97,33 +98,50 @@ static int cortex_a_restore_cp15_control_reg(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 */
@@ -2433,7 +2451,7 @@ static int cortex_a_read_apb_ab_memory_fast(struct target *target,
         */
        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. */
@@ -2441,19 +2459,24 @@ static int cortex_a_read_apb_ab_memory_fast(struct target *target,
        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
@@ -2462,26 +2485,21 @@ static int cortex_a_read_apb_ab_memory_fast(struct target *target,
                 * 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;
 
@@ -2649,7 +2667,6 @@ static int cortex_a_read_phys_memory(struct target *target,
        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,
@@ -2657,13 +2674,9 @@ static int cortex_a_read_phys_memory(struct target *target,
 
        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;
 }
@@ -2671,31 +2684,15 @@ static int cortex_a_read_phys_memory(struct target *target,
 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;
 }
@@ -2747,7 +2744,6 @@ static int cortex_a_write_phys_memory(struct target *target,
        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,
@@ -2755,12 +2751,9 @@ static int cortex_a_write_phys_memory(struct target *target,
 
        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;
@@ -2769,36 +2762,18 @@ static int cortex_a_write_phys_memory(struct target *target,
 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;
 }
 
@@ -2963,7 +2938,7 @@ static int cortex_a_examine_first(struct target *target)
        /* 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;
 
@@ -3003,7 +2978,7 @@ static int cortex_a_examine_first(struct target *target)
                        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;
 
@@ -3144,30 +3119,24 @@ static int cortex_a_init_arch_info(struct target *target,
        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;
 
@@ -3221,12 +3190,18 @@ static void cortex_a_deinit_target(struct target *target)
 
 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;
 }
 

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)