]> git.sur5r.net Git - openocd/blobdiff - src/target/cortex_m.c
cortex_m.c: Use two byte breakpoint for 32bit Thumb-2 request
[openocd] / src / target / cortex_m.c
index 44763943fb958a2c4f52e60575978a63c4c59851..a5230b75c737adabe6b8874e215282705ec693e5 100644 (file)
 static int cortex_m_store_core_reg_u32(struct target *target,
                uint32_t num, uint32_t value);
 
-static int cortexm_dap_read_coreregister_u32(struct adiv5_dap *swjdp,
+static int cortexm_dap_read_coreregister_u32(struct target *target,
        uint32_t *value, int regnum)
 {
+       struct armv7m_common *armv7m = target_to_armv7m(target);
+       struct adiv5_dap *swjdp = armv7m->arm.dap;
        int retval;
        uint32_t dcrdr;
 
        /* because the DCB_DCRDR is used for the emulated dcc channel
         * we have to save/restore the DCB_DCRDR when used */
+       if (target->dbg_msg_enabled) {
+               retval = mem_ap_read_u32(swjdp, DCB_DCRDR, &dcrdr);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
 
-       retval = mem_ap_read_u32(swjdp, DCB_DCRDR, &dcrdr);
-       if (retval != ERROR_OK)
-               return retval;
-
-       /* mem_ap_write_u32(swjdp, DCB_DCRSR, regnum); */
-       retval = dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0);
-       if (retval != ERROR_OK)
-               return retval;
-       retval = dap_queue_ap_write(swjdp, AP_REG_BD0 | (DCB_DCRSR & 0xC), regnum);
-       if (retval != ERROR_OK)
-               return retval;
-
-       /* mem_ap_read_u32(swjdp, DCB_DCRDR, value); */
-       retval = dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0);
-       if (retval != ERROR_OK)
-               return retval;
-       retval = dap_queue_ap_read(swjdp, AP_REG_BD0 | (DCB_DCRDR & 0xC), value);
+       retval = mem_ap_write_u32(swjdp, DCB_DCRSR, regnum);
        if (retval != ERROR_OK)
                return retval;
 
-       retval = dap_run(swjdp);
+       retval = mem_ap_read_atomic_u32(swjdp, DCB_DCRDR, value);
        if (retval != ERROR_OK)
                return retval;
 
-       /* restore DCB_DCRDR - this needs to be in a seperate
-        * transaction otherwise the emulated DCC channel breaks */
-       if (retval == ERROR_OK)
-               retval = mem_ap_write_atomic_u32(swjdp, DCB_DCRDR, dcrdr);
+       if (target->dbg_msg_enabled) {
+               /* restore DCB_DCRDR - this needs to be in a separate
+                * transaction otherwise the emulated DCC channel breaks */
+               if (retval == ERROR_OK)
+                       retval = mem_ap_write_atomic_u32(swjdp, DCB_DCRDR, dcrdr);
+       }
 
        return retval;
 }
 
-static int cortexm_dap_write_coreregister_u32(struct adiv5_dap *swjdp,
+static int cortexm_dap_write_coreregister_u32(struct target *target,
        uint32_t value, int regnum)
 {
+       struct armv7m_common *armv7m = target_to_armv7m(target);
+       struct adiv5_dap *swjdp = armv7m->arm.dap;
        int retval;
        uint32_t dcrdr;
 
        /* because the DCB_DCRDR is used for the emulated dcc channel
         * we have to save/restore the DCB_DCRDR when used */
+       if (target->dbg_msg_enabled) {
+               retval = mem_ap_read_u32(swjdp, DCB_DCRDR, &dcrdr);
+               if (retval != ERROR_OK)
+                       return retval;
+       }
 
-       retval = mem_ap_read_u32(swjdp, DCB_DCRDR, &dcrdr);
-       if (retval != ERROR_OK)
-               return retval;
-
-       /* mem_ap_write_u32(swjdp, DCB_DCRDR, core_regs[i]); */
-       retval = dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRDR & 0xFFFFFFF0);
-       if (retval != ERROR_OK)
-               return retval;
-       retval = dap_queue_ap_write(swjdp, AP_REG_BD0 | (DCB_DCRDR & 0xC), value);
-       if (retval != ERROR_OK)
-               return retval;
-
-       /* mem_ap_write_u32(swjdp, DCB_DCRSR, i | DCRSR_WnR); */
-       retval = dap_setup_accessport(swjdp, CSW_32BIT | CSW_ADDRINC_OFF, DCB_DCRSR & 0xFFFFFFF0);
-       if (retval != ERROR_OK)
-               return retval;
-       retval = dap_queue_ap_write(swjdp, AP_REG_BD0 | (DCB_DCRSR & 0xC), regnum | DCRSR_WnR);
+       retval = mem_ap_write_u32(swjdp, DCB_DCRDR, value);
        if (retval != ERROR_OK)
                return retval;
 
-       retval = dap_run(swjdp);
+       retval = mem_ap_write_atomic_u32(swjdp, DCB_DCRSR, regnum | DCRSR_WnR);
        if (retval != ERROR_OK)
                return retval;
 
-       /* restore DCB_DCRDR - this needs to be in a seperate
-        * transaction otherwise the emulated DCC channel breaks */
-       if (retval == ERROR_OK)
-               retval = mem_ap_write_atomic_u32(swjdp, DCB_DCRDR, dcrdr);
+       if (target->dbg_msg_enabled) {
+               /* restore DCB_DCRDR - this needs to be in a seperate
+                * transaction otherwise the emulated DCC channel breaks */
+               if (retval == ERROR_OK)
+                       retval = mem_ap_write_atomic_u32(swjdp, DCB_DCRDR, dcrdr);
+       }
 
        return retval;
 }
