]> git.sur5r.net Git - openocd/blobdiff - src/target/cortex_a8.c
cortex a8: add missing error handling for mem_ap_atomic_write_u32()
[openocd] / src / target / cortex_a8.c
index c2d61a3e4355742477576c6d1aaabfc1848f8555..441c93b2f37d590dceb08ab58ef3b6335c1b3737 100644 (file)
@@ -11,6 +11,9 @@
  *   Copyright (C) 2009 by Dirk Behme                                      *
  *   dirk.behme@gmail.com - copy from cortex_m3                            *
  *                                                                         *
+ *   Copyright (C) 2010 Ã˜yvind Harboe                                      *
+ *   oyvind.harboe@zylin.com                                               *
+ *                                                                         *
  *   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     *
@@ -39,6 +42,7 @@
 #include "target_request.h"
 #include "target_type.h"
 #include "arm_opcodes.h"
+#include <helper/time_support.h>
 
 static int cortex_a8_poll(struct target *target);
 static int cortex_a8_debug_entry(struct target *target);
@@ -88,16 +92,28 @@ static int cortex_a8_init_debug_access(struct target *target)
        /* The debugport might be uninitialised so try twice */
        retval = mem_ap_write_atomic_u32(swjdp, armv7a->debug_base + CPUDBG_LOCKACCESS, 0xC5ACCE55);
        if (retval != ERROR_OK)
-               mem_ap_write_atomic_u32(swjdp, armv7a->debug_base + CPUDBG_LOCKACCESS, 0xC5ACCE55);
+       {
+               /* try again */
+               retval = mem_ap_write_atomic_u32(swjdp, armv7a->debug_base + CPUDBG_LOCKACCESS, 0xC5ACCE55);
+               if (retval == ERROR_OK)
+               {
+                       LOG_USER("Locking debug access failed on first, but succeeded on second try.");
+               }
+       }
+       if (retval != ERROR_OK)
+               return retval;
        /* Clear Sticky Power Down status Bit in PRSR to enable access to
           the registers in the Core Power Domain */
        retval = mem_ap_read_atomic_u32(swjdp, armv7a->debug_base + CPUDBG_PRSR, &dummy);
+       if (retval != ERROR_OK)
+               return retval;
+
        /* Enabling of instruction execution in debug mode is done in debug_entry code */
 
        /* Resync breakpoint registers */
 
-       /* Since this is likley called from init or reset, update targtet state information*/
-       cortex_a8_poll(target);
+       /* Since this is likely called from init or reset, update target state information*/
+       retval = cortex_a8_poll(target);
 
        return retval;
 }
@@ -131,7 +147,9 @@ static int cortex_a8_exec_opcode(struct target *target,
                }
        }
 
