]> git.sur5r.net Git - openocd/blobdiff - src/target/cortex_a9.c
arm_adi_v5: add wrapping transfer functions with selection of ap
[openocd] / src / target / cortex_a9.c
index 5850ace7943010725931ff1cad5d514aa883c05a..422da3f7da0687b1810369adcb01853c2a7d9b71 100644 (file)
@@ -81,10 +81,13 @@ static int cortex_a9_init_debug_access(struct target *target)
 {
        struct armv7a_common *armv7a = target_to_armv7a(target);
        struct adiv5_dap *swjdp = &armv7a->dap;
+       uint8_t saved_apsel = dap_ap_get_select(swjdp);
 
        int retval;
        uint32_t dummy;
 
+       dap_ap_select(swjdp, swjdp_debugap);
+
        LOG_DEBUG(" ");
 
        /* Unlocking the debug registers for modification */
@@ -100,12 +103,12 @@ static int cortex_a9_init_debug_access(struct target *target)
                }
        }
        if (retval != ERROR_OK)
-               return retval;
+               goto out;
        /* Clear Sticky Power Down status Bit in PRSR to enable access to
           the registers in the Core Power Domain */
        retval = mem_ap_read_atomic_u32(swjdp, armv7a->debug_base + CPUDBG_PRSR, &dummy);
        if (retval != ERROR_OK)
-               return retval;
+               goto out;
 
        /* Enabling of instruction execution in debug mode is done in debug_entry code */
 
@@ -114,6 +117,8 @@ static int cortex_a9_init_debug_access(struct target *target)
        /* Since this is likely called from init or reset, update target state information*/
        retval = cortex_a9_poll(target);
 
+ out:
+       dap_ap_select(swjdp, saved_apsel);
        return retval;
 }
 
