Commit ca3385a5 authored by Marc Zyngier's avatar Marc Zyngier
Browse files

Merge branch kvm-arm64/generic-entry into kvmarm-master/next



Switch KVM/arm64 to the generic entry code, courtesy of Oliver Upton

* kvm-arm64/generic-entry:
  KVM: arm64: Use generic KVM xfer to guest work function
  entry: KVM: Allow use of generic KVM entry w/o full generic support
  KVM: arm64: Record number of signal exits as a vCPU stat

Signed-off-by: default avatarMarc Zyngier <maz@kernel.org>
parents 78bc1170 6caa5812
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -575,6 +575,7 @@ struct kvm_vcpu_stat {
	u64 wfi_exit_stat;
	u64 mmio_exit_user;
	u64 mmio_exit_kernel;
	u64 signal_exits;
	u64 exits;
};

+1 −0
Original line number Diff line number Diff line
@@ -26,6 +26,7 @@ menuconfig KVM
	select HAVE_KVM_ARCH_TLB_FLUSH_ALL
	select KVM_MMIO
	select KVM_GENERIC_DIRTYLOG_READ_PROTECT
	select KVM_XFER_TO_GUEST_WORK
	select SRCU
	select KVM_VFIO
	select HAVE_KVM_EVENTFD
+44 −27
Original line number Diff line number Diff line
@@ -6,6 +6,7 @@

#include <linux/bug.h>
#include <linux/cpu_pm.h>
#include <linux/entry-kvm.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/kvm_host.h>
@@ -715,6 +716,45 @@ static bool vcpu_mode_is_bad_32bit(struct kvm_vcpu *vcpu)
		static_branch_unlikely(&arm64_mismatched_32bit_el0);
}

/**
 * kvm_vcpu_exit_request - returns true if the VCPU should *not* enter the guest
 * @vcpu:	The VCPU pointer
 * @ret:	Pointer to write optional return code
 *
 * Returns: true if the VCPU needs to return to a preemptible + interruptible
 *	    and skip guest entry.
 *
 * This function disambiguates between two different types of exits: exits to a
 * preemptible + interruptible kernel context and exits to userspace. For an
 * exit to userspace, this function will write the return code to ret and return
 * true. For an exit to preemptible + interruptible kernel context (i.e. check
 * for pending work and re-enter), return true without writing to ret.
 */
static bool kvm_vcpu_exit_request(struct kvm_vcpu *vcpu, int *ret)
{
	struct kvm_run *run = vcpu->run;

	/*
	 * 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).
	 */
	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;
			return true;
		}
	}

	return kvm_request_pending(vcpu) ||
			need_new_vmid_gen(&vcpu->arch.hw_mmu->vmid) ||
			xfer_to_guest_mode_work_pending();
}

/**
 * kvm_arch_vcpu_ioctl_run - the main VCPU run function to execute guest code
 * @vcpu:	The VCPU pointer
@@ -758,7 +798,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
		/*
		 * Check conditions before entering the guest
		 */
		cond_resched();
		ret = xfer_to_guest_mode_handle_work(vcpu);
		if (!ret)
			ret = 1;

		update_vmid(&vcpu->arch.hw_mmu->vmid);

@@ -777,30 +819,6 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)

		kvm_vgic_flush_hwstate(vcpu);

		/*
		 * Exit if we have a signal pending so that we can deliver the
		 * signal to user space.
		 */
		if (signal_pending(current)) {
			ret = -EINTR;
			run->exit_reason = KVM_EXIT_INTR;
		}

		/*
		 * 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).
		 */
		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;
			}
		}

		/*
		 * Ensure we set mode to IN_GUEST_MODE after we disable
		 * interrupts and before the final VCPU requests check.
@@ -809,8 +827,7 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu)
		 */
		smp_store_mb(vcpu->mode, IN_GUEST_MODE);

		if (ret <= 0 || need_new_vmid_gen(&vcpu->arch.hw_mmu->vmid) ||
		    kvm_request_pending(vcpu)) {
		if (ret <= 0 || kvm_vcpu_exit_request(vcpu, &ret)) {
			vcpu->mode = OUTSIDE_GUEST_MODE;
			isb(); /* Ensure work in x_flush_hwstate is committed */
			kvm_pmu_sync_hwstate(vcpu);
+1 −0
Original line number Diff line number Diff line
@@ -50,6 +50,7 @@ const struct _kvm_stats_desc kvm_vcpu_stats_desc[] = {
	STATS_DESC_COUNTER(VCPU, wfi_exit_stat),
	STATS_DESC_COUNTER(VCPU, mmio_exit_user),
	STATS_DESC_COUNTER(VCPU, mmio_exit_kernel),
	STATS_DESC_COUNTER(VCPU, signal_exits),
	STATS_DESC_COUNTER(VCPU, exits)
};
static_assert(ARRAY_SIZE(kvm_vcpu_stats_desc) ==
+5 −1
Original line number Diff line number Diff line
@@ -2,7 +2,11 @@
#ifndef __LINUX_ENTRYKVM_H
#define __LINUX_ENTRYKVM_H

#include <linux/entry-common.h>
#include <linux/static_call_types.h>
#include <linux/tracehook.h>
#include <linux/syscalls.h>
#include <linux/seccomp.h>
#include <linux/sched.h>
#include <linux/tick.h>

/* Transfer to guest mode work */