Commit a53071bd authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull KVM fixes from Paolo Bonzini:
 "x86 bug fixes"

* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm:
  KVM: X86: Narrow down the IPI fastpath to single target IPI
  KVM: LAPIC: Also cancel preemption timer when disarm LAPIC timer
  KVM: VMX: don't allow memory operands for inline asm that modifies SP
  KVM: LAPIC: Mark hrtimer for period or oneshot mode to expire in hard interrupt context
  KVM: SVM: Issue WBINVD after deactivating an SEV guest
  KVM: SVM: document KVM_MEM_ENCRYPT_OP, let userspace detect if SEV is available
  KVM: x86: remove bogus user-triggerable WARN_ON
parents 23cb8490 e1be9ac8
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -53,6 +53,29 @@ key management interface to perform common hypervisor activities such as
encrypting bootstrap code, snapshot, migrating and debugging the guest. For more
information, see the SEV Key Management spec [api-spec]_

The main ioctl to access SEV is KVM_MEM_ENCRYPT_OP.  If the argument
to KVM_MEM_ENCRYPT_OP is NULL, the ioctl returns 0 if SEV is enabled
and ``ENOTTY` if it is disabled (on some older versions of Linux,
the ioctl runs normally even with a NULL argument, and therefore will
likely return ``EFAULT``).  If non-NULL, the argument to KVM_MEM_ENCRYPT_OP
must be a struct kvm_sev_cmd::

       struct kvm_sev_cmd {
               __u32 id;
               __u64 data;
               __u32 error;
               __u32 sev_fd;
       };


The ``id`` field contains the subcommand, and the ``data`` field points to
another struct containing arguments specific to command.  The ``sev_fd``
should point to a file descriptor that is opened on the ``/dev/sev``
device, if needed (see individual commands).

On output, ``error`` is zero on success, or an error code.  Error codes
are defined in ``<linux/psp-dev.h>`.

KVM implements the following commands to support common lifecycle events of SEV
guests, such as launching, running, snapshotting, migrating and decommissioning.

@@ -90,6 +113,8 @@ Returns: 0 on success, -negative on error

On success, the 'handle' field contains a new handle and on error, a negative value.

KVM_SEV_LAUNCH_START requires the ``sev_fd`` field to be valid.

For more details, see SEV spec Section 6.2.

3. KVM_SEV_LAUNCH_UPDATE_DATA
+7 −1
Original line number Diff line number Diff line
@@ -1445,6 +1445,8 @@ static void limit_periodic_timer_frequency(struct kvm_lapic *apic)
	}
}

static void cancel_hv_timer(struct kvm_lapic *apic);

static void apic_update_lvtt(struct kvm_lapic *apic)
{
	u32 timer_mode = kvm_lapic_get_reg(apic, APIC_LVTT) &
@@ -1454,6 +1456,10 @@ static void apic_update_lvtt(struct kvm_lapic *apic)
		if (apic_lvtt_tscdeadline(apic) != (timer_mode ==
				APIC_LVT_TIMER_TSCDEADLINE)) {
			hrtimer_cancel(&apic->lapic_timer.timer);
			preempt_disable();
			if (apic->lapic_timer.hv_timer_in_use)
				cancel_hv_timer(apic);
			preempt_enable();
			kvm_lapic_set_reg(apic, APIC_TMICT, 0);
			apic->lapic_timer.period = 0;
			apic->lapic_timer.tscdeadline = 0;
@@ -1715,7 +1721,7 @@ static void start_sw_period(struct kvm_lapic *apic)

	hrtimer_start(&apic->lapic_timer.timer,
		apic->lapic_timer.target_expiration,
		HRTIMER_MODE_ABS);
		HRTIMER_MODE_ABS_HARD);
}

bool kvm_lapic_hv_timer_in_use(struct kvm_vcpu *vcpu)
+17 −8
Original line number Diff line number Diff line
@@ -1933,14 +1933,6 @@ static void sev_clflush_pages(struct page *pages[], unsigned long npages)
static void __unregister_enc_region_locked(struct kvm *kvm,
					   struct enc_region *region)
{
	/*
	 * The guest may change the memory encryption attribute from C=0 -> C=1
	 * or vice versa for this memory range. Lets make sure caches are
	 * flushed to ensure that guest data gets written into memory with
	 * correct C-bit.
	 */
	sev_clflush_pages(region->pages, region->npages);

	sev_unpin_memory(kvm, region->pages, region->npages);
	list_del(&region->list);
	kfree(region);
@@ -1970,6 +1962,13 @@ static void sev_vm_destroy(struct kvm *kvm)

	mutex_lock(&kvm->lock);

	/*
	 * Ensure that all guest tagged cache entries are flushed before
	 * releasing the pages back to the system for use. CLFLUSH will
	 * not do this, so issue a WBINVD.
	 */
	wbinvd_on_all_cpus();

	/*
	 * if userspace was terminated before unregistering the memory regions
	 * then lets unpin all the registered memory.
@@ -7158,6 +7157,9 @@ static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
	if (!svm_sev_enabled())
		return -ENOTTY;

	if (!argp)
		return 0;

	if (copy_from_user(&sev_cmd, argp, sizeof(struct kvm_sev_cmd)))
		return -EFAULT;

@@ -7285,6 +7287,13 @@ static int svm_unregister_enc_region(struct kvm *kvm,
		goto failed;
	}

	/*
	 * Ensure that all guest tagged cache entries are flushed before
	 * releasing the pages back to the system for use. CLFLUSH will
	 * not do this, so issue a WBINVD.
	 */
	wbinvd_on_all_cpus();

	__unregister_enc_region_locked(kvm, region);

	mutex_unlock(&kvm->lock);
+1 −1
Original line number Diff line number Diff line
@@ -6287,7 +6287,7 @@ static void handle_external_interrupt_irqoff(struct kvm_vcpu *vcpu)
#endif
		ASM_CALL_CONSTRAINT
		:
		THUNK_TARGET(entry),
		[thunk_target]"r"(entry),
		[ss]"i"(__KERNEL_DS),
		[cs]"i"(__KERNEL_CS)
	);
+4 −2
Original line number Diff line number Diff line
@@ -1554,7 +1554,10 @@ EXPORT_SYMBOL_GPL(kvm_emulate_wrmsr);
 */
static int handle_fastpath_set_x2apic_icr_irqoff(struct kvm_vcpu *vcpu, u64 data)
{
	if (lapic_in_kernel(vcpu) && apic_x2apic_mode(vcpu->arch.apic) &&
	if (!lapic_in_kernel(vcpu) || !apic_x2apic_mode(vcpu->arch.apic))
		return 1;

	if (((data & APIC_SHORT_MASK) == APIC_DEST_NOSHORT) &&
		((data & APIC_DEST_MASK) == APIC_DEST_PHYSICAL) &&
		((data & APIC_MODE_MASK) == APIC_DM_FIXED)) {

@@ -2444,7 +2447,6 @@ static int kvm_guest_time_update(struct kvm_vcpu *v)
	vcpu->hv_clock.tsc_timestamp = tsc_timestamp;
	vcpu->hv_clock.system_time = kernel_ns + v->kvm->arch.kvmclock_offset;
	vcpu->last_guest_tsc = tsc_timestamp;
	WARN_ON((s64)vcpu->hv_clock.system_time < 0);

	/* If the host uses TSC clocksource, then it is stable */
	pvclock_flags = 0;