aarch64: introduce dpm extension for ARMv8
[openocd.git] / src / target / arm_dpm.c
index b83d17a1fcbf4ccfb09b2d9ece4a9e3c5e7d30cc..00ebebaef89b97ff99f56bf8db5205f015456426 100644 (file)
@@ -12,9 +12,7 @@
  * GNU General Public License for more details.
  *
  * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the
- * Free Software Foundation, Inc.,
- * 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
 
 #ifdef HAVE_CONFIG_H
@@ -23,6 +21,7 @@
 
 #include "arm.h"
 #include "arm_dpm.h"
+#include "armv8_dpm.h"
 #include <jtag/jtag.h>
 #include "register.h"
 #include "breakpoints.h"
@@ -167,6 +166,9 @@ static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
                                        /* core-specific ... ? */
                                        LOG_WARNING("Jazelle PC adjustment unknown");
                                        break;
+                               default:
+                                       LOG_WARNING("unknow core state");
+                                       break;
                        }
                        break;
                default:
@@ -230,6 +232,18 @@ static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
        return retval;
 }
 
+/**
+ * Write to program counter and switch the core state (arm/thumb) according to
+ * the address.
+ */
+static int dpm_write_pc_core_state(struct arm_dpm *dpm, struct reg *r)
+{
+       uint32_t value = buf_get_u32(r->value, 0, 32);
+
+       /* read r0 from DCC; then "BX r0" */
+       return dpm->instr_write_data_r0(dpm, ARMV4_5_BX(0), value);
+}
+
 /**
  * Read basic registers of the the current context:  R0 to R15, and CPSR;
  * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb).
@@ -423,20 +437,20 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
 
                                /* cope with special cases */
                                switch (regnum) {
-                                       case 8 ... 12:
-                                               /* r8..r12 "anything but FIQ" case;
-                                                * we "know" core mode is accurate
-                                                * since we haven't changed it yet
-                                                */
-                                               if (arm->core_mode == ARM_MODE_FIQ
-                                                       && ARM_MODE_ANY
-                                                       != mode)
-                                                       tmode = ARM_MODE_USR;
-                                               break;
-                                       case 16:
-                                               /* SPSR */
-                                               regnum++;
-                                               break;
+                               case 8 ... 12:
+                                       /* r8..r12 "anything but FIQ" case;
+                                        * we "know" core mode is accurate
+                                        * since we haven't changed it yet
+                                        */
+                                       if (arm->core_mode == ARM_MODE_FIQ
+                                           && ARM_MODE_ANY
+                                           != mode)
+                                               tmode = ARM_MODE_USR;
+                                       break;
+                               case 16:
+                                       /* SPSR */
+                                       regnum++;
+                                       break;
                                }
 
                                /* REVISIT error checks */
@@ -450,8 +464,8 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
                                continue;
 
                        retval = dpm_write_reg(dpm,
-                                       &cache->reg_list[i],
-                                       regnum);
+                                              &cache->reg_list[i],
+                                              regnum);
                        if (retval != ERROR_OK)
                                goto done;
                }
@@ -467,6 +481,19 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
                goto done;
        arm->cpsr->dirty = false;
 
+       /* restore the PC, make sure to also switch the core state
+        * to whatever it was set to with "arm core_state" command.
+        * target code will have set PC to an appropriate resume address.
+        */
+       retval = dpm_write_pc_core_state(dpm, arm->pc);
+       if (retval != ERROR_OK)
+               goto done;
+       /* on Cortex-A5 (as found on NXP VF610 SoC), BX instruction
+        * executed in debug state doesn't appear to set the PC,
+        * explicitly set it with a "MOV pc, r0". This doesn't influence
+        * CPSR on Cortex-A9 so it should be OK. Maybe due to different
+        * debug version?
+        */
        retval = dpm_write_reg(dpm, arm->pc, 15);
        if (retval != ERROR_OK)
                goto done;
@@ -571,7 +598,7 @@ fail:
 }
 
 static int arm_dpm_write_core_reg(struct target *target, struct reg *r,
-       int regnum, enum arm_mode mode, uint32_t value)
+       int regnum, enum arm_mode mode, uint8_t *value)
 {
        struct arm_dpm *dpm = target_to_arm(target)->dpm;
        int retval;
@@ -648,14 +675,15 @@ static int arm_dpm_full_context(struct target *target)
                                did_read = true;
                                mode = r->mode;
 
-                               /* For R8..R12 when we've entered debug
-                                * state in FIQ mode... patch mode.
+                               /* For regular (ARM_MODE_ANY) R8..R12
+                                * in case we've entered debug state
+                                * in FIQ mode we need to patch mode.
                                 */
-                               if (mode == ARM_MODE_ANY)
-                                       mode = ARM_MODE_USR;
+                               if (mode != ARM_MODE_ANY)
+                                       retval = dpm_modeswitch(dpm, mode);
+                               else
+                                       retval = dpm_modeswitch(dpm, ARM_MODE_USR);
 
-                               /* REVISIT error checks */
-                               retval = dpm_modeswitch(dpm, mode);
                                if (retval != ERROR_OK)
                                        goto done;
                        }
@@ -881,6 +909,7 @@ void arm_dpm_report_wfar(struct arm_dpm *dpm, uint32_t addr)
                        addr -= 4;
                        break;
                case ARM_STATE_JAZELLE:
+               case ARM_STATE_AARCH64:
                        /* ?? */
                        break;
        }
@@ -939,7 +968,7 @@ int arm_dpm_setup(struct arm_dpm *dpm)
 {
        struct arm *arm = dpm->arm;
        struct target *target = arm->target;
-       struct reg_cache *cache;
+       struct reg_cache *cache = 0;
 
        arm->dpm = dpm;
 
@@ -948,11 +977,13 @@ int arm_dpm_setup(struct arm_dpm *dpm)
        arm->read_core_reg = arm_dpm_read_core_reg;
        arm->write_core_reg = arm_dpm_write_core_reg;
 
-       cache = arm_build_reg_cache(target, arm);
-       if (!cache)
-               return ERROR_FAIL;
+       if (arm->core_cache != NULL) {
+               cache = arm_build_reg_cache(target, arm);
+               if (!cache)
+                       return ERROR_FAIL;
 
-       *register_get_last_cache_p(&target->reg_cache) = cache;
+               *register_get_last_cache_p(&target->reg_cache) = cache;
+       }
 
        /* coprocessor access setup */
        arm->mrc = dpm_mrc;
@@ -971,9 +1002,8 @@ int arm_dpm_setup(struct arm_dpm *dpm)
        /* FIXME add vector catch support */
 
        dpm->nbp = 1 + ((dpm->didr >> 24) & 0xf);
-       dpm->dbp = calloc(dpm->nbp, sizeof *dpm->dbp);
-
        dpm->nwp = 1 + ((dpm->didr >> 28) & 0xf);
+       dpm->dbp = calloc(dpm->nbp, sizeof *dpm->dbp);
        dpm->dwp = calloc(dpm->nwp, sizeof *dpm->dwp);
 
        if (!dpm->dbp || !dpm->dwp) {

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)