Skip to content

Commit f449561

Browse files
ashkalrabonzini
authored andcommitted
x86/kvm: Add guest support for detecting and enabling SEV Live Migration feature.
The guest support for detecting and enabling SEV Live migration feature uses the following logic : - kvm_init_plaform() checks if its booted under the EFI - If not EFI, i) if kvm_para_has_feature(KVM_FEATURE_MIGRATION_CONTROL), issue a wrmsrl() to enable the SEV live migration support - If EFI, i) If kvm_para_has_feature(KVM_FEATURE_MIGRATION_CONTROL), read the UEFI variable which indicates OVMF support for live migration ii) the variable indicates live migration is supported, issue a wrmsrl() to enable the SEV live migration support The EFI live migration check is done using a late_initcall() callback. Also, ensure that _bss_decrypted section is marked as decrypted in the hypervisor's guest page encryption status tracking. Signed-off-by: Ashish Kalra <[email protected]> Reviewed-by: Steve Rutherford <[email protected]> Message-Id: <b4453e4c87103ebef12217d2505ea99a1c3e0f0f.1629726117.git.ashish.kalra@amd.com> Signed-off-by: Paolo Bonzini <[email protected]>
1 parent 2f70ddb commit f449561

File tree

3 files changed

+91
-0
lines changed

3 files changed

+91
-0
lines changed

arch/x86/include/asm/mem_encrypt.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ void __init sme_enable(struct boot_params *bp);
4343

4444
int __init early_set_memory_decrypted(unsigned long vaddr, unsigned long size);
4545
int __init early_set_memory_encrypted(unsigned long vaddr, unsigned long size);
46+
void __init early_set_mem_enc_dec_hypercall(unsigned long vaddr, int npages,
47+
bool enc);
4648

4749
void __init mem_encrypt_free_decrypted_mem(void);
4850

@@ -83,6 +85,8 @@ static inline int __init
8385
early_set_memory_decrypted(unsigned long vaddr, unsigned long size) { return 0; }
8486
static inline int __init
8587
early_set_memory_encrypted(unsigned long vaddr, unsigned long size) { return 0; }
88+
static inline void __init
89+
early_set_mem_enc_dec_hypercall(unsigned long vaddr, int npages, bool enc) {}
8690

8791
static inline void mem_encrypt_free_decrypted_mem(void) { }
8892

arch/x86/kernel/kvm.c

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@
2727
#include <linux/nmi.h>
2828
#include <linux/swait.h>
2929
#include <linux/syscore_ops.h>
30+
#include <linux/efi.h>
3031
#include <asm/timer.h>
3132
#include <asm/cpu.h>
3233
#include <asm/traps.h>
@@ -40,6 +41,7 @@
4041
#include <asm/ptrace.h>
4142
#include <asm/reboot.h>
4243
#include <asm/svm.h>
44+
#include <asm/e820/api.h>
4345

4446
DEFINE_STATIC_KEY_FALSE(kvm_async_pf_enabled);
4547

@@ -433,6 +435,8 @@ static void kvm_guest_cpu_offline(bool shutdown)
433435
kvm_disable_steal_time();
434436
if (kvm_para_has_feature(KVM_FEATURE_PV_EOI))
435437
wrmsrl(MSR_KVM_PV_EOI_EN, 0);
438+
if (kvm_para_has_feature(KVM_FEATURE_MIGRATION_CONTROL))
439+
wrmsrl(MSR_KVM_MIGRATION_CONTROL, 0);
436440
kvm_pv_disable_apf();
437441
if (!shutdown)
438442
apf_task_wake_all();
@@ -547,6 +551,55 @@ static void kvm_send_ipi_mask_allbutself(const struct cpumask *mask, int vector)
547551
__send_ipi_mask(local_mask, vector);
548552
}
549553

