linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v4 3/5] mm: x86: Invoke hypercall when page encryption status is changed
       [not found] <cover.1623421410.git.ashish.kalra@amd.com>
@ 2021-06-11 14:26 ` Ashish Kalra
  2021-06-11 14:28 ` [PATCH v4 4/5] EFI: Introduce the new AMD Memory Encryption GUID Ashish Kalra
  2021-06-11 14:30 ` [PATCH v4 5/5] x86/kvm: Add guest support for detecting and enabling SEV Live Migration feature Ashish Kalra
  2 siblings, 0 replies; 7+ messages in thread
From: Ashish Kalra @ 2021-06-11 14:26 UTC (permalink / raw)
  To: pbonzini
  Cc: seanjc, tglx, bp, mingo, hpa, joro, Thomas.Lendacky, x86, kvm,
	linux-kernel, srutherford, brijesh.singh

From: Brijesh Singh <brijesh.singh@amd.com>

Invoke a hypercall when a memory region is changed from encrypted ->
decrypted and vice versa. Hypervisor needs to know the page encryption
status during the guest migration.

Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@redhat.com>
Cc: "H. Peter Anvin" <hpa@zytor.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Joerg Roedel <joro@8bytes.org>
Cc: Borislav Petkov <bp@suse.de>
Cc: Tom Lendacky <thomas.lendacky@amd.com>
Cc: x86@kernel.org
Cc: kvm@vger.kernel.org
Cc: linux-kernel@vger.kernel.org
Reviewed-by: Steve Rutherford <srutherford@google.com>
Reviewed-by: Venu Busireddy <venu.busireddy@oracle.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
Reviewed-by: Borislav Petkov <bp@suse.de>
---
 arch/x86/include/asm/paravirt.h       |  6 +++
 arch/x86/include/asm/paravirt_types.h |  1 +
 arch/x86/include/asm/set_memory.h     |  1 +
 arch/x86/kernel/paravirt.c            |  1 +
 arch/x86/mm/mem_encrypt.c             | 67 +++++++++++++++++++++++----
 arch/x86/mm/pat/set_memory.c          |  6 +++
 6 files changed, 73 insertions(+), 9 deletions(-)

diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index da3a1ac82be5..540bf8cb37db 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -97,6 +97,12 @@ static inline void paravirt_arch_exit_mmap(struct mm_struct *mm)
 	PVOP_VCALL1(mmu.exit_mmap, mm);
 }
 
+static inline void notify_page_enc_status_changed(unsigned long pfn,
+						  int npages, bool enc)
+{
+	PVOP_VCALL3(mmu.notify_page_enc_status_changed, pfn, npages, enc);
+}
+
 #ifdef CONFIG_PARAVIRT_XXL
 static inline void load_sp0(unsigned long sp0)
 {
diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h
index d9d6b0203ec4..664199820239 100644
--- a/arch/x86/include/asm/paravirt_types.h
+++ b/arch/x86/include/asm/paravirt_types.h
@@ -168,6 +168,7 @@ struct pv_mmu_ops {
 
 	/* Hook for intercepting the destruction of an mm_struct. */
 	void (*exit_mmap)(struct mm_struct *mm);
+	void (*notify_page_enc_status_changed)(unsigned long pfn, int npages, bool enc);
 
 #ifdef CONFIG_PARAVIRT_XXL
 	struct paravirt_callee_save read_cr2;
diff --git a/arch/x86/include/asm/set_memory.h b/arch/x86/include/asm/set_memory.h
index 43fa081a1adb..872617542bbc 100644
--- a/arch/x86/include/asm/set_memory.h
+++ b/arch/x86/include/asm/set_memory.h
@@ -83,6 +83,7 @@ int set_pages_rw(struct page *page, int numpages);
 int set_direct_map_invalid_noflush(struct page *page);
 int set_direct_map_default_noflush(struct page *page);
 bool kernel_page_present(struct page *page);
+void notify_range_enc_status_changed(unsigned long vaddr, int npages, bool enc);
 
 extern int kernel_set_to_readonly;
 
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index 04cafc057bed..1cc20ac9a54f 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -296,6 +296,7 @@ struct paravirt_patch_template pv_ops = {
 			(void (*)(struct mmu_gather *, void *))tlb_remove_page,
 
 	.mmu.exit_mmap		= paravirt_nop,
+	.mmu.notify_page_enc_status_changed	= paravirt_nop,
 
 #ifdef CONFIG_PARAVIRT_XXL
 	.mmu.read_cr2		= __PV_IS_CALLEE_SAVE(native_read_cr2),
diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c
index ff08dc463634..455ac487cb9d 100644
--- a/arch/x86/mm/mem_encrypt.c
+++ b/arch/x86/mm/mem_encrypt.c
@@ -228,29 +228,76 @@ void __init sev_setup_arch(void)
 	swiotlb_adjust_size(size);
 }
 
-static void __init __set_clr_pte_enc(pte_t *kpte, int level, bool enc)
+static unsigned long pg_level_to_pfn(int level, pte_t *kpte, pgprot_t *ret_prot)
 {
-	pgprot_t old_prot, new_prot;
-	unsigned long pfn, pa, size;
-	pte_t new_pte;
+	unsigned long pfn = 0;
+	pgprot_t prot;
 
 	switch (level) {
 	case PG_LEVEL_4K:
 		pfn = pte_pfn(*kpte);
-		old_prot = pte_pgprot(*kpte);
+		prot = pte_pgprot(*kpte);
 		break;
 	case PG_LEVEL_2M:
 		pfn = pmd_pfn(*(pmd_t *)kpte);
-		old_prot = pmd_pgprot(*(pmd_t *)kpte);
+		prot = pmd_pgprot(*(pmd_t *)kpte);
 		break;
 	case PG_LEVEL_1G:
 		pfn = pud_pfn(*(pud_t *)kpte);
-		old_prot = pud_pgprot(*(pud_t *)kpte);
+		prot = pud_pgprot(*(pud_t *)kpte);
 		break;
 	default:
-		return;
+		WARN_ONCE(1, "Invalid level for kpte\n");
+		return 0;
 	}
 
+	if (ret_prot)
+		*ret_prot = prot;
+
+	return pfn;
+}
+
+void notify_range_enc_status_changed(unsigned long vaddr, int npages, bool enc)
+{
+#ifdef CONFIG_PARAVIRT
+	unsigned long sz = npages << PAGE_SHIFT;
+	unsigned long vaddr_end = vaddr + sz;
+
+	while (vaddr < vaddr_end) {
+		int psize, pmask, level;
+		unsigned long pfn;
+		pte_t *kpte;
+
+		kpte = lookup_address(vaddr, &level);
+		if (!kpte || pte_none(*kpte)) {
+			WARN_ONCE(1, "kpte lookup for vaddr\n");
+			return;
+		}
+
+		pfn = pg_level_to_pfn(level, kpte, NULL);
+		if (!pfn)
+			continue;
+
+		psize = page_level_size(level);
+		pmask = page_level_mask(level);
+
+		notify_page_enc_status_changed(pfn, psize >> PAGE_SHIFT, enc);
+
+		vaddr = (vaddr & pmask) + psize;
+	}
+#endif
+}
+
+static void __init __set_clr_pte_enc(pte_t *kpte, int level, bool enc)
+{
+	pgprot_t old_prot, new_prot;
+	unsigned long pfn, pa, size;
+	pte_t new_pte;
+
+	pfn = pg_level_to_pfn(level, kpte, &old_prot);
+	if (!pfn)
+		return;
+
 	new_prot = old_prot;
 	if (enc)
 		pgprot_val(new_prot) |= _PAGE_ENC;
@@ -285,12 +332,13 @@ static void __init __set_clr_pte_enc(pte_t *kpte, int level, bool enc)
 static int __init early_set_memory_enc_dec(unsigned long vaddr,
 					   unsigned long size, bool enc)
 {
-	unsigned long vaddr_end, vaddr_next;
+	unsigned long vaddr_end, vaddr_next, start;
 	unsigned long psize, pmask;
 	int split_page_size_mask;
 	int level, ret;
 	pte_t *kpte;
 
+	start = vaddr;
 	vaddr_next = vaddr;
 	vaddr_end = vaddr + size;
 
@@ -345,6 +393,7 @@ static int __init early_set_memory_enc_dec(unsigned long vaddr,
 
 	ret = 0;
 
+	notify_range_enc_status_changed(start, PAGE_ALIGN(size) >> PAGE_SHIFT, enc);
 out:
 	__flush_tlb_all();
 	return ret;
diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
index 156cd235659f..0c937daea0ae 100644
--- a/arch/x86/mm/pat/set_memory.c
+++ b/arch/x86/mm/pat/set_memory.c
@@ -2020,6 +2020,12 @@ static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc)
 	 */
 	cpa_flush(&cpa, 0);
 
+	/*
+	 * Notify hypervisor that a given memory range is mapped encrypted
+	 * or decrypted.
+	 */
+	notify_range_enc_status_changed(addr, numpages, enc);
+
 	return ret;
 }
 
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v4 4/5] EFI: Introduce the new AMD Memory Encryption GUID.
       [not found] <cover.1623421410.git.ashish.kalra@amd.com>
  2021-06-11 14:26 ` [PATCH v4 3/5] mm: x86: Invoke hypercall when page encryption status is changed Ashish Kalra
