target/cortex_a: Use bool data type
[fw/openocd] / src / target / cortex_a.c
index 6eb6aa933836fd6bf510ccc4c422bc4f78d46366..ec02d179f748d6875ebba499055741b79efcd3ed 100644 (file)
@@ -23,6 +23,9 @@
  *   Copyright (C) 2013 Kamal Dasu                                         *
  *   kdasu.kdev@gmail.com                                                  *
  *                                                                         *
+ *   Copyright (C) 2016 Chengyu Zheng                                      *
+ *   chengyu.zheng@polimi.it : watchpoint support                          *
+ *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
  *   it under the terms of the GNU General Public License as published by  *
  *   the Free Software Foundation; either version 2 of the License, or     *
 #include "target_type.h"
 #include "arm_opcodes.h"
 #include "arm_semihosting.h"
+#include "jtag/interface.h"
 #include "transport/transport.h"
 #include "smp.h"
+#include <helper/bits.h>
 #include <helper/time_support.h>
 
 static int cortex_a_poll(struct target *target);
@@ -70,6 +75,8 @@ static int cortex_a_set_hybrid_breakpoint(struct target *target,
        struct breakpoint *breakpoint);
 static int cortex_a_unset_breakpoint(struct target *target,
        struct breakpoint *breakpoint);
+static int cortex_a_wait_dscr_bits(struct target *target, uint32_t mask,
+       uint32_t value, uint32_t *dscr);
 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,
