Inter-revision diff: patch 23

Comparing rfc (message) to v4 (message)

--- vrfc
+++ v4
@@ -1,91 +1,271 @@
-The SEV-SNP VMs may call the page state change VMGEXIT to add the GPA
-as private or shared in the RMP table. The page state change VMGEXIT
-will contain the RMP page level to be used in the RMP entry. If the
-page level between the TDP and RMP does not match then, it will result
-in nested-page-fault (RMP violation).
-
-The SEV-SNP VMGEXIT handler will use the kvm_mmu_get_tdp_walk() to get
-the current page-level in the TDP for the given GPA and calculate a
-workable page level. If a GPA is mapped as a 4K-page in the TDP, but
-the guest requested to add the GPA as a 2M in the RMP entry then the
-2M request will be broken into 4K-pages to keep the RMP and TDP
-page-levels in sync.
-
-Cc: Thomas Gleixner <tglx@linutronix.de>
-Cc: Ingo Molnar <mingo@redhat.com>
-Cc: Borislav Petkov <bp@alien8.de>
-Cc: Joerg Roedel <jroedel@suse.de>
-Cc: "H. Peter Anvin" <hpa@zytor.com>
-Cc: Tony Luck <tony.luck@intel.com>
-Cc: Dave Hansen <dave.hansen@intel.com>
-Cc: "Peter Zijlstra (Intel)" <peterz@infradead.org>
-Cc: Paolo Bonzini <pbonzini@redhat.com>
-Cc: Tom Lendacky <thomas.lendacky@amd.com>
-Cc: David Rientjes <rientjes@google.com>
-Cc: Sean Christopherson <seanjc@google.com>
-Cc: Vitaly Kuznetsov <vkuznets@redhat.com>
-Cc: Wanpeng Li <wanpengli@tencent.com>
-Cc: Jim Mattson <jmattson@google.com>
-Cc: x86@kernel.org
-Cc: kvm@vger.kernel.org
+KVM_SEV_SNP_LAUNCH_START begins the launch process for an SEV-SNP guest.
+The command initializes a cryptographic digest context used to construct
+the measurement of the guest. If the guest is expected to be migrated,
+the command also binds a migration agent (MA) to the guest.
+
+For more information see the SEV-SNP specification.
+
 Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
 ---
- arch/x86/kvm/mmu.h     |  1 +
- arch/x86/kvm/mmu/mmu.c | 29 +++++++++++++++++++++++++++++
- 2 files changed, 30 insertions(+)
-
-diff --git a/arch/x86/kvm/mmu.h b/arch/x86/kvm/mmu.h
-index 70dce26a5882..e7c4e55215bf 100644
---- a/arch/x86/kvm/mmu.h
-+++ b/arch/x86/kvm/mmu.h
-@@ -110,6 +110,7 @@ int kvm_tdp_page_fault(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code,
- 		       bool prefault);
- 
- int kvm_mmu_map_tdp_page(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code, int max_level);
-+bool kvm_mmu_get_tdp_walk(struct kvm_vcpu *vcpu, gpa_t gpa, kvm_pfn_t *pfn, int *level);
- 
- static inline int kvm_mmu_do_page_fault(struct kvm_vcpu *vcpu, gpa_t cr2_or_gpa,
- 					u32 err, bool prefault)
-diff --git a/arch/x86/kvm/mmu/mmu.c b/arch/x86/kvm/mmu/mmu.c
-index 33104943904b..147f22bda6e7 100644
---- a/arch/x86/kvm/mmu/mmu.c
-+++ b/arch/x86/kvm/mmu/mmu.c
-@@ -3828,6 +3828,35 @@ int kvm_mmu_map_tdp_page(struct kvm_vcpu *vcpu, gpa_t gpa, u32 error_code, int m
+ .../virt/kvm/amd-memory-encryption.rst        |  25 ++++
+ arch/x86/kvm/svm/sev.c                        | 132 +++++++++++++++++-
+ arch/x86/kvm/svm/svm.h                        |   1 +
+ include/uapi/linux/kvm.h                      |   9 ++
+ 4 files changed, 166 insertions(+), 1 deletion(-)
+
+diff --git a/Documentation/virt/kvm/amd-memory-encryption.rst b/Documentation/virt/kvm/amd-memory-encryption.rst
+index 75ca60b6d40a..8620383d405a 100644
+--- a/Documentation/virt/kvm/amd-memory-encryption.rst
++++ b/Documentation/virt/kvm/amd-memory-encryption.rst
+@@ -443,6 +443,31 @@ Returns: 0 on success, -negative on error
+                 __u64 flags;    /* must be zero */
+         };
+ 
++
++19. KVM_SNP_LAUNCH_START
++------------------------
++
++The KVM_SNP_LAUNCH_START command is used for creating the memory encryption
++context for the SEV-SNP guest. To create the encryption context, user must
++provide a guest policy, migration agent (if any) and guest OS visible
++workarounds value as defined SEV-SNP specification.
++
++Parameters (in): struct  kvm_snp_launch_start
++
++Returns: 0 on success, -negative on error
++
++::
++
++        struct kvm_sev_snp_launch_start {
++                __u64 policy;           /* Guest policy to use. */
++                __u64 ma_uaddr;         /* userspace address of migration agent */
++                __u8 ma_en;             /* 1 if the migtation agent is enabled */
++                __u8 imi_en;            /* set IMI to 1. */
++                __u8 gosvw[16];         /* guest OS visible workarounds */
++        };
++
++See the SEV-SNP specification for further detail on the launch input.
++
+ References
+ ==========
+ 
+diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
+index be31221f0a47..f44a657e8912 100644
+--- a/arch/x86/kvm/svm/sev.c
++++ b/arch/x86/kvm/svm/sev.c
+@@ -20,6 +20,7 @@
+ #include <asm/fpu/internal.h>
+ 
+ #include <asm/trapnr.h>
++#include <asm/sev.h>
+ 
+ #include "x86.h"
+ #include "svm.h"
+@@ -75,6 +76,8 @@ static unsigned long sev_me_mask;
+ static unsigned long *sev_asid_bitmap;
+ static unsigned long *sev_reclaim_asid_bitmap;
+ 
++static int snp_decommission_context(struct kvm *kvm);
++
+ struct enc_region {
+ 	struct list_head list;
+ 	unsigned long npages;
+@@ -1527,6 +1530,100 @@ static int sev_receive_finish(struct kvm *kvm, struct kvm_sev_cmd *argp)
+ 	return sev_issue_cmd(kvm, SEV_CMD_RECEIVE_FINISH, &data, &argp->error);
  }
