X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Ftarget%2Farmv8.c;h=df5e25102f0c9a9dee42a30756520a3ff8d52e15;hb=ea80232c5e67fe07dff00d54d4f4ac7adf9e3e78;hp=9b160a9f7e5b6ee9d78db8726745848b1acc227a;hpb=2539a323081f046b14ad613b4a163baaf2679a9f;p=openocd.git diff --git a/src/target/armv8.c b/src/target/armv8.c index 9b160a9f7e..df5e25102f 100644 --- a/src/target/armv8.c +++ b/src/target/armv8.c @@ -37,8 +37,6 @@ #include "target.h" #include "target_type.h" -#define __unused __attribute__((unused)) - static const char * const armv8_state_strings[] = { "AArch32", "Thumb", "Jazelle", "ThumbEE", "AArch64", }; @@ -46,11 +44,6 @@ static const char * const armv8_state_strings[] = { static const struct { const char *name; unsigned psr; - /* For user and system modes, these list indices for all registers. - * otherwise they're just indices for the shadow registers and SPSR. - */ - unsigned short n_indices; - const uint8_t *indices; } armv8_mode_data[] = { /* These special modes are currently only supported * by ARMv6M and ARMv7M profiles */ @@ -161,55 +154,332 @@ int armv8_mode_to_number(enum arm_mode mode) } } - -static int armv8_read_core_reg(struct target *target, struct reg *r, - int num, enum arm_mode mode) +static int armv8_read_reg(struct armv8_common *armv8, int regnum, uint64_t *regval) { - uint64_t reg_value; + struct arm_dpm *dpm = &armv8->dpm; int retval; - struct arm_reg *armv8_core_reg; - struct armv8_common *armv8 = target_to_armv8(target); + uint32_t value; + uint64_t value_64; + + switch (regnum) { + case 0 ... 30: + retval = dpm->instr_read_data_dcc_64(dpm, + ARMV8_MSR_GP(SYSTEM_DBG_DBGDTR_EL0, regnum), &value_64); + break; + case ARMV8_SP: + retval = dpm->instr_read_data_r0_64(dpm, + ARMV8_MOVFSP_64(0), &value_64); + break; + case ARMV8_PC: + retval = dpm->instr_read_data_r0_64(dpm, + ARMV8_MRS_DLR(0), &value_64); + break; + case ARMV8_xPSR: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS_DSPSR(0), &value); + value_64 = value; + break; + case ARMV8_ELR_EL1: + retval = dpm->instr_read_data_r0_64(dpm, + ARMV8_MRS(SYSTEM_ELR_EL1, 0), &value_64); + break; + case ARMV8_ELR_EL2: + retval = dpm->instr_read_data_r0_64(dpm, + ARMV8_MRS(SYSTEM_ELR_EL2, 0), &value_64); + break; + case ARMV8_ELR_EL3: + retval = dpm->instr_read_data_r0_64(dpm, + ARMV8_MRS(SYSTEM_ELR_EL3, 0), &value_64); + break; + case ARMV8_ESR_EL1: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS(SYSTEM_ESR_EL1, 0), &value); + value_64 = value; + break; + case ARMV8_ESR_EL2: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS(SYSTEM_ESR_EL2, 0), &value); + value_64 = value; + break; + case ARMV8_ESR_EL3: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS(SYSTEM_ESR_EL3, 0), &value); + value_64 = value; + break; + case ARMV8_SPSR_EL1: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS(SYSTEM_SPSR_EL1, 0), &value); + value_64 = value; + break; + case ARMV8_SPSR_EL2: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS(SYSTEM_SPSR_EL2, 0), &value); + value_64 = value; + break; + case ARMV8_SPSR_EL3: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS(SYSTEM_SPSR_EL3, 0), &value); + value_64 = value; + break; + default: + retval = ERROR_FAIL; + break; + } - assert(num < (int)armv8->arm.core_cache->num_regs); + if (retval == ERROR_OK && regval != NULL) + *regval = value_64; - armv8_core_reg = armv8->arm.core_cache->reg_list[num].arch_info; - retval = armv8->load_core_reg_u64(target, - armv8_core_reg->num, ®_value); + return retval; +} - buf_set_u64(armv8->arm.core_cache->reg_list[num].value, 0, 64, reg_value); - armv8->arm.core_cache->reg_list[num].valid = 1; - armv8->arm.core_cache->reg_list[num].dirty = 0; +static int armv8_write_reg(struct armv8_common *armv8, int regnum, uint64_t value_64) +{ + struct arm_dpm *dpm = &armv8->dpm; + int retval; + uint32_t value; + + switch (regnum) { + case 0 ... 30: + retval = dpm->instr_write_data_dcc_64(dpm, + ARMV8_MRS(SYSTEM_DBG_DBGDTR_EL0, regnum), + value_64); + break; + case ARMV8_SP: + retval = dpm->instr_write_data_r0_64(dpm, + ARMV8_MOVTSP_64(0), + value_64); + break; + case ARMV8_PC: + retval = dpm->instr_write_data_r0_64(dpm, + ARMV8_MSR_DLR(0), + value_64); + break; + case ARMV8_xPSR: + value = value_64; + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_DSPSR(0), + value); + break; + /* registers clobbered by taking exception in debug state */ + case ARMV8_ELR_EL1: + retval = dpm->instr_write_data_r0_64(dpm, + ARMV8_MSR_GP(SYSTEM_ELR_EL1, 0), value_64); + break; + case ARMV8_ELR_EL2: + retval = dpm->instr_write_data_r0_64(dpm, + ARMV8_MSR_GP(SYSTEM_ELR_EL2, 0), value_64); + break; + case ARMV8_ELR_EL3: + retval = dpm->instr_write_data_r0_64(dpm, + ARMV8_MSR_GP(SYSTEM_ELR_EL3, 0), value_64); + break; + case ARMV8_ESR_EL1: + value = value_64; + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_GP(SYSTEM_ESR_EL1, 0), value); + break; + case ARMV8_ESR_EL2: + value = value_64; + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_GP(SYSTEM_ESR_EL2, 0), value); + break; + case ARMV8_ESR_EL3: + value = value_64; + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_GP(SYSTEM_ESR_EL3, 0), value); + break; + case ARMV8_SPSR_EL1: + value = value_64; + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_GP(SYSTEM_SPSR_EL1, 0), value); + break; + case ARMV8_SPSR_EL2: + value = value_64; + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_GP(SYSTEM_SPSR_EL2, 0), value); + break; + case ARMV8_SPSR_EL3: + value = value_64; + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_GP(SYSTEM_SPSR_EL3, 0), value); + break; + default: + retval = ERROR_FAIL; + break; + } return retval; } -#if 0 -static int armv8_write_core_reg(struct target *target, struct reg *r, - int num, enum arm_mode mode, target_addr_t value) +static int armv8_read_reg32(struct armv8_common *armv8, int regnum, uint64_t *regval) { + struct arm_dpm *dpm = &armv8->dpm; + uint32_t value = 0; int retval; - struct arm_reg *armv8_core_reg; - struct armv8_common *armv8 = target_to_armv8(target); - assert(num < (int)armv8->arm.core_cache->num_regs); + switch (regnum) { + case ARMV8_R0 ... ARMV8_R14: + /* return via DCC: "MCR p14, 0, Rnum, c0, c5, 0" */ + retval = dpm->instr_read_data_dcc(dpm, + ARMV4_5_MCR(14, 0, regnum, 0, 5, 0), + &value); + break; + case ARMV8_SP: + retval = dpm->instr_read_data_dcc(dpm, + ARMV4_5_MCR(14, 0, 13, 0, 5, 0), + &value); + break; + case ARMV8_PC: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRC_DLR(0), + &value); + break; + case ARMV8_xPSR: + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRC_DSPSR(0), + &value); + break; + case ARMV8_ELR_EL1: /* mapped to LR_svc */ + retval = dpm->instr_read_data_dcc(dpm, + ARMV4_5_MCR(14, 0, 14, 0, 5, 0), + &value); + break; + case ARMV8_ELR_EL2: /* mapped to ELR_hyp */ + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS_T1(0, 14, 0, 1), + &value); + break; + case ARMV8_ELR_EL3: /* mapped to LR_mon */ + retval = dpm->instr_read_data_dcc(dpm, + ARMV4_5_MCR(14, 0, 14, 0, 5, 0), + &value); + break; + case ARMV8_ESR_EL1: /* mapped to DFSR */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_MRC(15, 0, 0, 5, 0, 0), + &value); + break; + case ARMV8_ESR_EL2: /* mapped to HSR */ + retval = dpm->instr_read_data_r0(dpm, + ARMV4_5_MRC(15, 4, 0, 5, 2, 0), + &value); + break; + case ARMV8_ESR_EL3: /* FIXME: no equivalent in aarch32? */ + retval = ERROR_FAIL; + break; + case ARMV8_SPSR_EL1: /* mapped to SPSR_svc */ + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS_xPSR_T1(1, 0), + &value); + break; + case ARMV8_SPSR_EL2: /* mapped to SPSR_hyp */ + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS_xPSR_T1(1, 0), + &value); + break; + case ARMV8_SPSR_EL3: /* mapped to SPSR_mon */ + retval = dpm->instr_read_data_r0(dpm, + ARMV8_MRS_xPSR_T1(1, 0), + &value); + break; + default: + retval = ERROR_FAIL; + break; + } + + if (retval == ERROR_OK && regval != NULL) + *regval = value; + + return retval; +} - armv8_core_reg = armv8->arm.core_cache->reg_list[num].arch_info; - retval = armv8->store_core_reg_u64(target, - armv8_core_reg->num, - value); - if (retval != ERROR_OK) { - LOG_ERROR("JTAG failure"); - armv8->arm.core_cache->reg_list[num].dirty = armv8->arm.core_cache->reg_list[num].valid; - return ERROR_JTAG_DEVICE_ERROR; +static int armv8_write_reg32(struct armv8_common *armv8, int regnum, uint64_t value) +{ + struct arm_dpm *dpm = &armv8->dpm; + int retval; + + switch (regnum) { + case ARMV8_R0 ... ARMV8_R14: + /* load register from DCC: "MRC p14, 0, Rnum, c0, c5, 0" */ + retval = dpm->instr_write_data_dcc(dpm, + ARMV4_5_MRC(14, 0, regnum, 0, 5, 0), value); + break; + case ARMV8_SP: + retval = dpm->instr_write_data_dcc(dpm, + ARMV4_5_MRC(14, 0, 13, 0, 5, 0), value); + break; + case ARMV8_PC:/* PC + * read r0 from DCC; then "MOV pc, r0" */ + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MCR_DLR(0), value); + break; + case ARMV8_xPSR: /* CPSR */ + /* read r0 from DCC, then "MCR r0, DSPSR" */ + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MCR_DSPSR(0), value); + break; + case ARMV8_ELR_EL1: /* mapped to LR_svc */ + retval = dpm->instr_write_data_dcc(dpm, + ARMV4_5_MRC(14, 0, 14, 0, 5, 0), + value); + break; + case ARMV8_ELR_EL2: /* mapped to ELR_hyp */ + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_GP_T1(0, 14, 0, 1), + value); + break; + case ARMV8_ELR_EL3: /* mapped to LR_mon */ + retval = dpm->instr_write_data_dcc(dpm, + ARMV4_5_MRC(14, 0, 14, 0, 5, 0), + value); + break; + case ARMV8_ESR_EL1: /* mapped to DFSR */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_MCR(15, 0, 0, 5, 0, 0), + value); + break; + case ARMV8_ESR_EL2: /* mapped to HSR */ + retval = dpm->instr_write_data_r0(dpm, + ARMV4_5_MCR(15, 4, 0, 5, 2, 0), + value); + break; + case ARMV8_ESR_EL3: /* FIXME: no equivalent in aarch32? */ + retval = ERROR_FAIL; + break; + case ARMV8_SPSR_EL1: /* mapped to SPSR_svc */ + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_GP_xPSR_T1(1, 0, 15), + value); + break; + case ARMV8_SPSR_EL2: /* mapped to SPSR_hyp */ + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_GP_xPSR_T1(1, 0, 15), + value); + break; + case ARMV8_SPSR_EL3: /* mapped to SPSR_mon */ + retval = dpm->instr_write_data_r0(dpm, + ARMV8_MSR_GP_xPSR_T1(1, 0, 15), + value); + break; + default: + retval = ERROR_FAIL; + break; } - LOG_DEBUG("write core reg %i value 0x%" PRIx64 "", num, value); - armv8->arm.core_cache->reg_list[num].valid = 1; - armv8->arm.core_cache->reg_list[num].dirty = 0; + return retval; - return ERROR_OK; } -#endif + +void armv8_select_reg_access(struct armv8_common *armv8, bool is_aarch64) +{ + if (is_aarch64) { + armv8->read_reg_u64 = armv8_read_reg; + armv8->write_reg_u64 = armv8_write_reg; + } else { + armv8->read_reg_u64 = armv8_read_reg32; + armv8->write_reg_u64 = armv8_write_reg32; + } +} /* retrieve core id cluster id */ int armv8_read_mpidr(struct armv8_common *armv8) @@ -232,10 +502,9 @@ int armv8_read_mpidr(struct armv8_common *armv8) LOG_INFO("%s cluster %x core %x %s", target_name(armv8->arm.target), armv8->cluster_id, armv8->cpu_id, - armv8->multi_processor_system == 0 ? "multi core" : "mono core"); - + armv8->multi_processor_system == 0 ? "multi core" : "single core"); } else - LOG_ERROR("mpdir not in multiprocessor format"); + LOG_ERROR("mpidr not in multiprocessor format"); done: dpm->finish(dpm); @@ -306,26 +575,26 @@ static void armv8_show_fault_registers32(struct armv8_common *armv8) /* c5/c0 - {data, instruction} fault status registers */ retval = dpm->instr_read_data_r0(dpm, - T32_FMTITR(ARMV4_5_MRC(15, 0, 0, 5, 0, 0)), + ARMV4_5_MRC(15, 0, 0, 5, 0, 0), &dfsr); if (retval != ERROR_OK) goto done; retval = dpm->instr_read_data_r0(dpm, - T32_FMTITR(ARMV4_5_MRC(15, 0, 0, 5, 0, 1)), + ARMV4_5_MRC(15, 0, 0, 5, 0, 1), &ifsr); if (retval != ERROR_OK) goto done; /* c6/c0 - {data, instruction} fault address registers */ retval = dpm->instr_read_data_r0(dpm, - T32_FMTITR(ARMV4_5_MRC(15, 0, 0, 6, 0, 0)), + ARMV4_5_MRC(15, 0, 0, 6, 0, 0), &dfar); if (retval != ERROR_OK) goto done; retval = dpm->instr_read_data_r0(dpm, - T32_FMTITR(ARMV4_5_MRC(15, 0, 0, 6, 0, 2)), + ARMV4_5_MRC(15, 0, 0, 6, 0, 2), &ifar); if (retval != ERROR_OK) goto done; @@ -339,7 +608,7 @@ done: /* (void) */ dpm->finish(dpm); } -static void armv8_show_fault_registers(struct target *target) +static __attribute__((unused)) void armv8_show_fault_registers(struct target *target) { struct armv8_common *armv8 = target_to_armv8(target); @@ -376,7 +645,7 @@ static uint8_t armv8_pa_size(uint32_t ps) return ret; } -static __unused int armv8_read_ttbcr32(struct target *target) +static __attribute__((unused)) int armv8_read_ttbcr32(struct target *target) { struct armv8_common *armv8 = target_to_armv8(target); struct arm_dpm *dpm = armv8->arm.dpm; @@ -386,7 +655,7 @@ static __unused int armv8_read_ttbcr32(struct target *target) goto done; /* MRC p15,0,,c2,c0,2 ; Read CP15 Translation Table Base Control Register*/ retval = dpm->instr_read_data_r0(dpm, - T32_FMTITR(ARMV4_5_MRC(15, 0, 0, 2, 0, 2)), + ARMV4_5_MRC(15, 0, 0, 2, 0, 2), &ttbcr); if (retval != ERROR_OK) goto done; @@ -415,7 +684,7 @@ done: return retval; } -static __unused int armv8_read_ttbcr(struct target *target) +static __attribute__((unused)) int armv8_read_ttbcr(struct target *target) { struct armv8_common *armv8 = target_to_armv8(target); struct arm_dpm *dpm = armv8->arm.dpm; @@ -431,7 +700,7 @@ static __unused int armv8_read_ttbcr(struct target *target) memset(&armv8->armv8_mmu.ttbr1_used, 0, sizeof(armv8->armv8_mmu.ttbr1_used)); memset(&armv8->armv8_mmu.ttbr0_mask, 0, sizeof(armv8->armv8_mmu.ttbr0_mask)); - switch (armv8_curel_from_core_mode(arm)) { + switch (armv8_curel_from_core_mode(arm->core_mode)) { case SYSTEM_CUREL_EL3: retval = dpm->instr_read_data_r0(dpm, ARMV8_MRS(SYSTEM_TCR_EL3, 0), @@ -459,6 +728,8 @@ static __unused int armv8_read_ttbcr(struct target *target) armv8->page_size = (ttbcr >> 14) & 3; break; case SYSTEM_CUREL_EL0: + armv8_dpm_modeswitch(dpm, ARMV8_64_EL1H); + /* fall through */ case SYSTEM_CUREL_EL1: retval = dpm->instr_read_data_r0_64(dpm, ARMV8_MRS(SYSTEM_TCR_EL1, 0), @@ -486,6 +757,7 @@ static __unused int armv8_read_ttbcr(struct target *target) LOG_INFO("TTBR0 access above %" PRIx64, (uint64_t)(armv8->armv8_mmu.ttbr0_mask)); done: + armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); dpm->finish(dpm); return retval; } @@ -503,6 +775,7 @@ int armv8_mmu_translate_va_pa(struct target *target, target_addr_t va, struct armv8_common *armv8 = target_to_armv8(target); struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = &armv8->dpm; + enum arm_mode target_mode = ARM_MODE_ANY; uint32_t retval; uint32_t instr = 0; uint64_t par; @@ -519,16 +792,16 @@ int armv8_mmu_translate_va_pa(struct target *target, target_addr_t va, if (retval != ERROR_OK) return retval; - switch (armv8_curel_from_core_mode(arm)) { + switch (armv8_curel_from_core_mode(arm->core_mode)) { case SYSTEM_CUREL_EL0: instr = ARMV8_SYS(SYSTEM_ATS12E0R, 0); /* can only execute instruction at EL2 */ - dpmv8_modeswitch(dpm, ARMV8_64_EL2T); + target_mode = ARMV8_64_EL2H; break; case SYSTEM_CUREL_EL1: instr = ARMV8_SYS(SYSTEM_ATS12E1R, 0); /* can only execute instruction at EL2 */ - dpmv8_modeswitch(dpm, ARMV8_64_EL2T); + target_mode = ARMV8_64_EL2H; break; case SYSTEM_CUREL_EL2: instr = ARMV8_SYS(SYSTEM_ATS1E2R, 0); @@ -541,16 +814,20 @@ int armv8_mmu_translate_va_pa(struct target *target, target_addr_t va, break; }; + if (target_mode != ARM_MODE_ANY) + armv8_dpm_modeswitch(dpm, target_mode); + /* write VA to R0 and execute translation instruction */ retval = dpm->instr_write_data_r0_64(dpm, instr, (uint64_t)va); /* read result from PAR_EL1 */ if (retval == ERROR_OK) retval = dpm->instr_read_data_r0_64(dpm, ARMV8_MRS(SYSTEM_PAR_EL1, 0), &par); - dpm->finish(dpm); - /* switch back to saved PE mode */ - dpmv8_modeswitch(dpm, ARM_MODE_ANY); + if (target_mode != ARM_MODE_ANY) + armv8_dpm_modeswitch(dpm, ARM_MODE_ANY); + + dpm->finish(dpm); if (retval != ERROR_OK) return retval; @@ -602,11 +879,6 @@ int armv8_init_arch_info(struct target *target, struct armv8_common *armv8) armv8->arm.common_magic = ARM_COMMON_MAGIC; armv8->common_magic = ARMV8_COMMON_MAGIC; - arm->read_core_reg = armv8_read_core_reg; -#if 0 - arm->write_core_reg = armv8_write_core_reg; -#endif - armv8->armv8_mmu.armv8_cache.l2_cache = NULL; armv8->armv8_mmu.armv8_cache.info = -1; armv8->armv8_mmu.armv8_cache.flush_all_data_cache = NULL; @@ -673,54 +945,94 @@ static const struct { unsigned id; const char *name; unsigned bits; + enum arm_mode mode; enum reg_type type; const char *group; const char *feature; } armv8_regs[] = { - { ARMV8_R0, "x0", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R1, "x1", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R2, "x2", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R3, "x3", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R4, "x4", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R5, "x5", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R6, "x6", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R7, "x7", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R8, "x8", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R9, "x9", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R10, "x10", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R11, "x11", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R12, "x12", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R13, "x13", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R14, "x14", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R15, "x15", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R16, "x16", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R17, "x17", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R18, "x18", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R19, "x19", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R20, "x20", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R21, "x21", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R22, "x22", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R23, "x23", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R24, "x24", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R25, "x25", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R26, "x26", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R27, "x27", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R28, "x28", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R29, "x29", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_R30, "x30", 64, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, - - { ARMV8_R31, "sp", 64, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.aarch64.core" }, - { ARMV8_PC, "pc", 64, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.aarch64.core" }, - - { ARMV8_xPSR, "CPSR", 32, REG_TYPE_UINT32, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R0, "x0", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R1, "x1", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R2, "x2", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R3, "x3", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R4, "x4", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R5, "x5", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R6, "x6", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R7, "x7", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R8, "x8", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R9, "x9", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R10, "x10", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R11, "x11", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R12, "x12", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R13, "x13", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R14, "x14", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R15, "x15", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R16, "x16", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R17, "x17", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R18, "x18", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R19, "x19", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R20, "x20", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R21, "x21", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R22, "x22", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R23, "x23", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R24, "x24", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R25, "x25", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R26, "x26", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R27, "x27", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R28, "x28", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R29, "x29", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_R30, "x30", 64, ARM_MODE_ANY, REG_TYPE_UINT64, "general", "org.gnu.gdb.aarch64.core" }, + + { ARMV8_SP, "sp", 64, ARM_MODE_ANY, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.aarch64.core" }, + { ARMV8_PC, "pc", 64, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.aarch64.core" }, + + { ARMV8_xPSR, "CPSR", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.aarch64.core" }, + + { ARMV8_ELR_EL1, "ELR_EL1", 64, ARMV8_64_EL1H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked" }, + { ARMV8_ESR_EL1, "ESR_EL1", 32, ARMV8_64_EL1H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" }, + { ARMV8_SPSR_EL1, "SPSR_EL1", 32, ARMV8_64_EL1H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" }, + + { ARMV8_ELR_EL2, "ELR_EL2", 64, ARMV8_64_EL2H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked" }, + { ARMV8_ESR_EL2, "ESR_EL2", 32, ARMV8_64_EL2H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" }, + { ARMV8_SPSR_EL2, "SPSR_EL2", 32, ARMV8_64_EL2H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" }, + + { ARMV8_ELR_EL3, "ELR_EL3", 64, ARMV8_64_EL3H, REG_TYPE_CODE_PTR, "banked", "net.sourceforge.openocd.banked" }, + { ARMV8_ESR_EL3, "ESR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" }, + { ARMV8_SPSR_EL3, "SPSR_EL3", 32, ARMV8_64_EL3H, REG_TYPE_UINT32, "banked", "net.sourceforge.openocd.banked" }, }; -#define ARMV8_NUM_REGS ARRAY_SIZE(armv8_regs) +static const struct { + unsigned id; + const char *name; + unsigned bits; + enum arm_mode mode; + enum reg_type type; + const char *group; + const char *feature; +} armv8_regs32[] = { + { ARMV8_R0, "r0", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R1, "r1", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R2, "r2", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R3, "r3", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R4, "r4", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R5, "r5", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R6, "r6", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R7, "r7", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R8, "r8", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R9, "r9", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R10, "r10", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R11, "r11", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R12, "r12", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R13, "sp", 32, ARM_MODE_ANY, REG_TYPE_DATA_PTR, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_R14, "lr", 32, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_PC, "pc", 32, ARM_MODE_ANY, REG_TYPE_CODE_PTR, "general", "org.gnu.gdb.arm.core" }, + { ARMV8_xPSR, "cpsr", 32, ARM_MODE_ANY, REG_TYPE_UINT32, "general", "org.gnu.gdb.arm.core" }, +}; +#define ARMV8_NUM_REGS ARRAY_SIZE(armv8_regs) +#define ARMV8_NUM_REGS32 ARRAY_SIZE(armv8_regs32) static int armv8_get_core_reg(struct reg *reg) { - int retval; struct arm_reg *armv8_reg = reg->arch_info; struct target *target = armv8_reg->target; struct arm *arm = target_to_arm(target); @@ -728,9 +1040,7 @@ static int armv8_get_core_reg(struct reg *reg) if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; - retval = arm->read_core_reg(target, reg, armv8_reg->num, arm->core_mode); - - return retval; + return arm->read_core_reg(target, reg, armv8_reg->num, arm->core_mode); } static int armv8_set_core_reg(struct reg *reg, uint8_t *buf) @@ -760,36 +1070,87 @@ static const struct reg_arch_type armv8_reg_type = { .set = armv8_set_core_reg, }; +static int armv8_get_core_reg32(struct reg *reg) +{ + struct arm_reg *armv8_reg = reg->arch_info; + struct target *target = armv8_reg->target; + struct arm *arm = target_to_arm(target); + struct reg_cache *cache = arm->core_cache; + struct reg *reg64; + int retval; + + /* get the corresponding Aarch64 register */ + reg64 = cache->reg_list + armv8_reg->num; + if (reg64->valid) { + reg->valid = true; + return ERROR_OK; + } + + retval = arm->read_core_reg(target, reg64, armv8_reg->num, arm->core_mode); + if (retval == ERROR_OK) + reg->valid = reg64->valid; + + return retval; +} + +static int armv8_set_core_reg32(struct reg *reg, uint8_t *buf) +{ + struct arm_reg *armv8_reg = reg->arch_info; + struct target *target = armv8_reg->target; + struct arm *arm = target_to_arm(target); + struct reg_cache *cache = arm->core_cache; + struct reg *reg64 = cache->reg_list + armv8_reg->num; + uint32_t value = buf_get_u32(buf, 0, 32); + + if (reg64 == arm->cpsr) { + armv8_set_cpsr(arm, value); + } else { + buf_set_u32(reg->value, 0, 32, value); + reg->valid = 1; + reg64->valid = 1; + } + + reg64->dirty = 1; + + return ERROR_OK; +} + +static const struct reg_arch_type armv8_reg32_type = { + .get = armv8_get_core_reg32, + .set = armv8_set_core_reg32, +}; + /** Builds cache of architecturally defined registers. */ struct reg_cache *armv8_build_reg_cache(struct target *target) { struct armv8_common *armv8 = target_to_armv8(target); struct arm *arm = &armv8->arm; int num_regs = ARMV8_NUM_REGS; + int num_regs32 = ARMV8_NUM_REGS32; struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct reg_cache *cache = malloc(sizeof(struct reg_cache)); + struct reg_cache *cache32 = malloc(sizeof(struct reg_cache)); struct reg *reg_list = calloc(num_regs, sizeof(struct reg)); + struct reg *reg_list32 = calloc(num_regs32, sizeof(struct reg)); struct arm_reg *arch_info = calloc(num_regs, sizeof(struct arm_reg)); struct reg_feature *feature; int i; /* Build the process context cache */ - cache->name = "arm v8 registers"; - cache->next = NULL; + cache->name = "Aarch64 registers"; + cache->next = cache32; cache->reg_list = reg_list; cache->num_regs = num_regs; - (*cache_p) = cache; for (i = 0; i < num_regs; i++) { arch_info[i].num = armv8_regs[i].id; + arch_info[i].mode = armv8_regs[i].mode; arch_info[i].target = target; arch_info[i].arm = arm; reg_list[i].name = armv8_regs[i].name; reg_list[i].size = armv8_regs[i].bits; - reg_list[i].value = calloc(1, 8); - reg_list[i].dirty = 0; - reg_list[i].valid = 0; + reg_list[i].value = &arch_info[i].value[0]; reg_list[i].type = &armv8_reg_type; reg_list[i].arch_info = &arch_info[i]; @@ -816,6 +1177,38 @@ struct reg_cache *armv8_build_reg_cache(struct target *target) arm->pc = reg_list + ARMV8_PC; arm->core_cache = cache; + /* shadow cache for ARM mode registers */ + cache32->name = "Aarch32 registers"; + cache32->next = NULL; + cache32->reg_list = reg_list32; + cache32->num_regs = num_regs32; + + for (i = 0; i < num_regs32; i++) { + reg_list32[i].name = armv8_regs32[i].name; + reg_list32[i].size = armv8_regs32[i].bits; + reg_list32[i].value = &arch_info[armv8_regs32[i].id].value[0]; + reg_list32[i].type = &armv8_reg32_type; + reg_list32[i].arch_info = &arch_info[armv8_regs32[i].id]; + reg_list32[i].group = armv8_regs32[i].group; + reg_list32[i].number = i; + reg_list32[i].exist = true; + reg_list32[i].caller_save = true; + + feature = calloc(1, sizeof(struct reg_feature)); + if (feature) { + feature->name = armv8_regs32[i].feature; + reg_list32[i].feature = feature; + } else + LOG_ERROR("unable to allocate feature list"); + + reg_list32[i].reg_data_type = calloc(1, sizeof(struct reg_data_type)); + if (reg_list32[i].reg_data_type) + reg_list32[i].reg_data_type->type = armv8_regs32[i].type; + else + LOG_ERROR("unable to allocate reg type list"); + } + + (*cache_p) = cache; return cache; } @@ -845,20 +1238,71 @@ int armv8_get_gdb_reg_list(struct target *target, struct arm *arm = target_to_arm(target); int i; - switch (reg_class) { - case REG_CLASS_GENERAL: - case REG_CLASS_ALL: - *reg_list_size = ARMV8_LAST_REG; - *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); + if (arm->core_state == ARM_STATE_AARCH64) { - for (i = 0; i < ARMV8_LAST_REG; i++) - (*reg_list)[i] = armv8_reg_current(arm, i); + LOG_DEBUG("Creating Aarch64 register list for target %s", target_name(target)); - return ERROR_OK; + switch (reg_class) { + case REG_CLASS_GENERAL: + *reg_list_size = ARMV8_ELR_EL1; + *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); - default: - LOG_ERROR("not a valid register class type in query."); - return ERROR_FAIL; - break; + for (i = 0; i < *reg_list_size; i++) + (*reg_list)[i] = armv8_reg_current(arm, i); + return ERROR_OK; + + case REG_CLASS_ALL: + *reg_list_size = ARMV8_LAST_REG; + *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); + + for (i = 0; i < *reg_list_size; i++) + (*reg_list)[i] = armv8_reg_current(arm, i); + + return ERROR_OK; + + default: + LOG_ERROR("not a valid register class type in query."); + return ERROR_FAIL; + } + } else { + struct reg_cache *cache32 = arm->core_cache->next; + + LOG_DEBUG("Creating Aarch32 register list for target %s", target_name(target)); + + switch (reg_class) { + case REG_CLASS_GENERAL: + case REG_CLASS_ALL: + *reg_list_size = cache32->num_regs; + *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); + + for (i = 0; i < *reg_list_size; i++) + (*reg_list)[i] = cache32->reg_list + i; + + return ERROR_OK; + default: + LOG_ERROR("not a valid register class type in query."); + return ERROR_FAIL; + } } } + +int armv8_set_dbgreg_bits(struct armv8_common *armv8, unsigned int reg, unsigned long mask, unsigned long value) +{ + uint32_t tmp; + + /* Read register */ + int retval = mem_ap_read_atomic_u32(armv8->debug_ap, + armv8->debug_base + reg, &tmp); + if (ERROR_OK != retval) + return retval; + + /* clear bitfield */ + tmp &= ~mask; + /* put new value */ + tmp |= value & mask; + + /* write new value */ + retval = mem_ap_write_atomic_u32(armv8->debug_ap, + armv8->debug_base + reg, tmp); + return retval; +}