diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2021-11-13 10:01:10 -0800 | 
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2021-11-13 10:01:10 -0800 | 
| commit | 4d6fe79fdeccb8f3968d71bc633e622d43f1309c (patch) | |
| tree | 7b28ad235cb023b464d9e21b3a5465c17ff7003b /arch/x86/kernel/kvm.c | |
| parent | d4fa09e514cdb51fc7a2289c445c44ba0c87117b (diff) | |
| parent | 84886c262ebcfa40751ed508268457af8a20c1aa (diff) | |
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
Pull more kvm updates from Paolo Bonzini:
 "New x86 features:
   - Guest API and guest kernel support for SEV live migration
   - SEV and SEV-ES intra-host migration
  Bugfixes and cleanups for x86:
   - Fix misuse of gfn-to-pfn cache when recording guest steal time /
     preempted status
   - Fix selftests on APICv machines
   - Fix sparse warnings
   - Fix detection of KVM features in CPUID
   - Cleanups for bogus writes to MSR_KVM_PV_EOI_EN
   - Fixes and cleanups for MSR bitmap handling
   - Cleanups for INVPCID
   - Make x86 KVM_SOFT_MAX_VCPUS consistent with other architectures
  Bugfixes for ARM:
   - Fix finalization of host stage2 mappings
   - Tighten the return value of kvm_vcpu_preferred_target()
   - Make sure the extraction of ESR_ELx.EC is limited to architected
     bits"
* tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm: (34 commits)
  KVM: SEV: unify cgroup cleanup code for svm_vm_migrate_from
  KVM: x86: move guest_pv_has out of user_access section
  KVM: x86: Drop arbitrary KVM_SOFT_MAX_VCPUS
  KVM: Move INVPCID type check from vmx and svm to the common kvm_handle_invpcid()
  KVM: VMX: Add a helper function to retrieve the GPR index for INVPCID, INVVPID, and INVEPT
  KVM: nVMX: Clean up x2APIC MSR handling for L2
  KVM: VMX: Macrofy the MSR bitmap getters and setters
  KVM: nVMX: Handle dynamic MSR intercept toggling
  KVM: nVMX: Query current VMCS when determining if MSR bitmaps are in use
  KVM: x86: Don't update vcpu->arch.pv_eoi.msr_val when a bogus value was written to MSR_KVM_PV_EOI_EN
  KVM: x86: Rename kvm_lapic_enable_pv_eoi()
  KVM: x86: Make sure KVM_CPUID_FEATURES really are KVM_CPUID_FEATURES
  KVM: x86: Add helper to consolidate core logic of SET_CPUID{2} flows
  kvm: mmu: Use fast PF path for access tracking of huge pages when possible
  KVM: x86/mmu: Properly dereference rcu-protected TDP MMU sptep iterator
  KVM: x86: inhibit APICv when KVM_GUESTDBG_BLOCKIRQ active
  kvm: x86: Convert return type of *is_valid_rdpmc_ecx() to bool
  KVM: x86: Fix recording of guest steal time / preempted status
  selftest: KVM: Add intra host migration tests
  selftest: KVM: Add open sev dev helper
  ...