- EXPORT_SYMBOL_GPL(kvm_mmu_map_tdp_page);
- 
-+bool kvm_mmu_get_tdp_walk(struct kvm_vcpu *vcpu, gpa_t gpa, kvm_pfn_t *pfn, int *level)
-+{
-+	u64 sptes[PT64_ROOT_MAX_LEVEL + 1];
-+	int leaf, root;
-+
-+	if (is_tdp_mmu_root(vcpu->kvm, vcpu->arch.mmu->root_hpa))
-+		leaf = kvm_tdp_mmu_get_walk(vcpu, gpa, sptes, &root);
-+	else
-+		leaf = get_walk(vcpu, gpa, sptes, &root);
-+
-+	if (unlikely(leaf < 0))
-+		return false;
-+
-+	/* Check if the leaf SPTE is present */
-+	if (!is_shadow_present_pte(sptes[leaf]))
-+		return false;
-+
-+	*pfn = spte_to_pfn(sptes[leaf]);
-+	if (leaf > PG_LEVEL_4K) {
-+		u64 page_mask = KVM_PAGES_PER_HPAGE(leaf) - KVM_PAGES_PER_HPAGE(leaf - 1);
-+		*pfn |= (gpa_to_gfn(gpa) & page_mask);
+ 
++static void *snp_context_create(struct kvm *kvm, struct kvm_sev_cmd *argp)
++{
++	struct sev_data_snp_gctx_create data = {};
++	void *context;
++	int rc;
++
++	/* Allocate memory for context page */
++	context = snp_alloc_firmware_page(GFP_KERNEL_ACCOUNT);
++	if (!context)
++		return NULL;
++
++	data.gctx_paddr = __psp_pa(context);
++	rc = __sev_issue_cmd(argp->sev_fd, SEV_CMD_SNP_GCTX_CREATE, &data, &argp->error);
++	if (rc) {
++		snp_free_firmware_page(context);
++		return NULL;
 +	}
 +
-+	*level = leaf;
-+
-+	return true;
-+}
-+EXPORT_SYMBOL_GPL(kvm_mmu_get_tdp_walk);
-+
- static void nonpaging_init_context(struct kvm_vcpu *vcpu,
- 				   struct kvm_mmu *context)
++	return context;
++}
++
++static int snp_bind_asid(struct kvm *kvm, int *error)
++{
++	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
++	struct sev_data_snp_activate data = {};
++	int asid = sev_get_asid(kvm);
++	int ret, retry_count = 0;
++
++	/* Activate ASID on the given context */
++	data.gctx_paddr = __psp_pa(sev->snp_context);
++	data.asid   = asid;
++again:
++	ret = sev_issue_cmd(kvm, SEV_CMD_SNP_ACTIVATE, &data, error);
++
++	/* Check if the DF_FLUSH is required, and try again */
++	if (ret && (*error == SEV_RET_DFFLUSH_REQUIRED) && (!retry_count)) {
++		/* Guard DEACTIVATE against WBINVD/DF_FLUSH used in ASID recycling */
++		down_read(&sev_deactivate_lock);
++		wbinvd_on_all_cpus();
++		ret = snp_guest_df_flush(error);
++		up_read(&sev_deactivate_lock);
++
++		if (ret)
++			return ret;
++
++		/* only one retry */
++		retry_count = 1;
++
++		goto again;
++	}
++
++	return ret;
++}
++
++static int snp_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
++{
++	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
++	struct sev_data_snp_launch_start start = {};
++	struct kvm_sev_snp_launch_start params;
++	int rc;
++
++	if (!sev_snp_guest(kvm))
++		return -ENOTTY;
++
++	if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data, sizeof(params)))
++		return -EFAULT;
++
++	/* Initialize the guest context */
++	sev->snp_context = snp_context_create(kvm, argp);
++	if (!sev->snp_context)
++		return -ENOTTY;
++
++	/* Issue the LAUNCH_START command */
++	start.gctx_paddr = __psp_pa(sev->snp_context);
++	start.policy = params.policy;
++	memcpy(start.gosvw, params.gosvw, sizeof(params.gosvw));
++	rc = __sev_issue_cmd(argp->sev_fd, SEV_CMD_SNP_LAUNCH_START, &start, &argp->error);
++	if (rc)
++		goto e_free_context;
++
++	/* Bind ASID to this guest */
++	sev->fd = argp->sev_fd;
++	rc = snp_bind_asid(kvm, &argp->error);
++	if (rc)
++		goto e_free_context;
++
++	return 0;
++
++e_free_context:
++	snp_decommission_context(kvm);
++
++	return rc;
++}
++
+ int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
  {
+ 	struct kvm_sev_cmd sev_cmd;
+@@ -1616,6 +1713,9 @@ int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
+ 	case KVM_SEV_RECEIVE_FINISH:
+ 		r = sev_receive_finish(kvm, &sev_cmd);
+ 		break;
++	case KVM_SEV_SNP_LAUNCH_START:
++		r = snp_launch_start(kvm, &sev_cmd);
++		break;
+ 	default:
+ 		r = -EINVAL;
+ 		goto out;
+@@ -1809,6 +1909,28 @@ int svm_vm_copy_asid_from(struct kvm *kvm, unsigned int source_fd)
+ 	return ret;
+ }
+ 
++static int snp_decommission_context(struct kvm *kvm)
++{
++	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
++	struct sev_data_snp_decommission data = {};
++	int ret;
++
++	/* If context is not created then do nothing */
++	if (!sev->snp_context)
++		return 0;
++
++	data.gctx_paddr = __sme_pa(sev->snp_context);
++	ret = snp_guest_decommission(&data, NULL);
++	if (ret)
++		return ret;
++
++	/* free the context page now */
++	snp_free_firmware_page(sev->snp_context);
++	sev->snp_context = NULL;
++
++	return 0;
++}
++
+ void sev_vm_destroy(struct kvm *kvm)
+ {
+ 	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+@@ -1847,7 +1969,15 @@ void sev_vm_destroy(struct kvm *kvm)
+ 
+ 	mutex_unlock(&kvm->lock);
+ 
+-	sev_unbind_asid(kvm, sev->handle);
++	if (sev_snp_guest(kvm)) {
++		if (snp_decommission_context(kvm)) {
++			pr_err("Failed to free SNP guest context, leaking asid!\n");
++			return;
++		}
++	} else {
++		sev_unbind_asid(kvm, sev->handle);
++	}
++
+ 	sev_asid_free(sev);
+ }
+ 
+diff --git a/arch/x86/kvm/svm/svm.h b/arch/x86/kvm/svm/svm.h
+index b9ea99f8579e..bc5582b44356 100644
+--- a/arch/x86/kvm/svm/svm.h
++++ b/arch/x86/kvm/svm/svm.h
+@@ -67,6 +67,7 @@ struct kvm_sev_info {
+ 	u64 ap_jump_table;	/* SEV-ES AP Jump Table address */
+ 	struct kvm *enc_context_owner; /* Owner of copied encryption context */
+ 	struct misc_cg *misc_cg; /* For misc cgroup accounting */
++	void *snp_context;      /* SNP guest context page */
+ };
+ 
+ struct kvm_svm {
+diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
+index 989a64aa1ae5..dbd05179d8fa 100644
+--- a/include/uapi/linux/kvm.h
++++ b/include/uapi/linux/kvm.h
+@@ -1680,6 +1680,7 @@ enum sev_cmd_id {
+ 
+ 	/* SNP specific commands */
+ 	KVM_SEV_SNP_INIT = 256,
++	KVM_SEV_SNP_LAUNCH_START,
+ 
+ 	KVM_SEV_NR_MAX,
+ };
+@@ -1781,6 +1782,14 @@ struct kvm_snp_init {
+ 	__u64 flags;
+ };
+ 
++struct kvm_sev_snp_launch_start {
++	__u64 policy;
++	__u64 ma_uaddr;
++	__u8 ma_en;
++	__u8 imi_en;
++	__u8 gosvw[16];
++};
++
+ #define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0)
+ #define KVM_DEV_ASSIGN_PCI_2_3		(1 << 1)
+ #define KVM_DEV_ASSIGN_MASK_INTX	(1 << 2)
 -- 
 2.17.1
 
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help