@ 2021-06-11 14:28 ` Ashish Kalra
  2021-06-11 14:30 ` [PATCH v4 5/5] x86/kvm: Add guest support for detecting and enabling SEV Live Migration feature Ashish Kalra
  2 siblings, 0 replies; 7+ messages in thread
From: Ashish Kalra @ 2021-06-11 14:28 UTC (permalink / raw)
  To: pbonzini
  Cc: seanjc, tglx, bp, mingo, hpa, joro, Thomas.Lendacky, x86, kvm,
	linux-kernel, srutherford, brijesh.singh, linux-efi

From: Ashish Kalra <ashish.kalra@amd.com>

Introduce a new AMD Memory Encryption GUID which is currently
used for defining a new UEFI environment variable which indicates
UEFI/OVMF support for the SEV live migration feature. This variable
is setup when UEFI/OVMF detects host/hypervisor support for SEV
live migration and later this variable is read by the kernel using
EFI runtime services to verify if OVMF supports the live migration
feature.

Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
Acked-by: Ard Biesheuvel <ardb@kernel.org>
---
 include/linux/efi.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/include/linux/efi.h b/include/linux/efi.h
index 6b5d36babfcc..dbd39b20e034 100644
--- a/include/linux/efi.h
+++ b/include/linux/efi.h
@@ -362,6 +362,7 @@ void efi_native_runtime_setup(void);
 
 /* OEM GUIDs */
 #define DELLEMC_EFI_RCI2_TABLE_GUID		EFI_GUID(0x2d9f28a2, 0xa886, 0x456a,  0x97, 0xa8, 0xf1, 0x1e, 0xf2, 0x4f, 0xf4, 0x55)
