]> git.sur5r.net Git - openocd/blobdiff - src/target/cortex_a.c
cortex_a: force cache and tlb bypass when cpu is in debug state
[openocd] / src / target / cortex_a.c
index 9ae04322b91e97713ae4daeee13eb068a49779bc..61a5df38918b426447994d07bb8c71fba71004ce 100644 (file)
@@ -146,14 +146,14 @@ static int cortex_a_mmu_modify(struct target *target, int enable)
                                        cortex_a->cp15_control_reg_curr);
                }
        } else {
-               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)) {
+                       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);
+                       }
                        cortex_a->cp15_control_reg_curr &= ~0x1U;
                        retval = armv7a->arm.mcr(target, 15,
                                        0, 0,   /* op1, op2 */
@@ -238,8 +238,20 @@ static int cortex_a_init_debug_access(struct target *target)
           the registers in the Core Power Domain */
        retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap,
                        armv7a->debug_base + CPUDBG_PRSR, &dbg_osreg);
-       LOG_DEBUG("target->coreid %d DBGPRSR  0x%x ", target->coreid, dbg_osreg);
+       LOG_DEBUG("target->coreid %" PRId32 " DBGPRSR  0x%" PRIx32, target->coreid, dbg_osreg);
+
+       if (retval != ERROR_OK)
+               return retval;
+
+       /* Disable cacheline fills and force cache write-through in debug state */
+       retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap,
+                       armv7a->debug_base + CPUDBG_DSCCR, 0);
+       if (retval != ERROR_OK)
+               return retval;
 
+       /* Disable TLB lookup and refill/eviction in debug state */
+       retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap,
+                       armv7a->debug_base + CPUDBG_DSMCR, 0);
        if (retval != ERROR_OK)
                return retval;
 
@@ -1305,7 +1317,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) {
@@ -1323,9 +1335,33 @@ static int cortex_a_post_debug_entry(struct target *target)
        return ERROR_OK;
 }
 
+int cortex_a_set_dscr_bits(struct target *target, unsigned long bit_mask, unsigned long value)
+{
+       struct armv7a_common *armv7a = target_to_armv7a(target);
+       struct adiv5_dap *swjdp = armv7a->arm.dap;
+       uint32_t dscr;
+
+       /* Read DSCR */
+       int retval = mem_ap_sel_read_atomic_u32(swjdp, armv7a->debug_ap,
+                       armv7a->debug_base + CPUDBG_DSCR, &dscr);
+       if (ERROR_OK != retval)
+               return retval;
+
+       /* clear bitfield */
+       dscr &= ~bit_mask;
+       /* put new value */
+       dscr |= value & bit_mask;
+
+       /* write new DSCR */
+       retval = mem_ap_sel_write_atomic_u32(swjdp, armv7a->debug_ap,
+                       armv7a->debug_base + CPUDBG_DSCR, dscr);
+       return retval;
+}
+
 static int cortex_a_step(struct target *target, int current, uint32_t address,
        int handle_breakpoints)
 {
+       struct cortex_a_common *cortex_a = target_to_cortex_a(target);
        struct armv7a_common *armv7a = target_to_armv7a(target);
        struct arm *arm = &armv7a->arm;
        struct breakpoint *breakpoint = NULL;
@@ -1363,6 +1399,13 @@ static int cortex_a_step(struct target *target, int current, uint32_t address,
        stepbreakpoint.type = BKPT_HARD;
        stepbreakpoint.set = 0;
 
+       /* Disable interrupts during single step if requested */
+       if (cortex_a->isrmasking_mode == CORTEX_A_ISRMASK_ON) {
+               retval = cortex_a_set_dscr_bits(target, DSCR_INT_DIS, DSCR_INT_DIS);
+               if (ERROR_OK != retval)
+                       return retval;
+       }
+
        /* Break on IVA mismatch */
        cortex_a_set_breakpoint(target, &stepbreakpoint, 0x04);
 
@@ -1385,6 +1428,14 @@ static int cortex_a_step(struct target *target, int current, uint32_t address,
 
        cortex_a_unset_breakpoint(target, &stepbreakpoint);
 
+       /* Re-enable interrupts if they were disabled */
+       if (cortex_a->isrmasking_mode == CORTEX_A_ISRMASK_ON) {
+               retval = cortex_a_set_dscr_bits(target, DSCR_INT_DIS, 0);
+               if (ERROR_OK != retval)
+                       return retval;
+       }
+
+
        target->debug_reason = DBG_REASON_BREAKPOINT;
 
        if (breakpoint)
@@ -1470,11 +1521,25 @@ static int cortex_a_set_breakpoint(struct target *target,
                                breakpoint->orig_instr);
                if (retval != ERROR_OK)
                        return retval;
+
+               /* make sure data cache is cleaned & invalidated down to PoC */
+               if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled) {
+                       armv7a_cache_flush_virt(target, breakpoint->address,
+                                               breakpoint->length);
+               }
+
                retval = target_write_memory(target,
                                breakpoint->address & 0xFFFFFFFE,
                                breakpoint->length, 1, code);
                if (retval != ERROR_OK)
                        return retval;
+
+               /* update i-cache at breakpoint location */
+               armv7a_l1_d_cache_inval_virt(target, breakpoint->address,
+                                       breakpoint->length);
+               armv7a_l1_i_cache_inval_virt(target, breakpoint->address,
+                                                breakpoint->length);
+
                breakpoint->set = 0x11; /* Any nice value but 0 */
        }
 
@@ -1694,6 +1759,13 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *b
                        return ERROR_OK;
                }
        } else {
+
+               /* make sure data cache is cleaned & invalidated down to PoC */
+               if (!armv7a->armv7a_mmu.armv7a_cache.auto_cache_enabled) {
+                       armv7a_cache_flush_virt(target, breakpoint->address,
+                                               breakpoint->length);
+               }
+
                /* restore original instruction (kept in target endianness) */
                if (breakpoint->length == 4) {
                        retval = target_write_memory(target,
@@ -1708,6 +1780,12 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *b
                        if (retval != ERROR_OK)
                                return retval;
                }
+
+               /* update i-cache at breakpoint location */
+               armv7a_l1_d_cache_inval_virt(target, breakpoint->address,
+                                                breakpoint->length);
+               armv7a_l1_i_cache_inval_virt(target, breakpoint->address,
+                                                breakpoint->length);
        }
        breakpoint->set = 0;
 
@@ -2572,34 +2650,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;
@@ -2609,6 +2710,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);
@@ -2620,31 +2724,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;
 }
 
