1191 lines · 28.9 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-or-later/* * KVM paravirt_ops implementation * * Copyright (C) 2007, Red Hat, Inc., Ingo Molnar <mingo@redhat.com> * Copyright IBM Corporation, 2007 *   Authors: Anthony Liguori <aliguori@us.ibm.com> */ #define pr_fmt(fmt) "kvm-guest: " fmt #include <linux/context_tracking.h>#include <linux/init.h>#include <linux/irq.h>#include <linux/kernel.h>#include <linux/kvm_para.h>#include <linux/cpu.h>#include <linux/mm.h>#include <linux/highmem.h>#include <linux/hardirq.h>#include <linux/notifier.h>#include <linux/reboot.h>#include <linux/hash.h>#include <linux/sched.h>#include <linux/slab.h>#include <linux/kprobes.h>#include <linux/nmi.h>#include <linux/swait.h>#include <linux/syscore_ops.h>#include <linux/cc_platform.h>#include <linux/efi.h>#include <linux/kvm_types.h>#include <linux/sched/cputime.h>#include <asm/timer.h>#include <asm/cpu.h>#include <asm/traps.h>#include <asm/desc.h>#include <asm/tlbflush.h>#include <asm/apic.h>#include <asm/apicdef.h>#include <asm/hypervisor.h>#include <asm/mtrr.h>#include <asm/tlb.h>#include <asm/cpuid/api.h>#include <asm/cpuidle_haltpoll.h>#include <asm/msr.h>#include <asm/ptrace.h>#include <asm/reboot.h>#include <asm/svm.h>#include <asm/e820/api.h> DEFINE_STATIC_KEY_FALSE_RO(kvm_async_pf_enabled); static int kvmapf = 1; static int __init parse_no_kvmapf(char *arg){        kvmapf = 0;        return 0;} early_param("no-kvmapf", parse_no_kvmapf); static int steal_acc = 1;static int __init parse_no_stealacc(char *arg){        steal_acc = 0;        return 0;} early_param("no-steal-acc", parse_no_stealacc); static DEFINE_PER_CPU_READ_MOSTLY(bool, async_pf_enabled);static DEFINE_PER_CPU_DECRYPTED(struct kvm_vcpu_pv_apf_data, apf_reason) __aligned(64);DEFINE_PER_CPU_DECRYPTED(struct kvm_steal_time, steal_time) __aligned(64) __visible;static int has_steal_clock = 0; static int has_guest_poll = 0; #define KVM_TASK_SLEEP_HASHBITS 8#define KVM_TASK_SLEEP_HASHSIZE (1<<KVM_TASK_SLEEP_HASHBITS) struct kvm_task_sleep_node {	struct hlist_node link;	struct swait_queue_head wq;	u32 token;	int cpu;	bool dummy;}; static struct kvm_task_sleep_head {	raw_spinlock_t lock;	struct hlist_head list;} async_pf_sleepers[KVM_TASK_SLEEP_HASHSIZE]; static struct kvm_task_sleep_node *_find_apf_task(struct kvm_task_sleep_head *b,						  u32 token){	struct hlist_node *p; 	hlist_for_each(p, &b->list) {		struct kvm_task_sleep_node *n =			hlist_entry(p, typeof(*n), link);		if (n->token == token)			return n;	} 	return NULL;} static bool kvm_async_pf_queue_task(u32 token, struct kvm_task_sleep_node *n){	u32 key = hash_32(token, KVM_TASK_SLEEP_HASHBITS);	struct kvm_task_sleep_head *b = &async_pf_sleepers[key];	struct kvm_task_sleep_node *e; 	raw_spin_lock(&b->lock);	e = _find_apf_task(b, token);	if (e) {		struct kvm_task_sleep_node *dummy = NULL; 		/*		 * The entry can either be a 'dummy' entry (which is put on the		 * list when wake-up happens ahead of APF handling completion)		 * or a token from another task which should not be touched.		 */		if (e->dummy) {			hlist_del(&e->link);			dummy = e;		} 		raw_spin_unlock(&b->lock);		kfree(dummy);		return false;	} 	n->token = token;	n->cpu = smp_processor_id();	n->dummy = false;	init_swait_queue_head(&n->wq);	hlist_add_head(&n->link, &b->list);	raw_spin_unlock(&b->lock);	return true;} /* * kvm_async_pf_task_wait_schedule - Wait for pagefault to be handled * @token:	Token to identify the sleep node entry * * Invoked from the async pagefault handling code or from the VM exit page * fault handler. In both cases RCU is watching. */void kvm_async_pf_task_wait_schedule(u32 token){	struct kvm_task_sleep_node n;	DECLARE_SWAITQUEUE(wait); 	lockdep_assert_irqs_disabled(); 	if (!kvm_async_pf_queue_task(token, &n))		return; 	for (;;) {		prepare_to_swait_exclusive(&n.wq, &wait, TASK_UNINTERRUPTIBLE);		if (hlist_unhashed(&n.link))			break; 		local_irq_enable();		schedule();		local_irq_disable();	}	finish_swait(&n.wq, &wait);}EXPORT_SYMBOL_FOR_KVM(kvm_async_pf_task_wait_schedule); static void apf_task_wake_one(struct kvm_task_sleep_node *n){	hlist_del_init(&n->link);	if (swq_has_sleeper(&n->wq))		swake_up_one(&n->wq);} static void apf_task_wake_all(void){	int i; 	for (i = 0; i < KVM_TASK_SLEEP_HASHSIZE; i++) {		struct kvm_task_sleep_head *b = &async_pf_sleepers[i];		struct kvm_task_sleep_node *n;		struct hlist_node *p, *next; 		raw_spin_lock(&b->lock);		hlist_for_each_safe(p, next, &b->list) {			n = hlist_entry(p, typeof(*n), link);			if (n->cpu == smp_processor_id())				apf_task_wake_one(n);		}		raw_spin_unlock(&b->lock);	}} static void kvm_async_pf_task_wake(u32 token){	u32 key = hash_32(token, KVM_TASK_SLEEP_HASHBITS);	struct kvm_task_sleep_head *b = &async_pf_sleepers[key];	struct kvm_task_sleep_node *n, *dummy = NULL; 	if (token == ~0) {		apf_task_wake_all();		return;	} again:	raw_spin_lock(&b->lock);	n = _find_apf_task(b, token);	if (!n) {		/*		 * Async #PF not yet handled, add a dummy entry for the token.		 * Allocating the token must be down outside of the raw lock		 * as the allocator is preemptible on PREEMPT_RT kernels.		 */		if (!dummy) {			raw_spin_unlock(&b->lock);			dummy = kzalloc_obj(*dummy, GFP_ATOMIC); 			/*			 * Continue looping on allocation failure, eventually			 * the async #PF will be handled and allocating a new			 * node will be unnecessary.			 */			if (!dummy)				cpu_relax(); 			/*			 * Recheck for async #PF completion before enqueueing			 * the dummy token to avoid duplicate list entries.			 */			goto again;		}		dummy->token = token;		dummy->cpu = smp_processor_id();		dummy->dummy = true;		init_swait_queue_head(&dummy->wq);		hlist_add_head(&dummy->link, &b->list);		dummy = NULL;	} else {		apf_task_wake_one(n);	}	raw_spin_unlock(&b->lock); 	/* A dummy token might be allocated and ultimately not used.  */	kfree(dummy);} noinstr u32 kvm_read_and_reset_apf_flags(void){	u32 flags = 0; 	if (__this_cpu_read(async_pf_enabled)) {		flags = __this_cpu_read(apf_reason.flags);		__this_cpu_write(apf_reason.flags, 0);	} 	return flags;}EXPORT_SYMBOL_FOR_KVM(kvm_read_and_reset_apf_flags); noinstr bool __kvm_handle_async_pf(struct pt_regs *regs, u32 token){	u32 flags = kvm_read_and_reset_apf_flags();	irqentry_state_t state; 	if (!flags)		return false; 	state = irqentry_enter(regs);	instrumentation_begin(); 	/*	 * If the host managed to inject an async #PF into an interrupt	 * disabled region, then die hard as this is not going to end well	 * and the host side is seriously broken.	 */	if (unlikely(!(regs->flags & X86_EFLAGS_IF)))		panic("Host injected async #PF in interrupt disabled region\n"); 	if (flags & KVM_PV_REASON_PAGE_NOT_PRESENT) {		if (unlikely(!(user_mode(regs))))			panic("Host injected async #PF in kernel mode\n");		/* Page is swapped out by the host. */		kvm_async_pf_task_wait_schedule(token);	} else {		WARN_ONCE(1, "Unexpected async PF flags: %x\n", flags);	} 	instrumentation_end();	irqentry_exit(regs, state);	return true;} DEFINE_IDTENTRY_SYSVEC(sysvec_kvm_asyncpf_interrupt){	struct pt_regs *old_regs = set_irq_regs(regs);	u32 token; 	apic_eoi(); 	inc_irq_stat(HYPERVISOR_CALLBACK); 	if (__this_cpu_read(async_pf_enabled)) {		token = __this_cpu_read(apf_reason.token);		kvm_async_pf_task_wake(token);		__this_cpu_write(apf_reason.token, 0);		wrmsrq(MSR_KVM_ASYNC_PF_ACK, 1);	} 	set_irq_regs(old_regs);} static void __init paravirt_ops_setup(void){	pv_info.name = "KVM"; 	if (kvm_para_has_feature(KVM_FEATURE_NOP_IO_DELAY))		pv_info.io_delay = false; #ifdef CONFIG_X86_IO_APIC	no_timer_check = 1;#endif} static void kvm_register_steal_time(void){	int cpu = smp_processor_id();	struct kvm_steal_time *st = &per_cpu(steal_time, cpu); 	if (!has_steal_clock)		return; 	wrmsrq(MSR_KVM_STEAL_TIME, (slow_virt_to_phys(st) | KVM_MSR_ENABLED));	pr_debug("stealtime: cpu %d, msr %llx\n", cpu,		(unsigned long long) slow_virt_to_phys(st));} static DEFINE_PER_CPU_DECRYPTED(unsigned long, kvm_apic_eoi) = KVM_PV_EOI_DISABLED; static notrace __maybe_unused void kvm_guest_apic_eoi_write(void){	/**	 * This relies on __test_and_clear_bit to modify the memory	 * in a way that is atomic with respect to the local CPU.	 * The hypervisor only accesses this memory from the local CPU so	 * there's no need for lock or memory barriers.	 * An optimization barrier is implied in apic write.	 */	if (__test_and_clear_bit(KVM_PV_EOI_BIT, this_cpu_ptr(&kvm_apic_eoi)))		return;	apic_native_eoi();} static void kvm_guest_cpu_init(void){	if (kvm_para_has_feature(KVM_FEATURE_ASYNC_PF_INT) && kvmapf) {		u64 pa; 		WARN_ON_ONCE(!static_branch_likely(&kvm_async_pf_enabled)); 		pa = slow_virt_to_phys(this_cpu_ptr(&apf_reason));		pa |= KVM_ASYNC_PF_ENABLED | KVM_ASYNC_PF_DELIVERY_AS_INT; 		if (kvm_para_has_feature(KVM_FEATURE_ASYNC_PF_VMEXIT))			pa |= KVM_ASYNC_PF_DELIVERY_AS_PF_VMEXIT; 		wrmsrq(MSR_KVM_ASYNC_PF_INT, HYPERVISOR_CALLBACK_VECTOR); 		wrmsrq(MSR_KVM_ASYNC_PF_EN, pa);		__this_cpu_write(async_pf_enabled, true);		pr_debug("setup async PF for cpu %d\n", smp_processor_id());	} 	if (kvm_para_has_feature(KVM_FEATURE_PV_EOI)) {		unsigned long pa; 		/* Size alignment is implied but just to make it explicit. */		BUILD_BUG_ON(__alignof__(kvm_apic_eoi) < 4);		__this_cpu_write(kvm_apic_eoi, 0);		pa = slow_virt_to_phys(this_cpu_ptr(&kvm_apic_eoi))			| KVM_MSR_ENABLED;		wrmsrq(MSR_KVM_PV_EOI_EN, pa);	} 	if (has_steal_clock)		kvm_register_steal_time();} static void kvm_pv_disable_apf(void){	if (!__this_cpu_read(async_pf_enabled))		return; 	wrmsrq(MSR_KVM_ASYNC_PF_EN, 0);	__this_cpu_write(async_pf_enabled, false); 	pr_debug("disable async PF for cpu %d\n", smp_processor_id());} static void kvm_disable_steal_time(void){	if (!has_steal_clock)		return; 	wrmsrq(MSR_KVM_STEAL_TIME, 0);} static u64 kvm_steal_clock(int cpu){	u64 steal;	struct kvm_steal_time *src;	int version; 	src = &per_cpu(steal_time, cpu);	do {		version = src->version;		virt_rmb();		steal = src->steal;		virt_rmb();	} while ((version & 1) || (version != src->version)); 	return steal;} static inline __init void __set_percpu_decrypted(void *ptr, unsigned long size){	early_set_memory_decrypted((unsigned long) ptr, size);} /* * Iterate through all possible CPUs and map the memory region pointed * by apf_reason, steal_time and kvm_apic_eoi as decrypted at once. * * Note: we iterate through all possible CPUs to ensure that CPUs * hotplugged will have their per-cpu variable already mapped as * decrypted. */static void __init sev_map_percpu_data(void){	int cpu; 	if (cc_vendor != CC_VENDOR_AMD ||	    !cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT))		return; 	for_each_possible_cpu(cpu) {		__set_percpu_decrypted(&per_cpu(apf_reason, cpu), sizeof(apf_reason));		__set_percpu_decrypted(&per_cpu(steal_time, cpu), sizeof(steal_time));		__set_percpu_decrypted(&per_cpu(kvm_apic_eoi, cpu), sizeof(kvm_apic_eoi));	}} static void kvm_guest_cpu_offline(bool shutdown){	kvm_disable_steal_time();	if (kvm_para_has_feature(KVM_FEATURE_PV_EOI))		wrmsrq(MSR_KVM_PV_EOI_EN, 0);	if (kvm_para_has_feature(KVM_FEATURE_MIGRATION_CONTROL))		wrmsrq(MSR_KVM_MIGRATION_CONTROL, 0);	kvm_pv_disable_apf();	if (!shutdown)		apf_task_wake_all();	kvmclock_disable();} static int kvm_cpu_online(unsigned int cpu){	unsigned long flags; 	local_irq_save(flags);	kvm_guest_cpu_init();	local_irq_restore(flags);	return 0;} #ifdef CONFIG_SMP static DEFINE_PER_CPU(cpumask_var_t, __pv_cpu_mask); static bool pv_tlb_flush_supported(void){	return (kvm_para_has_feature(KVM_FEATURE_PV_TLB_FLUSH) &&		!kvm_para_has_hint(KVM_HINTS_REALTIME) &&		kvm_para_has_feature(KVM_FEATURE_STEAL_TIME) &&		!boot_cpu_has(X86_FEATURE_MWAIT) &&		(num_possible_cpus() != 1));} static bool pv_ipi_supported(void){	return (kvm_para_has_feature(KVM_FEATURE_PV_SEND_IPI) &&	       (num_possible_cpus() != 1));}

Lines 1–500 of 1191.