@@ -77,6 +84,16 @@ static int cortex_a_virt2phys(struct target *target,
 static int cortex_a_read_cpu_memory(struct target *target,
        uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer);
 
+static unsigned int ilog2(unsigned int x)
+{
+       unsigned int y = 0;
+       x /= 2;
+       while (x) {
+               ++y;
+               x /= 2;
+               }
+       return y;
+}
 
 /*  restore cp15_control_reg at resume */
 static int cortex_a_restore_cp15_control_reg(struct target *target)
@@ -250,21 +267,21 @@ static int cortex_a_wait_instrcmpl(struct target *target, uint32_t *dscr, bool f
         * Writes final value of DSCR into *dscr. Pass force to force always
         * reading DSCR at least once. */
        struct armv7a_common *armv7a = target_to_armv7a(target);
-       int64_t then = timeval_ms();
-       while ((*dscr & DSCR_INSTR_COMP) == 0 || force) {
-               force = false;
-               int retval = mem_ap_read_atomic_u32(armv7a->debug_ap,
+       int retval;
+
+       if (force) {
+               retval = mem_ap_read_atomic_u32(armv7a->debug_ap,
                                armv7a->debug_base + CPUDBG_DSCR, dscr);
                if (retval != ERROR_OK) {
                        LOG_ERROR("Could not read DSCR register");
                        return retval;
                }
-               if (timeval_ms() > then + 1000) {
-                       LOG_ERROR("Timeout waiting for InstrCompl=1");
-                       return ERROR_FAIL;
-               }
        }
-       return ERROR_OK;
+
+       retval = cortex_a_wait_dscr_bits(target, DSCR_INSTR_COMP, DSCR_INSTR_COMP, dscr);
+       if (retval != ERROR_OK)
+               LOG_ERROR("Error waiting for InstrCompl=1");
+       return retval;
 }
 
 /* To reduce needless round-trips, pass in a pointer to the current
@@ -293,19 +310,12 @@ static int cortex_a_exec_opcode(struct target *target,
        if (retval != ERROR_OK)
                return retval;
 
-       int64_t then = timeval_ms();
-       do {
-               retval = mem_ap_read_atomic_u32(armv7a->debug_ap,
-                               armv7a->debug_base + CPUDBG_DSCR, &dscr);
-               if (retval != ERROR_OK) {
-                       LOG_ERROR("Could not read DSCR register");
-                       return retval;
-               }
-               if (timeval_ms() > then + 1000) {
-                       LOG_ERROR("Timeout waiting for cortex_a_exec_opcode");
-                       return ERROR_FAIL;
-               }
-       } while ((dscr & DSCR_INSTR_COMP) == 0);        /* Wait for InstrCompl bit to be set */
+       /* Wait for InstrCompl bit to be set */
+       retval = cortex_a_wait_instrcmpl(target, &dscr, true);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Error waiting for cortex_a_exec_opcode");
+               return retval;
+       }
 
        if (dscr_p)
                *dscr_p = dscr;
@@ -359,17 +369,11 @@ static int cortex_a_read_dcc(struct cortex_a_common *a, uint32_t *data,
                dscr = *dscr_p;
 
        /* Wait for DTRRXfull */
-       int64_t then = timeval_ms();
-       while ((dscr & DSCR_DTR_TX_FULL) == 0) {
-               retval = mem_ap_read_atomic_u32(a->armv7a_common.debug_ap,
-                               a->armv7a_common.debug_base + CPUDBG_DSCR,
-                               &dscr);
-               if (retval != ERROR_OK)
-                       return retval;
-               if (timeval_ms() > then + 1000) {
-                       LOG_ERROR("Timeout waiting for read dcc");
-                       return ERROR_FAIL;
-               }
+       retval = cortex_a_wait_dscr_bits(a->armv7a_common.arm.target,
+                       DSCR_DTR_TX_FULL, DSCR_DTR_TX_FULL, &dscr);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Error waiting for read dcc");
+               return retval;
        }
 
        retval = mem_ap_read_atomic_u32(a->armv7a_common.debug_ap,
@@ -391,19 +395,10 @@ static int cortex_a_dpm_prepare(struct arm_dpm *dpm)
        int retval;
 
        /* set up invariant:  INSTR_COMP is set after ever DPM operation */
-       int64_t then = timeval_ms();
-       for (;; ) {
-               retval = mem_ap_read_atomic_u32(a->armv7a_common.debug_ap,
-                               a->armv7a_common.debug_base + CPUDBG_DSCR,
-                               &dscr);
-               if (retval != ERROR_OK)
-                       return retval;
-               if ((dscr & DSCR_INSTR_COMP) != 0)
-                       break;
-               if (timeval_ms() > then + 1000) {
-                       LOG_ERROR("Timeout waiting for dpm prepare");
-                       return ERROR_FAIL;
-               }
+       retval = cortex_a_wait_instrcmpl(dpm->arm->target, &dscr, true);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Error waiting for dpm prepare");
+               return retval;
        }
 
        /* this "should never happen" ... */
@@ -444,22 +439,35 @@ static int cortex_a_instr_write_data_dcc(struct arm_dpm *dpm,
                        &dscr);
 }
 
-static int cortex_a_instr_write_data_r0(struct arm_dpm *dpm,
-       uint32_t opcode, uint32_t data)
+static int cortex_a_instr_write_data_rt_dcc(struct arm_dpm *dpm,
+       uint8_t rt, uint32_t data)
 {
        struct cortex_a_common *a = dpm_to_a(dpm);
        uint32_t dscr = DSCR_INSTR_COMP;
        int retval;
 
+       if (rt > 15)
+               return ERROR_TARGET_INVALID;
+
        retval = cortex_a_write_dcc(a, data);
        if (retval != ERROR_OK)
                return retval;
 
-       /* DCCRX to R0, "MCR p14, 0, R0, c0, c5, 0", 0xEE000E15 */
-       retval = cortex_a_exec_opcode(
+       /* DCCRX to Rt, "MCR p14, 0, R0, c0, c5, 0", 0xEE000E15 */
+       return cortex_a_exec_opcode(
                        a->armv7a_common.arm.target,
-                       ARMV4_5_MRC(14, 0, 0, 0, 5, 0),
+                       ARMV4_5_MRC(14, 0, rt, 0, 5, 0),
                        &dscr);
+}
+
+static int cortex_a_instr_write_data_r0(struct arm_dpm *dpm,
+       uint32_t opcode, uint32_t data)
+{
+       struct cortex_a_common *a = dpm_to_a(dpm);
+       uint32_t dscr = DSCR_INSTR_COMP;
+       int retval;
+
+       retval = cortex_a_instr_write_data_rt_dcc(dpm, 0, data);
        if (retval != ERROR_OK)
                return retval;
 
@@ -501,31 +509,43 @@ static int cortex_a_instr_read_data_dcc(struct arm_dpm *dpm,
        return cortex_a_read_dcc(a, data, &dscr);
 }
 
-
-static int cortex_a_instr_read_data_r0(struct arm_dpm *dpm,
-       uint32_t opcode, uint32_t *data)
+static int cortex_a_instr_read_data_rt_dcc(struct arm_dpm *dpm,
+       uint8_t rt, uint32_t *data)
 {
        struct cortex_a_common *a = dpm_to_a(dpm);
        uint32_t dscr = DSCR_INSTR_COMP;
        int retval;
 
-       /* the opcode, writing data to R0 */
+       if (rt > 15)
+               return ERROR_TARGET_INVALID;
+
        retval = cortex_a_exec_opcode(
                        a->armv7a_common.arm.target,
-                       opcode,
+                       ARMV4_5_MCR(14, 0, rt, 0, 5, 0),
                        &dscr);
        if (retval != ERROR_OK)
                return retval;
 
-       /* write R0 to DCC */
+       return cortex_a_read_dcc(a, data, &dscr);
+}
+
+static int cortex_a_instr_read_data_r0(struct arm_dpm *dpm,
+       uint32_t opcode, uint32_t *data)
+{
+       struct cortex_a_common *a = dpm_to_a(dpm);
+       uint32_t dscr = DSCR_INSTR_COMP;
+       int retval;
+
+       /* the opcode, writing data to R0 */
        retval = cortex_a_exec_opcode(
                        a->armv7a_common.arm.target,
-                       ARMV4_5_MCR(14, 0, 0, 0, 5, 0),
+                       opcode,
                        &dscr);
        if (retval != ERROR_OK)
                return retval;
 
-       return cortex_a_read_dcc(a, data, &dscr);
+       /* write R0 to DCC */
+       return cortex_a_instr_read_data_rt_dcc(dpm, 0, data);
 }
 
 static int cortex_a_bpwp_enable(struct arm_dpm *dpm, unsigned index_t,
@@ -752,7 +772,7 @@ static int cortex_a_poll(struct target *target)
 
 static int cortex_a_halt(struct target *target)
 {
-       int retval = ERROR_OK;
+       int retval;
        uint32_t dscr;
        struct armv7a_common *armv7a = target_to_armv7a(target);
 
@@ -765,18 +785,12 @@ static int cortex_a_halt(struct target *target)
        if (retval != ERROR_OK)
                return retval;
 
-       int64_t then = timeval_ms();
-       for (;; ) {
-               retval = mem_ap_read_atomic_u32(armv7a->debug_ap,
-                               armv7a->debug_base + CPUDBG_DSCR, &dscr);
-               if (retval != ERROR_OK)
-                       return retval;
-               if ((dscr & DSCR_CORE_HALTED) != 0)
-                       break;
-               if (timeval_ms() > then + 1000) {
-                       LOG_ERROR("Timeout waiting for halt");
-                       return ERROR_FAIL;
-               }
+       dscr = 0; /* force read of dscr */
+       retval = cortex_a_wait_dscr_bits(target, DSCR_CORE_HALTED,
+                       DSCR_CORE_HALTED, &dscr);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Error waiting for halt");
+               return retval;
        }
 
        target->debug_reason = DBG_REASON_DBGRQ;
@@ -841,7 +855,7 @@ static int cortex_a_internal_restore(struct target *target, int current,
                        LOG_ERROR("How do I resume into Jazelle state??");
                        return ERROR_FAIL;
                case ARM_STATE_AARCH64:
-                       LOG_ERROR("Shoudn't be in AARCH64 state");
+                       LOG_ERROR("Shouldn't be in AARCH64 state");
                        return ERROR_FAIL;
        }
        LOG_DEBUG("resume pc = 0x%08" PRIx32, resume_pc);
@@ -915,18 +929,12 @@ static int cortex_a_internal_restart(struct target *target)
        if (retval != ERROR_OK)
                return retval;
 
-       int64_t then = timeval_ms();
-       for (;; ) {
-               retval = mem_ap_read_atomic_u32(armv7a->debug_ap,
-                               armv7a->debug_base + CPUDBG_DSCR, &dscr);
-               if (retval != ERROR_OK)
-                       return retval;
-               if ((dscr & DSCR_CORE_RESTARTED) != 0)
-                       break;
-               if (timeval_ms() > then + 1000) {
-                       LOG_ERROR("Timeout waiting for resume");
-                       return ERROR_FAIL;
-               }
+       dscr = 0; /* force read of dscr */
+       retval = cortex_a_wait_dscr_bits(target, DSCR_CORE_RESTARTED,
+                       DSCR_CORE_RESTARTED, &dscr);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Error waiting for resume");
+               return retval;
        }
 
        target->debug_reason = DBG_REASON_NOTHALTED;
@@ -1121,7 +1129,8 @@ 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)
+static int cortex_a_set_dscr_bits(struct target *target,
+               unsigned long bit_mask, unsigned long value)
 {
        struct armv7a_common *armv7a = target_to_armv7a(target);
        uint32_t dscr;
@@ -1206,6 +1215,8 @@ static int cortex_a_step(struct target *target, int current, target_addr_t addre
                retval = cortex_a_poll(target);
                if (retval != ERROR_OK)
                        return retval;
+               if (target->state == TARGET_HALTED)
+                       break;
                if (timeval_ms() > then + 1000) {
                        LOG_ERROR("timeout waiting for target halt");
                        return ERROR_FAIL;
@@ -1279,7 +1290,7 @@ static int cortex_a_set_breakpoint(struct target *target,
                control = ((matchmode & 0x7) << 20)
                        | (byte_addr_select << 5)
                        | (3 << 1) | 1;
-               brp_list[brp_i].used = 1;
+               brp_list[brp_i].used = true;
                brp_list[brp_i].value = (breakpoint->address & 0xFFFFFFFC);
                brp_list[brp_i].control = control;
                retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base
@@ -1373,7 +1384,7 @@ static int cortex_a_set_context_breakpoint(struct target *target,
        control = ((matchmode & 0x7) << 20)
                | (byte_addr_select << 5)
                | (3 << 1) | 1;
-       brp_list[brp_i].used = 1;
+       brp_list[brp_i].used = true;
        brp_list[brp_i].value = (breakpoint->asid);
        brp_list[brp_i].control = control;
        retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base
@@ -1439,7 +1450,7 @@ static int cortex_a_set_hybrid_breakpoint(struct target *target, struct breakpoi
                | (0 << 14)
                | (CTX_byte_addr_select << 5)
                | (3 << 1) | 1;
-       brp_list[brp_1].used = 1;
+       brp_list[brp_1].used = true;
        brp_list[brp_1].value = (breakpoint->asid);
        brp_list[brp_1].control = control_CTX;
        retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base
@@ -1457,7 +1468,7 @@ static int cortex_a_set_hybrid_breakpoint(struct target *target, struct breakpoi
                | (brp_1 << 16)
                | (IVA_byte_addr_select << 5)
                | (3 << 1) | 1;
-       brp_list[brp_2].used = 1;
+       brp_list[brp_2].used = true;
        brp_list[brp_2].value = (breakpoint->address & 0xFFFFFFFC);
        brp_list[brp_2].control = control_IVA;
        retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base
@@ -1496,7 +1507,7 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *b
                        }
                        LOG_DEBUG("rbp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, brp_i,
                                brp_list[brp_i].control, brp_list[brp_i].value);
-                       brp_list[brp_i].used = 0;
+                       brp_list[brp_i].used = false;
                        brp_list[brp_i].value = 0;
                        brp_list[brp_i].control = 0;
                        retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base
@@ -1515,7 +1526,7 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *b
                        }
                        LOG_DEBUG("rbp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, brp_j,
                                brp_list[brp_j].control, brp_list[brp_j].value);
-                       brp_list[brp_j].used = 0;
+                       brp_list[brp_j].used = false;
                        brp_list[brp_j].value = 0;
                        brp_list[brp_j].control = 0;
                        retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base
@@ -1540,7 +1551,7 @@ static int cortex_a_unset_breakpoint(struct target *target, struct breakpoint *b
                        }
                        LOG_DEBUG("rbp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, brp_i,
                                brp_list[brp_i].control, brp_list[brp_i].value);
-                       brp_list[brp_i].used = 0;
+                       brp_list[brp_i].used = false;
                        brp_list[brp_i].value = 0;
                        brp_list[brp_i].control = 0;
                        retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base
@@ -1661,6 +1672,200 @@ static int cortex_a_remove_breakpoint(struct target *target, struct breakpoint *
        return ERROR_OK;
 }
 
+/**
+ * Sets a watchpoint for an Cortex-A target in one of the watchpoint units.  It is
+ * considered a bug to call this function when there are no available watchpoint
+ * units.
+ *
+ * @param target Pointer to an Cortex-A target to set a watchpoint on
+ * @param watchpoint Pointer to the watchpoint to be set
+ * @return Error status if watchpoint set fails or the result of executing the
+ * JTAG queue
+ */
+static int cortex_a_set_watchpoint(struct target *target, struct watchpoint *watchpoint)
+{
+       int retval = ERROR_OK;
+       int wrp_i = 0;
+       uint32_t control;
+       uint32_t address;
+       uint8_t address_mask;
+       uint8_t byte_address_select;
+       uint8_t load_store_access_control = 0x3;
+       struct cortex_a_common *cortex_a = target_to_cortex_a(target);
+       struct armv7a_common *armv7a = &cortex_a->armv7a_common;
+       struct cortex_a_wrp *wrp_list = cortex_a->wrp_list;
+
+       if (watchpoint->set) {
+               LOG_WARNING("watchpoint already set");
+               return retval;
+       }
+
+       /* check available context WRPs */
+       while (wrp_list[wrp_i].used && (wrp_i < cortex_a->wrp_num))
+               wrp_i++;
+
+       if (wrp_i >= cortex_a->wrp_num) {
+               LOG_ERROR("ERROR Can not find free Watchpoint Register Pair");
+               return ERROR_FAIL;
+       }
+
+       if (watchpoint->length == 0 || watchpoint->length > 0x80000000U ||
+                       (watchpoint->length & (watchpoint->length - 1))) {
+               LOG_WARNING("watchpoint length must be a power of 2");
+               return ERROR_FAIL;
+       }
+
+       if (watchpoint->address & (watchpoint->length - 1)) {
+               LOG_WARNING("watchpoint address must be aligned at length");
+               return ERROR_FAIL;
+       }
+
+       /* FIXME: ARM DDI 0406C: address_mask is optional. What to do if it's missing?  */
+       /* handle wp length 1 and 2 through byte select */
+       switch (watchpoint->length) {
+       case 1:
+               byte_address_select = BIT(watchpoint->address & 0x3);
+               address = watchpoint->address & ~0x3;
+               address_mask = 0;
+               break;
+
+       case 2:
+               byte_address_select = 0x03 << (watchpoint->address & 0x2);
+               address = watchpoint->address & ~0x3;
+               address_mask = 0;
+               break;
+
+       case 4:
+               byte_address_select = 0x0f;
+               address = watchpoint->address;
+               address_mask = 0;
+               break;
+
+       default:
+               byte_address_select = 0xff;
+               address = watchpoint->address;
+               address_mask = ilog2(watchpoint->length);
+               break;
+       }
+
+       watchpoint->set = wrp_i + 1;
+       control = (address_mask << 24) |
+               (byte_address_select << 5) |
+               (load_store_access_control << 3) |
+               (0x3 << 1) | 1;
+       wrp_list[wrp_i].used = true;
+       wrp_list[wrp_i].value = address;
+       wrp_list[wrp_i].control = control;
+
+       retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base
+                       + CPUDBG_WVR_BASE + 4 * wrp_list[wrp_i].WRPn,
+                       wrp_list[wrp_i].value);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base
+                       + CPUDBG_WCR_BASE + 4 * wrp_list[wrp_i].WRPn,
+                       wrp_list[wrp_i].control);
+       if (retval != ERROR_OK)
+               return retval;
+
+       LOG_DEBUG("wp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, wrp_i,
+                       wrp_list[wrp_i].control,
+                       wrp_list[wrp_i].value);
+
+       return ERROR_OK;
+}
+
+/**
+ * Unset an existing watchpoint and clear the used watchpoint unit.
+ *
+ * @param target Pointer to the target to have the watchpoint removed
+ * @param watchpoint Pointer to the watchpoint to be removed
+ * @return Error status while trying to unset the watchpoint or the result of
+ *         executing the JTAG queue
+ */
+static int cortex_a_unset_watchpoint(struct target *target, struct watchpoint *watchpoint)
+{
+       int retval;
+       struct cortex_a_common *cortex_a = target_to_cortex_a(target);
+       struct armv7a_common *armv7a = &cortex_a->armv7a_common;
+       struct cortex_a_wrp *wrp_list = cortex_a->wrp_list;
+
+       if (!watchpoint->set) {
+               LOG_WARNING("watchpoint not set");
+               return ERROR_OK;
+       }
+
+       int wrp_i = watchpoint->set - 1;
+       if (wrp_i < 0 || wrp_i >= cortex_a->wrp_num) {
+               LOG_DEBUG("Invalid WRP number in watchpoint");
+               return ERROR_OK;
+       }
+       LOG_DEBUG("wrp %i control 0x%0" PRIx32 " value 0x%0" PRIx32, wrp_i,
+                       wrp_list[wrp_i].control, wrp_list[wrp_i].value);
+       wrp_list[wrp_i].used = false;
+       wrp_list[wrp_i].value = 0;
+       wrp_list[wrp_i].control = 0;
+       retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base
+                       + CPUDBG_WCR_BASE + 4 * wrp_list[wrp_i].WRPn,
+                       wrp_list[wrp_i].control);
+       if (retval != ERROR_OK)
+               return retval;
+       retval = cortex_a_dap_write_memap_register_u32(target, armv7a->debug_base
+                       + CPUDBG_WVR_BASE + 4 * wrp_list[wrp_i].WRPn,
+                       wrp_list[wrp_i].value);
+       if (retval != ERROR_OK)
+               return retval;
+       watchpoint->set = 0;
+
+       return ERROR_OK;
+}
+
+/**
+ * Add a watchpoint to an Cortex-A target.  If there are no watchpoint units
+ * available, an error response is returned.
+ *
+ * @param target Pointer to the Cortex-A target to add a watchpoint to
+ * @param watchpoint Pointer to the watchpoint to be added
+ * @return Error status while trying to add the watchpoint
+ */
+static int cortex_a_add_watchpoint(struct target *target, struct watchpoint *watchpoint)
+{
+       struct cortex_a_common *cortex_a = target_to_cortex_a(target);
+
+       if (cortex_a->wrp_num_available < 1) {
+               LOG_INFO("no hardware watchpoint available");
+               return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+       }
+
+       int retval = cortex_a_set_watchpoint(target, watchpoint);
+       if (retval != ERROR_OK)
+               return retval;
+
+       cortex_a->wrp_num_available--;
+       return ERROR_OK;
+}
+
+/**
+ * Remove a watchpoint from an Cortex-A target.  The watchpoint will be unset and
+ * the used watchpoint unit will be reopened.
+ *
+ * @param target Pointer to the target to remove a watchpoint from
+ * @param watchpoint Pointer to the watchpoint to be removed
+ * @return Result of trying to unset the watchpoint
+ */
+static int cortex_a_remove_watchpoint(struct target *target, struct watchpoint *watchpoint)
+{
+       struct cortex_a_common *cortex_a = target_to_cortex_a(target);
+
+       if (watchpoint->set) {
+               cortex_a->wrp_num_available++;
+               cortex_a_unset_watchpoint(target, watchpoint);
+       }
+       return ERROR_OK;
+}
+
+
 /*
  * Cortex-A Reset functions
  */
@@ -1684,12 +1889,12 @@ static int cortex_a_assert_reset(struct target *target)
                 */
 
                /*
-                * FIXME: fix reset when transport is SWD. This is a temporary
+                * FIXME: fix reset when transport is not JTAG. This is a temporary
                 * work-around for release v0.10 that is not intended to stay!
                 */
-               if (transport_is_swd() ||
+               if (!transport_is_jtag() ||
                                (target->reset_halt && (jtag_get_reset_config() & RESET_SRST_NO_GATING)))
-                       jtag_add_reset(0, 1);
+                       adapter_assert_reset();
 
        } else {
                LOG_ERROR("%s: how to reset?", target_name(target));
@@ -1707,12 +1912,13 @@ static int cortex_a_assert_reset(struct target *target)
 
 static int cortex_a_deassert_reset(struct target *target)
 {
+       struct armv7a_common *armv7a = target_to_armv7a(target);
        int retval;
 
        LOG_DEBUG(" ");
 
        /* be certain SRST is off */
-       jtag_add_reset(0, 0);
+       adapter_deassert_reset();
 
        if (target_was_examined(target)) {
                retval = cortex_a_poll(target);
@@ -1725,7 +1931,8 @@ static int cortex_a_deassert_reset(struct target *target)
                        LOG_WARNING("%s: ran after reset and before halt ...",
                                target_name(target));
                        if (target_was_examined(target)) {
-                               retval = target_halt(target);
+                               retval = mem_ap_write_atomic_u32(armv7a->debug_ap,
+                                               armv7a->debug_base + CPUDBG_DRCR, DRCR_HALT);
                                if (retval != ERROR_OK)
                                        return retval;
                        } else
@@ -1763,14 +1970,22 @@ static int cortex_a_wait_dscr_bits(struct target *target, uint32_t mask,
 {
        /* Waits until the specified bit(s) of DSCR take on a specified value. */
        struct armv7a_common *armv7a = target_to_armv7a(target);
-       int64_t then = timeval_ms();
+       int64_t then;
        int retval;
 
-       while ((*dscr & mask) != value) {
+       if ((*dscr & mask) == value)
+               return ERROR_OK;
+
+       then = timeval_ms();
+       while (1) {
                retval = mem_ap_read_atomic_u32(armv7a->debug_ap,
                                armv7a->debug_base + CPUDBG_DSCR, dscr);
-               if (retval != ERROR_OK)
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Could not read DSCR register");
                        return retval;
+               }
+               if ((*dscr & mask) == value)
+                       break;
                if (timeval_ms() > then + 1000) {
                        LOG_ERROR("timeout waiting for DSCR bit change");
                        return ERROR_FAIL;
@@ -1914,7 +2129,8 @@ static int cortex_a_write_cpu_memory_slow(struct target *target,
 {
        /* Writes count objects of size size from *buffer. Old value of DSCR must
         * be in *dscr; updated to new value. This is slow because it works for
-        * non-word-sized objects and (maybe) unaligned accesses. If size == 4 and
+        * non-word-sized objects. Avoid unaligned accesses as they do not work
+        * on memory address space without "Normal" attribute. If size == 4 and
         * the address is aligned, cortex_a_write_cpu_memory_fast should be
         * preferred.
         * Preconditions:
@@ -2071,7 +2287,22 @@ static int cortex_a_write_cpu_memory(struct target *target,
                /* We are doing a word-aligned transfer, so use fast mode. */
                retval = cortex_a_write_cpu_memory_fast(target, count, buffer, &dscr);
        } else {
-               /* Use slow path. */
+               /* Use slow path. Adjust size for aligned accesses */
+               switch (address % 4) {
+                       case 1:
+                       case 3:
+                               count *= size;
+                               size = 1;
+                               break;
+                       case 2:
+                               if (size == 4) {
+                                       count *= 2;
+                                       size = 2;
+                               }
+                       case 0:
+                       default:
+                               break;
+               }
                retval = cortex_a_write_cpu_memory_slow(target, size, count, buffer, &dscr);
        }
 
@@ -2157,7 +2388,8 @@ static int cortex_a_read_cpu_memory_slow(struct target *target,
 {
        /* Reads count objects of size size into *buffer. Old value of DSCR must be
         * in *dscr; updated to new value. This is slow because it works for
-        * non-word-sized objects and (maybe) unaligned accesses. If size == 4 and
+        * non-word-sized objects. Avoid unaligned accesses as they do not work
+        * on memory address space without "Normal" attribute. If size == 4 and
         * the address is aligned, cortex_a_read_cpu_memory_fast should be
         * preferred.
         * Preconditions:
@@ -2373,7 +2605,23 @@ static int cortex_a_read_cpu_memory(struct target *target,
                /* We are doing a word-aligned transfer, so use fast mode. */
                retval = cortex_a_read_cpu_memory_fast(target, count, buffer, &dscr);
        } else {
-               /* Use slow path. */
+               /* Use slow path. Adjust size for aligned accesses */
+               switch (address % 4) {
+                       case 1:
+                       case 3:
+                               count *= size;
+                               size = 1;
+                               break;
+                       case 2:
+                               if (size == 4) {
+                                       count *= 2;
+                                       size = 2;
+                               }
+                               break;
+                       case 0:
+                       default:
+                               break;
+               }
                retval = cortex_a_read_cpu_memory_slow(target, size, count, buffer, &dscr);
        }
 
@@ -2459,7 +2707,7 @@ static int cortex_a_read_phys_memory(struct target *target,
        if (!count || !buffer)
                return ERROR_COMMAND_SYNTAX_ERROR;
 
-       LOG_DEBUG("Reading memory at real address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32,
+       LOG_DEBUG("Reading memory at real address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32,
                address, size, count);
 
        /* read memory through the CPU */
@@ -2476,7 +2724,7 @@ static int cortex_a_read_memory(struct target *target, target_addr_t address,
        int retval;
 
        /* cortex_a handles unaligned memory access */
-       LOG_DEBUG("Reading memory at address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32,
+       LOG_DEBUG("Reading memory at address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32,
                address, size, count);
 
        cortex_a_prep_memaccess(target, 0);
@@ -2495,7 +2743,7 @@ static int cortex_a_write_phys_memory(struct target *target,
        if (!count || !buffer)
                return ERROR_COMMAND_SYNTAX_ERROR;
 
-       LOG_DEBUG("Writing memory to real address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32,
+       LOG_DEBUG("Writing memory to real address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32,
                address, size, count);
 
        /* write memory through the CPU */
@@ -2512,7 +2760,7 @@ static int cortex_a_write_memory(struct target *target, target_addr_t address,
        int retval;
 
        /* cortex_a handles unaligned memory access */
-       LOG_DEBUG("Writing memory at address " TARGET_ADDR_FMT "; size %" PRId32 "; count %" PRId32,
+       LOG_DEBUG("Writing memory at address " TARGET_ADDR_FMT "; size %" PRIu32 "; count %" PRIu32,
                address, size, count);
 
        /* memory writes bypass the caches, must flush before writing */
@@ -2641,7 +2889,7 @@ static int cortex_a_examine_first(struct target *target)
 
        int i;
        int retval = ERROR_OK;
-       uint32_t didr, cpuid, dbg_osreg;
+       uint32_t didr, cpuid, dbg_osreg, dbg_idpfr1;
 
        /* Search for the APB-AP - it is needed for access to debug registers */
        retval = dap_find_ap(swjdp, AP_TYPE_APB_AP, &armv7a->debug_ap);
@@ -2681,6 +2929,10 @@ static int cortex_a_examine_first(struct target *target)
        } else
                armv7a->debug_base = target->dbgbase;
 
+       if ((armv7a->debug_base & (1UL<<31)) == 0)
+               LOG_WARNING("Debug base address for target %s has bit 31 set to 0. Access to debug registers will likely fail!\n"
+                           "Please fix the target configuration.", target_name(target));
+
        retval = mem_ap_read_atomic_u32(armv7a->debug_ap,
                        armv7a->debug_base + CPUDBG_DIDR, &didr);
        if (retval != ERROR_OK) {
@@ -2746,7 +2998,25 @@ static int cortex_a_examine_first(struct target *target)
                }
        }
 
-       armv7a->arm.core_type = ARM_MODE_MON;
+       retval = mem_ap_read_atomic_u32(armv7a->debug_ap,
+                                armv7a->debug_base + CPUDBG_ID_PFR1, &dbg_idpfr1);
+       if (retval != ERROR_OK)
+               return retval;
+
+       if (dbg_idpfr1 & 0x000000f0) {
+               LOG_DEBUG("target->coreid %" PRId32 " has security extensions",
+                               target->coreid);
+               armv7a->arm.core_type = ARM_CORE_TYPE_SEC_EXT;
+       }
+       if (dbg_idpfr1 & 0x0000f000) {
+               LOG_DEBUG("target->coreid %" PRId32 " has virtualization extensions",
+                               target->coreid);
+               /*
+                * overwrite and simplify the checks.
+                * virtualization extensions require implementation of security extension
+                */
+               armv7a->arm.core_type = ARM_CORE_TYPE_VIRT_EXT;
+       }
 
        /* Avoid recreating the registers cache */
        if (!target_was_examined(target)) {
@@ -2763,7 +3033,7 @@ static int cortex_a_examine_first(struct target *target)
        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++) {
-               cortex_a->brp_list[i].used = 0;
+               cortex_a->brp_list[i].used = false;
                if (i < (cortex_a->brp_num-cortex_a->brp_num_context))
                        cortex_a->brp_list[i].type = BRP_NORMAL;
                else
@@ -2775,6 +3045,20 @@ static int cortex_a_examine_first(struct target *target)
 
        LOG_DEBUG("Configured %i hw breakpoints", cortex_a->brp_num);
 
+       /* Setup Watchpoint Register Pairs */
+       cortex_a->wrp_num = ((didr >> 28) & 0x0F) + 1;
+       cortex_a->wrp_num_available = cortex_a->wrp_num;
+       free(cortex_a->wrp_list);
+       cortex_a->wrp_list = calloc(cortex_a->wrp_num, sizeof(struct cortex_a_wrp));
+       for (i = 0; i < cortex_a->wrp_num; i++) {
+               cortex_a->wrp_list[i].used = false;
+               cortex_a->wrp_list[i].value = 0;
+               cortex_a->wrp_list[i].control = 0;
+               cortex_a->wrp_list[i].WRPn = i;
+       }
+
+       LOG_DEBUG("Configured %i hw watchpoints", cortex_a->wrp_num);
+
        /* select debug_ap as default */
        swjdp->apsel = armv7a->debug_ap->ap_num;
 
@@ -2897,7 +3181,9 @@ static void cortex_a_deinit_target(struct target *target)
                                        dscr & ~DSCR_HALT_DBG_MODE);
        }
 
+       free(cortex_a->wrp_list);
        free(cortex_a->brp_list);
+       arm_free_reg_cache(dpm->arm);
        free(dpm->dbp);
        free(dpm->dwp);
        free(target->private_config);
@@ -2944,7 +3230,7 @@ static int cortex_a_virt2phys(struct target *target,
        if (retval != ERROR_OK)
                return retval;
        return armv7a_mmu_translate_va_pa(target, (uint32_t)virt,
-                                                   (uint32_t *)phys, 1);
+                                                   phys, 1);
 }
 
 COMMAND_HANDLER(cortex_a_handle_cache_info_command)
@@ -2952,7 +3238,7 @@ COMMAND_HANDLER(cortex_a_handle_cache_info_command)
        struct target *target = get_current_target(CMD_CTX);
        struct armv7a_common *armv7a = target_to_armv7a(target);
 
-       return armv7a_handle_cache_info_command(CMD_CTX,
+       return armv7a_handle_cache_info_command(CMD,
                        &armv7a->armv7a_mmu.armv7a_cache);
 }
 
@@ -2973,15 +3259,15 @@ 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[] = {
+       static const struct 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;
+       const struct jim_nvp *n;
 
        if (CMD_ARGC > 0) {
-               n = Jim_Nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]);
+               n = jim_nvp_name2value_simple(nvp_maskisr_modes, CMD_ARGV[0]);
                if (n->name == NULL) {
                        LOG_ERROR("Unknown parameter: %s - should be off or on", CMD_ARGV[0]);
                        return ERROR_COMMAND_SYNTAX_ERROR;
@@ -2990,8 +3276,8 @@ COMMAND_HANDLER(handle_cortex_a_mask_interrupts_command)
                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);
+       n = jim_nvp_value2name_simple(nvp_maskisr_modes, cortex_a->isrmasking_mode);
+       command_print(CMD, "cortex_a interrupt mask %s", n->name);
 
        return ERROR_OK;
 }
@@ -3001,23 +3287,23 @@ COMMAND_HANDLER(handle_cortex_a_dacrfixup_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_dacrfixup_modes[] = {
+       static const struct jim_nvp nvp_dacrfixup_modes[] = {
                { .name = "off", .value = CORTEX_A_DACRFIXUP_OFF },
                { .name = "on", .value = CORTEX_A_DACRFIXUP_ON },
                { .name = NULL, .value = -1 },
        };
-       const Jim_Nvp *n;
+       const struct jim_nvp *n;
 
        if (CMD_ARGC > 0) {
-               n = Jim_Nvp_name2value_simple(nvp_dacrfixup_modes, CMD_ARGV[0]);
+               n = jim_nvp_name2value_simple(nvp_dacrfixup_modes, CMD_ARGV[0]);
                if (n->name == NULL)
                        return ERROR_COMMAND_SYNTAX_ERROR;
                cortex_a->dacrfixup_mode = n->value;
 
        }
 
-       n = Jim_Nvp_value2name_simple(nvp_dacrfixup_modes, cortex_a->dacrfixup_mode);
-       command_print(CMD_CTX, "cortex_a domain access control fixup %s", n->name);
+       n = jim_nvp_value2name_simple(nvp_dacrfixup_modes, cortex_a->dacrfixup_mode);
+       command_print(CMD, "cortex_a domain access control fixup %s", n->name);
 
        return ERROR_OK;
 }
@@ -3080,7 +3366,6 @@ static const struct command_registration cortex_a_command_handlers[] = {
 
 struct target_type cortexa_target = {
        .name = "cortex_a",
-       .deprecated_name = "cortex_a8",
 
        .poll = cortex_a_poll,
        .arch_state = armv7a_arch_state,
@@ -3111,8 +3396,8 @@ struct target_type cortexa_target = {
        .add_context_breakpoint = cortex_a_add_context_breakpoint,
        .add_hybrid_breakpoint = cortex_a_add_hybrid_breakpoint,
        .remove_breakpoint = cortex_a_remove_breakpoint,
-       .add_watchpoint = NULL,
-       .remove_watchpoint = NULL,
+       .add_watchpoint = cortex_a_add_watchpoint,
+       .remove_watchpoint = cortex_a_remove_watchpoint,
 
        .commands = cortex_a_command_handlers,
        .target_create = cortex_a_target_create,
@@ -3188,8 +3473,8 @@ struct target_type cortexr4_target = {
        .add_context_breakpoint = cortex_a_add_context_breakpoint,
        .add_hybrid_breakpoint = cortex_a_add_hybrid_breakpoint,
        .remove_breakpoint = cortex_a_remove_breakpoint,
-       .add_watchpoint = NULL,
-       .remove_watchpoint = NULL,
+       .add_watchpoint = cortex_a_add_watchpoint,
+       .remove_watchpoint = cortex_a_remove_watchpoint,
 
        .commands = cortex_r4_command_handlers,
        .target_create = cortex_r4_target_create,