Diffstat (limited to 'arch/x86/kernel/kvm.c')
| -rw-r--r-- | arch/x86/kernel/kvm.c | 109 | 
1 files changed, 108 insertions, 1 deletions
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c index 8863d1941f1b..59abbdad7729 100644 --- a/arch/x86/kernel/kvm.c +++ b/arch/x86/kernel/kvm.c @@ -28,6 +28,7 @@  #include <linux/swait.h>  #include <linux/syscore_ops.h>  #include <linux/cc_platform.h> +#include <linux/efi.h>  #include <asm/timer.h>  #include <asm/cpu.h>  #include <asm/traps.h> @@ -41,6 +42,7 @@  #include <asm/ptrace.h>  #include <asm/reboot.h>  #include <asm/svm.h> +#include <asm/e820/api.h>  DEFINE_STATIC_KEY_FALSE(kvm_async_pf_enabled); @@ -434,6 +436,8 @@ static void kvm_guest_cpu_offline(bool shutdown)  	kvm_disable_steal_time();  	if (kvm_para_has_feature(KVM_FEATURE_PV_EOI))  		wrmsrl(MSR_KVM_PV_EOI_EN, 0); +	if (kvm_para_has_feature(KVM_FEATURE_MIGRATION_CONTROL)) +		wrmsrl(MSR_KVM_MIGRATION_CONTROL, 0);  	kvm_pv_disable_apf();  	if (!shutdown)  		apf_task_wake_all(); @@ -548,6 +552,55 @@ static void kvm_send_ipi_mask_allbutself(const struct cpumask *mask, int vector)  	__send_ipi_mask(local_mask, vector);  } +static int __init setup_efi_kvm_sev_migration(void) +{ +	efi_char16_t efi_sev_live_migration_enabled[] = L"SevLiveMigrationEnabled"; +	efi_guid_t efi_variable_guid = AMD_SEV_MEM_ENCRYPT_GUID; +	efi_status_t status; +	unsigned long size; +	bool enabled; + +	if (!cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT) || +	    !kvm_para_has_feature(KVM_FEATURE_MIGRATION_CONTROL)) +		return 0; + +	if (!efi_enabled(EFI_BOOT)) +		return 0; + +	if (!efi_enabled(EFI_RUNTIME_SERVICES)) { +		pr_info("%s : EFI runtime services are not enabled\n", __func__); +		return 0; +	} + +	size = sizeof(enabled); + +	/* Get variable contents into buffer */ +	status = efi.get_variable(efi_sev_live_migration_enabled, +				  &efi_variable_guid, NULL, &size, &enabled); + +	if (status == EFI_NOT_FOUND) { +		pr_info("%s : EFI live migration variable not found\n", __func__); +		return 0; +	} + +	if (status != EFI_SUCCESS) { +		pr_info("%s : EFI variable retrieval failed\n", __func__); +		return 0; +	} + +	if (enabled == 0) { +		pr_info("%s: live migration disabled in EFI\n", __func__); +		return 0; +	} + +	pr_info("%s : live migration enabled in EFI\n", __func__); +	wrmsrl(MSR_KVM_MIGRATION_CONTROL, KVM_MIGRATION_READY); + +	return 1; +} + +late_initcall(setup_efi_kvm_sev_migration); +  /*   * Set the IPI entry points   */ @@ -756,7 +809,7 @@ static noinline uint32_t __kvm_cpuid_base(void)  		return 0;	/* So we don't blow up on old processors */  	if (boot_cpu_has(X86_FEATURE_HYPERVISOR)) -		return hypervisor_cpuid_base("KVMKVMKVM\0\0\0", 0); +		return hypervisor_cpuid_base(KVM_SIGNATURE, 0);  	return 0;  } @@ -806,8 +859,62 @@ static bool __init kvm_msi_ext_dest_id(void)  	return kvm_para_has_feature(KVM_FEATURE_MSI_EXT_DEST_ID);  } +static void kvm_sev_hc_page_enc_status(unsigned long pfn, int npages, bool enc) +{ +	kvm_sev_hypercall3(KVM_HC_MAP_GPA_RANGE, pfn << PAGE_SHIFT, npages, +			   KVM_MAP_GPA_RANGE_ENC_STAT(enc) | KVM_MAP_GPA_RANGE_PAGE_SZ_4K); +} +  static void __init kvm_init_platform(void)  { +	if (cc_platform_has(CC_ATTR_GUEST_MEM_ENCRYPT) && +	    kvm_para_has_feature(KVM_FEATURE_MIGRATION_CONTROL)) { +		unsigned long nr_pages; +		int i; + +		pv_ops.mmu.notify_page_enc_status_changed = +			kvm_sev_hc_page_enc_status; + +		/* +		 * Reset the host's shared pages list related to kernel +		 * specific page encryption status settings before we load a +		 * new kernel by kexec. Reset the page encryption status +		 * during early boot intead of just before kexec to avoid SMP +		 * races during kvm_pv_guest_cpu_reboot(). +		 * NOTE: We cannot reset the complete shared pages list +		 * here as we need to retain the UEFI/OVMF firmware +		 * specific settings. +		 */ + +		for (i = 0; i < e820_table->nr_entries; i++) { +			struct e820_entry *entry = &e820_table->entries[i]; + +			if (entry->type != E820_TYPE_RAM) +				continue; + +			nr_pages = DIV_ROUND_UP(entry->size, PAGE_SIZE); + +			kvm_sev_hypercall3(KVM_HC_MAP_GPA_RANGE, entry->addr, +				       nr_pages, +				       KVM_MAP_GPA_RANGE_ENCRYPTED | KVM_MAP_GPA_RANGE_PAGE_SZ_4K); +		} + +		/* +		 * Ensure that _bss_decrypted section is marked as decrypted in the +		 * shared pages list. +		 */ +		nr_pages = DIV_ROUND_UP(__end_bss_decrypted - __start_bss_decrypted, +					PAGE_SIZE); +		early_set_mem_enc_dec_hypercall((unsigned long)__start_bss_decrypted, +						nr_pages, 0); + +		/* +		 * If not booted using EFI, enable Live migration support. +		 */ +		if (!efi_enabled(EFI_BOOT)) +			wrmsrl(MSR_KVM_MIGRATION_CONTROL, +			       KVM_MIGRATION_READY); +	}  	kvmclock_init();  	x86_platform.apic_post_init = kvm_apic_init;  }  | 