554+
static int __init setup_efi_kvm_sev_migration(void)
555+
{
556+
efi_char16_t efi_sev_live_migration_enabled[] = L"SevLiveMigrationEnabled";
557+
efi_guid_t efi_variable_guid = AMD_SEV_MEM_ENCRYPT_GUID;
558+
efi_status_t status;
559+
unsigned long size;
560+
bool enabled;
561+
562+
if (!sev_active() ||
563+
!kvm_para_has_feature(KVM_FEATURE_MIGRATION_CONTROL))
564+
return 0;
565+
566+
if (!efi_enabled(EFI_BOOT))
567+
return 0;
568+
569+
if (!efi_enabled(EFI_RUNTIME_SERVICES)) {
570+
pr_info("%s : EFI runtime services are not enabled\n", __func__);
571+
return 0;
572+
}
573+
574+
size = sizeof(enabled);
575+
576+
/* Get variable contents into buffer */
577+
status = efi.get_variable(efi_sev_live_migration_enabled,
578+
&efi_variable_guid, NULL, &size, &enabled);
579+
580+
if (status == EFI_NOT_FOUND) {
581+
pr_info("%s : EFI live migration variable not found\n", __func__);
582+
return 0;
583+
}
584+
585+
if (status != EFI_SUCCESS) {
586+
pr_info("%s : EFI variable retrieval failed\n", __func__);
587+
return 0;
588+
}
589+
590+
if (enabled == 0) {
591+
pr_info("%s: live migration disabled in EFI\n", __func__);
592+
return 0;
593+
}
594+
595+
pr_info("%s : live migration enabled in EFI\n", __func__);
596+
wrmsrl(MSR_KVM_MIGRATION_CONTROL, KVM_MIGRATION_READY);
597+
598+
return 1;
599+
}
600+
601+
late_initcall(setup_efi_kvm_sev_migration);
602+
550603
/*
551604
* Set the IPI entry points
552605
*/
@@ -805,8 +858,37 @@ static bool __init kvm_msi_ext_dest_id(void)
805858
return kvm_para_has_feature(KVM_FEATURE_MSI_EXT_DEST_ID);
806859
}
807860

861+
static void kvm_sev_hc_page_enc_status(unsigned long pfn, int npages, bool enc)
862+
{
863+
kvm_sev_hypercall3(KVM_HC_MAP_GPA_RANGE, pfn << PAGE_SHIFT, npages,
864+
KVM_MAP_GPA_RANGE_ENC_STAT(enc) | KVM_MAP_GPA_RANGE_PAGE_SZ_4K);
865+
}
866+
808867
static void __init kvm_init_platform(void)
809868
{
869+
if (sev_active() &&
870+
kvm_para_has_feature(KVM_FEATURE_MIGRATION_CONTROL)) {
871+
unsigned long nr_pages;
872+
873+
pv_ops.mmu.notify_page_enc_status_changed =
874+
kvm_sev_hc_page_enc_status;
875+
876+
/*
877+
* Ensure that _bss_decrypted section is marked as decrypted in the
878+
* shared pages list.
879+
*/
880+
nr_pages = DIV_ROUND_UP(__end_bss_decrypted - __start_bss_decrypted,
881+
PAGE_SIZE);
882+
early_set_mem_enc_dec_hypercall((unsigned long)__start_bss_decrypted,
883+
nr_pages, 0);
884+
885+
/*
886+
* If not booted using EFI, enable Live migration support.
887+
*/
888+
if (!efi_enabled(EFI_BOOT))
889+
wrmsrl(MSR_KVM_MIGRATION_CONTROL,
890+
KVM_MIGRATION_READY);
891+
}
810892
kvmclock_init();
811893
x86_platform.apic_post_init = kvm_apic_init;
812894
}

arch/x86/mm/mem_encrypt.c

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -409,6 +409,11 @@ int __init early_set_memory_encrypted(unsigned long vaddr, unsigned long size)
409409
return early_set_memory_enc_dec(vaddr, size, true);
410410
}
411411

412+
void __init early_set_mem_enc_dec_hypercall(unsigned long vaddr, int npages, bool enc)
413+
{
414+
notify_range_enc_status_changed(vaddr, npages, enc);
415+
}
416+
412417
/*
413418
* SME and SEV are very similar but they are not the same, so there are
414419
* times that the kernel will need to distinguish between SME and SEV. The

0 commit comments

Comments
 (0)