@@ -2653,90 +2748,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;
+}
+
+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);
 
-       /* REVISIT this op is generic ARMv7-A/R stuff */
-       if (retval == ERROR_OK && target->state == TARGET_HALTED) {
-               struct arm_dpm *dpm = armv7a->arm.dpm;
+       /* cortex_a handles unaligned memory access */
+       LOG_DEBUG("Writing memory at address 0x%" PRIx32 "; size %" PRId32 "; count %" PRId32, address,
+               size, count);
 
-               retval = dpm->prepare(dpm);
+       /* 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;
@@ -2746,6 +2812,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);
@@ -2757,35 +2826,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)
@@ -2871,8 +2997,11 @@ static int cortex_a_examine_first(struct target *target)
                /* Lookup 0x15 -- Processor DAP */
                retval = dap_lookup_cs_component(swjdp, 1, dbgbase, 0x15,
                                &armv7a->debug_base, &coreidx);
-               if (retval != ERROR_OK)
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Can't detect %s's dbgbase from the ROM table; you need to specify it explicitly.",
+                                 target->cmd_name);
                        return retval;
+               }
                LOG_DEBUG("Detected core %" PRId32 " dbgbase: %08" PRIx32,
                          coreidx, armv7a->debug_base);
        } else
@@ -2951,17 +3080,22 @@ static int cortex_a_examine_first(struct target *target)
        if (retval != ERROR_OK)
                return retval;
 
-       LOG_DEBUG("target->coreid %d DBGPRSR  0x%" PRIx32, target->coreid, dbg_osreg);
+       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;
        cortex_a->brp_num_context = ((didr >> 20) & 0x0F) + 1;
        cortex_a->brp_num_available = cortex_a->brp_num;
+       free(cortex_a->brp_list);
        cortex_a->brp_list = calloc(cortex_a->brp_num, sizeof(struct cortex_a_brp));
 /*     cortex_a->brb_enabled = ????; */
        for (i = 0; i < cortex_a->brp_num; i++) {
@@ -2985,9 +3119,8 @@ static int cortex_a_examine(struct target *target)
 {
        int retval = ERROR_OK;
 
-       /* don't re-probe hardware after each reset */
-       if (!target_was_examined(target))
-               retval = cortex_a_examine_first(target);
+       /* Reestablish communication after target reset */
+       retval = cortex_a_examine_first(target);
 
        /* Configure core debug access */
        if (retval == ERROR_OK)
@@ -3075,6 +3208,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)
 {
@@ -3190,6 +3333,37 @@ COMMAND_HANDLER(cortex_a_handle_smp_gdb_command)
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(handle_cortex_a_mask_interrupts_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct cortex_a_common *cortex_a = target_to_cortex_a(target);
+
+       static const Jim_Nvp nvp_maskisr_modes[] = {
+               { .name = "off", .value = CORTEX_A_ISRMASK_OFF },
+               { .name = "on", .value = CORTEX_A_ISRMASK_ON },
+               { .name = NULL, .value = -1 },
+       };
+       const Jim_Nvp *n;
+
+       if (target->state != TARGET_HALTED) {
+               command_print(CMD_CTX, "target must be stopped for \"%s\" command", CMD_NAME);
+               return ERROR_OK;
+       }
+
+       if (CMD_ARGC > 0) {
+               n = Jim_Nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]);
+               if (n->name == NULL)
+                       return ERROR_COMMAND_SYNTAX_ERROR;
+               cortex_a->isrmasking_mode = n->value;
+
+       }
+
+       n = Jim_Nvp_value2name_simple(nvp_maskisr_modes, cortex_a->isrmasking_mode);
+       command_print(CMD_CTX, "cortex_a interrupt mask %s", n->name);
+
+       return ERROR_OK;
+}
+
 static const struct command_registration cortex_a_exec_command_handlers[] = {
        {
                .name = "cache_info",
@@ -3224,6 +3398,13 @@ static const struct command_registration cortex_a_exec_command_handlers[] = {
                .help = "display/fix current core played to gdb",
                .usage = "",
        },
+       {
+               .name = "maskisr",
+               .handler = handle_cortex_a_mask_interrupts_command,
+               .mode = COMMAND_EXEC,
+               .help = "mask cortex_a interrupts",
+               .usage = "['on'|'off']",
+       },
 
 
        COMMAND_REGISTRATION_DONE
@@ -3265,6 +3446,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,
 
@@ -3281,6 +3465,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,
@@ -3303,6 +3488,13 @@ static const struct command_registration cortex_r4_exec_command_handlers[] = {
                .help = "Initialize core debug",
                .usage = "",
        },
+       {
+               .name = "maskisr",
+               .handler = handle_cortex_a_mask_interrupts_command,
+               .mode = COMMAND_EXEC,
+               .help = "mask cortex_r4 interrupts",
+               .usage = "['on'|'off']",
+       },
 
        COMMAND_REGISTRATION_DONE
 };
@@ -3358,4 +3550,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,
 };