aarch64: introduce dpm extension for ARMv8
[openocd.git] / src / target / arm_dpm.c
index 55f253e464ff95e730541939b8d44de1d03d2021..00ebebaef89b97ff99f56bf8db5205f015456426 100644 (file)
@@ -21,6 +21,7 @@
 
 #include "arm.h"
 #include "arm_dpm.h"
+#include "armv8_dpm.h"
 #include <jtag/jtag.h>
 #include "register.h"
 #include "breakpoints.h"
@@ -130,11 +131,11 @@ int dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode)
        return retval;
 }
 
-
-static int dpm_read_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
+/* just read the register -- rely on the core mode being right */
+static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
 {
        uint32_t value;
-       int retval = ERROR_FAIL;
+       int retval;
 
        switch (regnum) {
                case 0 ... 14:
@@ -165,8 +166,8 @@ static int dpm_read_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
                                        /* core-specific ... ? */
                                        LOG_WARNING("Jazelle PC adjustment unknown");
                                        break;
-                               case ARM_STATE_AARCH64:
-                                       LOG_ERROR("AARCH64: 32bit read requested");
+                               default:
+                                       LOG_WARNING("unknow core state");
                                        break;
                        }
                        break;
@@ -190,57 +191,10 @@ static int dpm_read_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
        return retval;
 }
 