-       mem_ap_write_u32(swjdp, armv7a->debug_base + CPUDBG_ITR, opcode);
+       retval = mem_ap_write_u32(swjdp, armv7a->debug_base + CPUDBG_ITR, opcode);
+       if (retval != ERROR_OK)
+               return retval;
 
        do
        {
@@ -215,6 +233,8 @@ static int cortex_a8_dap_read_coreregister_u32(struct target *target,
        {
                retval = mem_ap_read_atomic_u32(swjdp,
                                armv7a->debug_base + CPUDBG_DSCR, &dscr);
+               if (retval != ERROR_OK)
+                       return retval;
        }
 
        retval = mem_ap_read_atomic_u32(swjdp,
@@ -238,6 +258,8 @@ static int cortex_a8_dap_write_coreregister_u32(struct target *target,
        /* Check that DCCRX is not full */
        retval = mem_ap_read_atomic_u32(swjdp,
                                armv7a->debug_base + CPUDBG_DSCR, &dscr);
+       if (retval != ERROR_OK)
+               return retval;
        if (dscr & DSCR_DTR_RX_FULL)
        {
                LOG_ERROR("DSCR_DTR_RX_FULL, dscr 0x%08" PRIx32, dscr);
@@ -253,6 +275,8 @@ static int cortex_a8_dap_write_coreregister_u32(struct target *target,
        LOG_DEBUG("write DCC 0x%08" PRIx32, value);
        retval = mem_ap_write_u32(swjdp,
                        armv7a->debug_base + CPUDBG_DTRRX, value);
+       if (retval != ERROR_OK)
+               return retval;
 
        if (Rd < 15)
        {
@@ -339,10 +363,14 @@ static int cortex_a8_read_dcc(struct cortex_a8_common *a8, uint32_t *data,
                retval = mem_ap_read_atomic_u32(swjdp,
                                a8->armv7a_common.debug_base + CPUDBG_DSCR,
                                &dscr);
+               if (retval != ERROR_OK)
+                       return retval;
        }
 
        retval = mem_ap_read_atomic_u32(swjdp,
                        a8->armv7a_common.debug_base + CPUDBG_DTRTX, data);
+       if (retval != ERROR_OK)
+               return retval;
        //LOG_DEBUG("read DCC 0x%08" PRIx32, *data);
 
        if (dscr_p)
@@ -359,11 +387,22 @@ static int cortex_a8_dpm_prepare(struct arm_dpm *dpm)
        int retval;
 
        /* set up invariant:  INSTR_COMP is set after ever DPM operation */
-       do {
+       long long then = timeval_ms();
+       for (;;)
+       {
                retval = mem_ap_read_atomic_u32(swjdp,
                                a8->armv7a_common.debug_base + CPUDBG_DSCR,
                                &dscr);
-       } while ((dscr & DSCR_INSTR_COMP) == 0);
+               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;
+               }
+       }
 
        /* this "should never happen" ... */
        if (dscr & DSCR_DTR_RX_FULL) {
@@ -473,7 +512,7 @@ static int cortex_a8_instr_read_data_r0(struct arm_dpm *dpm,
        return cortex_a8_read_dcc(a8, data, &dscr);
 }
 
-static int cortex_a8_bpwp_enable(struct arm_dpm *dpm, unsigned index,
+static int cortex_a8_bpwp_enable(struct arm_dpm *dpm, unsigned index_t,
                uint32_t addr, uint32_t control)
 {
        struct cortex_a8_common *a8 = dpm_to_a8(dpm);
@@ -481,7 +520,7 @@ static int cortex_a8_bpwp_enable(struct arm_dpm *dpm, unsigned index,
        uint32_t cr = a8->armv7a_common.debug_base;
        int retval;
 
-       switch (index) {
+       switch (index_t) {
        case 0 ... 15:          /* breakpoints */
                vr += CPUDBG_BVR_BASE;
                cr += CPUDBG_BCR_BASE;
@@ -489,13 +528,13 @@ static int cortex_a8_bpwp_enable(struct arm_dpm *dpm, unsigned index,
        case 16 ... 31:         /* watchpoints */
                vr += CPUDBG_WVR_BASE;
                cr += CPUDBG_WCR_BASE;
-               index -= 16;
+               index_t -= 16;
                break;
        default:
                return ERROR_FAIL;
        }
-       vr += 4 * index;
-       cr += 4 * index;
+       vr += 4 * index_t;
+       cr += 4 * index_t;
 
        LOG_DEBUG("A8: bpwp enable, vr %08x cr %08x",
                        (unsigned) vr, (unsigned) cr);
@@ -509,23 +548,23 @@ static int cortex_a8_bpwp_enable(struct arm_dpm *dpm, unsigned index,
        return retval;
 }
 
-static int cortex_a8_bpwp_disable(struct arm_dpm *dpm, unsigned index)
+static int cortex_a8_bpwp_disable(struct arm_dpm *dpm, unsigned index_t)
 {
        struct cortex_a8_common *a8 = dpm_to_a8(dpm);
        uint32_t cr;
 
-       switch (index) {
+       switch (index_t) {
        case 0 ... 15:
                cr = a8->armv7a_common.debug_base + CPUDBG_BCR_BASE;
                break;
        case 16 ... 31:
                cr = a8->armv7a_common.debug_base + CPUDBG_WCR_BASE;
-               index -= 16;
+               index_t -= 16;
                break;
        default:
                return ERROR_FAIL;
        }
-       cr += 4 * index;
+       cr += 4 * index_t;
 
        LOG_DEBUG("A8: bpwp disable, cr %08x", (unsigned) cr);
 
@@ -646,21 +685,38 @@ static int cortex_a8_halt(struct target *target)
         */
        retval = mem_ap_write_atomic_u32(swjdp,
                        armv7a->debug_base + CPUDBG_DRCR, 0x1);
+       if (retval != ERROR_OK)
+               goto out;
 
        /*
         * enter halting debug mode
         */
-       mem_ap_read_atomic_u32(swjdp, armv7a->debug_base + CPUDBG_DSCR, &dscr);
+       retval = mem_ap_read_atomic_u32(swjdp, armv7a->debug_base + CPUDBG_DSCR, &dscr);
+       if (retval != ERROR_OK)
+               goto out;
+
        retval = mem_ap_write_atomic_u32(swjdp,
                armv7a->debug_base + CPUDBG_DSCR, dscr | DSCR_HALT_DBG_MODE);
-
        if (retval != ERROR_OK)
                goto out;
 
-       do {
-               mem_ap_read_atomic_u32(swjdp,
+       long long then = timeval_ms();
+       for (;;)
+       {
+               retval = mem_ap_read_atomic_u32(swjdp,
                        armv7a->debug_base + CPUDBG_DSCR, &dscr);
-       } while ((dscr & DSCR_CORE_HALTED) == 0);
+               if (retval != ERROR_OK)
+                       goto out;
+               if ((dscr & DSCR_CORE_HALTED) != 0)
+               {
+                       break;
+               }
+               if (timeval_ms() > then + 1000)
+               {
+                       LOG_ERROR("Timeout waiting for halt");
+                       return ERROR_FAIL;
+               }
+       }
 
        target->debug_reason = DBG_REASON_DBGRQ;
 
@@ -675,6 +731,7 @@ static int cortex_a8_resume(struct target *target, int current,
        struct armv7a_common *armv7a = target_to_armv7a(target);
        struct arm *armv4_5 = &armv7a->armv4_5_common;
        struct adiv5_dap *swjdp = &armv7a->dap;
+       int retval;
 
 //     struct breakpoint *breakpoint = NULL;
        uint32_t resume_pc, dscr;
@@ -758,12 +815,25 @@ static int cortex_a8_resume(struct target *target, int current,
         * REVISIT: for single stepping, we probably want to
         * disable IRQs by default, with optional override...
         */
-       mem_ap_write_atomic_u32(swjdp, armv7a->debug_base + CPUDBG_DRCR, 0x2);
+       retval = mem_ap_write_atomic_u32(swjdp, armv7a->debug_base + CPUDBG_DRCR, 0x2);
+       if (retval != ERROR_OK)
+               return retval;
 
-       do {
-               mem_ap_read_atomic_u32(swjdp,
+       long long then = timeval_ms();
+       for (;;)
+       {
+               retval = mem_ap_read_atomic_u32(swjdp,
                        armv7a->debug_base + CPUDBG_DSCR, &dscr);
-       } while ((dscr & DSCR_CORE_RESTARTED) == 0);
+               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;
+               }
+       }
 
        target->debug_reason = DBG_REASON_NOTHALTED;
        target->state = TARGET_RUNNING;
@@ -804,8 +874,10 @@ static int cortex_a8_debug_entry(struct target *target)
        LOG_DEBUG("dscr = 0x%08" PRIx32, cortex_a8->cpudbg_dscr);
 
        /* REVISIT surely we should not re-read DSCR !! */
-       mem_ap_read_atomic_u32(swjdp,
+       retval = mem_ap_read_atomic_u32(swjdp,
                                armv7a->debug_base + CPUDBG_DSCR, &dscr);
+       if (retval != ERROR_OK)
+               return retval;
 
        /* REVISIT see A8 TRM 12.11.4 steps 2..3 -- make sure that any
         * imprecise data aborts get discarded by issuing a Data
@@ -816,6 +888,8 @@ static int cortex_a8_debug_entry(struct target *target)
        dscr |= DSCR_ITR_EN;
        retval = mem_ap_write_atomic_u32(swjdp,
                        armv7a->debug_base + CPUDBG_DSCR, dscr);
+       if (retval != ERROR_OK)
+               return retval;
 
        /* Examine debug reason */
        arm_dpm_report_dscr(&armv7a->dpm, cortex_a8->cpudbg_dscr);
@@ -827,6 +901,8 @@ static int cortex_a8_debug_entry(struct target *target)
                retval = mem_ap_read_atomic_u32(swjdp,
                                armv7a->debug_base + CPUDBG_WFAR,
                                &wfar);
+               if (retval != ERROR_OK)
+                       return retval;
                arm_dpm_report_wfar(&armv7a->dpm, wfar);
        }
 
@@ -951,6 +1027,7 @@ static int cortex_a8_step(struct target *target, int current, uint32_t address,
        struct breakpoint *breakpoint = NULL;
        struct breakpoint stepbreakpoint;
        struct reg *r;
+       int retval;
 
        int timeout = 100;
 
@@ -994,15 +1071,19 @@ static int cortex_a8_step(struct target *target, int current, uint32_t address,
 
        target->debug_reason = DBG_REASON_SINGLESTEP;
 
-       cortex_a8_resume(target, 1, address, 0, 0);
+       retval = cortex_a8_resume(target, 1, address, 0, 0);
+       if (retval != ERROR_OK)
+               return retval;
 
        while (target->state != TARGET_HALTED)
        {
-               cortex_a8_poll(target);
+               retval = cortex_a8_poll(target);
+               if (retval != ERROR_OK)
+                       return retval;
                if (--timeout == 0)
                {
-                       LOG_WARNING("timeout waiting for target halt");
-                       break;
+                       LOG_ERROR("timeout waiting for target halt");
+                       return ERROR_FAIL;
                }
        }
 
@@ -1035,7 +1116,7 @@ static int cortex_a8_restore_context(struct target *target, bool bpwp)
 
 
 /*
- * Cortex-A8 Breakpoint and watchpoint fuctions
+ * Cortex-A8 Breakpoint and watchpoint functions
  */
 
 /* Setup hardware Breakpoint Register Pair */
@@ -1195,7 +1276,7 @@ static int cortex_a8_remove_breakpoint(struct target *target, struct breakpoint
        struct cortex_a8_common *cortex_a8 = target_to_cortex_a8(target);
 
 #if 0
-/* It is perfectly possible to remove brakpoints while the taget is running */
+/* It is perfectly possible to remove breakpoints while the target is running */
        if (target->state != TARGET_HALTED)
        {
                LOG_WARNING("target not halted");
@@ -1217,7 +1298,7 @@ static int cortex_a8_remove_breakpoint(struct target *target, struct breakpoint
 
 
 /*
- * Cortex-A8 Reset fuctions
+ * Cortex-A8 Reset functions
  */
 
 static int cortex_a8_assert_reset(struct target *target)
@@ -1259,6 +1340,8 @@ static int cortex_a8_deassert_reset(struct target *target)
        jtag_add_reset(0, 0);
 
        retval = cortex_a8_poll(target);
+       if (retval != ERROR_OK)
+               return retval;
 
        if (target->reset_halt) {
                if (target->state != TARGET_HALTED) {
@@ -1313,12 +1396,16 @@ static int cortex_a8_read_memory(struct target *target, uint32_t address,
 {
         int enabled = 0;
         uint32_t virt, phys;
+        int retval;
 
        /* cortex_a8 handles unaligned memory access */
 
 // ??? dap_ap_select(swjdp, swjdp_memoryap);
         LOG_DEBUG("Reading memory at address 0x%x; size %d; count %d", address, size, count);
-        cortex_a8_mmu(target, &enabled);
+        retval = cortex_a8_mmu(target, &enabled);
+        if (retval != ERROR_OK)
+               return retval;
+
         if(enabled)
         {
             virt = address;
@@ -1416,11 +1503,14 @@ static int cortex_a8_write_memory(struct target *target, uint32_t address,
 {
         int enabled = 0;
         uint32_t virt, phys;
+        int retval;
 
 // ???  dap_ap_select(swjdp, swjdp_memoryap);
 
         LOG_DEBUG("Writing memory to address 0x%x; size %d; count %d", address, size, count);
-        cortex_a8_mmu(target, &enabled);
+        retval = cortex_a8_mmu(target, &enabled);
+        if (retval != ERROR_OK)
+               return retval;
         if(enabled)
         {
             virt = address;
@@ -1523,8 +1613,14 @@ static int cortex_a8_examine_first(struct target *target)
        /* We do one extra read to ensure DAP is configured,
         * we call ahbap_debugport_init(swjdp) instead
         */
-       ahbap_debugport_init(swjdp);
-       mem_ap_read_atomic_u32(swjdp, armv7a->debug_base + CPUDBG_CPUID, &cpuid);
+       retval = ahbap_debugport_init(swjdp);
+       if (retval != ERROR_OK)
+               return retval;
+
+       retval = mem_ap_read_atomic_u32(swjdp, armv7a->debug_base + CPUDBG_CPUID, &cpuid);
+       if (retval != ERROR_OK)
+               return retval;
+
        if ((retval = mem_ap_read_atomic_u32(swjdp,
                        armv7a->debug_base + CPUDBG_CPUID, &cpuid)) != ERROR_OK)
        {
@@ -1559,7 +1655,9 @@ static int cortex_a8_examine_first(struct target *target)
        LOG_DEBUG("didr = 0x%08" PRIx32, didr);
 
        armv7a->armv4_5_common.core_type = ARM_MODE_MON;
-       cortex_a8_dpm_setup(cortex_a8, didr);
+       retval = cortex_a8_dpm_setup(cortex_a8, didr);
+       if (retval != ERROR_OK)
+               return retval;
 
        /* Setup Breakpoint Register Pairs */
        cortex_a8->brp_num = ((didr >> 24) & 0x0F) + 1;
@@ -1720,7 +1818,7 @@ static uint32_t cortex_a8_get_ttb(struct target *target)
                     2, 0,   /* CRn, CRm */
                     &ttb);
     }
-    /* finaly we don't know whose ttb to use: user or kernel */
+    /* finally we don't know whose ttb to use: user or kernel */
     else
         LOG_ERROR("Don't know how to get ttb for current mode!!!");
 
@@ -1839,10 +1937,13 @@ COMMAND_HANDLER(cortex_a8_handle_cache_info_command)
 COMMAND_HANDLER(cortex_a8_handle_dbginit_command)
 {
        struct target *target = get_current_target(CMD_CTX);
+       if (!target_was_examined(target))
+       {
+               LOG_ERROR("target not examined yet");
+               return ERROR_FAIL;
+       }
 
-       cortex_a8_init_debug_access(target);
-
-       return ERROR_OK;
+       return cortex_a8_init_debug_access(target);
 }
 
 static const struct command_registration cortex_a8_exec_command_handlers[] = {