armv7a: rework automatic flush-on-write handling
[openocd.git] / src / target / cortex_a.c
index 39a79ddff53bf35526a66949163ed9bbbd85d021..39e59ae7b66819a9c40ac156e620d786ec75f545 100644 (file)
@@ -1305,7 +1305,7 @@ static int cortex_a_post_debug_entry(struct target *target)
        LOG_DEBUG("cp15_control_reg: %8.8" PRIx32, cortex_a->cp15_control_reg);
        cortex_a->cp15_control_reg_curr = cortex_a->cp15_control_reg;
 
-       if (armv7a->armv7a_mmu.armv7a_cache.ctype == -1)
+       if (armv7a->armv7a_mmu.armv7a_cache.info == -1)
                armv7a_identify_cache(target);
 
        if (armv7a->is_armv7r) {
@@ -2611,34 +2611,57 @@ static int cortex_a_read_phys_memory(struct target *target,
        uint32_t count, uint8_t *buffer)
 {
        struct armv7a_common *armv7a = target_to_armv7a(target);
-       struct adiv5_dap *swjdp = armv7a->arm.dap;
        int retval = ERROR_COMMAND_SYNTAX_ERROR;
-       uint8_t apsel = swjdp->apsel;
+
        LOG_DEBUG("Reading memory at real address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32,
                address, size, count);
 
        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;
+               }
+               retval = cortex_a_read_apb_ab_memory(target, address, size, count, buffer);
+       }
+       return retval;
+}
 
-               if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap)) {
+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);
 
-                       /* read memory through AHB-AP */
-                       retval = mem_ap_sel_read_buf(swjdp, armv7a->memory_ap, buffer, size, count, address);
-               } else {
+       /* cortex_a handles unaligned memory access */
+       LOG_DEBUG("Reading memory at address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address,
+               size, count);
 
-                       /* read memory through APB-AP */
-                       if (!armv7a->is_armv7r) {
-                               /*  disable mmu */
-                               retval = cortex_a_mmu_modify(target, 0);
-                               if (retval != ERROR_OK)
-                                       return retval;
-                       }
-                       retval = cortex_a_read_apb_ab_memory(target, address, size, count, buffer);
-               }
+       /* 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;
+       }
+       retval = cortex_a_read_apb_ab_memory(target, address, size, count, buffer);
+
        return retval;
 }
 
-static int cortex_a_read_memory(struct target *target, uint32_t address,
+static int cortex_a_read_memory_ahb(struct target *target, uint32_t address,
        uint32_t size, uint32_t count, uint8_t *buffer)
 {
        int mmu_enabled = 0;
@@ -2648,6 +2671,9 @@ static int cortex_a_read_memory(struct target *target, uint32_t address,
        struct adiv5_dap *swjdp = armv7a->arm.dap;
        uint8_t apsel = swjdp->apsel;
 
+       if (!armv7a->memory_ap_available || (apsel != armv7a->memory_ap))
+               return target_read_memory(target, address, size, count, buffer);
+
        /* cortex_a handles unaligned memory access */
        LOG_DEBUG("Reading memory at address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address,
                size, count);
@@ -2659,31 +2685,22 @@ static int cortex_a_read_memory(struct target *target, uint32_t address,
                        return retval;
        }
 
-       if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap)) {
-               if (mmu_enabled) {
-                       virt = address;
-                       retval = cortex_a_virt2phys(target, virt, &phys);
-                       if (retval != ERROR_OK)
-                               return retval;
+       if (mmu_enabled) {
+               virt = address;
+               retval = cortex_a_virt2phys(target, virt, &phys);
+               if (retval != ERROR_OK)
+                       return retval;
 
-                       LOG_DEBUG("Reading at virtual address. Translating v:0x%" PRIx32 " to r:0x%" PRIx32,
-                                 virt, phys);
-                       address = phys;
-               }
-               retval = cortex_a_read_phys_memory(target, address, size,
-                           count, buffer);
-       } else {
-               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;
-               }
-               retval = cortex_a_read_apb_ab_memory(target, address, size, count, buffer);
+               LOG_DEBUG("Reading at virtual address. Translating v:0x%" PRIx32 " to r:0x%" PRIx32,
+                         virt, phys);
+               address = phys;
        }
+
+       if (!count || !buffer)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       retval = mem_ap_sel_read_buf(swjdp, armv7a->memory_ap, buffer, size, count, address);
+
        return retval;
 }
 