-static int dpm_read_reg64(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
-{
-       uint64_t value;
-       uint32_t i;
-       int retval = ERROR_FAIL;
-
-       switch (regnum) {
-               case 0 ... 30:
-                       i = 0xd5130400 + regnum; /* msr dbgdtr_el0,reg */
-                       retval = dpm->instr_read_data_dcc_64(dpm, i, &value);
-                       break;
-               case 31: /* SP */
-                       i = 0x910003e0;
-                       retval = dpm->instr_read_data_r0_64(dpm, i, &value);
-                       break;
-               case 32: /* PC */
-                       i = 0xd53b4520;
-                       retval = dpm->instr_read_data_r0_64(dpm, i, &value);
-                       break;
-               case 33: /* CPSR */
-                       i = 0xd53b4500;
-                       retval = dpm->instr_read_data_r0_64(dpm, i, &value);
-                       break;
-
-               default:
-                       break;
-       }
-
-       if (retval == ERROR_OK) {
-               buf_set_u64(r->value, 0, 64, value);
-               r->valid = true;
-               r->dirty = false;
-               LOG_DEBUG("READ: %s, %16.16llx", r->name, (long long)value);
-       }
-
-       return retval;
-}
-
-
-/* just read the register -- rely on the core mode being right */
-static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
-{
-       if (r->size == 64)
-               return dpm_read_reg64(dpm, r, regnum);
-       else
-               return dpm_read_reg32(dpm, r, regnum);
-}
-
-static int dpm_write_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
+/* just write the register -- rely on the core mode being right */
+static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
 {
-       int retval = ERROR_FAIL;
+       int retval;
        uint32_t value = buf_get_u32(r->value, 0, 32);
 
        switch (regnum) {
@@ -290,51 +244,19 @@ static int dpm_write_pc_core_state(struct arm_dpm *dpm, struct reg *r)
        return dpm->instr_write_data_r0(dpm, ARMV4_5_BX(0), value);
 }
 
-static int dpm_write_reg64(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
-{
-       int retval = ERROR_FAIL;
-       uint32_t i;
-       uint64_t value = buf_get_u64(r->value, 0, 64);
-
-       switch (regnum) {
-               case 0 ... 30:
-                       i = 0xd5330400 + regnum;
-                       retval = dpm->instr_write_data_dcc_64(dpm, i, value);
-                       break;
-               case 32: /* PC */
-                       i = 0xd51b4520;
-                       retval = dpm->instr_write_data_r0_64(dpm, i, value);
-                       break;
-               default:
-                       LOG_DEBUG("register %s (%16.16llx) not defined", r->name,
-                                 (unsigned long long)value);
-                       break;
-       }
-
-       if (retval == ERROR_OK) {
-               r->dirty = false;
-               LOG_DEBUG("WRITE: %s, %16.16llx", r->name, (unsigned long long)value);
-       }
-
-       return retval;
-}
-
-/* just write the register -- rely on the core mode being right */
-static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
-{
-       if (r->size == 64)
-               return dpm_write_reg64(dpm, r, regnum);
-       else
-               return dpm_write_reg32(dpm, r, regnum);
-}
-
-static int arm_dpm_read_current_registers_i(struct arm_dpm *dpm)
+/**
+ * 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).
+ * In normal operation this is called on entry to halting debug state,
+ * possibly after some other operations supporting restore of debug state
+ * or making sure the CPU is fully idle (drain write buffer, etc).
+ */
+int arm_dpm_read_current_registers(struct arm_dpm *dpm)
 {
        struct arm *arm = dpm->arm;
-       uint32_t cpsr, instr, core_regs;
+       uint32_t cpsr;
        int retval;
        struct reg *r;
-       enum arm_state core_state = arm->core_state;
 
        retval = dpm->prepare(dpm);
        if (retval != ERROR_OK)
@@ -349,25 +271,16 @@ static int arm_dpm_read_current_registers_i(struct arm_dpm *dpm)
        }
        r->dirty = true;
 
-       if (core_state == ARM_STATE_AARCH64)
-               instr = 0xd53b4500;  /* mrs x0, dspsr_el0 */
-       else
-               instr = ARMV4_5_MRS(0, 0);
-       retval = dpm->instr_read_data_r0(dpm, instr, &cpsr);
+       retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRS(0, 0), &cpsr);
        if (retval != ERROR_OK)
                goto fail;
 
        /* update core mode and state, plus shadow mapping for R8..R14 */
        arm_set_cpsr(arm, cpsr);
-       if (core_state == ARM_STATE_AARCH64)
-               /* arm_set_cpsr changes core_state, restore it for now */
-               arm->core_state = ARM_STATE_AARCH64;
-
-       core_regs = arm->core_cache->num_regs;
 
        /* REVISIT we can probably avoid reading R1..R14, saving time... */
-       for (unsigned i = 1; i < core_regs; i++) {
-               r = dpm->arm_reg_current(arm, i);
+       for (unsigned i = 1; i < 16; i++) {
+               r = arm_reg_current(arm, i);
                if (r->valid)
                        continue;
 
@@ -388,23 +301,6 @@ fail:
        return retval;
 }
 
-/**
- * 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).
- * In normal operation this is called on entry to halting debug state,
- * possibly after some other operations supporting restore of debug state
- * or making sure the CPU is fully idle (drain write buffer, etc).
- */
-int arm_dpm_read_current_registers(struct arm_dpm *dpm)
-{
-       return arm_dpm_read_current_registers_i(dpm);
-}
-
-int arm_dpm_read_current_registers_64(struct arm_dpm *dpm)
-{
-       return arm_dpm_read_current_registers_i(dpm);
-}
-
 /* Avoid needless I/O ... leave breakpoints and watchpoints alone
  * unless they're removed, or need updating because of single-stepping
  * or running debugger code.
@@ -453,14 +349,59 @@ done:
 
 static int dpm_add_breakpoint(struct target *target, struct breakpoint *bp);
 
-
-static int arm_dpm_write_dirty_registers_32(struct arm_dpm *dpm)
+/**
+ * Writes all modified core registers for all processor modes.  In normal
+ * operation this is called on exit from halting debug state.
+ *
+ * @param dpm: represents the processor
+ * @param bpwp: true ensures breakpoints and watchpoints are set,
+ *     false ensures they are cleared
+ */
+int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
 {
        struct arm *arm = dpm->arm;
        struct reg_cache *cache = arm->core_cache;
        int retval;
        bool did_write;
 
+       retval = dpm->prepare(dpm);
+       if (retval != ERROR_OK)
+               goto done;
+
+       /* If we're managing hardware breakpoints for this core, enable
+        * or disable them as requested.
+        *
+        * REVISIT We don't yet manage them for ANY cores.  Eventually
+        * we should be able to assume we handle them; but until then,
+        * cope with the hand-crafted breakpoint code.
+        */
+       if (arm->target->type->add_breakpoint == dpm_add_breakpoint) {
+               for (unsigned i = 0; i < dpm->nbp; i++) {
+                       struct dpm_bp *dbp = dpm->dbp + i;
+                       struct breakpoint *bp = dbp->bp;
+
+                       retval = dpm_maybe_update_bpwp(dpm, bpwp, &dbp->bpwp,
+                                       bp ? &bp->set : NULL);
+                       if (retval != ERROR_OK)
+                               goto done;
+               }
+       }
+
+       /* enable/disable watchpoints */
+       for (unsigned i = 0; i < dpm->nwp; i++) {
+               struct dpm_wp *dwp = dpm->dwp + i;
+               struct watchpoint *wp = dwp->wp;
+
+               retval = dpm_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp,
+                               wp ? &wp->set : NULL);
+               if (retval != ERROR_OK)
+                       goto done;
+       }
+
+       /* NOTE:  writes to breakpoint and watchpoint registers might
+        * be queued, and need (efficient/batched) flushing later.
+        */
+
        /* Scan the registers until we find one that's both dirty and
         * eligible for flushing.  Flush that and everything else that
         * shares the same core mode setting.  Typically this won't
@@ -564,106 +505,6 @@ static int arm_dpm_write_dirty_registers_32(struct arm_dpm *dpm)
                goto done;
        cache->reg_list[0].dirty = false;
 
-done:
-       return retval;
-}
-
-static int arm_dpm_write_dirty_registers_64(struct arm_dpm *dpm)
-{
-       struct arm *arm = dpm->arm;
-       struct reg_cache *cache = arm->core_cache;
-       int retval;
-
-       /* Scan the registers until we find one that's both dirty and
-        * eligible for flushing.  Flush that and everything else that
-        * shares the same core mode setting.  Typically this won't
-        * actually find anything to do...
-        */
-
-       /* check everything except our scratch register R0 */
-       for (unsigned i = 1; i <= 32; i++) {
-               struct arm_reg *r;
-               unsigned regnum;
-
-               if (!cache->reg_list[i].dirty)
-                       continue;
-
-               r = cache->reg_list[i].arch_info;
-               regnum = r->num;
-               retval = dpm_write_reg(dpm,
-                                      &cache->reg_list[i],
-                                      regnum);
-               if (retval != ERROR_OK)
-                       goto done;
-       }
-
-       /* flush R0 -- it's *very* dirty by now */
-       retval = dpm_write_reg(dpm, &cache->reg_list[0], 0);
-       if (retval != ERROR_OK)
-               goto done;
-       cache->reg_list[0].dirty = false;
-
-done:
-       return retval;
-}
-
-/**
- * Writes all modified core registers for all processor modes.  In normal
- * operation this is called on exit from halting debug state.
- *
- * @param dpm: represents the processor
- * @param bpwp: true ensures breakpoints and watchpoints are set,
- *     false ensures they are cleared
- */
-int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
-{
-       struct arm *arm = dpm->arm;
-       struct reg_cache *cache = arm->core_cache;
-       int retval;
-
-       retval = dpm->prepare(dpm);
-       if (retval != ERROR_OK)
-               goto done;
-
-       /* If we're managing hardware breakpoints for this core, enable
-        * or disable them as requested.
-        *
-        * REVISIT We don't yet manage them for ANY cores.  Eventually
-        * we should be able to assume we handle them; but until then,
-        * cope with the hand-crafted breakpoint code.
-        */
-       if (arm->target->type->add_breakpoint == dpm_add_breakpoint) {
-               for (unsigned i = 0; i < dpm->nbp; i++) {
-                       struct dpm_bp *dbp = dpm->dbp + i;
-                       struct breakpoint *bp = dbp->bp;
-
-                       retval = dpm_maybe_update_bpwp(dpm, bpwp, &dbp->bpwp,
-                                       bp ? &bp->set : NULL);
-                       if (retval != ERROR_OK)
-                               goto done;
-               }
-       }
-
-       /* enable/disable watchpoints */
-       for (unsigned i = 0; i < dpm->nwp; i++) {
-               struct dpm_wp *dwp = dpm->dwp + i;
-               struct watchpoint *wp = dwp->wp;
-
-               retval = dpm_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp,
-                               wp ? &wp->set : NULL);
-               if (retval != ERROR_OK)
-                       goto done;
-       }
-
-       /* NOTE:  writes to breakpoint and watchpoint registers might
-        * be queued, and need (efficient/batched) flushing later.
-        */
-
-       if (cache->reg_list[0].size == 64)
-               retval = arm_dpm_write_dirty_registers_64(dpm);
-       else
-               retval = arm_dpm_write_dirty_registers_32(dpm);
-
        /* (void) */ dpm->finish(dpm);
 done:
        return retval;
@@ -1133,20 +974,15 @@ int arm_dpm_setup(struct arm_dpm *dpm)
 
        /* register access setup */
        arm->full_context = arm_dpm_full_context;
-       arm->read_core_reg = arm->read_core_reg ? : arm_dpm_read_core_reg;
-       arm->write_core_reg = arm->write_core_reg ? : arm_dpm_write_core_reg;
+       arm->read_core_reg = arm_dpm_read_core_reg;
+       arm->write_core_reg = arm_dpm_write_core_reg;
 
        if (arm->core_cache != NULL) {
-               if (arm->core_state == ARM_STATE_AARCH64) {
-                       cache = armv8_build_reg_cache(target);
-                       target->reg_cache = cache;
-               } else {
-                       cache = arm_build_reg_cache(target, arm);
-                       *register_get_last_cache_p(&target->reg_cache) = cache;
-               }
-
+               cache = arm_build_reg_cache(target, arm);
                if (!cache)
                        return ERROR_FAIL;
+
+               *register_get_last_cache_p(&target->reg_cache) = cache;
        }
 
        /* coprocessor access setup */
@@ -1163,20 +999,10 @@ int arm_dpm_setup(struct arm_dpm *dpm)
        target->type->add_watchpoint = dpm_add_watchpoint;
        target->type->remove_watchpoint = dpm_remove_watchpoint;
 
-
-       if (dpm->arm_reg_current == 0)
-               dpm->arm_reg_current = arm_reg_current;
-
        /* FIXME add vector catch support */
 
-       if (arm->core_state == ARM_STATE_AARCH64) {
-               dpm->nbp = 1 + ((dpm->didr >> 24) & 0xf);
-               dpm->nwp = 1 + ((dpm->didr >> 28) & 0xf);
-       } else {
-               dpm->nbp = 1 + ((dpm->didr >> 12) & 0xf);
-               dpm->nwp = 1 + ((dpm->didr >> 20) & 0xf);
-       }
-
+       dpm->nbp = 1 + ((dpm->didr >> 24) & 0xf);
+       dpm->nwp = 1 + ((dpm->didr >> 28) & 0xf);
        dpm->dbp = calloc(dpm->nbp, sizeof *dpm->dbp);
        dpm->dwp = calloc(dpm->nwp, sizeof *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)