}
 }
 
-int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
+/*
+ * Return true when we were able to fixup the guest exit and should return to
+ * the guest, false when we should restore the host state and return to the
+ * main run loop.
+ */
+static bool __hyp_text fixup_guest_exit(struct kvm_vcpu *vcpu, u64 *exit_code)
 {
-       struct kvm_cpu_context *host_ctxt;
-       struct kvm_cpu_context *guest_ctxt;
-       bool fp_enabled;
-       u64 exit_code;
-
-       vcpu = kern_hyp_va(vcpu);
-
-       host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
-       host_ctxt->__hyp_running_vcpu = vcpu;
-       guest_ctxt = &vcpu->arch.ctxt;
-
-       __sysreg_save_host_state(host_ctxt);
-
-       __activate_traps(vcpu);
-       __activate_vm(vcpu);
-
-       __vgic_restore_state(vcpu);
-       __timer_enable_traps(vcpu);
-
-       /*
-        * We must restore the 32-bit state before the sysregs, thanks
-        * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
-        */
-       __sysreg32_restore_state(vcpu);
-       __sysreg_restore_guest_state(guest_ctxt);
-       __debug_switch_to_guest(vcpu);
-
-       /* Jump in the fire! */
-again:
-       exit_code = __guest_enter(vcpu, host_ctxt);
-       /* And we're baaack! */
-
-       if (ARM_EXCEPTION_CODE(exit_code) != ARM_EXCEPTION_IRQ)
+       if (ARM_EXCEPTION_CODE(*exit_code) != ARM_EXCEPTION_IRQ)
                vcpu->arch.fault.esr_el2 = read_sysreg_el2(esr);
+
        /*
         * We're using the raw exception code in order to only process
         * the trap if no SError is pending. We will come back to the
         * same PC once the SError has been injected, and replay the
         * trapping instruction.
         */
-       if (exit_code == ARM_EXCEPTION_TRAP && !__populate_fault_info(vcpu))
-               goto again;
+       if (*exit_code == ARM_EXCEPTION_TRAP && !__populate_fault_info(vcpu))
+               return true;
 
        if (static_branch_unlikely(&vgic_v2_cpuif_trap) &&
-           exit_code == ARM_EXCEPTION_TRAP) {
+           *exit_code == ARM_EXCEPTION_TRAP) {
                bool valid;
 
                valid = kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_DABT_LOW &&
 
                        if (ret == 1) {
                                if (__skip_instr(vcpu))
-                                       goto again;
+                                       return true;
                                else
-                                       exit_code = ARM_EXCEPTION_TRAP;
+                                       *exit_code = ARM_EXCEPTION_TRAP;
                        }
 
                        if (ret == -1) {
                                 */
                                if (!__skip_instr(vcpu))
                                        *vcpu_cpsr(vcpu) &= ~DBG_SPSR_SS;
-                               exit_code = ARM_EXCEPTION_EL1_SERROR;
+                               *exit_code = ARM_EXCEPTION_EL1_SERROR;
                        }
-
-                       /* 0 falls through to be handler out of EL2 */
                }
        }
 
        if (static_branch_unlikely(&vgic_v3_cpuif_trap) &&
-           exit_code == ARM_EXCEPTION_TRAP &&
+           *exit_code == ARM_EXCEPTION_TRAP &&
            (kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_SYS64 ||
             kvm_vcpu_trap_get_class(vcpu) == ESR_ELx_EC_CP15_32)) {
                int ret = __vgic_v3_perform_cpuif_access(vcpu);
 
                if (ret == 1) {
                        if (__skip_instr(vcpu))
-                               goto again;
+                               return true;
                        else
-                               exit_code = ARM_EXCEPTION_TRAP;
+                               *exit_code = ARM_EXCEPTION_TRAP;
                }
-
-               /* 0 falls through to be handled out of EL2 */
        }
 
+       /* Return to the host kernel and handle the exit */
+       return false;
+}
+
+int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
+{
+       struct kvm_cpu_context *host_ctxt;
+       struct kvm_cpu_context *guest_ctxt;
+       bool fp_enabled;
+       u64 exit_code;
+
+       vcpu = kern_hyp_va(vcpu);
+
+       host_ctxt = kern_hyp_va(vcpu->arch.host_cpu_context);
+       host_ctxt->__hyp_running_vcpu = vcpu;
+       guest_ctxt = &vcpu->arch.ctxt;
+
+       __sysreg_save_host_state(host_ctxt);
+
+       __activate_traps(vcpu);
+       __activate_vm(vcpu);
+
+       __vgic_restore_state(vcpu);
+       __timer_enable_traps(vcpu);
+
+       /*
+        * We must restore the 32-bit state before the sysregs, thanks
+        * to erratum #852523 (Cortex-A57) or #853709 (Cortex-A72).
+        */
+       __sysreg32_restore_state(vcpu);
+       __sysreg_restore_guest_state(guest_ctxt);
+       __debug_switch_to_guest(vcpu);
+
+       do {
+               /* Jump in the fire! */
+               exit_code = __guest_enter(vcpu, host_ctxt);
+
+               /* And we're baaack! */
+       } while (fixup_guest_exit(vcpu, &exit_code));
+
        if (cpus_have_const_cap(ARM64_HARDEN_BP_POST_GUEST_EXIT)) {
                u32 midr = read_cpuid_id();