On 1 September 2014 13:55, Ard Biesheuvel <ard.biesheu...@linaro.org> wrote: > From: Rob Herring <rob.herr...@linaro.org> > > Add the infrastructure to handle and emulate hvc and smc exceptions. > This will enable emulation of things such as PSCI calls. This commit > does not change the behavior and will exit with unknown exception. > > Signed-off-by: Rob Herring <rob.herr...@linaro.org> > Signed-off-by: Ard Biesheuvel <ard.biesheu...@linaro.org> > --- > target-arm/cpu-qom.h | 3 +++ > target-arm/cpu.h | 2 ++ > target-arm/helper-a64.c | 16 ++++++++++++++++ > target-arm/helper.c | 32 ++++++++++++++++++++++++++++++++ > target-arm/internals.h | 20 ++++++++++++++++++++ > target-arm/translate-a64.c | 26 +++++++++++++++++--------- > target-arm/translate.c | 24 +++++++++++++++++------- > 7 files changed, 107 insertions(+), 16 deletions(-) > > diff --git a/target-arm/cpu-qom.h b/target-arm/cpu-qom.h > index eae0a7b9c908..104cc67e82d2 100644 > --- a/target-arm/cpu-qom.h > +++ b/target-arm/cpu-qom.h > @@ -192,6 +192,9 @@ extern const struct VMStateDescription vmstate_arm_cpu; > void register_cp_regs_for_features(ARMCPU *cpu); > void init_cpreg_list(ARMCPU *cpu); > > +bool arm_cpu_do_hvc(CPUState *cs); > +bool arm_cpu_do_smc(CPUState *cs); > + > void arm_cpu_do_interrupt(CPUState *cpu); > void arm_v7m_cpu_do_interrupt(CPUState *cpu); > > diff --git a/target-arm/cpu.h b/target-arm/cpu.h > index 51bedc826299..d235929f4c12 100644 > --- a/target-arm/cpu.h > +++ b/target-arm/cpu.h > @@ -51,6 +51,8 @@ > #define EXCP_EXCEPTION_EXIT 8 /* Return from v7M exception. */ > #define EXCP_KERNEL_TRAP 9 /* Jumped to kernel code page. */ > #define EXCP_STREX 10 > +#define EXCP_HVC 11 > +#define EXCP_SMC 12 > > #define ARMV7M_EXCP_RESET 1 > #define ARMV7M_EXCP_NMI 2 > diff --git a/target-arm/helper-a64.c b/target-arm/helper-a64.c > index 89b913ee9396..1f8072ab141b 100644 > --- a/target-arm/helper-a64.c > +++ b/target-arm/helper-a64.c > @@ -485,6 +485,22 @@ void aarch64_cpu_do_interrupt(CPUState *cs) > case EXCP_FIQ: > addr += 0x100; > break; > + case EXCP_HVC: > + if (arm_cpu_do_hvc(cs)) { > + return; > + } > + /* Treat as unallocated encoding */ > + qemu_log_mask(LOG_GUEST_ERROR, "HVC not implemented on this CPU\n"); > + env->exception.syndrome = syn_uncategorized(); > + break; > + case EXCP_SMC: > + if (arm_cpu_do_smc(cs)) { > + return; > + } > + /* Treat as unallocated encoding */ > + qemu_log_mask(LOG_GUEST_ERROR, "SMC not implemented on this CPU\n"); > + env->exception.syndrome = syn_uncategorized(); > + break; > default: > cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index); > } > diff --git a/target-arm/helper.c b/target-arm/helper.c > index 2b95f33872cb..51a01a815b7b 100644 > --- a/target-arm/helper.c > +++ b/target-arm/helper.c > @@ -3497,6 +3497,16 @@ void arm_v7m_cpu_do_interrupt(CPUState *cs) > env->thumb = addr & 1; > } > > +bool arm_cpu_do_hvc(CPUState *cs) > +{ > + return false; > +} > + > +bool arm_cpu_do_smc(CPUState *cs) > +{ > + return false; > +} > + > /* Handle a CPU exception. */ > void arm_cpu_do_interrupt(CPUState *cs) > { > @@ -3599,6 +3609,28 @@ void arm_cpu_do_interrupt(CPUState *cs) > mask = CPSR_A | CPSR_I | CPSR_F; > offset = 4; > break; > + case EXCP_HVC: > + if (arm_cpu_do_hvc(cs)) { > + return; > + } > + qemu_log_mask(LOG_GUEST_ERROR, "HVC not implemented on this CPU\n"); > + goto hvc_unallocated; > + case EXCP_SMC: > + if (arm_cpu_do_smc(cs)) { > + return; > + } > + qemu_log_mask(LOG_GUEST_ERROR, "SMC not implemented on this CPU\n"); > + hvc_unallocated: > + /* Treat as unallocated encoding */ > + new_mode = ARM_CPU_MODE_UND; > + addr = 0x04; > + mask = CPSR_I; > + if (env->thumb) { > + offset = 2; > + } else { > + offset = 4; > + } > + break;
Replying to self: I guess I forgot to set the correct ESR value here, would this env->cp15.esr_el[1] = syn_uncategorized(); be sufficient? > default: > cpu_abort(cs, "Unhandled exception 0x%x\n", cs->exception_index); > return; /* Never happens. Keep compiler happy. */ > diff --git a/target-arm/internals.h b/target-arm/internals.h > index 53c2e3cf3e7e..caab98e6b508 100644 > --- a/target-arm/internals.h > +++ b/target-arm/internals.h > @@ -210,6 +210,26 @@ static inline uint32_t syn_aa32_svc(uint32_t imm16, bool > is_thumb) > | (is_thumb ? 0 : ARM_EL_IL); > } > > +static inline uint32_t syn_aa64_hvc(uint32_t imm16) > +{ > + return (EC_AA64_HVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff); > +} > + > +static inline uint32_t syn_aa32_hvc(uint32_t imm16) > +{ > + return (EC_AA32_HVC << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff); > +} > + > +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_smc(void) > +{ > + return (EC_AA32_SMC << ARM_EL_EC_SHIFT) | ARM_EL_IL; > +} > + > static inline uint32_t syn_aa64_bkpt(uint32_t imm16) > { > return (EC_AA64_BKPT << ARM_EL_EC_SHIFT) | ARM_EL_IL | (imm16 & 0xffff); > diff --git a/target-arm/translate-a64.c b/target-arm/translate-a64.c > index 8e66b6c97282..65e35e3aaec0 100644 > --- a/target-arm/translate-a64.c > +++ b/target-arm/translate-a64.c > @@ -1473,20 +1473,28 @@ static void disas_exc(DisasContext *s, uint32_t insn) > > switch (opc) { > case 0: > - /* SVC, HVC, SMC; since we don't support the Virtualization > - * or TrustZone extensions these all UNDEF except SVC. > - */ > - if (op2_ll != 1) { > - unallocated_encoding(s); > - break; > - } > /* For SVC, HVC and SMC we advance the single-step state > * machine before taking the exception. This is architecturally > * mandated, to ensure that single-stepping a system call > * instruction works properly. > */ > - gen_ss_advance(s); > - gen_exception_insn(s, 0, EXCP_SWI, syn_aa64_svc(imm16)); > + switch (op2_ll) { > + case 1: > + gen_ss_advance(s); > + gen_exception_insn(s, 0, EXCP_SWI, syn_aa64_svc(imm16)); > + break; > + case 2: > + gen_ss_advance(s); > + gen_exception_insn(s, 0, EXCP_HVC, syn_aa64_hvc(imm16)); > + break; > + case 3: > + gen_ss_advance(s); > + gen_exception_insn(s, 0, EXCP_SMC, syn_aa64_smc(imm16)); > + break; > + default: > + unallocated_encoding(s); > + break; > + } > break; > case 1: > if (op2_ll != 0) { > diff --git a/target-arm/translate.c b/target-arm/translate.c > index 2c0b1deaea81..a4545ed2bc40 100644 > --- a/target-arm/translate.c > +++ b/target-arm/translate.c > @@ -7871,9 +7871,14 @@ static void disas_arm_insn(CPUARMState * env, > DisasContext *s) > case 7: > { > int imm16 = extract32(insn, 0, 4) | (extract32(insn, 8, 12) << > 4); > - /* SMC instruction (op1 == 3) > - and undefined instructions (op1 == 0 || op1 == 2) > - will trap */ > + /* HVC and SMC instructions */ > + if (op1 == 2) { > + gen_exception_insn(s, 0, EXCP_HVC, syn_aa32_hvc(imm16)); > + break; > + } else if (op1 == 3) { > + gen_exception_insn(s, 0, EXCP_SMC, syn_aa32_smc()); > + break; > + } > if (op1 != 1) { > goto illegal_op; > } > @@ -9709,10 +9714,15 @@ static int disas_thumb2_insn(CPUARMState *env, > DisasContext *s, uint16_t insn_hw > goto illegal_op; > > if (insn & (1 << 26)) { > - /* Secure monitor call (v6Z) */ > - qemu_log_mask(LOG_UNIMP, > - "arm: unimplemented secure monitor > call\n"); > - goto illegal_op; /* not implemented. */ > + if (!(insn & (1 << 20))) { > + /* Hypervisor call (v7) */ > + uint32_t imm16 = extract32(insn, 16, 4) << 12; > + imm16 |= extract32(insn, 0, 12); > + gen_exception_insn(s, 0, EXCP_HVC, > syn_aa32_hvc(imm16)); > + } else { > + /* Secure monitor call (v6+) */ > + gen_exception_insn(s, 0, EXCP_SMC, syn_aa32_smc()); > + } > } else { > op = (insn >> 20) & 7; > switch (op) { > -- > 1.8.3.2 >