diff options
Diffstat (limited to 'target-arm')
| -rw-r--r-- | target-arm/cpu.c | 1 | ||||
| -rw-r--r-- | target-arm/cpu.h | 55 | ||||
| -rw-r--r-- | target-arm/cpu64.c | 2 | ||||
| -rw-r--r-- | target-arm/helper.c | 173 | ||||
| -rw-r--r-- | target-arm/helper.h | 2 | ||||
| -rw-r--r-- | target-arm/internals.h | 31 | ||||
| -rw-r--r-- | target-arm/op_helper.c | 40 | ||||
| -rw-r--r-- | target-arm/translate-a64.c | 6 | ||||
| -rw-r--r-- | target-arm/translate.c | 21 |
9 files changed, 248 insertions, 83 deletions
diff --git a/target-arm/cpu.c b/target-arm/cpu.c index 7ddbf3d19b..f2393cd9f2 100644 --- a/target-arm/cpu.c +++ b/target-arm/cpu.c @@ -1483,6 +1483,7 @@ static void arm_cpu_class_init(ObjectClass *oc, void *data) cc->gdb_arch_name = arm_gdb_arch_name; cc->gdb_stop_before_watchpoint = true; cc->debug_excp_handler = arm_debug_excp_handler; + cc->debug_check_watchpoint = arm_debug_check_watchpoint; cc->disas_set_info = arm_disas_set_info; diff --git a/target-arm/cpu.h b/target-arm/cpu.h index b8b3364615..5137632ccc 100644 --- a/target-arm/cpu.h +++ b/target-arm/cpu.h @@ -382,6 +382,7 @@ typedef struct CPUARMState { uint64_t mdscr_el1; uint64_t oslsr_el1; /* OS Lock Status */ uint64_t mdcr_el2; + uint64_t mdcr_el3; /* If the counter is enabled, this stores the last time the counter * was reset. Otherwise it stores the counter value */ @@ -931,7 +932,7 @@ static inline bool arm_is_secure_below_el3(CPUARMState *env) if (arm_feature(env, ARM_FEATURE_EL3)) { return !(env->cp15.scr_el3 & SCR_NS); } else { - /* If EL2 is not supported then the secure state is implementation + /* If EL3 is not supported then the secure state is implementation * defined, in which case QEMU defaults to non-secure. */ return false; @@ -1318,7 +1319,9 @@ typedef uint64_t CPReadFn(CPUARMState *env, const ARMCPRegInfo *opaque); typedef void CPWriteFn(CPUARMState *env, const ARMCPRegInfo *opaque, uint64_t value); /* Access permission check functions for coprocessor registers. */ -typedef CPAccessResult CPAccessFn(CPUARMState *env, const ARMCPRegInfo *opaque); +typedef CPAccessResult CPAccessFn(CPUARMState *env, + const ARMCPRegInfo *opaque, + bool isread); /* Hook function for register reset */ typedef void CPResetFn(CPUARMState *env, const ARMCPRegInfo *opaque); @@ -1741,9 +1744,7 @@ typedef enum ARMASIdx { ARMASIdx_S = 1, } ARMASIdx; -/* Return the Exception Level targeted by debug exceptions; - * currently always EL1 since we don't implement EL2 or EL3. - */ +/* Return the Exception Level targeted by debug exceptions. */ static inline int arm_debug_target_el(CPUARMState *env) { bool secure = arm_is_secure(env); @@ -1766,6 +1767,14 @@ static inline int arm_debug_target_el(CPUARMState *env) static inline bool aa64_generate_debug_exceptions(CPUARMState *env) { + if (arm_is_secure(env)) { + /* MDCR_EL3.SDD disables debug events from Secure state */ + if (extract32(env->cp15.mdcr_el3, 16, 1) != 0 + || arm_current_el(env) == 3) { + return false; + } + } + if (arm_current_el(env) == arm_debug_target_el(env)) { if ((extract32(env->cp15.mdscr_el1, 13, 1) == 0) || (env->daif & PSTATE_D)) { @@ -1777,10 +1786,42 @@ static inline bool aa64_generate_debug_exceptions(CPUARMState *env) static inline bool aa32_generate_debug_exceptions(CPUARMState *env) { - if (arm_current_el(env) == 0 && arm_el_is_aa64(env, 1)) { + int el = arm_current_el(env); + + if (el == 0 && arm_el_is_aa64(env, 1)) { return aa64_generate_debug_exceptions(env); } - return arm_current_el(env) != 2; + + if (arm_is_secure(env)) { + int spd; + + if (el == 0 && (env->cp15.sder & 1)) { + /* SDER.SUIDEN means debug exceptions from Secure EL0 + * are always enabled. Otherwise they are controlled by + * SDCR.SPD like those from other Secure ELs. + */ + return true; + } + + spd = extract32(env->cp15.mdcr_el3, 14, 2); + switch (spd) { + case 1: + /* SPD == 0b01 is reserved, but behaves as 0b00. */ + case 0: + /* For 0b00 we return true if external secure invasive debug + * is enabled. On real hardware this is controlled by external + * signals to the core. QEMU always permits debug, and behaves + * as if DBGEN, SPIDEN, NIDEN and SPNIDEN are all tied high. + */ + return true; + case 2: + return false; + case 3: + return true; + } + } + + return el != 2; } /* Return true if debugging exceptions are currently enabled. diff --git a/target-arm/cpu64.c b/target-arm/cpu64.c index c847513b25..c5bc19a405 100644 --- a/target-arm/cpu64.c +++ b/target-arm/cpu64.c @@ -109,6 +109,7 @@ static void aarch64_a57_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_V8_SHA256); set_feature(&cpu->env, ARM_FEATURE_V8_PMULL); set_feature(&cpu->env, ARM_FEATURE_CRC); + set_feature(&cpu->env, ARM_FEATURE_EL3); cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A57; cpu->midr = 0x411fd070; cpu->revidr = 0x00000000; @@ -161,6 +162,7 @@ static void aarch64_a53_initfn(Object *obj) set_feature(&cpu->env, ARM_FEATURE_V8_SHA256); set_feature(&cpu->env, ARM_FEATURE_V8_PMULL); set_feature(&cpu->env, ARM_FEATURE_CRC); + set_feature(&cpu->env, ARM_FEATURE_EL3); cpu->kvm_target = QEMU_KVM_ARM_TARGET_CORTEX_A53; cpu->midr = 0x410fd034; cpu->revidr = 0x00000000; diff --git a/target-arm/helper.c b/target-arm/helper.c index 5ea507f5bc..2f9db72806 100644 --- a/target-arm/helper.c +++ b/target-arm/helper.c @@ -344,7 +344,8 @@ void init_cpreg_list(ARMCPU *cpu) * access_el3_aa32ns_aa64any: Used to check both AArch32/64 register views. */ static CPAccessResult access_el3_aa32ns(CPUARMState *env, - const ARMCPRegInfo *ri) + const ARMCPRegInfo *ri, + bool isread) { bool secure = arm_is_secure_below_el3(env); @@ -356,14 +357,34 @@ static CPAccessResult access_el3_aa32ns(CPUARMState *env, } static CPAccessResult access_el3_aa32ns_aa64any(CPUARMState *env, - const ARMCPRegInfo *ri) + const ARMCPRegInfo *ri, + bool isread) { if (!arm_el_is_aa64(env, 3)) { - return access_el3_aa32ns(env, ri); + return access_el3_aa32ns(env, ri, isread); } return CP_ACCESS_OK; } +/* Some secure-only AArch32 registers trap to EL3 if used from + * Secure EL1 (but are just ordinary UNDEF in other non-EL3 contexts). + * Note that an access from Secure EL1 can only happen if EL3 is AArch64. + * We assume that the .access field is set to PL1_RW. + */ +static CPAccessResult access_trap_aa32s_el1(CPUARMState *env, + const ARMCPRegInfo *ri, + bool isread) +{ + if (arm_current_el(env) == 3) { + return CP_ACCESS_OK; + } + if (arm_is_secure_below_el3(env)) { + return CP_ACCESS_TRAP_EL3; + } + /* This will be EL1 NS and EL2 NS, which just UNDEF */ + return CP_ACCESS_TRAP_UNCATEGORIZED; +} + static void dacr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { ARMCPU *cpu = arm_env_get_cpu(env); @@ -634,7 +655,8 @@ static void cpacr_write(CPUARMState *env, const ARMCPRegInfo *ri, env->cp15.cpacr_el1 = value; } -static CPAccessResult cpacr_access(CPUARMState *env, const ARMCPRegInfo *ri) +static CPAccessResult cpacr_access(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) { if (arm_feature(env, ARM_FEATURE_V8)) { /* Check if CPACR accesses are to be trapped to EL2 */ @@ -651,7 +673,8 @@ static CPAccessResult cpacr_access(CPUARMState *env, const ARMCPRegInfo *ri) return CP_ACCESS_OK; } -static CPAccessResult cptr_access(CPUARMState *env, const ARMCPRegInfo *ri) +static CPAccessResult cptr_access(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) { /* Check if CPTR accesses are set to trap to EL3 */ if (arm_current_el(env) == 2 && (env->cp15.cptr_el[3] & CPTR_TCPAC)) { @@ -693,7 +716,8 @@ static const ARMCPRegInfo v6_cp_reginfo[] = { REGINFO_SENTINEL }; -static CPAccessResult pmreg_access(CPUARMState *env, const ARMCPRegInfo *ri) +static CPAccessResult pmreg_access(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) { /* Performance monitor registers user accessibility is controlled * by PMUSERENR. @@ -1137,7 +1161,8 @@ static void teecr_write(CPUARMState *env, const ARMCPRegInfo *ri, env->teecr = value; } -static CPAccessResult teehbr_access(CPUARMState *env, const ARMCPRegInfo *ri) +static CPAccessResult teehbr_access(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) { if (arm_current_el(env) == 0 && (env->teecr & 1)) { return CP_ACCESS_TRAP; @@ -1190,7 +1215,8 @@ static const ARMCPRegInfo v6k_cp_reginfo[] = { #ifndef CONFIG_USER_ONLY -static CPAccessResult gt_cntfrq_access(CPUARMState *env, const ARMCPRegInfo *ri) +static CPAccessResult gt_cntfrq_access(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) { /* CNTFRQ: not visible from PL0 if both PL0PCTEN and PL0VCTEN are zero */ if (arm_current_el(env) == 0 && !extract32(env->cp15.c14_cntkctl, 0, 2)) { @@ -1199,7 +1225,8 @@ static CPAccessResult gt_cntfrq_access(CPUARMState *env, const ARMCPRegInfo *ri) return CP_ACCESS_OK; } -static CPAccessResult gt_counter_access(CPUARMState *env, int timeridx) +static CPAccessResult gt_counter_access(CPUARMState *env, int timeridx, + bool isread) { unsigned int cur_el = arm_current_el(env); bool secure = arm_is_secure(env); @@ -1218,7 +1245,8 @@ static CPAccessResult gt_counter_access(CPUARMState *env, int timeridx) return CP_ACCESS_OK; } -static CPAccessResult gt_timer_access(CPUARMState *env, int timeridx) +static CPAccessResult gt_timer_access(CPUARMState *env, int timeridx, + bool isread) { unsigned int cur_el = arm_current_el(env); bool secure = arm_is_secure(env); @@ -1240,29 +1268,34 @@ static CPAccessResult gt_timer_access(CPUARMState *env, int timeridx) } static CPAccessResult gt_pct_access(CPUARMState *env, - const ARMCPRegInfo *ri) + const ARMCPRegInfo *ri, + bool isread) { - return gt_counter_access(env, GTIMER_PHYS); + return gt_counter_access(env, GTIMER_PHYS, isread); } static CPAccessResult gt_vct_access(CPUARMState *env, - const ARMCPRegInfo *ri) + const ARMCPRegInfo *ri, + bool isread) { - return gt_counter_access(env, GTIMER_VIRT); + return gt_counter_access(env, GTIMER_VIRT, isread); } -static CPAccessResult gt_ptimer_access(CPUARMState *env, const ARMCPRegInfo *ri) +static CPAccessResult gt_ptimer_access(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) { - return gt_timer_access(env, GTIMER_PHYS); + return gt_timer_access(env, GTIMER_PHYS, isread); } -static CPAccessResult gt_vtimer_access(CPUARMState *env, const ARMCPRegInfo *ri) +static CPAccessResult gt_vtimer_access(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) { - return gt_timer_access(env, GTIMER_VIRT); + return gt_timer_access(env, GTIMER_VIRT, isread); } static CPAccessResult gt_stimer_access(CPUARMState *env, - const ARMCPRegInfo *ri) + const ARMCPRegInfo *ri, + bool isread) { /* The AArch64 register view of the secure physical timer is * always accessible from EL3, and configurably accessible from @@ -1759,7 +1792,8 @@ static void par_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) #ifndef CONFIG_USER_ONLY /* get_phys_addr() isn't present for user-mode-only targets */ -static CPAccessResult ats_access(CPUARMState *env, const ARMCPRegInfo *ri) +static CPAccessResult ats_access(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) { if (ri->opc2 & 4) { /* The ATS12NSO* operations must trap to EL3 if executed in @@ -1904,7 +1938,8 @@ static void ats1h_write(CPUARMState *env, const ARMCPRegInfo *ri, A32_BANKED_CURRENT_REG_SET(env, par, par64); } -static CPAccessResult at_s1e2_access(CPUARMState *env, const ARMCPRegInfo *ri) +static CPAccessResult at_s1e2_access(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) { if (arm_current_el(env) == 3 && !(env->cp15.scr_el3 & SCR_NS)) { return CP_ACCESS_TRAP; @@ -2558,7 +2593,8 @@ static void aa64_fpsr_write(CPUARMState *env, const ARMCPRegInfo *ri, vfp_set_fpsr(env, value); } -static CPAccessResult aa64_daif_access(CPUARMState *env, const ARMCPRegInfo *ri) +static CPAccessResult aa64_daif_access(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) { if (arm_current_el(env) == 0 && !(env->cp15.sctlr_el[1] & SCTLR_UMA)) { return CP_ACCESS_TRAP; @@ -2573,7 +2609,8 @@ static void aa64_daif_write(CPUARMState *env, const ARMCPRegInfo *ri, } static CPAccessResult aa64_cacheop_access(CPUARMState *env, - const ARMCPRegInfo *ri) + const ARMCPRegInfo *ri, + bool isread) { /* Cache invalidate/clean: NOP, but EL0 must UNDEF unless * SCTLR_EL1.UCI is set. @@ -2829,7 +2866,8 @@ static void tlbi_aa64_ipas2e1is_write(CPUARMState *env, const ARMCPRegInfo *ri, } } -static CPAccessResult aa64_zva_access(CPUARMState *env, const ARMCPRegInfo *ri) +static CPAccessResult aa64_zva_access(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) { /* We don't implement EL2, so the only control on DC ZVA is the * bit in the SCTLR which can prohibit access for EL0. @@ -2846,13 +2884,14 @@ static uint64_t aa64_dczid_read(CPUARMState *env, const ARMCPRegInfo *ri) int dzp_bit = 1 << 4; /* DZP indicates whether DC ZVA access is allowed */ - if (aa64_zva_access(env, NULL) == CP_ACCESS_OK) { + if (aa64_zva_access(env, NULL, false) == CP_ACCESS_OK) { dzp_bit = 0; } return cpu->dcz_blocksize | dzp_bit; } -static CPAccessResult sp_el0_access(CPUARMState *env, const ARMCPRegInfo *ri) +static CPAccessResult sp_el0_access(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) { if (!(env->pstate & PSTATE_SP)) { /* Access to SP_EL0 is undefined if it's being used as @@ -2891,7 +2930,8 @@ static void sctlr_write(CPUARMState *env, const ARMCPRegInfo *ri, tlb_flush(CPU(cpu), 1); } -static CPAccessResult fpexc32_access(CPUARMState *env, const ARMCPRegInfo *ri) +static CPAccessResult fpexc32_access(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) { if ((env->cp15.cptr_el[2] & CPTR_TFP) && arm_current_el(env) == 2) { return CP_ACCESS_TRAP_EL2; @@ -3523,6 +3563,25 @@ static const ARMCPRegInfo el2_cp_reginfo[] = { REGINFO_SENTINEL }; +static CPAccessResult nsacr_access(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) +{ + /* The NSACR is RW at EL3, and RO for NS EL1 and NS EL2. + * At Secure EL1 it traps to EL3. + */ + if (arm_current_el(env) == 3) { + return CP_ACCESS_OK; + } + if (arm_is_secure_below_el3(env)) { + return CP_ACCESS_TRAP_EL3; + } + /* Accesses from EL1 NS and EL2 NS are UNDEF for write but allow reads. */ + if (isread) { + return CP_ACCESS_OK; + } + return CP_ACCESS_TRAP_UNCATEGORIZED; +} + static const ARMCPRegInfo el3_cp_reginfo[] = { { .name = "SCR_EL3", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 1, .opc2 = 0, @@ -3530,8 +3589,17 @@ static const ARMCPRegInfo el3_cp_reginfo[] = { .resetvalue = 0, .writefn = scr_write }, { .name = "SCR", .type = ARM_CP_ALIAS, .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 0, - .access = PL3_RW, .fieldoffset = offsetoflow32(CPUARMState, cp15.scr_el3), + .access = PL1_RW, .accessfn = access_trap_aa32s_el1, + .fieldoffset = offsetoflow32(CPUARMState, cp15.scr_el3), .writefn = scr_write }, + { .name = "MDCR_EL3", .state = ARM_CP_STATE_AA64, + .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 3, .opc2 = 1, + .resetvalue = 0, + .access = PL3_RW, .fieldoffset = offsetof(CPUARMState, cp15.mdcr_el3) }, + { .name = "SDCR", .type = ARM_CP_ALIAS, + .cp = 15, .opc1 = 0, .crn = 1, .crm = 3, .opc2 = 1, + .access = PL1_RW, .accessfn = access_trap_aa32s_el1, + .fieldoffset = offsetoflow32(CPUARMState, cp15.mdcr_el3) }, { .name = "SDER32_EL3", .state = ARM_CP_STATE_AA64, .opc0 = 3, .opc1 = 6, .crn = 1, .crm = 1, .opc2 = 1, .access = PL3_RW, .resetvalue = 0, @@ -3540,12 +3608,9 @@ static const ARMCPRegInfo el3_cp_reginfo[] = { .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 1, .access = PL3_RW, .resetvalue = 0, .fieldoffset = offsetoflow32(CPUARMState, cp15.sder) }, - /* TODO: Implement NSACR trapping of secure EL1 accesses to EL3 */ - { .name = "NSACR", .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2, - .access = PL3_W | PL1_R, .resetvalue = 0, - .fieldoffset = offsetof(CPUARMState, cp15.nsacr) }, { .name = "MVBAR", .cp = 15, .opc1 = 0, .crn = 12, .crm = 0, .opc2 = 1, - .access = PL3_RW, .writefn = vbar_write, .resetvalue = 0, + .access = PL1_RW, .accessfn = access_trap_aa32s_el1, + .writefn = vbar_write, .resetvalue = 0, .fieldoffset = offsetof(CPUARMState, cp15.mvbar) }, { .name = "SCTLR_EL3", .state = ARM_CP_STATE_AA64, .type = ARM_CP_ALIAS, /* reset handled by AArch32 view */ @@ -3630,7 +3695,8 @@ static const ARMCPRegInfo el3_cp_reginfo[] = { REGINFO_SENTINEL }; -static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri) +static CPAccessResult ctr_el0_access(CPUARMState *env, const ARMCPRegInfo *ri, + bool isread) { /* Only accessible in EL0 if SCTLR.UCT is set (and only in AArch64, * but the AArch32 CTR has its own reginfo struct) @@ -4312,6 +4378,45 @@ void register_cp_regs_for_features(ARMCPU *cpu) }; define_one_arm_cp_reg(cpu, &rvbar); } + /* The behaviour of NSACR is sufficiently various that we don't + * try to describe it in a single reginfo: + * if EL3 is 64 bit, then trap to EL3 from S EL1, + * reads as constant 0xc00 from NS EL1 and NS EL2 + * if EL3 is 32 bit, then RW at EL3, RO at NS EL1 and NS EL2 + * if v7 without EL3, register doesn't exist + * if v8 without EL3, reads as constant 0xc00 from NS EL1 and NS EL2 + */ + if (arm_feature(env, ARM_FEATURE_EL3)) { + if (arm_feature(env, ARM_FEATURE_AARCH64)) { + ARMCPRegInfo nsacr = { + .name = "NSACR", .type = ARM_CP_CONST, + .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2, + .access = PL1_RW, .accessfn = nsacr_access, + .resetvalue = 0xc00 + }; + define_one_arm_cp_reg(cpu, &nsacr); + } else { + ARMCPRegInfo nsacr = { + .name = "NSACR", + .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2, + .access = PL3_RW | PL1_R, + .resetvalue = 0, + .fieldoffset = offsetof(CPUARMState, cp15.nsacr) + }; + define_one_arm_cp_reg(cpu, &nsacr); + } + } else { + if (arm_feature(env, ARM_FEATURE_V8)) { + ARMCPRegInfo nsacr = { + .name = "NSACR", .type = ARM_CP_CONST, + .cp = 15, .opc1 = 0, .crn = 1, .crm = 1, .opc2 = 2, + .access = PL1_R, + .resetvalue = 0xc00 + }; + define_one_arm_cp_reg(cpu, &nsacr); + } + } + if (arm_feature(env, ARM_FEATURE_MPU)) { if (arm_feature(env, ARM_FEATURE_V6)) { /* PMSAv6 not implemented */ diff --git a/target-arm/helper.h b/target-arm/helper.h index c2a85c722a..c98e9cea3d 100644 --- a/target-arm/helper.h +++ b/target-arm/helper.h @@ -62,7 +62,7 @@ DEF_HELPER_1(cpsr_read, i32, env) DEF_HELPER_3(v7m_msr, void, env, i32, i32) DEF_HELPER_2(v7m_mrs, i32, env, i32) -DEF_HELPER_3(access_check_cp_reg, void, env, ptr, i32) +DEF_HELPER_4(access_check_cp_reg, void, env, ptr, i32, i32) DEF_HELPER_3(set_cp_reg, void, env, ptr, i32) DEF_HELPER_2(get_cp_reg, i32, env, ptr) DEF_HELPER_3(set_cp_reg64, void, env, ptr, i64) diff --git a/target-arm/internals.h b/target-arm/internals.h index d226bbe857..70bec4a4d2 100644 --- a/target-arm/internals.h +++ b/target-arm/internals.h @@ -270,10 +270,10 @@ static inline uint32_t syn_aa64_smc(uint32_t imm16) return (EC_AA64_SMC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff); } -static inline uint32_t syn_aa32_svc(uint32_t imm16, bool is_thumb) +static inline uint32_t syn_aa32_svc(uint32_t imm16, bool is_16bit) { return (EC_AA32_SVC << ARM_EL_EC_SHIFT) | (imm16 & 0xffff) - | (is_thumb ? 0 : ARM_EL_IL); + | (is_16bit ? 0 : ARM_EL_IL); } static inline uint32_t syn_aa32_hvc(uint32_t imm16) @@ -291,10 +291,10 @@ static inline uint32_t syn_aa64_bkpt(uint32_t imm16) return (EC_AA64_BKPT << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff); } -static inline uint32_t syn_aa32_bkpt(uint32_t imm16, bool is_thumb) +static inline uint32_t syn_aa32_bkpt(uint32_t imm16, bool is_16bit) { return (EC_AA32_BKPT << ARM_EL_EC_SHIFT) | (imm16 & 0xffff) - | (is_thumb ? 0 : ARM_EL_IL); + | (is_16bit ? 0 : ARM_EL_IL); } static inline uint32_t syn_aa64_sysregtrap(int op0, int op1, int op2, @@ -308,48 +308,48 @@ static inline uint32_t syn_aa64_sysregtrap(int op0, int op1, int op2, static inline uint32_t syn_cp14_rt_trap(int cv, int cond, int opc1, int opc2, int crn, int crm, int rt, int isread, - bool is_thumb) + bool is_16bit) { return (EC_CP14RTTRAP << ARM_EL_EC_SHIFT) - | (is_thumb ? 0 : ARM_EL_IL) + | (is_16bit ? 0 : ARM_EL_IL) | (cv << 24) | (cond << 20) | (opc2 << 17) | (opc1 << 14) | (crn << 10) | (rt << 5) | (crm << 1) | isread; } static inline uint32_t syn_cp15_rt_trap(int cv, int cond, int opc1, int opc2, int crn, int crm, int rt, int isread, - bool is_thumb) + bool is_16bit) { return (EC_CP15RTTRAP << ARM_EL_EC_SHIFT) - | (is_thumb ? 0 : ARM_EL_IL) + | (is_16bit ? 0 : ARM_EL_IL) | (cv << 24) | (cond << 20) | (opc2 << 17) | (opc1 << 14) | (crn << 10) | (rt << 5) | (crm << 1) | isread; } static inline uint32_t syn_cp14_rrt_trap(int cv, int cond, int opc1, int crm, int rt, int rt2, int isread, - bool is_thumb) + bool is_16bit) { return (EC_CP14RRTTRAP << ARM_EL_EC_SHIFT) - | (is_thumb ? 0 : ARM_EL_IL) + | (is_16bit ? 0 : ARM_EL_IL) | (cv << 24) | (cond << 20) | (opc1 << 16) | (rt2 << 10) | (rt << 5) | (crm << 1) | isread; } static inline uint32_t syn_cp15_rrt_trap(int cv, int cond, int opc1, int crm, int rt, int rt2, int isread, - bool is_thumb) + bool is_16bit) { return (EC_CP15RRTTRAP << ARM_EL_EC_SHIFT) - | (is_thumb ? 0 : ARM_EL_IL) + | (is_16bit ? 0 : ARM_EL_IL) | (cv << 24) | (cond << 20) | (opc1 << 16) | (rt2 << 10) | (rt << 5) | (crm << 1) | isread; } -static inline uint32_t syn_fp_access_trap(int cv, int cond, bool is_thumb) +static inline uint32_t syn_fp_access_trap(int cv, int cond, bool is_16bit) { return (EC_ADVSIMDFPACCESSTRAP << ARM_EL_EC_SHIFT) - | (is_thumb ? 0 : ARM_EL_IL) + | (is_16bit ? 0 : ARM_EL_IL) | (cv << 24) | (cond << 20); } @@ -409,6 +409,9 @@ void hw_breakpoint_update(ARMCPU *cpu, int n); */ void hw_breakpoint_update_all(ARMCPU *cpu); +/* Callback function for checking if a watchpoint should trigger. */ +bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp); + /* Callback function for when a watchpoint or breakpoint triggers. */ void arm_debug_excp_handler(CPUState *cs); diff --git a/target-arm/op_helper.c b/target-arm/op_helper.c index a5ee65fe2f..bd48549826 100644 --- a/target-arm/op_helper.c +++ b/target-arm/op_helper.c @@ -457,7 +457,8 @@ void HELPER(set_user_reg)(CPUARMState *env, uint32_t regno, uint32_t val) } } -void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome) +void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome, + uint32_t isread) { const ARMCPRegInfo *ri = rip; int target_el; @@ -471,7 +472,7 @@ void HELPER(access_check_cp_reg)(CPUARMState *env, void *rip, uint32_t syndrome) return; } - switch (ri->accessfn(env, ri)) { + switch (ri->accessfn(env, ri, isread)) { case CP_ACCESS_OK: return; case CP_ACCESS_TRAP: @@ -975,6 +976,16 @@ void HELPER(check_breakpoints)(CPUARMState *env) } } +bool arm_debug_check_watchpoint(CPUState *cs, CPUWatchpoint *wp) +{ + /* Called by core code when a CPU watchpoint fires; need to check if this + * is also an architectural watchpoint match. + */ + ARMCPU *cpu = ARM_CPU(cs); + + return check_watchpoints(cpu); +} + void arm_debug_excp_handler(CPUState *cs) { /* Called by core code when a watchpoint or breakpoint fires; @@ -986,23 +997,20 @@ void arm_debug_excp_handler(CPUState *cs) if (wp_hit) { if (wp_hit->flags & BP_CPU) { + bool wnr = (wp_hit->flags & BP_WATCHPOINT_HIT_WRITE) != 0; + bool same_el = arm_debug_target_el(env) == arm_current_el(env); + cs->watchpoint_hit = NULL; - if (check_watchpoints(cpu)) { - bool wnr = (wp_hit->flags & BP_WATCHPOINT_HIT_WRITE) != 0; - bool same_el = arm_debug_target_el(env) == arm_current_el(env); - - if (extended_addresses_enabled(env)) { - env->exception.fsr = (1 << 9) | 0x22; - } else { - env->exception.fsr = 0x2; - } - env->exception.vaddress = wp_hit->hitaddr; - raise_exception(env, EXCP_DATA_ABORT, - syn_watchpoint(same_el, 0, wnr), - arm_debug_target_el(env)); + + if (extended_addresses_enabled(env)) { + env->exception.fsr = (1 << 9) | 0x22; } else { - cpu_resume_from_signal(cs, NULL); + env->exception.fsr = 0x2; } + env->exception.vaddress = wp_hit->hitaddr; + raise_exception(env, EXCP_DATA_ABORT, + syn_watchpoint(same_el, 0, wnr), + arm_debug_target_el(env)); } } else { uint64_t pc = is_a64(env) ? env->pc : env->regs[15]; diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c index d780e09900..7f65aeab64 100644 --- a/target-arm/translate-a64.c +++ b/target-arm/translate-a64.c @@ -1367,16 +1367,18 @@ static void handle_sys(DisasContext *s, uint32_t insn, bool isread, * runtime; this may result in an exception. */ TCGv_ptr tmpptr; - TCGv_i32 tcg_syn; + TCGv_i32 tcg_syn, tcg_isread; uint32_t syndrome; gen_a64_set_pc_im(s->pc - 4); tmpptr = tcg_const_ptr(ri); syndrome = syn_aa64_sysregtrap(op0, op1, op2, crn, crm, rt, isread); tcg_syn = tcg_const_i32(syndrome); - gen_helper_access_check_cp_reg(cpu_env, tmpptr, tcg_syn); + tcg_isread = tcg_const_i32(isread); + gen_helper_access_check_cp_reg(cpu_env, tmpptr, tcg_syn, tcg_isread); tcg_temp_free_ptr(tmpptr); tcg_temp_free_i32(tcg_syn); + tcg_temp_free_i32(tcg_isread); } /* Handle special cases first */ diff --git a/target-arm/translate.c b/target-arm/translate.c index f6a38bcc09..cf3dc33774 100644 --- a/target-arm/translate.c +++ b/target-arm/translate.c @@ -3077,7 +3077,7 @@ static int disas_vfp_insn(DisasContext *s, uint32_t insn) */ if (s->fp_excp_el) { gen_exception_insn(s, 4, EXCP_UDEF, - syn_fp_access_trap(1, 0xe, s->thumb), s->fp_excp_el); + syn_fp_access_trap(1, 0xe, false), s->fp_excp_el); return 0; } @@ -4399,7 +4399,7 @@ static int disas_neon_ls_insn(DisasContext *s, uint32_t insn) */ if (s->fp_excp_el) { gen_exception_insn(s, 4, EXCP_UDEF, - syn_fp_access_trap(1, 0xe, s->thumb), s->fp_excp_el); + syn_fp_access_trap(1, 0xe, false), s->fp_excp_el); return 0; } @@ -5137,7 +5137,7 @@ static int disas_neon_data_insn(DisasContext *s, uint32_t insn) */ if (s->fp_excp_el) { gen_exception_insn(s, 4, EXCP_UDEF, - syn_fp_access_trap(1, 0xe, s->thumb), s->fp_excp_el); + syn_fp_access_trap(1, 0xe, false), s->fp_excp_el); return 0; } @@ -7169,7 +7169,7 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn) * call in order to handle c15_cpar. */ TCGv_ptr tmpptr; - TCGv_i32 tcg_syn; + TCGv_i32 tcg_syn, tcg_isread; uint32_t syndrome; /* Note that since we are an implementation which takes an @@ -7184,19 +7184,19 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn) case 14: if (is64) { syndrome = syn_cp14_rrt_trap(1, 0xe, opc1, crm, rt, rt2, - isread, s->thumb); + isread, false); } else { syndrome = syn_cp14_rt_trap(1, 0xe, opc1, opc2, crn, crm, - rt, isread, s->thumb); + rt, isread, false); } break; case 15: if (is64) { syndrome = syn_cp15_rrt_trap(1, 0xe, opc1, crm, rt, rt2, - isread, s->thumb); + isread, false); } else { syndrome = syn_cp15_rt_trap(1, 0xe, opc1, opc2, crn, crm, - rt, isread, s->thumb); + rt, isread, false); } break; default: @@ -7214,9 +7214,12 @@ static int disas_coproc_insn(DisasContext *s, uint32_t insn) gen_set_pc_im(s, s->pc - 4); tmpptr = tcg_const_ptr(ri); tcg_syn = tcg_const_i32(syndrome); - gen_helper_access_check_cp_reg(cpu_env, tmpptr, tcg_syn); + tcg_isread = tcg_const_i32(isread); + gen_helper_access_check_cp_reg(cpu_env, tmpptr, tcg_syn, + tcg_isread); tcg_temp_free_ptr(tmpptr); tcg_temp_free_i32(tcg_syn); + tcg_temp_free_i32(tcg_isread); } /* Handle special cases first */ |