linux/virt/kvm/arm/arm.c
/**
 * kvm_arch_vcpu_ioctl_run - the main VCPU run function to execute guest code
 * @vcpu:	The VCPU pointer
 * @run:	The kvm_run structure pointer used for userspace state exchange
 *
 * This function is called through the VCPU_RUN ioctl called from user space. It
 * will execute VM code in a loop until the time slice for the process is used
 * or some emulation is needed from user space in which case the function will
 * return with return value 0 and with the kvm_run structure filled in with the
 * required data for the requested emulation.
 */
the main VCPU run function to execute guest code
@vcpu:       The VCPU pointer
@run:        The kvm_run structure pointer used for userspace state exchange

This function is called through the VCPU_RUN ioctl called from user space. It
will execute VM code in a loop until the time slice for the process is used
or some emulation is needed from user space in which case the function will
return with return value 0 and with the kvm_run structure filled in with the
required data for the requested emulation.
the main VCPU run function to execute guest code @vcpu : The VCPU pointer @run : The kvm_run structure pointer used for userspace state exchange This function is called through the VCPU_RUN ioctl called from user space . It will execute VM code in a loop until the time slice for the process is used or some emulation is needed from user space in which case the function will return with return value 0 and with the kvm_run structure filled in with the required data for the requested emulation .
int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run)
{
	int ret;
	if (unlikely(!kvm_vcpu_initialized(vcpu)))
		return -ENOEXEC;
	ret = kvm_vcpu_first_run_init(vcpu);
	if (ret)
		return ret;
	if (run->exit_reason == KVM_EXIT_MMIO) {
		ret = kvm_handle_mmio_return(vcpu, vcpu->run);
		if (ret)
			return ret;
		if (kvm_arm_handle_step_debug(vcpu, vcpu->run))
			return 0;
	}
	if (run->immediate_exit)
		return -EINTR;
	vcpu_load(vcpu);
	kvm_sigset_activate(vcpu);
	ret = 1;
	run->exit_reason = KVM_EXIT_UNKNOWN;
	while (ret > 0) {
		cond_resched();
		update_vttbr(vcpu->kvm);
		check_vcpu_requests(vcpu);
		preempt_disable();
		kvm_pmu_flush_hwstate(vcpu);
		local_irq_disable();
		kvm_vgic_flush_hwstate(vcpu);
		if (signal_pending(current)) {
			ret = -EINTR;
			run->exit_reason = KVM_EXIT_INTR;
		}
		if (static_branch_unlikely(&userspace_irqchip_in_use)) {
			if (kvm_timer_should_notify_user(vcpu) ||
			    kvm_pmu_should_notify_user(vcpu)) {
				ret = -EINTR;
				run->exit_reason = KVM_EXIT_INTR;
			}
		}
		smp_store_mb(vcpu->mode, IN_GUEST_MODE);
		if (ret <= 0 || need_new_vmid_gen(vcpu->kvm) ||
		    kvm_request_pending(vcpu)) {
			vcpu->mode = OUTSIDE_GUEST_MODE;
			isb(); 
			kvm_pmu_sync_hwstate(vcpu);
			if (static_branch_unlikely(&userspace_irqchip_in_use))
				kvm_timer_sync_hwstate(vcpu);
			kvm_vgic_sync_hwstate(vcpu);
			local_irq_enable();
			preempt_enable();
			continue;
		}
		kvm_arm_setup_debug(vcpu);
		trace_kvm_entry(*vcpu_pc(vcpu));
		guest_enter_irqoff();
		if (has_vhe()) {
			kvm_arm_vhe_guest_enter();
			ret = kvm_vcpu_run_vhe(vcpu);
			kvm_arm_vhe_guest_exit();
		} else {
			ret = kvm_call_hyp(__kvm_vcpu_run_nvhe, vcpu);
		}
		vcpu->mode = OUTSIDE_GUEST_MODE;
		vcpu->stat.exits++;
		kvm_arm_clear_debug(vcpu);
		kvm_pmu_sync_hwstate(vcpu);
		kvm_vgic_sync_hwstate(vcpu);
		if (static_branch_unlikely(&userspace_irqchip_in_use))
			kvm_timer_sync_hwstate(vcpu);
		kvm_arch_vcpu_ctxsync_fp(vcpu);
		local_irq_enable();
		guest_exit();
		trace_kvm_exit(ret, kvm_vcpu_trap_get_class(vcpu), *vcpu_pc(vcpu));
		handle_exit_early(vcpu, run, ret);
		preempt_enable();
		ret = handle_exit(vcpu, run, ret);
	}
	if (unlikely(!irqchip_in_kernel(vcpu->kvm))) {
		kvm_timer_update_run(vcpu);
		kvm_pmu_update_run(vcpu);
	}
	kvm_sigset_deactivate(vcpu);
	vcpu_put(vcpu);
	return ret;
}
int kvm_arch_vcpu_ioctl_run ( struct kvm_vcpu * vcpu , struct kvm_run * run ) { int ret ; if ( unlikely ( ! kvm_vcpu_initialized ( vcpu ) ) ) return - ENOEXEC ; ret = kvm_vcpu_first_run_init ( vcpu ) ; if ( ret ) return ret ; if ( run -> exit_reason == KVM_EXIT_MMIO ) { ret = kvm_handle_mmio_return ( vcpu , vcpu -> run ) ; if ( ret ) return ret ; if ( kvm_arm_handle_step_debug ( vcpu , vcpu -> run ) ) return 0 ; } if ( run -> immediate_exit ) return - EINTR ; vcpu_load ( vcpu ) ; kvm_sigset_activate ( vcpu ) ; ret = 1 ; run -> exit_reason = KVM_EXIT_UNKNOWN ; while ( ret > 0 ) { cond_resched ( ) ; update_vttbr ( vcpu -> kvm ) ; check_vcpu_requests ( vcpu ) ; preempt_disable ( ) ; kvm_pmu_flush_hwstate ( vcpu ) ; local_irq_disable ( ) ; kvm_vgic_flush_hwstate ( vcpu ) ; if ( signal_pending ( current ) ) { ret = - EINTR ; run -> exit_reason = KVM_EXIT_INTR ; } if ( static_branch_unlikely ( & userspace_irqchip_in_use ) ) { if ( kvm_timer_should_notify_user ( vcpu ) || kvm_pmu_should_notify_user ( vcpu ) ) { ret = - EINTR ; run -> exit_reason = KVM_EXIT_INTR ; } } smp_store_mb ( vcpu -> mode , IN_GUEST_MODE ) ; if ( ret <= 0 || need_new_vmid_gen ( vcpu -> kvm ) || kvm_request_pending ( vcpu ) ) { vcpu -> mode = OUTSIDE_GUEST_MODE ; isb ( ) ; kvm_pmu_sync_hwstate ( vcpu ) ; if ( static_branch_unlikely ( & userspace_irqchip_in_use ) ) kvm_timer_sync_hwstate ( vcpu ) ; kvm_vgic_sync_hwstate ( vcpu ) ; local_irq_enable ( ) ; preempt_enable ( ) ; continue ; } kvm_arm_setup_debug ( vcpu ) ; trace_kvm_entry ( * vcpu_pc ( vcpu ) ) ; guest_enter_irqoff ( ) ; if ( has_vhe ( ) ) { kvm_arm_vhe_guest_enter ( ) ; ret = kvm_vcpu_run_vhe ( vcpu ) ; kvm_arm_vhe_guest_exit ( ) ; } else { ret = kvm_call_hyp ( __kvm_vcpu_run_nvhe , vcpu ) ; } vcpu -> mode = OUTSIDE_GUEST_MODE ; vcpu -> stat . exits ++ ; kvm_arm_clear_debug ( vcpu ) ; kvm_pmu_sync_hwstate ( vcpu ) ; kvm_vgic_sync_hwstate ( vcpu ) ; if ( static_branch_unlikely ( & userspace_irqchip_in_use ) ) kvm_timer_sync_hwstate ( vcpu ) ; kvm_arch_vcpu_ctxsync_fp ( vcpu ) ; local_irq_enable ( ) ; guest_exit ( ) ; trace_kvm_exit ( ret , kvm_vcpu_trap_get_class ( vcpu ) , * vcpu_pc ( vcpu ) ) ; handle_exit_early ( vcpu , run , ret ) ; preempt_enable ( ) ; ret = handle_exit ( vcpu , run , ret ) ; } if ( unlikely ( ! irqchip_in_kernel ( vcpu -> kvm ) ) ) { kvm_timer_update_run ( vcpu ) ; kvm_pmu_update_run ( vcpu ) ; } kvm_sigset_deactivate ( vcpu ) ; vcpu_put ( vcpu ) ; return ret ; }
kvm_arch_vcpu_ioctl_run - the main VCPU run function to execute guest code
 @vcpu:       The VCPU pointer
 @run:        The kvm_run structure pointer used for userspace state exchange
