If we enter debug state from EL0, some registers are not accessible.
Temporarily move to EL1H and back to gain access. Also, fix
armv8_dpm_modeswitch() to not immediately restore the previous state
on elevating the privilege level.
Change-Id: Ic2a92109230ff4eb6834c00ef544397a5b7ad56a
Signed-off-by: Matthias Welwarsky <matthias.welwarsky@sysgo.com>
Reviewed-on: http://openocd.zylin.com/4461
Tested-by: jenkins
Reviewed-by: Matthias Welwarsky <matthias@welwarsky.de>
if (dscr & (DSCR_ERR | DSCR_SYS_ERROR_PEND)) {
/* Abort occurred - clear it and exit */
LOG_ERROR("abort occurred - dscr = 0x%08" PRIx32, dscr);
- armv8_dpm_handle_exception(dpm);
+ armv8_dpm_handle_exception(dpm, true);
return ERROR_FAIL;
}
if (dscr & (DSCR_ERR | DSCR_SYS_ERROR_PEND)) {
/* Abort occurred - clear it and exit */
LOG_ERROR("abort occurred - dscr = 0x%08" PRIx32, dscr);
- armv8_dpm_handle_exception(dpm);
+ armv8_dpm_handle_exception(dpm, true);
return ERROR_FAIL;
}
int armv8_read_mpidr(struct armv8_common *armv8)
{
int retval = ERROR_FAIL;
+ struct arm *arm = &armv8->arm;
struct arm_dpm *dpm = armv8->arm.dpm;
uint32_t mpidr;
if (retval != ERROR_OK)
goto done;
+ /* check if we're in an unprivileged mode */
+ if (armv8_curel_from_core_mode(arm->core_mode) < SYSTEM_CUREL_EL1) {
+ retval = armv8_dpm_modeswitch(dpm, ARMV8_64_EL1H);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
retval = dpm->instr_read_data_r0(dpm, armv8_opcode(armv8, READ_REG_MPIDR), &mpidr);
if (retval != ERROR_OK)
goto done;
LOG_ERROR("mpidr not in multiprocessor format");
done:
+ armv8_dpm_modeswitch(dpm, ARM_MODE_ANY);
dpm->finish(dpm);
return retval;
}
{
/* read cache descriptor */
int retval = ERROR_FAIL;
+ struct arm *arm = &armv8->arm;
struct arm_dpm *dpm = armv8->arm.dpm;
uint32_t csselr, clidr, ctr;
uint32_t cache_reg;
if (retval != ERROR_OK)
goto done;
+ /* check if we're in an unprivileged mode */
+ if (armv8_curel_from_core_mode(arm->core_mode) < SYSTEM_CUREL_EL1) {
+ retval = armv8_dpm_modeswitch(dpm, ARMV8_64_EL1H);
+ if (retval != ERROR_OK)
+ return retval;
+ }
+
/* retrieve CTR */
retval = dpm->instr_read_data_r0(dpm,
armv8_opcode(armv8, READ_REG_CTR), &ctr);
}
done:
+ armv8_dpm_modeswitch(dpm, ARM_MODE_ANY);
dpm->finish(dpm);
return retval;
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;
}
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) {
* 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;
armv8_select_opcodes(armv8, core_state == ARM_STATE_AARCH64);
armv8_select_reg_access(armv8, core_state == ARM_STATE_AARCH64);
- armv8_dpm_modeswitch(dpm, ARM_MODE_ANY);
+ if (do_restore)
+ armv8_dpm_modeswitch(dpm, ARM_MODE_ANY);
}
/*----------------------------------------------------------------------*/
#define PRCR_COREPURQ (1 << 3)
void armv8_dpm_report_dscr(struct arm_dpm *dpm, uint32_t dcsr);
-void armv8_dpm_handle_exception(struct arm_dpm *dpm);
+void armv8_dpm_handle_exception(struct arm_dpm *dpm, bool do_restore);
enum arm_state armv8_dpm_get_core_state(struct arm_dpm *dpm);
#endif /* OPENOCD_TARGET_ARM_DPM_H */