tcl/target: add config for Qualcomm QCA4531
[fw/openocd] / src / target / armv8_dpm.c
index 56e2eb8fef5e7f0ec995bee57338dc9750fd8032..3c941fa2db17b97f09683dcdaee1c9675d4a164d 100644 (file)
@@ -51,17 +51,11 @@ enum arm_state armv8_dpm_get_core_state(struct arm_dpm *dpm)
 {
        int el = (dpm->dscr >> 8) & 0x3;
        int rw = (dpm->dscr >> 10) & 0xF;
-       int pos;
 
        dpm->last_el = el;
 
-       /* find the first '0' in DSCR.RW */
-       for (pos = 3; pos >= 0; pos--) {
-               if ((rw & (1 << pos)) == 0)
-                       break;
-       }
-
-       if (el > pos)
+       /* In Debug state, each bit gives the current Execution state of each EL */
+       if ((rw >> el) & 0b1)
                return ARM_STATE_AARCH64;
 
        return ARM_STATE_ARM;
@@ -264,7 +258,7 @@ static int dpmv8_exec_opcode(struct arm_dpm *dpm,
 
        if (dscr & DSCR_ERR) {
                LOG_ERROR("Opcode 0x%08"PRIx32", DSCR.ERR=1, DSCR.EL=%i", opcode, dpm->last_el);
-               armv8_dpm_handle_exception(dpm);
+               armv8_dpm_handle_exception(dpm, true);
                retval = ERROR_FAIL;
        }
 
@@ -567,12 +561,7 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode)
 
        } else {
                LOG_DEBUG("setting mode 0x%"PRIx32, mode);
-
-               /* else force to the specified mode */
-               if (is_arm_mode(mode))
-                       cpsr = mode;
-               else
-                       cpsr = mode >> 4;
+               cpsr = mode;
        }
 
        switch (cpsr & 0x1f) {
@@ -611,7 +600,7 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode)
                                armv8_opcode(armv8, ARMV8_OPC_DCPS) | target_el);
 
                /* DCPS clobbers registers just like an exception taken */
