Inter-revision diff: patch 27

Comparing v3 (message) to v5 (message)

--- v3
+++ v5
@@ -1,43 +1,232 @@
-When SEV-SNP is enabled globally, the hardware places restrictions on all
-memory accesses based on the RMP entry, whether the hyperviso or a VM,
-performs the accesses. When hardware encounters an RMP access violation
-during a guest access, it will cause a #VMEXIT(NPF).
-
-See APM2 section 16.36.10 for more details.
+The KVM_SEV_SNP_LAUNCH_FINISH finalize the cryptographic digest and stores
+it as the measurement of the guest at launch.
+
+While finalizing the launch flow, it also issues the LAUNCH_UPDATE command
+to encrypt the VMSA pages.
 
 Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
 ---
- arch/x86/include/asm/kvm_host.h | 8 ++++++++
- 1 file changed, 8 insertions(+)
-
-diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
-index cd2e19e1d323..59185b6bc82a 100644
---- a/arch/x86/include/asm/kvm_host.h
-+++ b/arch/x86/include/asm/kvm_host.h
-@@ -239,8 +239,12 @@ enum x86_intercept_stage;
- #define PFERR_FETCH_BIT 4
- #define PFERR_PK_BIT 5
- #define PFERR_SGX_BIT 15
-+#define PFERR_GUEST_RMP_BIT 31
- #define PFERR_GUEST_FINAL_BIT 32
- #define PFERR_GUEST_PAGE_BIT 33
-+#define PFERR_GUEST_ENC_BIT 34
-+#define PFERR_GUEST_SIZEM_BIT 35
-+#define PFERR_GUEST_VMPL_BIT 36
- 
- #define PFERR_PRESENT_MASK (1U << PFERR_PRESENT_BIT)
- #define PFERR_WRITE_MASK (1U << PFERR_WRITE_BIT)
-@@ -251,6 +255,10 @@ enum x86_intercept_stage;
- #define PFERR_SGX_MASK (1U << PFERR_SGX_BIT)
- #define PFERR_GUEST_FINAL_MASK (1ULL << PFERR_GUEST_FINAL_BIT)
- #define PFERR_GUEST_PAGE_MASK (1ULL << PFERR_GUEST_PAGE_BIT)
-+#define PFERR_GUEST_RMP_MASK (1ULL << PFERR_GUEST_RMP_BIT)
-+#define PFERR_GUEST_ENC_MASK (1ULL << PFERR_GUEST_ENC_BIT)
-+#define PFERR_GUEST_SIZEM_MASK (1ULL << PFERR_GUEST_SIZEM_BIT)
-+#define PFERR_GUEST_VMPL_MASK (1ULL << PFERR_GUEST_VMPL_BIT)
- 
- #define PFERR_NESTED_GUEST_PAGE (PFERR_GUEST_PAGE_MASK |	\
- 				 PFERR_WRITE_MASK |		\
+ .../virt/kvm/amd-memory-encryption.rst        |  22 ++++
+ arch/x86/kvm/svm/sev.c                        | 116 ++++++++++++++++++
+ include/uapi/linux/kvm.h                      |  14 +++
+ 3 files changed, 152 insertions(+)
+
+diff --git a/Documentation/virt/kvm/amd-memory-encryption.rst b/Documentation/virt/kvm/amd-memory-encryption.rst
+index ddcd94e9ffed..c7332e0e0baa 100644
+--- a/Documentation/virt/kvm/amd-memory-encryption.rst
++++ b/Documentation/virt/kvm/amd-memory-encryption.rst
+@@ -506,6 +506,28 @@ Returns: 0 on success, -negative on error
+ See the SEV-SNP spec for further details on how to build the VMPL permission
+ mask and page type.
+ 
++21. KVM_SNP_LAUNCH_FINISH
++-------------------------
++
++After completion of the SNP guest launch flow, the KVM_SNP_LAUNCH_FINISH command can be
++issued to make the guest ready for the execution.
++
++Parameters (in): struct kvm_sev_snp_launch_finish
++
++Returns: 0 on success, -negative on error
++
++::
++
++        struct kvm_sev_snp_launch_finish {
++                __u64 id_block_uaddr;
++                __u64 id_auth_uaddr;
++                __u8 id_block_en;
++                __u8 auth_key_en;
++                __u8 host_data[32];
++        };
++
++
++See SEV-SNP specification for further details on launch finish input parameters.
+ 
+ References
+ ==========
+diff --git a/arch/x86/kvm/svm/sev.c b/arch/x86/kvm/svm/sev.c
+index dcef0ae5f8e4..248096a5c307 100644
+--- a/arch/x86/kvm/svm/sev.c
++++ b/arch/x86/kvm/svm/sev.c
+@@ -1813,6 +1813,106 @@ static int snp_launch_update(struct kvm *kvm, struct kvm_sev_cmd *argp)
+ 	return ret;
+ }
+ 
++static int snp_launch_update_vmsa(struct kvm *kvm, struct kvm_sev_cmd *argp)
++{
++	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
++	struct sev_data_snp_launch_update data = {};
++	int i, ret;
++
++	data.gctx_paddr = __psp_pa(sev->snp_context);
++	data.page_type = SNP_PAGE_TYPE_VMSA;
++
++	for (i = 0; i < kvm->created_vcpus; i++) {
++		struct vcpu_svm *svm = to_svm(kvm->vcpus[i]);
++		u64 pfn = __pa(svm->vmsa) >> PAGE_SHIFT;
++
++		/* Perform some pre-encryption checks against the VMSA */
++		ret = sev_es_sync_vmsa(svm);
++		if (ret)
++			return ret;
++
++		/* Transition the VMSA page to a firmware state. */
++		ret = rmp_make_private(pfn, -1, PG_LEVEL_4K, sev->asid, true);
++		if (ret)
++			return ret;
++
++		/* Issue the SNP command to encrypt the VMSA */
++		data.address = __sme_pa(svm->vmsa);
++		ret = __sev_issue_cmd(argp->sev_fd, SEV_CMD_SNP_LAUNCH_UPDATE,
++				      &data, &argp->error);
++		if (ret) {
++			snp_page_reclaim(pfn);
++			return ret;
++		}
++
++		svm->vcpu.arch.guest_state_protected = true;
++	}
++
++	return 0;
++}
++
++static int snp_launch_finish(struct kvm *kvm, struct kvm_sev_cmd *argp)
++{
++	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
++	struct sev_data_snp_launch_finish *data;
++	void *id_block = NULL, *id_auth = NULL;
++	struct kvm_sev_snp_launch_finish params;
++	int ret;
++
++	if (!sev_snp_guest(kvm))
++		return -ENOTTY;
++
++	if (!sev->snp_context)
++		return -EINVAL;
++
++	if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data, sizeof(params)))
++		return -EFAULT;
++
++	/* Measure all vCPUs using LAUNCH_UPDATE before we finalize the launch flow. */
++	ret = snp_launch_update_vmsa(kvm, argp);
++	if (ret)
++		return ret;
++
++	data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
++	if (!data)
++		return -ENOMEM;
++
++	if (params.id_block_en) {
++		id_block = psp_copy_user_blob(params.id_block_uaddr, KVM_SEV_SNP_ID_BLOCK_SIZE);
++		if (IS_ERR(id_block)) {
++			ret = PTR_ERR(id_block);
++			goto e_free;
++		}
++
++		data->id_block_en = 1;
++		data->id_block_paddr = __sme_pa(id_block);
++	}
++
++	if (params.auth_key_en) {
++		id_auth = psp_copy_user_blob(params.id_auth_uaddr, KVM_SEV_SNP_ID_AUTH_SIZE);
++		if (IS_ERR(id_auth)) {
++			ret = PTR_ERR(id_auth);
++			goto e_free_id_block;
++		}
++
++		data->auth_key_en = 1;
++		data->id_auth_paddr = __sme_pa(id_auth);
++	}
++
++	data->gctx_paddr = __psp_pa(sev->snp_context);
++	ret = sev_issue_cmd(kvm, SEV_CMD_SNP_LAUNCH_FINISH, data, &argp->error);
++
++	kfree(id_auth);
++
++e_free_id_block:
++	kfree(id_block);
++
++e_free:
++	kfree(data);
++
++	return ret;
++}
++
+ int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
+ {
+ 	struct kvm_sev_cmd sev_cmd;
+@@ -1908,6 +2008,9 @@ int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
+ 	case KVM_SEV_SNP_LAUNCH_UPDATE:
+ 		r = snp_launch_update(kvm, &sev_cmd);
+ 		break;
++	case KVM_SEV_SNP_LAUNCH_FINISH:
++		r = snp_launch_finish(kvm, &sev_cmd);
++		break;
+ 	default:
+ 		r = -EINVAL;
+ 		goto out;
+@@ -2364,16 +2467,29 @@ static void sev_flush_guest_memory(struct vcpu_svm *svm, void *va,
+ void sev_free_vcpu(struct kvm_vcpu *vcpu)
+ {
+ 	struct vcpu_svm *svm;
++	u64 pfn;
+ 
+ 	if (!sev_es_guest(vcpu->kvm))
+ 		return;
+ 
+ 	svm = to_svm(vcpu);
++	pfn = __pa(svm->vmsa) >> PAGE_SHIFT;
+ 
+ 	if (vcpu->arch.guest_state_protected)
+ 		sev_flush_guest_memory(svm, svm->vmsa, PAGE_SIZE);
++
++	/*
++	 * If its an SNP guest, then VMSA was added in the RMP entry as
++	 * a guest owned page. Transition the page to hyperivosr state
++	 * before releasing it back to the system.
++	 */
++	if (sev_snp_guest(vcpu->kvm) &&
++	    host_rmp_make_shared(pfn, PG_LEVEL_4K, false))
++		goto skip_vmsa_free;
++
+ 	__free_page(virt_to_page(svm->vmsa));
+ 
++skip_vmsa_free:
+ 	if (svm->ghcb_sa_free)
+ 		kfree(svm->ghcb_sa);
+ }
+diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
+index 0681be4bdfdf..ab9b1c82b0ee 100644
+--- a/include/uapi/linux/kvm.h
++++ b/include/uapi/linux/kvm.h
+@@ -1716,6 +1716,7 @@ enum sev_cmd_id {
+ 	KVM_SEV_SNP_INIT,
+ 	KVM_SEV_SNP_LAUNCH_START,
+ 	KVM_SEV_SNP_LAUNCH_UPDATE,
++	KVM_SEV_SNP_LAUNCH_FINISH,
+ 
+ 	KVM_SEV_NR_MAX,
+ };
+@@ -1850,6 +1851,19 @@ struct kvm_sev_snp_launch_update {
+ 	__u8 vmpl1_perms;
+ };
+ 
++#define KVM_SEV_SNP_ID_BLOCK_SIZE	96
++#define KVM_SEV_SNP_ID_AUTH_SIZE	4096
++#define KVM_SEV_SNP_FINISH_DATA_SIZE	32
++
++struct kvm_sev_snp_launch_finish {
++	__u64 id_block_uaddr;
++	__u64 id_auth_uaddr;
++	__u8 id_block_en;
++	__u8 auth_key_en;
++	__u8 host_data[KVM_SEV_SNP_FINISH_DATA_SIZE];
++	__u8 pad[6];
++};
++
+ #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