diff --git a/xen/arch/arm/traps.c b/xen/arch/arm/traps.c index 1e130fbbcb..c5c5ff59fb 100644 --- a/xen/arch/arm/traps.c +++ b/xen/arch/arm/traps.c @@ -667,7 +667,6 @@ static void inject_dabt_exception(struct cpu_user_regs *regs, #endif } -#if 0 /* Inject a virtual Abort/SError into the guest. */ static void inject_vabt_exception(struct cpu_user_regs *regs) { @@ -698,7 +697,59 @@ static void inject_vabt_exception(struct cpu_user_regs *regs) current->arch.hcr_el2 |= HCR_VA; WRITE_SYSREG(current->arch.hcr_el2, HCR_EL2); } -#endif + +/* + * SError exception handler. We only handle the following 3 types of SErrors: + * 1) Guest-generated SError and had been delivered in EL1 and then + * been forwarded to EL2. + * 2) Guest-generated SError but hadn't been delivered in EL1 before + * trapping to EL2. This SError would be caught in EL2 as soon as + * we just unmasked the PSTATE.A bit. + * 3) Hypervisor generated native SError, that would be a bug. + * + * A true parameter "guest" means that the SError is type#1 or type#2. + */ +static void __do_trap_serror(struct cpu_user_regs *regs, bool guest) +{ + /* + * Only "DIVERSE" option needs to distinguish the guest-generated SErrors + * from hypervisor SErrors. + */ + if ( serrors_op == SERRORS_DIVERSE ) + { + /* Forward the type#1 and type#2 SErrors to guests. */ + if ( guest ) + return inject_vabt_exception(regs); + + /* Type#3 SErrors will panic the whole system */ + goto crash_system; + } + + /* + * The "FORWARD" option will forward all SErrors to the guests, except + * idle domain generated SErrors. + */ + if ( serrors_op == SERRORS_FORWARD ) + { + /* + * Because the idle domain doesn't have the ability to handle the + * SErrors, we have to crash the whole system while we get a SError + * generated by idle domain. + */ + if ( is_idle_vcpu(current) ) + goto crash_system; + + return inject_vabt_exception(regs); + } + +crash_system: + /* Three possibilities to crash the whole system: + * 1) "DIVERSE" option with Hypervisor generated SErrors. + * 2) "FORWARD" option with Idle Domain generated SErrors. + * 3) "PANIC" option with all SErrors. + */ + do_unexpected_trap("SError", regs); +} struct reg_ctxt { /* Guest-side state */ @@ -2917,6 +2968,20 @@ asmlinkage void do_trap_guest_error(struct cpu_user_regs *regs) domain_crash_synchronous(); } +asmlinkage void do_trap_hyp_serror(struct cpu_user_regs *regs) +{ + enter_hypervisor_head(regs); + + __do_trap_serror(regs, VABORT_GEN_BY_GUEST(regs)); +} + +asmlinkage void do_trap_guest_serror(struct cpu_user_regs *regs) +{ + enter_hypervisor_head(regs); + + __do_trap_serror(regs, true); +} + asmlinkage void do_trap_irq(struct cpu_user_regs *regs) { enter_hypervisor_head(regs); diff --git a/xen/include/asm-arm/processor.h b/xen/include/asm-arm/processor.h index 163c39c516..81227aa477 100644 --- a/xen/include/asm-arm/processor.h +++ b/xen/include/asm-arm/processor.h @@ -709,6 +709,10 @@ int call_smc(register_t function_id, register_t arg0, register_t arg1, void do_trap_guest_error(struct cpu_user_regs *regs); +void do_trap_hyp_serror(struct cpu_user_regs *regs); + +void do_trap_guest_serror(struct cpu_user_regs *regs); + register_t get_default_hcr_flags(void); /* Functions for pending virtual abort checking window. */