@@ -535,15 +521,8 @@ static int cortex_m_poll(struct target *target)
        }
 
        if (cortex_m->dcb_dhcsr & S_RESET_ST) {
-               /* check if still in reset */
-               retval = mem_ap_read_atomic_u32(swjdp, DCB_DHCSR, &cortex_m->dcb_dhcsr);
-               if (retval != ERROR_OK)
-                       return retval;
-
-               if (cortex_m->dcb_dhcsr & S_RESET_ST) {
-                       target->state = TARGET_RESET;
-                       return ERROR_OK;
-               }
+               target->state = TARGET_RESET;
+               return ERROR_OK;
        }
 
        if (target->state == TARGET_RESET) {
@@ -552,7 +531,11 @@ static int cortex_m_poll(struct target *target)
                 */
                LOG_DEBUG("Exit from reset with dcb_dhcsr 0x%" PRIx32,
                        cortex_m->dcb_dhcsr);
-               cortex_m_endreset_event(target);
+               retval = cortex_m_endreset_event(target);
+               if (retval != ERROR_OK) {
+                       target->state = TARGET_UNKNOWN;
+                       return retval;
+               }
                target->state = TARGET_RUNNING;
                prev_target_state = TARGET_RUNNING;
        }
@@ -771,7 +754,7 @@ static int cortex_m_resume(struct target *target, int current,
                /* Single step past breakpoint at current address */
                breakpoint = breakpoint_find(target, resume_pc);
                if (breakpoint) {
-                       LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 " (ID: %d)",
+                       LOG_DEBUG("unset breakpoint at 0x%8.8" PRIx32 " (ID: %" PRIu32 ")",
                                breakpoint->address,
                                breakpoint->unique_id);
                        cortex_m_unset_breakpoint(target, breakpoint);
@@ -1083,6 +1066,19 @@ static int cortex_m_assert_reset(struct target *target)
                                "handler to reset any peripherals or configure hardware srst support.");
                }
 