kvm_arch_vcpu_ioctl_run - the main VCPU run function to execute guest code @vcpu : The VCPU pointer @run : The kvm_run structure pointer used for userspace state exchange
/*
		 * Check conditions before entering the guest
		 */ /*
		 * Preparing the interrupts to be injected also
		 * involves poking the GIC, which must be done in a
		 * non-preemptible context.
		 */ /*
		 * Exit if we have a signal pending so that we can deliver the
		 * signal to user space.
		 */ /*
		 * If we're using a userspace irqchip, then check if we need
		 * to tell a userspace irqchip about timer or PMU level
		 * changes and if so, exit to userspace (the actual level
		 * state gets updated in kvm_timer_update_run and
		 * kvm_pmu_update_run below).
		 */ /*
		 * Ensure we set mode to IN_GUEST_MODE after we disable
		 * interrupts and before the final VCPU requests check.
		 * See the comment in kvm_vcpu_exiting_guest_mode() and
		 * Documentation/virtual/kvm/vcpu-requests.rst
		 */ /* Ensure work in x_flush_hwstate is committed */ /**************************************************************
		 * Enter the guest
		 */ /*
		 * Back from guest
		 *************************************************************/ /*
		 * We must sync the PMU state before the vgic state so
		 * that the vgic can properly sample the updated state of the
		 * interrupt line.
		 */ /*
		 * Sync the vgic state before syncing the timer state because
		 * the timer code needs to know if the virtual timer
		 * interrupts are active.
		 */ /*
		 * Sync the timer hardware state before enabling interrupts as
		 * we don't want vtimer interrupts to race with syncing the
		 * timer virtual interrupt state.
		 */ /*
		 * We may have taken a host interrupt in HYP mode (ie
		 * while executing the guest). This interrupt is still
		 * pending, as we haven't serviced it yet!
		 *
		 * We're now back in SVC mode, with interrupts
		 * disabled.  Enabling the interrupts now will have
		 * the effect of taking the interrupt again, in SVC
		 * mode this time.
		 */ /*
		 * We do local_irq_enable() before calling guest_exit() so
		 * that if a timer interrupt hits while running the guest we
		 * account that tick as being spent in the guest.  We enable
		 * preemption after calling guest_exit() so that if we get
		 * preempted we make sure ticks after that is not counted as
		 * guest time.
		 */ /* Exit types that need handling before we can be preempted */ /* Tell userspace about in-kernel device output levels */