#define ARM_EXCEPTION_IRQ        0
 #define ARM_EXCEPTION_EL1_SERROR  1
 #define ARM_EXCEPTION_TRAP       2
+#define ARM_EXCEPTION_IL         3
 /* The hyp-stub will return this for any kvm_call_hyp() call */
 #define ARM_EXCEPTION_HYP_GONE   HVC_STUB_ERR
 
 
 #define CurrentEL_EL1          (1 << 2)
 #define CurrentEL_EL2          (2 << 2)
 
+/* Additional SPSR bits not exposed in the UABI */
+#define PSR_IL_BIT             (1 << 20)
+
 /* AArch32-specific ptrace requests */
 #define COMPAT_PTRACE_GETREGS          12
 #define COMPAT_PTRACE_SETREGS          13
 
                 */
                run->exit_reason = KVM_EXIT_FAIL_ENTRY;
                return 0;
+       case ARM_EXCEPTION_IL:
+               /*
+                * We attempted an illegal exception return.  Guest state must
+                * have been corrupted somehow.  Give up.
+                */
+               run->exit_reason = KVM_EXIT_FAIL_ENTRY;
+               return -EINVAL;
        default:
                kvm_pr_unimpl("Unsupported exception type: %d",
                              exception_index);
 
        mov     x0, #ARM_EXCEPTION_EL1_SERROR
        b       __guest_exit
 
+el2_sync:
+       /* Check for illegal exception return, otherwise panic */
+       mrs     x0, spsr_el2
+
+       /* if this was something else, then panic! */
+       tst     x0, #PSR_IL_BIT
+       b.eq    __hyp_panic
+
+       /* Let's attempt a recovery from the illegal exception return */
+       get_vcpu_ptr    x1, x0
+       mov     x0, #ARM_EXCEPTION_IL
+       b       __guest_exit
+
+
 el2_error:
        ldp     x0, x1, [sp], #16
 
        invalid_vect    el2t_fiq_invalid        // FIQ EL2t
        invalid_vect    el2t_error_invalid      // Error EL2t
 
-       invalid_vect    el2h_sync_invalid       // Synchronous EL2h
+       valid_vect      el2_sync                // Synchronous EL2h
        invalid_vect    el2h_irq_invalid        // IRQ EL2h
        invalid_vect    el2h_fiq_invalid        // FIQ EL2h
        valid_vect      el2_error               // Error EL2h
 
 static void __hyp_text
 __sysreg_restore_el2_return_state(struct kvm_cpu_context *ctxt)
 {
+       u64 pstate = ctxt->gp_regs.regs.pstate;
+       u64 mode = pstate & PSR_AA32_MODE_MASK;
+
+       /*
+        * Safety check to ensure we're setting the CPU up to enter the guest
+        * in a less privileged mode.
+        *
+        * If we are attempting a return to EL2 or higher in AArch64 state,
+        * program SPSR_EL2 with M=EL2h and the IL bit set which ensures that
+        * we'll take an illegal exception state exception immediately after
+        * the ERET to the guest.  Attempts to return to AArch32 Hyp will
+        * result in an illegal exception return because EL2's execution state
+        * is determined by SCR_EL3.RW.
+        */
+       if (!(mode & PSR_MODE32_BIT) && mode >= PSR_MODE_EL2t)
+               pstate = PSR_MODE_EL2h | PSR_IL_BIT;
+
        write_sysreg_el2(ctxt->gp_regs.regs.pc,         elr);
-       write_sysreg_el2(ctxt->gp_regs.regs.pstate,     spsr);
+       write_sysreg_el2(pstate,                        spsr);
 
        if (cpus_have_const_cap(ARM64_HAS_RAS_EXTN))
                write_sysreg_s(ctxt->sys_regs[DISR_EL1], SYS_VDISR_EL2);