+               /*
+                 SAM4L needs to execute security initalization
+                 startup sequence before AP access would be enabled.
+                 During the intialization CDBGPWRUPACK is pulled low and we
+                 need to wait for it to be set to 1 again.
+               */
+               retval = dap_dp_poll_register(swjdp, DP_CTRL_STAT,
+                                             CDBGPWRUPACK, CDBGPWRUPACK, 100);
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("Failed waitnig for CDBGPWRUPACK");
+                       return ERROR_FAIL;
+               }
+
                {
                        /* I do not know why this is necessary, but it
                         * fixes strange effects (step/resume cause NMI
@@ -1129,7 +1125,7 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint
        struct cortex_m_fp_comparator *comparator_list = cortex_m->fp_comparator_list;
 
        if (breakpoint->set) {
-               LOG_WARNING("breakpoint (BPID: %d) already set", breakpoint->unique_id);
+               LOG_WARNING("breakpoint (BPID: %" PRIu32 ") already set", breakpoint->unique_id);
                return ERROR_OK;
        }
 
@@ -1185,7 +1181,7 @@ int cortex_m_set_breakpoint(struct target *target, struct breakpoint *breakpoint
                breakpoint->set = true;
        }
 
-       LOG_DEBUG("BPID: %d, Type: %d, Address: 0x%08" PRIx32 " Length: %d (set=%d)",
+       LOG_DEBUG("BPID: %" PRIu32 ", Type: %d, Address: 0x%08" PRIx32 " Length: %d (set=%d)",
                breakpoint->unique_id,
                (int)(breakpoint->type),
                breakpoint->address,
@@ -1206,7 +1202,7 @@ int cortex_m_unset_breakpoint(struct target *target, struct breakpoint *breakpoi
                return ERROR_OK;
        }
 
-       LOG_DEBUG("BPID: %d, Type: %d, Address: 0x%08" PRIx32 " Length: %d (set=%d)",
+       LOG_DEBUG("BPID: %" PRIu32 ", Type: %d, Address: 0x%08" PRIx32 " Length: %d (set=%d)",
                breakpoint->unique_id,
                (int)(breakpoint->type),
                breakpoint->address,
@@ -1266,6 +1262,11 @@ int cortex_m_add_breakpoint(struct target *target, struct breakpoint *breakpoint
                return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
        }
 
+       if (breakpoint->length == 3) {
+               LOG_DEBUG("Using a two byte breakpoint for 32bit Thumb-2 request");
+               breakpoint->length = 2;
+       }
+
        if ((breakpoint->length != 2)) {
                LOG_INFO("only breakpoints of two bytes length supported");
                return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
@@ -1480,8 +1481,6 @@ static int cortex_m_load_core_reg_u32(struct target *target,
                uint32_t num, uint32_t *value)
 {
        int retval;
-       struct armv7m_common *armv7m = target_to_armv7m(target);
-       struct adiv5_dap *swjdp = armv7m->arm.dap;
 
        /* NOTE:  we "know" here that the register identifiers used
         * in the v7m header match the Cortex-M3 Debug Core Register
@@ -1490,7 +1489,7 @@ static int cortex_m_load_core_reg_u32(struct target *target,
        switch (num) {
                case 0 ... 18:
                        /* read a normal core register */
-                       retval = cortexm_dap_read_coreregister_u32(swjdp, value, num);
+                       retval = cortexm_dap_read_coreregister_u32(target, value, num);
 
                        if (retval != ERROR_OK) {
                                LOG_ERROR("JTAG failure %i", retval);
@@ -1507,7 +1506,7 @@ static int cortex_m_load_core_reg_u32(struct target *target,
                         * in one Debug Core register.  So say r0 and r2 docs;
                         * it was removed from r1 docs, but still works.
                         */
-                       cortexm_dap_read_coreregister_u32(swjdp, value, 20);
+                       cortexm_dap_read_coreregister_u32(target, value, 20);
 
                        switch (num) {
                                case ARMV7M_PRIMASK:
@@ -1543,7 +1542,6 @@ static int cortex_m_store_core_reg_u32(struct target *target,
        int retval;
        uint32_t reg;
        struct armv7m_common *armv7m = target_to_armv7m(target);
-       struct adiv5_dap *swjdp = armv7m->arm.dap;
 
        /* NOTE:  we "know" here that the register identifiers used
         * in the v7m header match the Cortex-M3 Debug Core Register
@@ -1551,7 +1549,7 @@ static int cortex_m_store_core_reg_u32(struct target *target,
         */
        switch (num) {
                case 0 ... 18:
-                       retval = cortexm_dap_write_coreregister_u32(swjdp, value, num);
+                       retval = cortexm_dap_write_coreregister_u32(target, value, num);
                        if (retval != ERROR_OK) {
                                struct reg *r;
 
@@ -1571,7 +1569,7 @@ static int cortex_m_store_core_reg_u32(struct target *target,
                         * in one Debug Core register.  So say r0 and r2 docs;
                         * it was removed from r1 docs, but still works.
                         */
-                       cortexm_dap_read_coreregister_u32(swjdp, &reg, 20);
+                       cortexm_dap_read_coreregister_u32(target, &reg, 20);
 
                        switch (num) {
                                case ARMV7M_PRIMASK:
@@ -1591,7 +1589,7 @@ static int cortex_m_store_core_reg_u32(struct target *target,
                                        break;
                        }
 
-                       cortexm_dap_write_coreregister_u32(swjdp, reg, 20);
+                       cortexm_dap_write_coreregister_u32(target, reg, 20);
 
                        LOG_DEBUG("write special reg %i value 0x%" PRIx32 " ", (int)num, value);
                        break;
@@ -1745,7 +1743,7 @@ fail1:
                free(cm->dwt_comparator_list);
                goto fail0;
        }
-       cache->name = "cortex-m3 dwt registers";
+       cache->name = "Cortex-M DWT registers";
        cache->num_regs = 2 + cm->dwt_num_comp * 3;
        cache->reg_list = calloc(cache->num_regs, sizeof *cache->reg_list);
        if (!cache->reg_list) {
@@ -1879,12 +1877,19 @@ int cortex_m_examine(struct target *target)
        return ERROR_OK;
 }
 
-static int cortex_m_dcc_read(struct adiv5_dap *swjdp, uint8_t *value, uint8_t *ctrl)
+static int cortex_m_dcc_read(struct target *target, uint8_t *value, uint8_t *ctrl)
 {
+       struct armv7m_common *armv7m = target_to_armv7m(target);
+       struct adiv5_dap *swjdp = armv7m->arm.dap;
        uint16_t dcrdr;
+       uint8_t buf[2];
        int retval;
 
-       mem_ap_read_buf_u16(swjdp, (uint8_t *)&dcrdr, 2, DCB_DCRDR);
+       retval = mem_ap_read(swjdp, buf, 2, 1, DCB_DCRDR, false);
+       if (retval != ERROR_OK)
+               return retval;
+
+       dcrdr = target_buffer_get_u16(target, buf);
        *ctrl = (uint8_t)dcrdr;
        *value = (uint8_t)(dcrdr >> 8);
 
@@ -1893,8 +1898,8 @@ static int cortex_m_dcc_read(struct adiv5_dap *swjdp, uint8_t *value, uint8_t *c
        /* write ack back to software dcc register
         * signify we have read data */
        if (dcrdr & (1 << 0)) {
-               dcrdr = 0;
-               retval = mem_ap_write_buf_u16(swjdp, (uint8_t *)&dcrdr, 2, DCB_DCRDR);
+               target_buffer_set_u16(target, buf, 0);
+               retval = mem_ap_write(swjdp, buf, 2, 1, DCB_DCRDR, false);
                if (retval != ERROR_OK)
                        return retval;
        }
@@ -1905,14 +1910,14 @@ static int cortex_m_dcc_read(struct adiv5_dap *swjdp, uint8_t *value, uint8_t *c
 static int cortex_m_target_request_data(struct target *target,
        uint32_t size, uint8_t *buffer)
 {
-       struct armv7m_common *armv7m = target_to_armv7m(target);
-       struct adiv5_dap *swjdp = armv7m->arm.dap;
        uint8_t data;
        uint8_t ctrl;
        uint32_t i;
 
        for (i = 0; i < (size * 4); i++) {
-               cortex_m_dcc_read(swjdp, &data, &ctrl);
+               int retval = cortex_m_dcc_read(target, &data, &ctrl);
+               if (retval != ERROR_OK)
+                       return retval;
                buffer[i] = data;
        }
 
@@ -1924,8 +1929,6 @@ static int cortex_m_handle_target_request(void *priv)
        struct target *target = priv;
        if (!target_was_examined(target))
                return ERROR_OK;
-       struct armv7m_common *armv7m = target_to_armv7m(target);
-       struct adiv5_dap *swjdp = armv7m->arm.dap;
 
        if (!target->dbg_msg_enabled)
                return ERROR_OK;
@@ -1933,8 +1936,11 @@ static int cortex_m_handle_target_request(void *priv)
        if (target->state == TARGET_RUNNING) {
                uint8_t data;
                uint8_t ctrl;
+               int retval;
 
-               cortex_m_dcc_read(swjdp, &data, &ctrl);
+               retval = cortex_m_dcc_read(target, &data, &ctrl);
+               if (retval != ERROR_OK)
+                       return retval;
 
                /* check if we have data */
                if (ctrl & (1 << 0)) {
@@ -1942,12 +1948,12 @@ static int cortex_m_handle_target_request(void *priv)
 
                        /* we assume target is quick enough */
                        request = data;
-                       cortex_m_dcc_read(swjdp, &data, &ctrl);
-                       request |= (data << 8);
-                       cortex_m_dcc_read(swjdp, &data, &ctrl);
-                       request |= (data << 16);
-                       cortex_m_dcc_read(swjdp, &data, &ctrl);
-                       request |= (data << 24);
+                       for (int i = 1; i <= 3; i++) {
+                               retval = cortex_m_dcc_read(target, &data, &ctrl);
+                               if (retval != ERROR_OK)
+                                       return retval;
+                               request |= ((uint32_t)data << (i * 8));
+                       }
                        target_request(target, request);
                }
        }