+#define AMD_SEV_MEM_ENCRYPT_GUID		EFI_GUID(0x0cf29b71, 0x9e51, 0x433a,  0xa3, 0xb7, 0x81, 0xf3, 0xab, 0x16, 0xb8, 0x75)
 
 typedef struct {
 	efi_guid_t guid;
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* [PATCH v4 5/5] x86/kvm: Add guest support for detecting and enabling SEV Live Migration feature.
       [not found] <cover.1623421410.git.ashish.kalra@amd.com>
  2021-06-11 14:26 ` [PATCH v4 3/5] mm: x86: Invoke hypercall when page encryption status is changed Ashish Kalra
  2021-06-11 14:28 ` [PATCH v4 4/5] EFI: Introduce the new AMD Memory Encryption GUID Ashish Kalra
@ 2021-06-11 14:30 ` Ashish Kalra
  2021-06-25 21:02   ` Steve Rutherford
  2 siblings, 1 reply; 7+ messages in thread
From: Ashish Kalra @ 2021-06-11 14:30 UTC (permalink / raw)
  To: pbonzini
  Cc: seanjc, tglx, bp, mingo, hpa, joro, Thomas.Lendacky, x86, kvm,
	linux-kernel, srutherford, brijesh.singh

From: Ashish Kalra <ashish.kalra@amd.com>

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
shared pages list.

Also adds kexec support for SEV Live Migration.

Reset the host's shared pages list related to kernel
specific page encryption status settings before we load a
new kernel by kexec. We cannot reset the complete
shared pages list here as we need to retain the
UEFI/OVMF firmware specific settings.

The host's shared pages list is maintained for the
guest to keep track of all unencrypted guest memory regions,
therefore we need to explicitly mark all shared pages as
encrypted again before rebooting into the new guest kernel.

Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
---
 arch/x86/include/asm/mem_encrypt.h |   4 ++
 arch/x86/kernel/kvm.c              | 107 +++++++++++++++++++++++++++++
 arch/x86/mm/mem_encrypt.c          |   5 ++
 3 files changed, 116 insertions(+)

diff --git a/arch/x86/include/asm/mem_encrypt.h b/arch/x86/include/asm/mem_encrypt.h
index 9c80c68d75b5..8dd373cc8b66 100644
--- a/arch/x86/include/asm/mem_encrypt.h
+++ b/arch/x86/include/asm/mem_encrypt.h
@@ -43,6 +43,8 @@ void __init sme_enable(struct boot_params *bp);
 
 int __init early_set_memory_decrypted(unsigned long vaddr, unsigned long size);
 int __init early_set_memory_encrypted(unsigned long vaddr, unsigned long size);
+void __init early_set_mem_enc_dec_hypercall(unsigned long vaddr, int npages,
+					    bool enc);
 
 void __init mem_encrypt_free_decrypted_mem(void);
 
@@ -83,6 +85,8 @@ static inline int __init
 early_set_memory_decrypted(unsigned long vaddr, unsigned long size) { return 0; }
 static inline int __init
 early_set_memory_encrypted(unsigned long vaddr, unsigned long size) { return 0; }
+static inline void __init
+early_set_mem_enc_dec_hypercall(unsigned long vaddr, int npages, bool enc) {}
 
 static inline void mem_encrypt_free_decrypted_mem(void) { }
 
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index a26643dc6bd6..80a81de4c470 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -27,6 +27,7 @@
 #include <linux/nmi.h>
 #include <linux/swait.h>
 #include <linux/syscore_ops.h>
+#include <linux/efi.h>
 #include <asm/timer.h>
 #include <asm/cpu.h>
 #include <asm/traps.h>
@@ -40,6 +41,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);
 