@@ -1129,10 +1134,12 @@ static int cortex_a9_step(struct target *target, int current, uint32_t address,
 {
        struct armv7a_common *armv7a = target_to_armv7a(target);
        struct arm *armv4_5 = &armv7a->armv4_5_common;
+       struct adiv5_dap *swjdp = &armv7a->dap;
        struct breakpoint *breakpoint = NULL;
        struct breakpoint stepbreakpoint;
        struct reg *r;
        int retval;
+       uint8_t saved_apsel = dap_ap_get_select(swjdp);
 
        if (target->state != TARGET_HALTED)
        {
@@ -1140,6 +1147,8 @@ static int cortex_a9_step(struct target *target, int current, uint32_t address,
                return ERROR_TARGET_NOT_HALTED;
        }
 
+       dap_ap_select(swjdp, swjdp_debugap);
+
        /* current = 1: continue on current pc, otherwise continue at <address> */
        r = armv4_5->pc;
        if (!current)
@@ -1176,18 +1185,19 @@ static int cortex_a9_step(struct target *target, int current, uint32_t address,
 
        retval = cortex_a9_resume(target, 1, address, 0, 0);
        if (retval != ERROR_OK)
-               return retval;
+               goto out;
 
        long long then = timeval_ms();
        while (target->state != TARGET_HALTED)
        {
                retval = cortex_a9_poll(target);
                if (retval != ERROR_OK)
-                       return retval;
+                       goto out;
                if (timeval_ms() > then + 1000)
                {
                        LOG_ERROR("timeout waiting for target halt");
-                       return ERROR_FAIL;
+                       retval = ERROR_FAIL;
+                       goto out;
                }
        }
 
@@ -1201,7 +1211,11 @@ static int cortex_a9_step(struct target *target, int current, uint32_t address,
        if (target->state != TARGET_HALTED)
                LOG_DEBUG("target stepped");
 
-       return ERROR_OK;
+       retval = ERROR_OK;
+
+ out:
+       dap_ap_select(swjdp, saved_apsel);
+       return retval;
 }
 
 static int cortex_a9_restore_context(struct target *target, bool bpwp)
@@ -1478,29 +1492,94 @@ static int cortex_a9_read_phys_memory(struct target *target,
        struct armv7a_common *armv7a = target_to_armv7a(target);
        struct adiv5_dap *swjdp = &armv7a->dap;
        int retval = ERROR_INVALID_ARGUMENTS;
-       uint8_t saved_apsel = dap_ap_get_select(swjdp);
-
-       /* cortex_a9 handles unaligned memory access */
-
-       dap_ap_select(swjdp, swjdp_memoryap);
+       uint8_t apsel = dap_ap_get_select(swjdp);
 
        LOG_DEBUG("Reading memory at real address 0x%x; size %d; count %d", address, size, count);
+
        if (count && buffer) {
-               switch (size) {
-                       case 4:
-                               retval = mem_ap_read_buf_u32(swjdp, buffer, 4 * count, address);
-                               break;
-                       case 2:
-                               retval = mem_ap_read_buf_u16(swjdp, buffer, 2 * count, address);
-                               break;
-                       case 1:
-                               retval = mem_ap_read_buf_u8(swjdp, buffer, count, address);
-                               break;
+
+               if ( apsel == swjdp_memoryap ) {
+
+                       /* read memory through AHB-AP */
+
+                       switch (size) {
+                               case 4:
+                                       retval = mem_ap_read_buf_u32(swjdp, buffer, 4 * count, address);
+                                       break;
+                               case 2:
+                                       retval = mem_ap_read_buf_u16(swjdp, buffer, 2 * count, address);
+                                       break;
+                               case 1:
+                                       retval = mem_ap_read_buf_u8(swjdp, buffer, count, address);
+                                       break;
+                       }
+
+               } else {
+
+                       /* read memory through APB-AP */
+
+                       uint32_t saved_r0, saved_r1;
+                       int nbytes = count * size;
+                       uint32_t data;
+                       int enabled = 0;
+
+                       if (target->state != TARGET_HALTED)
+                       {
+                               LOG_WARNING("target not halted");
+                               return ERROR_TARGET_NOT_HALTED;
+                       }
+
+                       retval = cortex_a9_mmu(target, &enabled);
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       if (enabled)
+                       {
+                               LOG_WARNING("Reading physical memory through APB with MMU enabled is not yet implemented");
+                               return ERROR_TARGET_FAILURE;
+                       }
+
+                       /* save registers r0 and r1, we are going to corrupt them  */
+                       retval = cortex_a9_dap_read_coreregister_u32(target, &saved_r0, 0);
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       retval = cortex_a9_dap_read_coreregister_u32(target, &saved_r1, 1);
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       retval = cortex_a9_dap_write_coreregister_u32(target, address, 0);
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       while (nbytes > 0) {
+
+                               /* execute instruction LDRB r1, [r0], 1 (0xe4d01001) */
+                               retval = cortex_a9_exec_opcode(target, ARMV4_5_LDRB_IP(1, 0) , NULL);
+                               if (retval != ERROR_OK)
+                                               return retval;
+
+                               retval = cortex_a9_dap_read_coreregister_u32(target, &data, 1);
+                               if (retval != ERROR_OK)
+                                       return retval;
+
+                               *buffer++ = data;
+                               --nbytes;
+
+                       }
+
+                       /* restore corrupted registers r0 and r1 */
+                       retval = cortex_a9_dap_write_coreregister_u32(target, saved_r0, 0);
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       retval = cortex_a9_dap_write_coreregister_u32(target, saved_r1, 1);
+                       if (retval != ERROR_OK)
+                               return retval;
+
                }
        }
 
-       dap_ap_select(swjdp, saved_apsel);
-
        return retval;
 }
 
@@ -1543,22 +1622,90 @@ static int cortex_a9_write_phys_memory(struct target *target,
        LOG_DEBUG("Writing memory to real address 0x%x; size %d; count %d", address, size, count);
 
        if (count && buffer) {
-               uint8_t saved_apsel = dap_ap_get_select(swjdp);
-               dap_ap_select(swjdp, swjdp_memoryap);
+               uint8_t apsel = dap_ap_get_select(swjdp);
+
+               if ( apsel == swjdp_memoryap ) {
+
+                       /* write memory through AHB-AP */
+                       switch (size) {
+                               case 4:
+                                       retval = mem_ap_write_buf_u32(swjdp, buffer, 4 * count, address);
+                                       break;
+                               case 2:
+                                       retval = mem_ap_write_buf_u16(swjdp, buffer, 2 * count, address);
+                                       break;
+                               case 1:
+                                       retval = mem_ap_write_buf_u8(swjdp, buffer, count, address);
+                                       break;
+                       }
 
-               switch (size) {
-                       case 4:
-                               retval = mem_ap_write_buf_u32(swjdp, buffer, 4 * count, address);
-                               break;
-                       case 2:
-                               retval = mem_ap_write_buf_u16(swjdp, buffer, 2 * count, address);
-                               break;
-                       case 1:
-                               retval = mem_ap_write_buf_u8(swjdp, buffer, count, address);
-                               break;
-               }
+               } else {
 
-               dap_ap_select(swjdp, saved_apsel);
+                       /* write memory through APB-AP */
+
+                       uint32_t saved_r0, saved_r1;
+                       int nbytes = count * size;
+                       uint32_t data;
+                       int enabled = 0;
+
+                       if (target->state != TARGET_HALTED)
+                       {
+                               LOG_WARNING("target not halted");
+                               return ERROR_TARGET_NOT_HALTED;
+                       }
+
+                       retval = cortex_a9_mmu(target, &enabled);
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       if (enabled)
+                       {
+                               LOG_WARNING("Writing physical memory through APB with MMU enabled is not yet implemented");
+                               return ERROR_TARGET_FAILURE;
+                       }
+
+                       /* save registers r0 and r1, we are going to corrupt them  */
+                       retval = cortex_a9_dap_read_coreregister_u32(target, &saved_r0, 0);
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       retval = cortex_a9_dap_read_coreregister_u32(target, &saved_r1, 1);
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       retval = cortex_a9_dap_write_coreregister_u32(target, address, 0);
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       while (nbytes > 0) {
+
+                               data = *buffer++;
+
+                               retval = cortex_a9_dap_write_coreregister_u32(target, data, 1);
+                               if (retval != ERROR_OK)
+                                       return retval;
+
+                                       /* execute instruction STRB r1, [r0], 1 (0xe4c01001) */
+                               retval = cortex_a9_exec_opcode(target, ARMV4_5_STRB_IP(1, 0) , NULL);
+                               if (retval != ERROR_OK)
+                                               return retval;
+
+                               --nbytes;
+                       }
+
+                       /* restore corrupted registers r0 and r1 */
+                       retval = cortex_a9_dap_write_coreregister_u32(target, saved_r0, 0);
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       retval = cortex_a9_dap_write_coreregister_u32(target, saved_r1, 1);
+                       if (retval != ERROR_OK)
+                               return retval;
+
+                       /* we can return here without invalidating D/I-cache because */
+                       /* access through APB maintains cache coherency              */
+                       return retval;
+               }
        }