-               armv8_dpm_handle_exception(dpm);
+               armv8_dpm_handle_exception(dpm, false);
        } else {
                core_state = armv8_dpm_get_core_state(dpm);
                if (core_state != ARM_STATE_AARCH64) {
@@ -661,21 +650,37 @@ int armv8_dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode)
 static int dpmv8_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
 {
        struct armv8_common *armv8 = dpm->arm->arch_info;
-       uint64_t value_64;
-       int retval;
+       int retval = ERROR_FAIL;
+
+       if (r->size <= 64) {
+               uint64_t value_64;
+               retval = armv8->read_reg_u64(armv8, regnum, &value_64);
+
+               if (retval == ERROR_OK) {
+                       r->valid = true;
+                       r->dirty = false;
+                       buf_set_u64(r->value, 0, r->size, value_64);
+                       if (r->size == 64)
+                               LOG_DEBUG("READ: %s, %16.8llx", r->name, (unsigned long long) value_64);
+                       else
+                               LOG_DEBUG("READ: %s, %8.8x", r->name, (unsigned int) value_64);
+               }
+       } else if (r->size <= 128) {
+               uint64_t lvalue = 0, hvalue = 0;
+               retval = armv8->read_reg_u128(armv8, regnum, &lvalue, &hvalue);
+
+               if (retval == ERROR_OK) {
+                       r->valid = true;
+                       r->dirty = false;
 
-       retval = armv8->read_reg_u64(armv8, regnum, &value_64);
+                       buf_set_u64(r->value, 0, 64, lvalue);
+                       buf_set_u64(r->value + 8, 0, r->size - 64, hvalue);
 
-       if (retval == ERROR_OK) {
-               r->valid = true;
-               r->dirty = false;
-               buf_set_u64(r->value, 0, r->size, value_64);
-               if (r->size == 64)
-                       LOG_DEBUG("READ: %s, %16.8llx", r->name, (unsigned long long) value_64);
-               else
-                       LOG_DEBUG("READ: %s, %8.8x", r->name, (unsigned int) value_64);
+                       LOG_DEBUG("READ: %s, lvalue=%16.8llx", r->name, (unsigned long long) lvalue);
+                       LOG_DEBUG("READ: %s, hvalue=%16.8llx", r->name, (unsigned long long) hvalue);
+               }
        }
-       return ERROR_OK;
+       return retval;
 }
 
 /*
@@ -685,20 +690,36 @@ static int dpmv8_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
 {
        struct armv8_common *armv8 = dpm->arm->arch_info;
        int retval = ERROR_FAIL;
-       uint64_t value_64;
 
-       value_64 = buf_get_u64(r->value, 0, r->size);
+       if (r->size <= 64) {
+               uint64_t value_64;
+
+               value_64 = buf_get_u64(r->value, 0, r->size);
+               retval = armv8->write_reg_u64(armv8, regnum, value_64);
+
+               if (retval == ERROR_OK) {
+                       r->dirty = false;
+                       if (r->size == 64)
+                               LOG_DEBUG("WRITE: %s, %16.8llx", r->name, (unsigned long long)value_64);
+                       else
+                               LOG_DEBUG("WRITE: %s, %8.8x", r->name, (unsigned int)value_64);
+               }
+       } else if (r->size <= 128) {
+               uint64_t lvalue, hvalue;
+
+               lvalue = buf_get_u64(r->value, 0, 64);
+               hvalue = buf_get_u64(r->value + 8, 0, r->size - 64);
+               retval = armv8->write_reg_u128(armv8, regnum, lvalue, hvalue);
 
-       retval = armv8->write_reg_u64(armv8, regnum, value_64);
-       if (retval == ERROR_OK) {
-               r->dirty = false;
-               if (r->size == 64)
-                       LOG_DEBUG("WRITE: %s, %16.8llx", r->name, (unsigned long long)value_64);
-               else
-                       LOG_DEBUG("WRITE: %s, %8.8x", r->name, (unsigned int)value_64);
+               if (retval == ERROR_OK) {
+                       r->dirty = false;
+
+                       LOG_DEBUG("WRITE: %s, lvalue=%16.8llx", r->name, (unsigned long long) lvalue);
+                       LOG_DEBUG("WRITE: %s, hvalue=%16.8llx", r->name, (unsigned long long) hvalue);
+               }
        }
 
-       return ERROR_OK;
+       return retval;
 }
 
 /**
@@ -724,14 +745,22 @@ int armv8_dpm_read_current_registers(struct arm_dpm *dpm)
        cache = arm->core_cache;
 
        /* read R0 first (it's used for scratch), then CPSR */
-       r = cache->reg_list + 0;
+       r = cache->reg_list + ARMV8_R0;
        if (!r->valid) {
-               retval = dpmv8_read_reg(dpm, r, 0);
+               retval = dpmv8_read_reg(dpm, r, ARMV8_R0);
                if (retval != ERROR_OK)
                        goto fail;
        }
        r->dirty = true;
 
+       /* read R1, too, it will be clobbered during memory access */
+       r = cache->reg_list + ARMV8_R1;
+       if (!r->valid) {
+               retval = dpmv8_read_reg(dpm, r, ARMV8_R1);
+               if (retval != ERROR_OK)
+                       goto fail;
+       }
+
        /* read cpsr to r0 and get it back */
        retval = dpm->instr_read_data_r0(dpm,
                        armv8_opcode(armv8, READ_REG_DSPSR), &cpsr);
@@ -741,13 +770,17 @@ int armv8_dpm_read_current_registers(struct arm_dpm *dpm)
        /* update core mode and state */
        armv8_set_cpsr(arm, cpsr);
 
-       for (unsigned int i = 1; i < cache->num_regs ; i++) {
+       for (unsigned int i = ARMV8_PC; i < cache->num_regs ; i++) {
                struct arm_reg *arm_reg;
 
                r = armv8_reg_current(arm, i);
                if (r->valid)
                        continue;
 
+               /* Skip reading FP-SIMD registers */
+               if (r->number >= ARMV8_V0 && r->number <= ARMV8_FPCR)
+                       continue;
+
                /*
                 * Only read registers that are available from the
                 * current EL (or core mode).
@@ -1265,7 +1298,7 @@ void armv8_dpm_report_wfar(struct arm_dpm *dpm, uint64_t addr)
  * This function must not perform any actions that trigger another exception
  * or a recursion will happen.
  */
-void armv8_dpm_handle_exception(struct arm_dpm *dpm)
+void armv8_dpm_handle_exception(struct arm_dpm *dpm, bool do_restore)
 {
        struct armv8_common *armv8 = dpm->arm->arch_info;
        struct reg_cache *cache = dpm->arm->core_cache;
@@ -1310,6 +1343,9 @@ void armv8_dpm_handle_exception(struct arm_dpm *dpm)
        core_state = armv8_dpm_get_core_state(dpm);
        armv8_select_opcodes(armv8, core_state == ARM_STATE_AARCH64);
        armv8_select_reg_access(armv8, core_state == ARM_STATE_AARCH64);
+
+       if (do_restore)
+               armv8_dpm_modeswitch(dpm, ARM_MODE_ANY);
 }
 
 /*----------------------------------------------------------------------*/