@@ -2692,90 +2709,61 @@ static int cortex_a_write_phys_memory(struct target *target,
        uint32_t count, const uint8_t *buffer)
 {
        struct armv7a_common *armv7a = target_to_armv7a(target);
-       struct adiv5_dap *swjdp = armv7a->arm.dap;
        int retval = ERROR_COMMAND_SYNTAX_ERROR;
-       uint8_t apsel = swjdp->apsel;
 
        LOG_DEBUG("Writing memory to real address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address,
                size, count);
 
        if (count && buffer) {
-
-               if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap)) {
-
-                       /* write memory through AHB-AP */
-                       retval = mem_ap_sel_write_buf(swjdp, armv7a->memory_ap, buffer, size, count, address);
-               } else {
-
-                       /* 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);
+               /* 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);
        }
 
+       return retval;
+}
 
-       /* REVISIT this op is generic ARMv7-A/R stuff */
-       if (retval == ERROR_OK && target->state == TARGET_HALTED) {
-               struct arm_dpm *dpm = armv7a->arm.dpm;
+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);
 
-               retval = dpm->prepare(dpm);
+       /* 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;
+       }
 
-               /* The Cache handling will NOT work with MMU active, the
-                * wrong addresses will be invalidated!
-                *
-                * For both ICache and DCache, walk all cache lines in the
-                * address range. Cortex-A has fixed 64 byte line length.
-                *
-                * REVISIT per ARMv7, these may trigger watchpoints ...
-                */
-
-               /* invalidate I-Cache */
-               if (armv7a->armv7a_mmu.armv7a_cache.i_cache_enabled) {
-                       /* ICIMVAU - Invalidate Cache single entry
-                        * with MVA to PoU
-                        *      MCR p15, 0, r0, c7, c5, 1
-                        */
-                       for (uint32_t cacheline = 0;
-                               cacheline < size * count;
-                               cacheline += 64) {
-                               retval = dpm->instr_write_data_r0(dpm,
-                                               ARMV4_5_MCR(15, 0, 0, 7, 5, 1),
-                                               address + cacheline);
-                               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;
+       }
 
-               /* invalidate D-Cache */
-               if (armv7a->armv7a_mmu.armv7a_cache.d_u_cache_enabled) {
-                       /* DCIMVAC - Invalidate data Cache line
-                        * with MVA to PoC
-                        *      MCR p15, 0, r0, c7, c6, 1
-                        */
-                       for (uint32_t cacheline = 0;
-                               cacheline < size * count;
-                               cacheline += 64) {
-                               retval = dpm->instr_write_data_r0(dpm,
-                                               ARMV4_5_MCR(15, 0, 0, 7, 6, 1),
-                                               address + cacheline);
-                               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);
 
-               /* (void) */ dpm->finish(dpm);
-       }
+       retval = cortex_a_write_apb_ab_memory(target, address, size, count, buffer);
 
        return retval;
 }
 
-static int cortex_a_write_memory(struct target *target, uint32_t address,
+static int cortex_a_write_memory_ahb(struct target *target, uint32_t address,
        uint32_t size, uint32_t count, const uint8_t *buffer)
 {
        int mmu_enabled = 0;
@@ -2785,6 +2773,9 @@ static int cortex_a_write_memory(struct target *target, uint32_t address,
        struct adiv5_dap *swjdp = armv7a->arm.dap;
        uint8_t apsel = swjdp->apsel;
 
+       if (!armv7a->memory_ap_available || (apsel != armv7a->memory_ap))
+               return target_write_memory(target, address, size, count, buffer);
+
        /* cortex_a handles unaligned memory access */
        LOG_DEBUG("Writing memory at address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address,
                size, count);
@@ -2796,35 +2787,92 @@ static int cortex_a_write_memory(struct target *target, uint32_t address,
                        return retval;
        }
 
-       if (armv7a->memory_ap_available && (apsel == armv7a->memory_ap)) {
-               LOG_DEBUG("Writing memory to address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address, size,
-                       count);
-               if (mmu_enabled) {
-                       virt = address;
-                       retval = cortex_a_virt2phys(target, virt, &phys);
+       if (mmu_enabled) {
+               virt = address;
+               retval = cortex_a_virt2phys(target, virt, &phys);
+               if (retval != ERROR_OK)
+                       return retval;
+
+               LOG_DEBUG("Writing to virtual address. Translating v:0x%" PRIx32 " to r:0x%" PRIx32,
+                         virt,
+                         phys);
+               address = phys;
+       }
+
+       if (!count || !buffer)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       retval = mem_ap_sel_write_buf(swjdp, armv7a->memory_ap, buffer, size, count, address);
+
+       return retval;
+}
+
+static int cortex_a_read_buffer(struct target *target, uint32_t address,
+                               uint32_t count, uint8_t *buffer)
+{
+       uint32_t size;
+
+       /* Align up to maximum 4 bytes. The loop condition makes sure the next pass
+        * will have something to do with the size we leave to it. */
+       for (size = 1; size < 4 && count >= size * 2 + (address & size); size *= 2) {
+               if (address & size) {
+                       int retval = cortex_a_read_memory_ahb(target, address, size, 1, buffer);
                        if (retval != ERROR_OK)
                                return retval;
+                       address += size;
+                       count -= size;
+                       buffer += size;
+               }
+       }
 
-                       LOG_DEBUG("Writing to virtual address. Translating v:0x%" PRIx32 " to r:0x%" PRIx32,
-                                 virt,
-                                 phys);
-                       address = phys;
+       /* Read the data with as large access size as possible. */
+       for (; size > 0; size /= 2) {
+               uint32_t aligned = count - count % size;
+               if (aligned > 0) {
+                       int retval = cortex_a_read_memory_ahb(target, address, size, aligned / size, buffer);
+                       if (retval != ERROR_OK)
+                               return retval;
+                       address += aligned;
+                       count -= aligned;
+                       buffer += aligned;
                }
-               retval = cortex_a_write_phys_memory(target, address, size,
-                               count, buffer);
-       } else {
-               if (mmu_enabled) {
-                       retval = cortex_a_check_address(target, address);
+       }
+
+       return ERROR_OK;
+}
+
+static int cortex_a_write_buffer(struct target *target, uint32_t address,
+                                uint32_t count, const uint8_t *buffer)
+{
+       uint32_t size;
+
+       /* Align up to maximum 4 bytes. The loop condition makes sure the next pass
+        * will have something to do with the size we leave to it. */
+       for (size = 1; size < 4 && count >= size * 2 + (address & size); size *= 2) {
+               if (address & size) {
+                       int retval = cortex_a_write_memory_ahb(target, address, size, 1, buffer);
                        if (retval != ERROR_OK)
                                return retval;
-                       /* enable MMU as we could have disabled it for phys access */
-                       retval = cortex_a_mmu_modify(target, 1);
+                       address += size;
+                       count -= size;
+                       buffer += size;
+               }
+       }
+
+       /* Write the data with as large access size as possible. */
+       for (; size > 0; size /= 2) {
+               uint32_t aligned = count - count % size;
+               if (aligned > 0) {
+                       int retval = cortex_a_write_memory_ahb(target, address, size, aligned / size, buffer);
                        if (retval != ERROR_OK)
                                return retval;
+                       address += aligned;
+                       count -= aligned;
+                       buffer += aligned;
                }
-               retval = cortex_a_write_apb_ab_memory(target, address, size, count, buffer);
        }
-       return retval;
+
+       return ERROR_OK;
 }
 
 static int cortex_a_handle_target_request(void *priv)
@@ -2996,9 +3044,13 @@ static int cortex_a_examine_first(struct target *target)
        LOG_DEBUG("target->coreid %" PRId32 " DBGPRSR  0x%" PRIx32, target->coreid, dbg_osreg);
 
        armv7a->arm.core_type = ARM_MODE_MON;
-       retval = cortex_a_dpm_setup(cortex_a, didr);
-       if (retval != ERROR_OK)
-               return retval;
+
+       /* Avoid recreating the registers cache */
+       if (!target_was_examined(target)) {
+               retval = cortex_a_dpm_setup(cortex_a, didr);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
 
        /* Setup Breakpoint Register Pairs */
        cortex_a->brp_num = ((didr >> 24) & 0x0F) + 1;
@@ -3117,6 +3169,16 @@ static int cortex_r4_target_create(struct target *target, Jim_Interp *interp)
        return cortex_a_init_arch_info(target, cortex_a, target->tap);
 }
 
+static void cortex_a_deinit_target(struct target *target)
+{
+       struct cortex_a_common *cortex_a = target_to_cortex_a(target);
+       struct arm_dpm *dpm = &cortex_a->armv7a_common.dpm;
+
+       free(cortex_a->brp_list);
+       free(dpm->dbp);
+       free(dpm->dwp);
+       free(cortex_a);
+}
 
 static int cortex_a_mmu(struct target *target, int *enabled)
 {
@@ -3345,6 +3407,9 @@ struct target_type cortexa_target = {
        .read_memory = cortex_a_read_memory,
        .write_memory = cortex_a_write_memory,
 
+       .read_buffer = cortex_a_read_buffer,
+       .write_buffer = cortex_a_write_buffer,
+
        .checksum_memory = arm_checksum_memory,
        .blank_check_memory = arm_blank_check_memory,
 
@@ -3361,6 +3426,7 @@ struct target_type cortexa_target = {
        .target_create = cortex_a_target_create,
        .init_target = cortex_a_init_target,
        .examine = cortex_a_examine,
+       .deinit_target = cortex_a_deinit_target,
 
        .read_phys_memory = cortex_a_read_phys_memory,
        .write_phys_memory = cortex_a_write_phys_memory,
@@ -3445,4 +3511,5 @@ struct target_type cortexr4_target = {
        .target_create = cortex_r4_target_create,
        .init_target = cortex_a_init_target,
        .examine = cortex_a_examine,
+       .deinit_target = cortex_a_deinit_target,
 };

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)