@@ -433,6 +435,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();
@@ -547,6 +551,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 (!sev_active() ||
+	    !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 true;
+}
+
+late_initcall(setup_efi_kvm_sev_migration);
+
 /*
  * Set the IPI entry points
  */
@@ -805,8 +858,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_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 (sev_active() &&
+	    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_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;
 }
diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c
index 455ac487cb9d..2673a89d17d9 100644
--- a/arch/x86/mm/mem_encrypt.c
+++ b/arch/x86/mm/mem_encrypt.c
@@ -409,6 +409,11 @@ int __init early_set_memory_encrypted(unsigned long vaddr, unsigned long size)
 	return early_set_memory_enc_dec(vaddr, size, true);
 }
 
+void __init early_set_mem_enc_dec_hypercall(unsigned long vaddr, int npages, bool enc)
+{
+	notify_range_enc_status_changed(vaddr, npages, enc);
+}
+
 /*
  * SME and SEV are very similar but they are not the same, so there are
  * times that the kernel will need to distinguish between SME and SEV. The
-- 
2.17.1


^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v4 5/5] x86/kvm: Add guest support for detecting and enabling SEV Live Migration feature.
  2021-06-11 14:30 ` [PATCH v4 5/5] x86/kvm: Add guest support for detecting and enabling SEV Live Migration feature Ashish Kalra
@ 2021-06-25 21:02   ` Steve Rutherford
  2021-06-25 22:22     ` Borislav Petkov
  0 siblings, 1 reply; 7+ messages in thread
From: Steve Rutherford @ 2021-06-25 21:02 UTC (permalink / raw)
  To: Ashish Kalra
  Cc: pbonzini, seanjc, tglx, bp, mingo, hpa, joro, thomas.lendacky,
	x86, kvm, linux-kernel, brijesh.singh

On Fri, Jun 11, 2021 at 7:30 AM Ashish Kalra <Ashish.Kalra@amd.com> wrote:
>
> From: Ashish Kalra <ashish.kalra@amd.com>
>
> 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
> shared pages list.
>
> Also adds kexec support for SEV Live Migration.
>
> Reset the host's shared pages list related to kernel
> specific page encryption status settings before we load a
> new kernel by kexec. We cannot reset the complete
> shared pages list here as we need to retain the
> UEFI/OVMF firmware specific settings.
>
> The host's shared pages list is maintained for the
> guest to keep track of all unencrypted guest memory regions,
> therefore we need to explicitly mark all shared pages as
> encrypted again before rebooting into the new guest kernel.
>
> Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
> ---
>  arch/x86/include/asm/mem_encrypt.h |   4 ++
>  arch/x86/kernel/kvm.c              | 107 +++++++++++++++++++++++++++++
>  arch/x86/mm/mem_encrypt.c          |   5 ++
>  3 files changed, 116 insertions(+)
>
> diff --git a/arch/x86/include/asm/mem_encrypt.h b/arch/x86/include/asm/mem_encrypt.h
> index 9c80c68d75b5..8dd373cc8b66 100644
> --- a/arch/x86/include/asm/mem_encrypt.h
> +++ b/arch/x86/include/asm/mem_encrypt.h
> @@ -43,6 +43,8 @@ void __init sme_enable(struct boot_params *bp);
>
>  int __init early_set_memory_decrypted(unsigned long vaddr, unsigned long size);
>  int __init early_set_memory_encrypted(unsigned long vaddr, unsigned long size);
> +void __init early_set_mem_enc_dec_hypercall(unsigned long vaddr, int npages,
> +                                           bool enc);
>
>  void __init mem_encrypt_free_decrypted_mem(void);
>
> @@ -83,6 +85,8 @@ static inline int __init
>  early_set_memory_decrypted(unsigned long vaddr, unsigned long size) { return 0; }
>  static inline int __init
>  early_set_memory_encrypted(unsigned long vaddr, unsigned long size) { return 0; }
> +static inline void __init
> +early_set_mem_enc_dec_hypercall(unsigned long vaddr, int npages, bool enc) {}
>
>  static inline void mem_encrypt_free_decrypted_mem(void) { }
>
> diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
> index a26643dc6bd6..80a81de4c470 100644
> --- a/arch/x86/kernel/kvm.c
> +++ b/arch/x86/kernel/kvm.c
> @@ -27,6 +27,7 @@
>  #include <linux/nmi.h>
>  #include <linux/swait.h>
>  #include <linux/syscore_ops.h>
> +#include <linux/efi.h>
>  #include <asm/timer.h>
>  #include <asm/cpu.h>
>  #include <asm/traps.h>
> @@ -40,6 +41,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);
>
> @@ -433,6 +435,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();
> @@ -547,6 +551,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 (!sev_active() ||
> +           !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 true;
> +}
> +
> +late_initcall(setup_efi_kvm_sev_migration);
> +
>  /*
>   * Set the IPI entry points
>   */
> @@ -805,8 +858,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_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 (sev_active() &&
> +           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_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;
>  }
> diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c
> index 455ac487cb9d..2673a89d17d9 100644
> --- a/arch/x86/mm/mem_encrypt.c
> +++ b/arch/x86/mm/mem_encrypt.c
> @@ -409,6 +409,11 @@ int __init early_set_memory_encrypted(unsigned long vaddr, unsigned long size)
>         return early_set_memory_enc_dec(vaddr, size, true);
>  }
>
> +void __init early_set_mem_enc_dec_hypercall(unsigned long vaddr, int npages, bool enc)
> +{
> +       notify_range_enc_status_changed(vaddr, npages, enc);
> +}
> +
>  /*
>   * SME and SEV are very similar but they are not the same, so there are
>   * times that the kernel will need to distinguish between SME and SEV. The
> --
> 2.17.1
>

Most of this looks good to me.

The one thing I find hard to understand is the kexec state machine.
Based on my naive reading, this should work fine for "normal" kexecs,
since it should disable migration on shutdown (with one call per
vCPU), and reenable on reboot (with a single call). That said, I don't
really understand how this interacts with the
hibernate-old-kernel/preserve-context mode of kexec (which allows
jumping back into the original kernel). That may "just work" if
reloading memory would also trigger all of the necessary c-bit
hypercalls. If there are concerns that this would not "just work", the
kernel could choose not to reenable migration on return to the
original kernel until someone implements support for this.

Boris, do you have any thoughts on the kexec aspect of this change?

Steve

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v4 5/5] x86/kvm: Add guest support for detecting and enabling SEV Live Migration feature.
  2021-06-25 21:02   ` Steve Rutherford
@ 2021-06-25 22:22     ` Borislav Petkov
  2021-06-28 19:34       ` Ashish Kalra
  0 siblings, 1 reply; 7+ messages in thread
From: Borislav Petkov @ 2021-06-25 22:22 UTC (permalink / raw)
  To: Steve Rutherford
  Cc: Ashish Kalra, pbonzini, seanjc, tglx, mingo, hpa, joro,
	thomas.lendacky, x86, kvm, linux-kernel, brijesh.singh

On Fri, Jun 25, 2021 at 02:02:32PM -0700, Steve Rutherford wrote:
> Boris, do you have any thoughts on the kexec aspect of this change?

I'm suspecting you're asking here the wrong guy - I think you mean
Paolo.

But if I were to give some thoughts on this, I'd first request that this
patch be split because it is doing a bunch of things at once.

Then, I have no clue what "kexec support for SEV Live Migration" is. So
this whole use case would need a lot more detailed explanation of all
the moving parts and the "why" and the "because" and so on...

But I'm no virt guy so perhaps this all makes sense to virt folks.

Oh, and there's silly stuff like

+static int __init setup_efi_kvm_sev_migration(void)
{
	...
	return true;
}

returning a bool but that's minor.

-- 
Regards/Gruss,
    Boris.

https://people.kernel.org/tglx/notes-about-netiquette

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v4 5/5] x86/kvm: Add guest support for detecting and enabling SEV Live Migration feature.
  2021-06-25 22:22     ` Borislav Petkov
@ 2021-06-28 19:34       ` Ashish Kalra
  2021-06-28 20:37         ` Steve Rutherford
  0 siblings, 1 reply; 7+ messages in thread
From: Ashish Kalra @ 2021-06-28 19:34 UTC (permalink / raw)
  To: Borislav Petkov
  Cc: Steve Rutherford, pbonzini, seanjc, tglx, mingo, hpa, joro,
	thomas.lendacky, x86, kvm, linux-kernel, brijesh.singh

Hello Steve,

Do you have any final thoughts on this ?

I do need to resend the patch as per Boris's review below and i want to
do that before the merge window closes. 

Thanks,
Ashish

On Sat, Jun 26, 2021 at 12:22:52AM +0200, Borislav Petkov wrote:
> On Fri, Jun 25, 2021 at 02:02:32PM -0700, Steve Rutherford wrote:
> > Boris, do you have any thoughts on the kexec aspect of this change?
> 
> I'm suspecting you're asking here the wrong guy - I think you mean
> Paolo.
> 
> But if I were to give some thoughts on this, I'd first request that this
> patch be split because it is doing a bunch of things at once.
> 
> Then, I have no clue what "kexec support for SEV Live Migration" is. So
> this whole use case would need a lot more detailed explanation of all
> the moving parts and the "why" and the "because" and so on...
> 
> But I'm no virt guy so perhaps this all makes sense to virt folks.
> 
> Oh, and there's silly stuff like
> 
> +static int __init setup_efi_kvm_sev_migration(void)
> {
> 	...
> 	return true;
> }
> 
> returning a bool but that's minor.
> 
> -- 
> Regards/Gruss,
>     Boris.
> 
> https://nam11.safelinks.protection.outlook.com/?url=https%3A%2F%2Fpeople.kernel.org%2Ftglx%2Fnotes-about-netiquette&amp;data=04%7C01%7CAshish.Kalra%40amd.com%7Cfca523e6b5b64a467b0408d93827ccc1%7C3dd8961fe4884e608e11a82d994e183d%7C0%7C0%7C637602565894090530%7CUnknown%7CTWFpbGZsb3d8eyJWIjoiMC4wLjAwMDAiLCJQIjoiV2luMzIiLCJBTiI6Ik1haWwiLCJXVCI6Mn0%3D%7C1000&amp;sdata=JmqtrGxhzgVczPYWdCKEyRIxDDRcDI2Q%2FI83j2dxhGE%3D&amp;reserved=0

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v4 5/5] x86/kvm: Add guest support for detecting and enabling SEV Live Migration feature.
  2021-06-28 19:34       ` Ashish Kalra
@ 2021-06-28 20:37         ` Steve Rutherford
  0 siblings, 0 replies; 7+ messages in thread
From: Steve Rutherford @ 2021-06-28 20:37 UTC (permalink / raw)
  To: Ashish Kalra
  Cc: Borislav Petkov, pbonzini, seanjc, tglx, mingo, hpa, joro,
	thomas.lendacky, x86, kvm, linux-kernel, brijesh.singh

On Mon, Jun 28, 2021 at 12:34 PM Ashish Kalra <ashish.kalra@amd.com> wrote:
>
> Hello Steve,
>
> Do you have any final thoughts on this ?

Hi Ashish,

Don't block this because of my lack of understanding.  I'm still
curious about the interactions between SEV and kexec
--preserved-state. If you have concerns about --preserved-state
breaking live-migration (when returning to the original kernel), you
could have kexec's with that flag return an error on Live Migratable
SEV kernels.

Thanks,
Steve

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2021-06-28 20:38 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
     [not found] <cover.1623421410.git.ashish.kalra@amd.com>
2021-06-11 14:26 ` [PATCH v4 3/5] mm: x86: Invoke hypercall when page encryption status is changed Ashish Kalra
2021-06-11 14:28 ` [PATCH v4 4/5] EFI: Introduce the new AMD Memory Encryption GUID Ashish Kalra
2021-06-11 14:30 ` [PATCH v4 5/5] x86/kvm: Add guest support for detecting and enabling SEV Live Migration feature Ashish Kalra
2021-06-25 21:02   ` Steve Rutherford
2021-06-25 22:22     ` Borislav Petkov
2021-06-28 19:34       ` Ashish Kalra
2021-06-28 20:37         ` Steve Rutherford

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).