linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH v1 00/10] Add AMD SEV guest live migration support
@ 2019-04-24 16:09 Singh, Brijesh
  2019-04-24 16:09 ` [RFC PATCH v1 01/10] KVM: SVM: Add KVM_SEV SEND_START command Singh, Brijesh
                   ` (10 more replies)
  0 siblings, 11 replies; 27+ messages in thread
From: Singh, Brijesh @ 2019-04-24 16:09 UTC (permalink / raw)
  To: kvm
  Cc: qemu-devel, Singh, Brijesh, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Borislav Petkov, Lendacky, Thomas, x86,
	linux-kernel

The series add support for AMD SEV guest live migration commands. To protect the
confidentiality of an SEV protected guest memory while in transit we need to
use the SEV commands defined in SEV API spec [1].

SEV guest VMs have the concept of private and shared memory. Private memory
is encrypted with the guest-specific key, while shared memory may be encrypted
with hypervisor key. The commands provided by the SEV FW are meant to be used
for the private memory only. The patch series introduces a new hypercall.
The guest OS can use this hypercall to notify the page encryption status.
If the page is encrypted with guest specific-key then we use SEV command during
the migration. If page is not encrypted then fallback to default.

The patch adds a new ioctl KVM_GET_PAGE_ENC_BITMAP. The ioctl can be used
by the qemu to get the page encrypted bitmap. Qemu can consult this bitmap
during the migration to know whether the page is encrypted.

[1] https://developer.amd.com/wp-content/resources/55766.PDF

The series is tested with the Qemu, I am in process of cleaning
up the Qemu code and will submit soon.

While implementing the migration I stumbled on the follow question:

- Since there is a guest OS changes required to support the migration,
  so how do we know whether guest OS is updated? Should we extend KVM
  capabilities/feature bits to check this?

TODO:
 - add an ioctl to build encryption bitmap. The encryption bitmap is built during
   the guest bootup/execution. We should provide an ioctl so that destination
   can build the bitmap as it receives the pages. 
 - reset the bitmap on guest reboot.

The complete tree with patch is available at:
https://github.com/codomania/kvm/tree/sev-migration-rfc-v1

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: "Radim Krčmář" <rkrcmar@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

Brijesh Singh (10):
  KVM: SVM: Add KVM_SEV SEND_START command
  KVM: SVM: Add KVM_SEND_UPDATE_DATA command
  KVM: SVM: Add KVM_SEV_SEND_FINISH command
  KVM: SVM: Add support for KVM_SEV_RECEIVE_START command
  KVM: SVM: Add KVM_SEV_RECEIVE_UPDATE_DATA command
  KVM: SVM: Add KVM_SEV_RECEIVE_FINISH command
  KVM: x86: Add AMD SEV specific Hypercall3
  KVM: X86: Introduce KVM_HC_PAGE_ENC_STATUS hypercall
  KVM: x86: Introduce KVM_GET_PAGE_ENC_BITMAP ioctl
  mm: x86: Invoke hypercall when page encryption status is changed

 .../virtual/kvm/amd-memory-encryption.rst     | 116 ++++
 Documentation/virtual/kvm/hypercalls.txt      |  14 +
 arch/x86/include/asm/kvm_host.h               |   3 +
 arch/x86/include/asm/kvm_para.h               |  12 +
 arch/x86/include/asm/mem_encrypt.h            |   3 +
 arch/x86/kvm/svm.c                            | 560 +++++++++++++++++-
 arch/x86/kvm/vmx/vmx.c                        |   1 +
 arch/x86/kvm/x86.c                            |  17 +
 arch/x86/mm/mem_encrypt.c                     |  45 +-
 arch/x86/mm/pageattr.c                        |  15 +
 include/uapi/linux/kvm.h                      |  51 ++
 include/uapi/linux/kvm_para.h                 |   1 +
 12 files changed, 834 insertions(+), 4 deletions(-)

-- 
2.17.1


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

* [RFC PATCH v1 01/10] KVM: SVM: Add KVM_SEV SEND_START command
  2019-04-24 16:09 [RFC PATCH v1 00/10] Add AMD SEV guest live migration support Singh, Brijesh
@ 2019-04-24 16:09 ` Singh, Brijesh
  2019-04-26 14:10   ` Borislav Petkov
  2019-04-24 16:10 ` [RFC PATCH v1 02/10] KVM: SVM: Add KVM_SEND_UPDATE_DATA command Singh, Brijesh
                   ` (9 subsequent siblings)
  10 siblings, 1 reply; 27+ messages in thread
From: Singh, Brijesh @ 2019-04-24 16:09 UTC (permalink / raw)
  To: kvm
  Cc: qemu-devel, Singh, Brijesh, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Borislav Petkov, Lendacky, Thomas, x86,
	linux-kernel

The command is used to create an outgoing SEV guest encryption context.

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: "Radim Krčmář" <rkrcmar@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
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 .../virtual/kvm/amd-memory-encryption.rst     |  24 +++++
 arch/x86/kvm/svm.c                            | 101 ++++++++++++++++++
 include/uapi/linux/kvm.h                      |  12 +++
 3 files changed, 137 insertions(+)

diff --git a/Documentation/virtual/kvm/amd-memory-encryption.rst b/Documentation/virtual/kvm/amd-memory-encryption.rst
index 659bbc093b52..340ac4f87321 100644
--- a/Documentation/virtual/kvm/amd-memory-encryption.rst
+++ b/Documentation/virtual/kvm/amd-memory-encryption.rst
@@ -238,6 +238,30 @@ Returns: 0 on success, -negative on error
                 __u32 trans_len;
         };
 
+10. KVM_SEV_SEND_START
+----------------------
+
+The KVM_SEV_SEND_START command can be used by the hypervisor to create an
+outgoing guest encryption context.
+
+Parameters (in): struct kvm_sev_send_start
+
+Returns: 0 on success, -negative on error
+
+::
+        struct kvm_sev_send_start {
+                __u32 policy;                 /* guest policy */
+
+                __u64 pdh_cert_uaddr;         /* platform Diffie-Hellman certificate */
+                __u32 pdh_cert_len;
+
+                __u64 plat_cert_uaddr;        /* platform certificate chain */
+                __u32 plat_cert_len;
+
+                __u64 amd_cert_uaddr;         /* AMD certificate */
+                __u32 amd_cert_len;
+        };
+
 References
 ==========
 
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 406b558abfef..4c2a225ba546 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -6955,6 +6955,104 @@ static int sev_launch_secret(struct kvm *kvm, struct kvm_sev_cmd *argp)
 	return ret;
 }
 
+static int sev_send_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
+{
+	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+	void *amd_cert = NULL, *session_data = NULL;
+	void *pdh_cert = NULL, *plat_cert = NULL;
+	struct sev_data_send_start *data = NULL;
+	struct kvm_sev_send_start params;
+	int ret;
+
+	if (!sev_guest(kvm))
+		return -ENOTTY;
+
+	if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data,
+				sizeof(struct kvm_sev_send_start)))
+		return -EFAULT;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	/* userspace wants to query the session length */
+	if (!params.session_len)
+		goto cmd;
+
+	if (!params.pdh_cert_uaddr || !params.pdh_cert_len ||
+	    !params.session_uaddr)
+		return -EINVAL;
+
+	/* copy the certificate blobs from userspace */
+	pdh_cert = psp_copy_user_blob(params.pdh_cert_uaddr, params.pdh_cert_len);
+	if (IS_ERR(pdh_cert)) {
+		ret = PTR_ERR(pdh_cert);
+		goto e_free;
+	}
+
+	data->pdh_cert_address = __psp_pa(pdh_cert);
+	data->pdh_cert_len = params.pdh_cert_len;
+
+	plat_cert = psp_copy_user_blob(params.plat_cert_uaddr, params.plat_cert_len);
+	if (IS_ERR(plat_cert)) {
+		ret = PTR_ERR(plat_cert);
+		goto e_free_pdh;
+	}
+
+	data->plat_cert_address = __psp_pa(plat_cert);
+	data->plat_cert_len = params.plat_cert_len;
+
+	amd_cert = psp_copy_user_blob(params.amd_cert_uaddr, params.amd_cert_len);
+	if (IS_ERR(amd_cert)) {
+		ret = PTR_ERR(amd_cert);
+		goto e_free_plat_cert;
+	}
+
+	data->amd_cert_address = __psp_pa(amd_cert);
+	data->amd_cert_len = params.amd_cert_len;
+
+	ret = -ENOMEM;
+	session_data = kmalloc(params.session_len, GFP_KERNEL);
+	if (!session_data)
+		goto e_free_amd_cert;
+
+	data->session_address = __psp_pa(session_data);
+	data->session_len = params.session_len;
+cmd:
+	data->handle = sev->handle;
+	ret = sev_issue_cmd(kvm, SEV_CMD_SEND_START, data, &argp->error);
+
+	/* if we queried the session length, FW responded with expected data */
+	if (!params.session_len)
+		goto done;
+
+	if (copy_to_user((void __user *)(uintptr_t) params.session_uaddr,
+			session_data, params.session_len)) {
+		ret = -EFAULT;
+		goto e_free_session;
+	}
+
+	params.policy = data->policy;
+
+done:
+	params.session_len = data->session_len;
+	if (copy_to_user((void __user *)(uintptr_t)argp->data, &params,
+				sizeof(struct kvm_sev_send_start)))
+		ret = -EFAULT;
+
+e_free_session:
+	kfree(session_data);
+e_free_amd_cert:
+	kfree(amd_cert);
+e_free_plat_cert:
+	kfree(plat_cert);
+e_free_pdh:
+	kfree(pdh_cert);
+e_free:
+	kfree(data);
+	return ret;
+}
+
 static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
 {
 	struct kvm_sev_cmd sev_cmd;
@@ -6996,6 +7094,9 @@ static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
 	case KVM_SEV_LAUNCH_SECRET:
 		r = sev_launch_secret(kvm, &sev_cmd);
 		break;
+	case KVM_SEV_SEND_START:
+		r = sev_send_start(kvm, &sev_cmd);
+		break;
 	default:
 		r = -EINVAL;
 		goto out;
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 6d4ea4b6c922..f425418bec13 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1520,6 +1520,18 @@ struct kvm_sev_dbg {
 	__u32 len;
 };
 
+struct kvm_sev_send_start {
+	__u32 policy;
+	__u64 pdh_cert_uaddr;
+	__u32 pdh_cert_len;
+	__u64 plat_cert_uaddr;
+	__u32 plat_cert_len;
+	__u64 amd_cert_uaddr;
+	__u32 amd_cert_len;
+	__u64 session_uaddr;
+	__u32 session_len;
+};
+
 #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


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

* [RFC PATCH v1 02/10] KVM: SVM: Add KVM_SEND_UPDATE_DATA command
  2019-04-24 16:09 [RFC PATCH v1 00/10] Add AMD SEV guest live migration support Singh, Brijesh
  2019-04-24 16:09 ` [RFC PATCH v1 01/10] KVM: SVM: Add KVM_SEV SEND_START command Singh, Brijesh
@ 2019-04-24 16:10 ` Singh, Brijesh
  2019-04-26 20:31   ` Lendacky, Thomas
  2019-04-24 16:10 ` [RFC PATCH v1 03/10] KVM: SVM: Add KVM_SEV_SEND_FINISH command Singh, Brijesh
                   ` (8 subsequent siblings)
  10 siblings, 1 reply; 27+ messages in thread
From: Singh, Brijesh @ 2019-04-24 16:10 UTC (permalink / raw)
  To: kvm
  Cc: qemu-devel, Singh, Brijesh, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Borislav Petkov, Lendacky, Thomas, x86,
	linux-kernel

The command is used for encrypting the guest memory region using the encryption
context created with KVM_SEV_SEND_START.

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: "Radim Krčmář" <rkrcmar@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
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 .../virtual/kvm/amd-memory-encryption.rst     |  23 ++++
 arch/x86/kvm/svm.c                            | 128 +++++++++++++++++-
 include/uapi/linux/kvm.h                      |   9 ++
 3 files changed, 157 insertions(+), 3 deletions(-)

diff --git a/Documentation/virtual/kvm/amd-memory-encryption.rst b/Documentation/virtual/kvm/amd-memory-encryption.rst
index 340ac4f87321..a0208e171489 100644
--- a/Documentation/virtual/kvm/amd-memory-encryption.rst
+++ b/Documentation/virtual/kvm/amd-memory-encryption.rst
@@ -262,6 +262,29 @@ Returns: 0 on success, -negative on error
                 __u32 amd_cert_len;
         };
 
+11. KVM_SEV_SEND_UPDATE_DATA
+----------------------------
+
+The KVM_SEV_SEND_UPDATE_DATA command can be used by the hypervisor to encrypt the
+outgoing guest memory region with encryption context creating using KVM_SEV_SEND_START.
+
+Parameters (in): struct kvm_sev_send_update_data
+
+Returns: 0 on success, -negative on error
+
+::
+
+        struct kvm_sev_launch_send_update_data {
+                __u64 hdr_uaddr;        /* userspace address containing the packet header */
+                __u32 hdr_len;
+
+                __u64 guest_uaddr;      /* the source memory region to be encrypted */
+                __u32 guest_len;
+
+                __u64 trans_uaddr;      /* the destition memory region  */
+                __u32 trans_len;
+        };
+
 References
 ==========
 
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 4c2a225ba546..a1cfd36d6195 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -418,6 +418,7 @@ enum {
 
 static unsigned int max_sev_asid;
 static unsigned int min_sev_asid;
+static unsigned long me_mask;
 static unsigned long *sev_asid_bitmap;
 #define __sme_page_pa(x) __sme_set(page_to_pfn(x) << PAGE_SHIFT)
 
@@ -1216,15 +1217,21 @@ static int avic_ga_log_notifier(u32 ga_tag)
 static __init int sev_hardware_setup(void)
 {
 	struct sev_user_data_status *status;
+	int eax, ebx;
 	int rc;
 
-	/* Maximum number of encrypted guests supported simultaneously */
-	max_sev_asid = cpuid_ecx(0x8000001F);
+	/*
+	 * Query the memory encryption information.
+	 *  EBX:  Bit 0:5 Pagetable bit position used to indicate encryption (aka Cbit).
+	 *  ECX:  Maximum number of encrypted guests supported simultaneously.
+	 *  EDX:  Minimum ASID value that should be used for SEV guest.
+	 */
+	cpuid(0x8000001f, &eax, &ebx, &max_sev_asid, &min_sev_asid);
 
 	if (!max_sev_asid)
 		return 1;
 
-	/* Minimum ASID value that should be used for SEV guest */
+	me_mask = 1UL << (ebx & 0x3f);
 	min_sev_asid = cpuid_edx(0x8000001F);
 
 	/* Initialize SEV ASID bitmap */
@@ -7053,6 +7060,118 @@ static int sev_send_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
 	return ret;
 }
 
+static int sev_send_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)
+{
+	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+	struct sev_data_send_update_data *data;
+	struct kvm_sev_send_update_data params;
+	void *hdr = NULL, *trans_data = NULL;
+	struct page **guest_page = NULL;
+	unsigned long n;
+	int ret, offset;
+
+	if (!sev_guest(kvm))
+		return -ENOTTY;
+
+	if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data,
+			sizeof(struct kvm_sev_send_update_data)))
+		return -EFAULT;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	/* userspace wants to query either header or trans length */
+	if (!params.trans_len || !params.hdr_len)
+		goto cmd;
+
+	ret = -EINVAL;
+	if (!params.trans_uaddr || !params.guest_uaddr ||
+	    !params.guest_len || !params.hdr_uaddr)
+		goto e_free;
+
+	/* Check if we are crossing the page boundry */
+	ret = -EINVAL;
+	offset = params.guest_uaddr & (PAGE_SIZE - 1);
+	if ((params.guest_len + offset > PAGE_SIZE))
+		goto e_free;
+
+	ret = -ENOMEM;
+	hdr = kmalloc(params.hdr_len, GFP_KERNEL);
+	if (!hdr)
+		goto e_free;
+
+	data->hdr_address = __psp_pa(hdr);
+	data->hdr_len = params.hdr_len;
+
+	ret = -ENOMEM;
+	trans_data = kmalloc(params.trans_len, GFP_KERNEL);
+	if (!trans_data)
+		goto e_free;
+
+	data->trans_address = __psp_pa(trans_data);
+	data->trans_len = params.trans_len;
+
+	/* Pin guest memory */
+	ret = -EFAULT;
+	guest_page = sev_pin_memory(kvm, params.guest_uaddr & PAGE_MASK,
+				    PAGE_SIZE, &n, 0);
+	if (!guest_page)
+		goto e_free;
+
+	data->guest_address = __sme_page_pa(guest_page[0]) + offset;
+	data->guest_len = params.guest_len;
+
+	/*
+	 * The SEND_UPDATE_DATA command requires C-bit to be always set.
+	 * The __sme_page_pa() takes care of setting the C-bit only when SME
+	 * is enabled on the host. But we need to set the C-bit regarless of
+	 * the SME state.
+	 */
+	data->guest_address |= me_mask;
+
+	/* flush the caches to ensure that DRAM has recent contents */
+	sev_clflush_pages(guest_page, 1);
+
+cmd:
+	data->handle = sev->handle;
+	ret = sev_issue_cmd(kvm, SEV_CMD_SEND_UPDATE_DATA, data, &argp->error);
+
+	/* userspace asked for header or trans length and FW responded with data */
+	if (!params.trans_len || !params.hdr_len) {
+		params.hdr_len = data->hdr_len;
+		params.trans_len = data->trans_len;
+		goto done;
+	}
+
+	if (ret)
+		goto e_unpin;
+
+	/* copy transport buffer to user space */
+	if (copy_to_user((void __user *)(uintptr_t)params.trans_uaddr,
+			 trans_data, params.trans_len)) {
+		ret = -EFAULT;
+		goto e_unpin;
+	}
+
+	/* copy packet header to userspace */
+	if (copy_to_user((void __user *)(uintptr_t)params.hdr_uaddr, hdr, params.hdr_len))
+		ret = -EFAULT;
+
+e_unpin:
+	sev_unpin_memory(kvm, guest_page, n);
+done:
+	if (copy_to_user((void __user *)(uintptr_t)argp->data, &params,
+			sizeof(struct kvm_sev_send_update_data)))
+		ret = -EFAULT;
+e_free:
+	kfree(data);
+	kfree(trans_data);
+	kfree(hdr);
+
+	return ret;
+}
+
 static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
 {
 	struct kvm_sev_cmd sev_cmd;
@@ -7097,6 +7216,9 @@ static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
 	case KVM_SEV_SEND_START:
 		r = sev_send_start(kvm, &sev_cmd);
 		break;
+	case KVM_SEV_SEND_UPDATE_DATA:
+		r = sev_send_update_data(kvm, &sev_cmd);
+		break;
 	default:
 		r = -EINVAL;
 		goto out;
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index f425418bec13..0bee91bba329 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1532,6 +1532,15 @@ struct kvm_sev_send_start {
 	__u32 session_len;
 };
 
+struct kvm_sev_send_update_data {
+	__u64 hdr_uaddr;
+	__u32 hdr_len;
+	__u64 guest_uaddr;
+	__u32 guest_len;
+	__u64 trans_uaddr;
+	__u32 trans_len;
+};
+
 #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


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

* [RFC PATCH v1 03/10] KVM: SVM: Add KVM_SEV_SEND_FINISH command
  2019-04-24 16:09 [RFC PATCH v1 00/10] Add AMD SEV guest live migration support Singh, Brijesh
  2019-04-24 16:09 ` [RFC PATCH v1 01/10] KVM: SVM: Add KVM_SEV SEND_START command Singh, Brijesh
  2019-04-24 16:10 ` [RFC PATCH v1 02/10] KVM: SVM: Add KVM_SEND_UPDATE_DATA command Singh, Brijesh
@ 2019-04-24 16:10 ` Singh, Brijesh
  2019-04-24 16:10 ` [RFC PATCH v1 04/10] KVM: SVM: Add support for KVM_SEV_RECEIVE_START command Singh, Brijesh
                   ` (7 subsequent siblings)
  10 siblings, 0 replies; 27+ messages in thread
From: Singh, Brijesh @ 2019-04-24 16:10 UTC (permalink / raw)
  To: kvm
  Cc: qemu-devel, Singh, Brijesh, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Borislav Petkov, Lendacky, Thomas, x86,
	linux-kernel

The command is used to finailize the encryption context created with
KVM_SEV_SEND_START command.

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: "Radim Krčmář" <rkrcmar@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
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 .../virtual/kvm/amd-memory-encryption.rst     |  8 +++++++
 arch/x86/kvm/svm.c                            | 23 +++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/Documentation/virtual/kvm/amd-memory-encryption.rst b/Documentation/virtual/kvm/amd-memory-encryption.rst
index a0208e171489..006832256ae3 100644
--- a/Documentation/virtual/kvm/amd-memory-encryption.rst
+++ b/Documentation/virtual/kvm/amd-memory-encryption.rst
@@ -285,6 +285,14 @@ Returns: 0 on success, -negative on error
                 __u32 trans_len;
         };
 
+12. KVM_SEV_SEND_FINISH
+------------------------
+
+After completion of the migration flow, the KVM_SEV_SEND_FINISH command can be
+issued by the hypervisor to delete the encryption context.
+
+Returns: 0 on success, -negative on error
+
 References
 ==========
 
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index a1cfd36d6195..263f3c7deae7 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -7172,6 +7172,26 @@ static int sev_send_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)
 	return ret;
 }
 
+static int sev_send_finish(struct kvm *kvm, struct kvm_sev_cmd *argp)
+{
+	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+	struct sev_data_send_finish *data;
+	int ret;
+
+	if (!sev_guest(kvm))
+		return -ENOTTY;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->handle = sev->handle;
+	ret = sev_issue_cmd(kvm, SEV_CMD_SEND_FINISH, data, &argp->error);
+
+	kfree(data);
+	return ret;
+}
+
 static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
 {
 	struct kvm_sev_cmd sev_cmd;
@@ -7219,6 +7239,9 @@ static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
 	case KVM_SEV_SEND_UPDATE_DATA:
 		r = sev_send_update_data(kvm, &sev_cmd);
 		break;
+	case KVM_SEV_SEND_FINISH:
+		r = sev_send_finish(kvm, &sev_cmd);
+		break;
 	default:
 		r = -EINVAL;
 		goto out;
-- 
2.17.1


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

* [RFC PATCH v1 04/10] KVM: SVM: Add support for KVM_SEV_RECEIVE_START command
  2019-04-24 16:09 [RFC PATCH v1 00/10] Add AMD SEV guest live migration support Singh, Brijesh
                   ` (2 preceding siblings ...)
  2019-04-24 16:10 ` [RFC PATCH v1 03/10] KVM: SVM: Add KVM_SEV_SEND_FINISH command Singh, Brijesh
@ 2019-04-24 16:10 ` Singh, Brijesh
  2019-04-26 21:08   ` Lendacky, Thomas
  2019-04-24 16:10 ` [RFC PATCH v1 05/10] KVM: SVM: Add KVM_SEV_RECEIVE_UPDATE_DATA command Singh, Brijesh
                   ` (6 subsequent siblings)
  10 siblings, 1 reply; 27+ messages in thread
From: Singh, Brijesh @ 2019-04-24 16:10 UTC (permalink / raw)
  To: kvm
  Cc: qemu-devel, Singh, Brijesh, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Borislav Petkov, Lendacky, Thomas, x86,
	linux-kernel

The command is used to create encryption context for the incoming
SEV guest. The encryption context can be later unused by the hypervisor
to import the incoming data into the SEV guest memory space.

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: "Radim Krčmář" <rkrcmar@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
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 .../virtual/kvm/amd-memory-encryption.rst     | 29 +++++++
 arch/x86/kvm/svm.c                            | 80 +++++++++++++++++++
 include/uapi/linux/kvm.h                      |  9 +++
 3 files changed, 118 insertions(+)

diff --git a/Documentation/virtual/kvm/amd-memory-encryption.rst b/Documentation/virtual/kvm/amd-memory-encryption.rst
index 006832256ae3..acdff2454649 100644
--- a/Documentation/virtual/kvm/amd-memory-encryption.rst
+++ b/Documentation/virtual/kvm/amd-memory-encryption.rst
@@ -293,6 +293,35 @@ issued by the hypervisor to delete the encryption context.
 
 Returns: 0 on success, -negative on error
 
+13. KVM_SEV_RECEIVE_START
+------------------------
+
+The KVM_SEV_RECEIVE_START command is used for creating the memory encryption
+context for an incoming SEV guest. To create the encryption context, user must
+provide a guest policy, the platform public Diffie-Hellman (PDH) key and session
+information.
+
+Parameters: struct  kvm_sev_receive_start (in/out)
+
+Returns: 0 on success, -negative on error
+
+::
+
+        struct kvm_sev_receive_start {
+                __u32 handle;           /* if zero then firmware creates a new handle */
+                __u32 policy;           /* guest's policy */
+
+                __u64 pdh_uaddr;         /* userspace address pointing to the PDH key */
+                __u32 dh_len;
+
+                __u64 session_addr;     /* userspace address which points to the guest session information */
+                __u32 session_len;
+        };
+
+On success, the 'handle' field contains a new handle and on error, a negative value.
+
+For more details, see SEV spec Section 6.12.
+
 References
 ==========
 
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 263f3c7deae7..a7dcf19baefb 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -7192,6 +7192,83 @@ static int sev_send_finish(struct kvm *kvm, struct kvm_sev_cmd *argp)
 	return ret;
 }
 
+static int sev_receive_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
+{
+	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+	struct sev_data_receive_start *start;
+	struct kvm_sev_receive_start params;
+	int *error = &argp->error;
+	void *session_data = NULL;
+	void *pdh_data = NULL;
+	int ret;
+
+	if (!sev_guest(kvm))
+		return -ENOTTY;
+
+	/* Get parameter from the user */
+	if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data,
+			sizeof(struct kvm_sev_receive_start)))
+		return -EFAULT;
+
+	if (!params.pdh_uaddr || !params.pdh_len ||
+	    !params.session_uaddr || !params.session_len)
+		return -EINVAL;
+
+	start = kzalloc(sizeof(*start), GFP_KERNEL);
+	if (!start)
+		return -ENOMEM;
+
+	start->handle = params.handle;
+	start->policy = params.policy;
+
+	pdh_data = psp_copy_user_blob(params.pdh_uaddr, params.pdh_len);
+	if (IS_ERR(pdh_data)) {
+		ret = PTR_ERR(pdh_data);
+		goto e_free;
+	}
+
+	start->pdh_cert_address = __psp_pa(pdh_data);
+	start->pdh_cert_len = params.pdh_len;
+
+	session_data = psp_copy_user_blob(params.session_uaddr, params.session_len);
+	if (IS_ERR(session_data)) {
+		ret = PTR_ERR(session_data);
+		goto e_free_pdh;
+	}
+
+	start->session_address = __psp_pa(session_data);
+	start->session_len = params.session_len;
+
+	/* create memory encryption context */
+	ret = __sev_issue_cmd(argp->sev_fd, SEV_CMD_RECEIVE_START, start, error);
+	if (ret)
+		goto e_free_session;
+
+	/* Bind ASID to this guest */
+	ret = sev_bind_asid(kvm, start->handle, error);
+	if (ret)
+		goto e_free_session;
+
+	params.handle = start->handle;
+	if (copy_to_user((void __user *)(uintptr_t)argp->data,
+			 &params, sizeof(struct kvm_sev_receive_start))) {
+		ret = -EFAULT;
+		sev_unbind_asid(kvm, start->handle);
+		goto e_free_session;
+	}
+
+	sev->handle = start->handle;
+	sev->fd = argp->sev_fd;
+
+e_free_session:
+	kfree(session_data);
+e_free_pdh:
+	kfree(pdh_data);
+e_free:
+	kfree(start);
+	return ret;
+}
+
 static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
 {
 	struct kvm_sev_cmd sev_cmd;
@@ -7242,6 +7319,9 @@ static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
 	case KVM_SEV_SEND_FINISH:
 		r = sev_send_finish(kvm, &sev_cmd);
 		break;
+	case KVM_SEV_RECEIVE_START:
+		r = sev_receive_start(kvm, &sev_cmd);
+		break;
 	default:
 		r = -EINVAL;
 		goto out;
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 0bee91bba329..fee75bf1fd90 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1541,6 +1541,15 @@ struct kvm_sev_send_update_data {
 	__u32 trans_len;
 };
 
+struct kvm_sev_receive_start {
+	__u32 handle;
+	__u32 policy;
+	__u64 pdh_uaddr;
+	__u32 pdh_len;
+	__u64 session_uaddr;
+	__u32 session_len;
+};
+
 #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


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

* [RFC PATCH v1 05/10] KVM: SVM: Add KVM_SEV_RECEIVE_UPDATE_DATA command
  2019-04-24 16:09 [RFC PATCH v1 00/10] Add AMD SEV guest live migration support Singh, Brijesh
                   ` (3 preceding siblings ...)
  2019-04-24 16:10 ` [RFC PATCH v1 04/10] KVM: SVM: Add support for KVM_SEV_RECEIVE_START command Singh, Brijesh
@ 2019-04-24 16:10 ` Singh, Brijesh
  2019-04-26 21:11   ` Lendacky, Thomas
  2019-04-24 16:10 ` [RFC PATCH v1 06/10] KVM: SVM: Add KVM_SEV_RECEIVE_FINISH command Singh, Brijesh
                   ` (5 subsequent siblings)
  10 siblings, 1 reply; 27+ messages in thread
From: Singh, Brijesh @ 2019-04-24 16:10 UTC (permalink / raw)
  To: kvm
  Cc: qemu-devel, Singh, Brijesh, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Borislav Petkov, Lendacky, Thomas, x86,
	linux-kernel

The command is used for copying the incoming buffer into the
SEV guest memory space.

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: "Radim Krčmář" <rkrcmar@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
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 .../virtual/kvm/amd-memory-encryption.rst     | 24 ++++++
 arch/x86/kvm/svm.c                            | 84 +++++++++++++++++++
 include/uapi/linux/kvm.h                      |  9 ++
 3 files changed, 117 insertions(+)

diff --git a/Documentation/virtual/kvm/amd-memory-encryption.rst b/Documentation/virtual/kvm/amd-memory-encryption.rst
index acdff2454649..b9c3dc02f344 100644
--- a/Documentation/virtual/kvm/amd-memory-encryption.rst
+++ b/Documentation/virtual/kvm/amd-memory-encryption.rst
@@ -322,6 +322,30 @@ On success, the 'handle' field contains a new handle and on error, a negative va
 
 For more details, see SEV spec Section 6.12.
 
+14. KVM_SEV_RECEIVE_UPDATE_DATA
+----------------------------
+
+The KVM_SEV_RECEIVE_UPDATE_DATA command can be used by the hypervisor to copy
+the incoming buffers into the guest memory region with encryption context
+created during the KVM_SEV_RECEIVE_START.
+
+Parameters (in): struct kvm_sev_receive_update_data
+
+Returns: 0 on success, -negative on error
+
+::
+
+        struct kvm_sev_launch_receive_update_data {
+                __u64 hdr_uaddr;        /* userspace address containing the packet header */
+                __u32 hdr_len;
+
+                __u64 guest_uaddr;      /* the destination guest memory region */
+                __u32 guest_len;
+
+                __u64 trans_uaddr;      /* the incoming buffer memory region  */
+                __u32 trans_len;
+        };
+
 References
 ==========
 
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index a7dcf19baefb..c81cac09c5af 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -7269,6 +7269,87 @@ static int sev_receive_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
 	return ret;
 }
 
+static int sev_receive_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)
+{
+	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+	struct kvm_sev_receive_update_data params;
+	struct sev_data_receive_update_data *data;
+	void *hdr = NULL, *trans = NULL;
+	struct page **guest_page;
+	unsigned long n;
+	int ret, offset;
+
+	if (!sev_guest(kvm))
+		return -EINVAL;
+
+	if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data,
+			sizeof(struct kvm_sev_receive_update_data)))
+		return -EFAULT;
+
+	if (!params.hdr_uaddr || !params.hdr_len ||
+	    !params.guest_uaddr || !params.guest_len ||
+	    !params.trans_uaddr || !params.trans_len)
+		return -EINVAL;
+
+	/* Check if we are crossing the page boundry */
+	offset = params.guest_uaddr & (PAGE_SIZE - 1);
+	if ((params.guest_len + offset > PAGE_SIZE))
+		return -EINVAL;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	hdr = psp_copy_user_blob(params.hdr_uaddr, params.hdr_len);
+	if (IS_ERR(hdr)) {
+		ret = PTR_ERR(hdr);
+		goto e_free;
+	}
+
+	data->hdr_address = __psp_pa(hdr);
+	data->hdr_len = params.hdr_len;
+
+	trans = psp_copy_user_blob(params.trans_uaddr, params.trans_len);
+	if (IS_ERR(trans)) {
+		ret = PTR_ERR(trans);
+		goto e_free;
+	}
+
+	data->trans_address = __psp_pa(trans);
+	data->trans_len = params.trans_len;
+
+	/* Pin guest memory */
+	ret = -EFAULT;
+	guest_page = sev_pin_memory(kvm, params.guest_uaddr & PAGE_MASK,
+				    PAGE_SIZE, &n, 0);
+	if (!guest_page)
+		goto e_free;
+
+	data->guest_address = __sme_page_pa(guest_page[0]) + offset;
+	data->guest_len = params.guest_len;
+
+	/*
+	 * The RECEIVE_UPDATE_DATA command requires C-bit to be always set.
+	 * The __sme_page_pa() takes care of setting the C-bit only when SME
+	 * is enabled on the host. But we need to set the C-bit regarless of
+	 * the SME state.
+	 */
+	data->guest_address |= me_mask;
+
+	/* flush the caches to ensure that DRAM has recent contents */
+	sev_clflush_pages(guest_page, n);
+
+	data->handle = sev->handle;
+	ret = sev_issue_cmd(kvm, SEV_CMD_RECEIVE_UPDATE_DATA, data, &argp->error);
+
+	sev_unpin_memory(kvm, guest_page, n);
+e_free:
+	kfree(data);
+	kfree(hdr);
+	kfree(trans);
+	return ret;
+}
+
 static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
 {
 	struct kvm_sev_cmd sev_cmd;
@@ -7322,6 +7403,9 @@ static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
 	case KVM_SEV_RECEIVE_START:
 		r = sev_receive_start(kvm, &sev_cmd);
 		break;
+	case KVM_SEV_RECEIVE_UPDATE_DATA:
+		r = sev_receive_update_data(kvm, &sev_cmd);
+		break;
 	default:
 		r = -EINVAL;
 		goto out;
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index fee75bf1fd90..07e058a3ec11 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1550,6 +1550,15 @@ struct kvm_sev_receive_start {
 	__u32 session_len;
 };
 
+struct kvm_sev_receive_update_data {
+	__u64 hdr_uaddr;
+	__u32 hdr_len;
+	__u64 guest_uaddr;
+	__u32 guest_len;
+	__u64 trans_uaddr;
+	__u32 trans_len;
+};
+
 #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


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

* [RFC PATCH v1 06/10] KVM: SVM: Add KVM_SEV_RECEIVE_FINISH command
  2019-04-24 16:09 [RFC PATCH v1 00/10] Add AMD SEV guest live migration support Singh, Brijesh
                   ` (4 preceding siblings ...)
  2019-04-24 16:10 ` [RFC PATCH v1 05/10] KVM: SVM: Add KVM_SEV_RECEIVE_UPDATE_DATA command Singh, Brijesh
@ 2019-04-24 16:10 ` Singh, Brijesh
  2019-04-26 21:11   ` Lendacky, Thomas
  2019-04-24 16:10 ` [RFC PATCH v1 07/10] KVM: x86: Add AMD SEV specific Hypercall3 Singh, Brijesh
                   ` (4 subsequent siblings)
  10 siblings, 1 reply; 27+ messages in thread
From: Singh, Brijesh @ 2019-04-24 16:10 UTC (permalink / raw)
  To: kvm
  Cc: qemu-devel, Singh, Brijesh, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Borislav Petkov, Lendacky, Thomas, x86,
	linux-kernel

The command finalize the guest receiving process and make the SEV guest
ready for the execution.

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: "Radim Krčmář" <rkrcmar@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
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 .../virtual/kvm/amd-memory-encryption.rst     |  8 +++++++
 arch/x86/kvm/svm.c                            | 23 +++++++++++++++++++
 2 files changed, 31 insertions(+)

diff --git a/Documentation/virtual/kvm/amd-memory-encryption.rst b/Documentation/virtual/kvm/amd-memory-encryption.rst
index b9c3dc02f344..72c45f93abd7 100644
--- a/Documentation/virtual/kvm/amd-memory-encryption.rst
+++ b/Documentation/virtual/kvm/amd-memory-encryption.rst
@@ -346,6 +346,14 @@ Returns: 0 on success, -negative on error
                 __u32 trans_len;
         };
 
+15. KVM_SEV_RECEIVE_FINISH
+------------------------
+
+After completion of the migration flow, the KVM_SEV_RECEIVE_FINISH command can be
+issued by the hypervisor to make the guest ready for the execution.
+
+Returns: 0 on success, -negative on error
+
 References
 ==========
 
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index c81cac09c5af..74b57ab742ad 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -7350,6 +7350,26 @@ static int sev_receive_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)
 	return ret;
 }
 
+static int sev_receive_finish(struct kvm *kvm, struct kvm_sev_cmd *argp)
+{
+	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+	struct sev_data_receive_finish *data;
+	int ret;
+
+	if (!sev_guest(kvm))
+		return -ENOTTY;
+
+	data = kzalloc(sizeof(*data), GFP_KERNEL);
+	if (!data)
+		return -ENOMEM;
+
+	data->handle = sev->handle;
+	ret = sev_issue_cmd(kvm, SEV_CMD_RECEIVE_FINISH, data, &argp->error);
+
+	kfree(data);
+	return ret;
+}
+
 static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
 {
 	struct kvm_sev_cmd sev_cmd;
@@ -7406,6 +7426,9 @@ static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
 	case KVM_SEV_RECEIVE_UPDATE_DATA:
 		r = sev_receive_update_data(kvm, &sev_cmd);
 		break;
+	case KVM_SEV_RECEIVE_FINISH:
+		r = sev_receive_finish(kvm, &sev_cmd);
+		break;
 	default:
 		r = -EINVAL;
 		goto out;
-- 
2.17.1


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

* [RFC PATCH v1 07/10] KVM: x86: Add AMD SEV specific Hypercall3
  2019-04-24 16:09 [RFC PATCH v1 00/10] Add AMD SEV guest live migration support Singh, Brijesh
                   ` (5 preceding siblings ...)
  2019-04-24 16:10 ` [RFC PATCH v1 06/10] KVM: SVM: Add KVM_SEV_RECEIVE_FINISH command Singh, Brijesh
@ 2019-04-24 16:10 ` Singh, Brijesh
  2019-04-24 16:10 ` [RFC PATCH v1 08/10] KVM: X86: Introduce KVM_HC_PAGE_ENC_STATUS hypercall Singh, Brijesh
                   ` (3 subsequent siblings)
  10 siblings, 0 replies; 27+ messages in thread
From: Singh, Brijesh @ 2019-04-24 16:10 UTC (permalink / raw)
  To: kvm
  Cc: qemu-devel, Singh, Brijesh, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Borislav Petkov, Lendacky, Thomas, x86,
	linux-kernel

KVM hypercall framework relies on alternative framework to patch the
VMCALL -> VMMCALL on AMD platform. If a hypercall is made before
apply_alternative() is called then it defaults to VMCALL. The approach
works fine on non SEV guest. A VMCALL would causes #UD, and hypervisor
will be able to decode the instruction and do the right things. But
when SEV is active, guest memory is encrypted with guest key and
hypervisor will not be able to decode the instruction bytes.

Add SEV specific hypercall3, it unconditionally uses VMMCALL. The hypercall
will be used by the SEV guest to notify encrypted pages to the hypervisor.

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: "Radim Krčmář" <rkrcmar@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
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 arch/x86/include/asm/kvm_para.h | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/arch/x86/include/asm/kvm_para.h b/arch/x86/include/asm/kvm_para.h
index 5ed3cf1c3934..94e91c0bc2e0 100644
--- a/arch/x86/include/asm/kvm_para.h
+++ b/arch/x86/include/asm/kvm_para.h
@@ -84,6 +84,18 @@ static inline long kvm_hypercall4(unsigned int nr, unsigned long p1,
 	return ret;
 }
 
+static inline long kvm_sev_hypercall3(unsigned int nr, unsigned long p1,
+				      unsigned long p2, unsigned long p3)
+{
+	long ret;
+
+	asm volatile("vmmcall"
+		     : "=a"(ret)
+		     : "a"(nr), "b"(p1), "c"(p2), "d"(p3)
+		     : "memory");
+	return ret;
+}
+
 #ifdef CONFIG_KVM_GUEST
 bool kvm_para_available(void);
 unsigned int kvm_arch_para_features(void);
-- 
2.17.1


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

* [RFC PATCH v1 08/10] KVM: X86: Introduce KVM_HC_PAGE_ENC_STATUS hypercall
  2019-04-24 16:09 [RFC PATCH v1 00/10] Add AMD SEV guest live migration support Singh, Brijesh
                   ` (6 preceding siblings ...)
  2019-04-24 16:10 ` [RFC PATCH v1 07/10] KVM: x86: Add AMD SEV specific Hypercall3 Singh, Brijesh
@ 2019-04-24 16:10 ` Singh, Brijesh
  2019-04-26 21:39   ` Lendacky, Thomas
  2019-04-24 16:10 ` [RFC PATCH v1 09/10] KVM: x86: Introduce KVM_GET_PAGE_ENC_BITMAP ioctl Singh, Brijesh
                   ` (2 subsequent siblings)
  10 siblings, 1 reply; 27+ messages in thread
From: Singh, Brijesh @ 2019-04-24 16:10 UTC (permalink / raw)
  To: kvm
  Cc: qemu-devel, Singh, Brijesh, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Borislav Petkov, Lendacky, Thomas, x86,
	linux-kernel

The hypercall can be used by the SEV guest to notify the page encryption
status to the hypervisor. The hypercall should be invoked only when
the encryption attribute is changed from encrypted -> decrypted and vice
versa. By default all the guest pages should be considered encrypted.

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: "Radim Krčmář" <rkrcmar@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
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 Documentation/virtual/kvm/hypercalls.txt | 14 +++++
 arch/x86/include/asm/kvm_host.h          |  2 +
 arch/x86/kvm/svm.c                       | 69 ++++++++++++++++++++++++
 arch/x86/kvm/vmx/vmx.c                   |  1 +
 arch/x86/kvm/x86.c                       |  5 ++
 include/uapi/linux/kvm_para.h            |  1 +
 6 files changed, 92 insertions(+)

diff --git a/Documentation/virtual/kvm/hypercalls.txt b/Documentation/virtual/kvm/hypercalls.txt
index da24c138c8d1..ecd44e488679 100644
--- a/Documentation/virtual/kvm/hypercalls.txt
+++ b/Documentation/virtual/kvm/hypercalls.txt
@@ -141,3 +141,17 @@ a0 corresponds to the APIC ID in the third argument (a2), bit 1
 corresponds to the APIC ID a2+1, and so on.
 
 Returns the number of CPUs to which the IPIs were delivered successfully.
+
+7. KVM_HC_PAGE_ENC_STATUS
+-------------------------
+Architecture: x86
+Status: active
+Purpose: Notify the encryption status changes in guest page table (SEV guest)
+
+a0: the guest physical address of the start page
+a1: the number of pages
+a2: set or clear the encryption attribute
+
+   Where:
+	* 1: Encryption attribute is set
+	* 0: Encryption attribute is cleared
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index a9d03af34030..adb0ca035b97 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1196,6 +1196,8 @@ struct kvm_x86_ops {
 	uint16_t (*nested_get_evmcs_version)(struct kvm_vcpu *vcpu);
 
 	bool (*need_emulation_on_page_fault)(struct kvm_vcpu *vcpu);
+	int (*page_enc_status_hc)(struct kvm *kvm, unsigned long gpa,
+				  unsigned long sz, unsigned long mode);
 };
 
 struct kvm_arch_async_pf {
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 74b57ab742ad..f024f208b052 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -138,6 +138,8 @@ struct kvm_sev_info {
 	int fd;			/* SEV device fd */
 	unsigned long pages_locked; /* Number of pages locked */
 	struct list_head regions_list;  /* List of registered regions */
+	unsigned long *page_enc_bmap;
+	unsigned long page_enc_bmap_size;
 };
 
 struct kvm_svm {
@@ -1911,6 +1913,8 @@ static void sev_vm_destroy(struct kvm *kvm)
 
 	sev_unbind_asid(kvm, sev->handle);
 	sev_asid_free(kvm);
+
+	kvfree(sev->page_enc_bmap);
 }
 
 static void avic_vm_destroy(struct kvm *kvm)
@@ -7370,6 +7374,69 @@ static int sev_receive_finish(struct kvm *kvm, struct kvm_sev_cmd *argp)
 	return ret;
 }
 
+static int sev_resize_page_enc_bitmap(struct kvm *kvm, unsigned long new_size)
+{
+	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+	unsigned long *map;
+	unsigned long sz;
+
+	if (sev->page_enc_bmap_size >= new_size)
+		return 0;
+
+	sz = ALIGN(new_size, BITS_PER_LONG) / 8;
+
+	if (sz > PAGE_SIZE)
+		map = vmalloc(sz);
+	else
+		map = kmalloc(sz, GFP_KERNEL);
+
+	if (!map) {
+		pr_err_once("Failed to allocate decrypted bitmap size %lx\n", sz);
+		return 1;
+	}
+
+	/* mark the page encrypted (by default) */
+	memset(map, 0xff, sz);
+
+	bitmap_copy(map, sev->page_enc_bmap, sev->page_enc_bmap_size);
+	kvfree(sev->page_enc_bmap);
+
+	sev->page_enc_bmap = map;
+	sev->page_enc_bmap_size = new_size;
+
+	return 0;
+}
+
+static int svm_page_enc_status_hc(struct kvm *kvm, unsigned long gpa,
+				  unsigned long npages, unsigned long enc)
+{
+	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+	gfn_t gfn_start, gfn_end;
+	int r;
+
+	if (!npages)
+		return 0;
+
+	gfn_start = gpa_to_gfn(gpa);
+	gfn_end = gfn_start + npages;
+
+	mutex_lock(&kvm->lock);
+
+	r = 1;
+	if (sev_resize_page_enc_bitmap(kvm, gfn_end))
+		goto unlock;
+
+	if (enc)
+		__bitmap_set(sev->page_enc_bmap, gfn_start, gfn_end - gfn_start);
+	else
+		__bitmap_clear(sev->page_enc_bmap, gfn_start, gfn_end - gfn_start);
+
+	r = 0;
+unlock:
+	mutex_unlock(&kvm->lock);
+	return r;
+}
+
 static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
 {
 	struct kvm_sev_cmd sev_cmd;
@@ -7711,6 +7778,8 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
 	.nested_get_evmcs_version = nested_get_evmcs_version,
 
 	.need_emulation_on_page_fault = svm_need_emulation_on_page_fault,
+
+	.page_enc_status_hc = svm_page_enc_status_hc
 };
 
 static int __init svm_init(void)
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index b4e7d645275a..9c814e560e0f 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -7731,6 +7731,7 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = {
 	.get_vmcs12_pages = NULL,
 	.nested_enable_evmcs = NULL,
 	.need_emulation_on_page_fault = vmx_need_emulation_on_page_fault,
+	.page_enc_status_hc = NULL,
 };
 
 static void vmx_cleanup_l1d_flush(void)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index a0d1fc80ac5a..dea644be5992 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -7141,6 +7141,11 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
 	case KVM_HC_SEND_IPI:
 		ret = kvm_pv_send_ipi(vcpu->kvm, a0, a1, a2, a3, op_64_bit);
 		break;
+	case KVM_HC_PAGE_ENC_STATUS:
+		ret = -KVM_ENOSYS;
+		if (kvm_x86_ops->page_enc_status_hc)
+			ret = kvm_x86_ops->page_enc_status_hc(vcpu->kvm, a0, a1, a2);
+		break;
 	default:
 		ret = -KVM_ENOSYS;
 		break;
diff --git a/include/uapi/linux/kvm_para.h b/include/uapi/linux/kvm_para.h
index 6c0ce49931e5..3dc9e579f4f9 100644
--- a/include/uapi/linux/kvm_para.h
+++ b/include/uapi/linux/kvm_para.h
@@ -28,6 +28,7 @@
 #define KVM_HC_MIPS_CONSOLE_OUTPUT	8
 #define KVM_HC_CLOCK_PAIRING		9
 #define KVM_HC_SEND_IPI		10
+#define KVM_HC_PAGE_ENC_STATUS		11
 
 /*
  * hypercalls use architecture specific
-- 
2.17.1


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

* [RFC PATCH v1 09/10] KVM: x86: Introduce KVM_GET_PAGE_ENC_BITMAP ioctl
  2019-04-24 16:09 [RFC PATCH v1 00/10] Add AMD SEV guest live migration support Singh, Brijesh
                   ` (7 preceding siblings ...)
  2019-04-24 16:10 ` [RFC PATCH v1 08/10] KVM: X86: Introduce KVM_HC_PAGE_ENC_STATUS hypercall Singh, Brijesh
@ 2019-04-24 16:10 ` Singh, Brijesh
  2019-04-24 16:10 ` [RFC PATCH v1 10/10] mm: x86: Invoke hypercall when page encryption status is changed Singh, Brijesh
  2019-04-24 19:15 ` [RFC PATCH v1 00/10] Add AMD SEV guest live migration support Steve Rutherford
  10 siblings, 0 replies; 27+ messages in thread
From: Singh, Brijesh @ 2019-04-24 16:10 UTC (permalink / raw)
  To: kvm
  Cc: qemu-devel, Singh, Brijesh, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Borislav Petkov, Lendacky, Thomas, x86,
	linux-kernel

The ioctl can be used to retrieve page encryption bitmap for a given
kvm memory slot.

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: "Radim Krčmář" <rkrcmar@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
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 arch/x86/include/asm/kvm_host.h |  1 +
 arch/x86/kvm/svm.c              | 54 ++++++++++++++++++++++++++++++++-
 arch/x86/kvm/x86.c              | 12 ++++++++
 include/uapi/linux/kvm.h        | 12 ++++++++
 4 files changed, 78 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index adb0ca035b97..9947c4be825d 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1198,6 +1198,7 @@ struct kvm_x86_ops {
 	bool (*need_emulation_on_page_fault)(struct kvm_vcpu *vcpu);
 	int (*page_enc_status_hc)(struct kvm *kvm, unsigned long gpa,
 				  unsigned long sz, unsigned long mode);
+	int (*get_page_enc_bitmap)(struct kvm *kvm, struct kvm_page_enc_bitmap *bmap);
 };
 
 struct kvm_arch_async_pf {
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index f024f208b052..f386d72c929b 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -7437,6 +7437,57 @@ static int svm_page_enc_status_hc(struct kvm *kvm, unsigned long gpa,
 	return r;
 }
 
+static int svm_get_page_enc_bitmap(struct kvm *kvm,
+				   struct kvm_page_enc_bitmap *bmap)
+{
+	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+	unsigned long gfn_start, gfn_end;
+	struct kvm_memory_slot *memslot;
+	struct kvm_memslots *slots;
+	unsigned long *bitmap;
+	unsigned long sz, i;
+	int ret, as_id, id;
+
+	if (!sev_guest(kvm))
+		return -ENOTTY;
+
+	as_id = bmap->slot >> 16;
+	id = (u16)bmap->slot;
+	if (as_id >= KVM_ADDRESS_SPACE_NUM || id >= KVM_USER_MEM_SLOTS)
+		return -EINVAL;
+
+	slots = __kvm_memslots(kvm, as_id);
+	memslot = id_to_memslot(slots, id);
+
+	gfn_start = memslot->base_gfn;
+	gfn_end = gfn_start + memslot->npages;
+
+	sz = ALIGN(memslot->npages, BITS_PER_LONG) / 8;
+	bitmap = kmalloc(sz, GFP_KERNEL);
+	if (!bitmap)
+		return -ENOMEM;
+
+	memset(bitmap, 0xff, sz); /* by default all pages are marked encrypted */
+
+	mutex_lock(&kvm->lock);
+	if (sev->page_enc_bmap) {
+		i = gfn_start;
+		for_each_clear_bit_from(i, sev->page_enc_bmap,
+				      min(sev->page_enc_bmap_size, gfn_end))
+			clear_bit(i - gfn_start, bitmap);
+	}
+	mutex_unlock(&kvm->lock);
+
+	ret = -EFAULT;
+	if (copy_to_user(bmap->enc_bitmap, bitmap, sz))
+		goto out;
+
+	ret = 0;
+out:
+	kfree(bitmap);
+	return ret;
+}
+
 static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
 {
 	struct kvm_sev_cmd sev_cmd;
@@ -7779,7 +7830,8 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
 
 	.need_emulation_on_page_fault = svm_need_emulation_on_page_fault,
 
-	.page_enc_status_hc = svm_page_enc_status_hc
+	.page_enc_status_hc = svm_page_enc_status_hc,
+	.get_page_enc_bitmap = svm_get_page_enc_bitmap
 };
 
 static int __init svm_init(void)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index dea644be5992..44079979b1c5 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -4882,6 +4882,18 @@ long kvm_arch_vm_ioctl(struct file *filp,
 		r = kvm_vm_ioctl_hv_eventfd(kvm, &hvevfd);
 		break;
 	}
+	case KVM_GET_PAGE_ENC_BITMAP: {
+		struct kvm_page_enc_bitmap bitmap;
+
+		r = -EFAULT;
+		if (copy_from_user(&bitmap, argp, sizeof(bitmap)))
+			goto out;
+
+		r = -ENOTTY;
+		if (kvm_x86_ops->get_page_enc_bitmap)
+			r = kvm_x86_ops->get_page_enc_bitmap(kvm, &bitmap);
+		break;
+	}
 	default:
 		r = -ENOTTY;
 	}
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 07e058a3ec11..7f944d4e252c 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -492,6 +492,16 @@ struct kvm_dirty_log {
 	};
 };
 
+/* for KVM_GET_PAGE_ENC_BITMAP */
+struct kvm_page_enc_bitmap {
+	__u32 slot;
+	__u32 padding1;
+	union {
+		void __user *enc_bitmap; /* one bit per page */
+		__u64 padding2;
+	};
+};
+
 /* for KVM_CLEAR_DIRTY_LOG */
 struct kvm_clear_dirty_log {
 	__u32 slot;
@@ -1440,6 +1450,8 @@ struct kvm_enc_region {
 /* Available with KVM_CAP_HYPERV_CPUID */
 #define KVM_GET_SUPPORTED_HV_CPUID _IOWR(KVMIO, 0xc1, struct kvm_cpuid2)
 
+#define KVM_GET_PAGE_ENC_BITMAP	_IOW(KVMIO, 0xc2, struct kvm_page_enc_bitmap)
+
 /* Secure Encrypted Virtualization command */
 enum sev_cmd_id {
 	/* Guest initialization commands */
-- 
2.17.1


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

* [RFC PATCH v1 10/10] mm: x86: Invoke hypercall when page encryption status is changed
  2019-04-24 16:09 [RFC PATCH v1 00/10] Add AMD SEV guest live migration support Singh, Brijesh
                   ` (8 preceding siblings ...)
  2019-04-24 16:10 ` [RFC PATCH v1 09/10] KVM: x86: Introduce KVM_GET_PAGE_ENC_BITMAP ioctl Singh, Brijesh
@ 2019-04-24 16:10 ` Singh, Brijesh
  2019-04-24 19:15 ` [RFC PATCH v1 00/10] Add AMD SEV guest live migration support Steve Rutherford
  10 siblings, 0 replies; 27+ messages in thread
From: Singh, Brijesh @ 2019-04-24 16:10 UTC (permalink / raw)
  To: kvm
  Cc: qemu-devel, Singh, Brijesh, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Borislav Petkov, Lendacky, Thomas, x86,
	linux-kernel

Invoke a hypercall when a memory region is changed from encrypted ->
decrypted and vice versa. Hypervisor need 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: "Radim Krčmář" <rkrcmar@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
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
---
 arch/x86/include/asm/mem_encrypt.h |  3 ++
 arch/x86/mm/mem_encrypt.c          | 45 +++++++++++++++++++++++++++++-
 arch/x86/mm/pageattr.c             | 15 ++++++++++
 3 files changed, 62 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/mem_encrypt.h b/arch/x86/include/asm/mem_encrypt.h
index 616f8e637bc3..3f43cfdd0209 100644
--- a/arch/x86/include/asm/mem_encrypt.h
+++ b/arch/x86/include/asm/mem_encrypt.h
@@ -97,4 +97,7 @@ extern char __start_bss_decrypted[], __end_bss_decrypted[], __start_bss_decrypte
 
 #endif	/* __ASSEMBLY__ */
 
+extern void set_memory_enc_dec_hypercall(unsigned long vaddr,
+					 unsigned long size, bool enc);
+
 #endif	/* __X86_MEM_ENCRYPT_H__ */
diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c
index 385afa2b9e17..24261b58ac99 100644
--- a/arch/x86/mm/mem_encrypt.c
+++ b/arch/x86/mm/mem_encrypt.c
@@ -18,6 +18,7 @@
 #include <linux/dma-direct.h>
 #include <linux/swiotlb.h>
 #include <linux/mem_encrypt.h>
+#include <linux/kvm_para.h>
 
 #include <asm/tlbflush.h>
 #include <asm/fixmap.h>
@@ -28,6 +29,7 @@
 #include <asm/processor-flags.h>
 #include <asm/msr.h>
 #include <asm/cmdline.h>
+#include <asm/kvm_para.h>
 
 #include "mm_internal.h"
 
@@ -195,6 +197,45 @@ void __init sme_early_init(void)
 		swiotlb_force = SWIOTLB_FORCE;
 }
 
+void set_memory_enc_dec_hypercall(unsigned long vaddr, unsigned long sz, bool enc)
+{
+	unsigned long vaddr_end, vaddr_next;
+
+	vaddr_end = vaddr + sz;
+
+	for (; vaddr < vaddr_end; vaddr = vaddr_next) {
+		int psize, pmask, level;
+		unsigned long pfn;
+		pte_t *kpte;
+
+		kpte = lookup_address(vaddr, &level);
+		if (!kpte || pte_none(*kpte))
+			return;
+
+		switch (level) {
+		case PG_LEVEL_4K:
+			pfn = pte_pfn(*kpte);
+			break;
+		case PG_LEVEL_2M:
+			pfn = pmd_pfn(*(pmd_t *)kpte);
+			break;
+		case PG_LEVEL_1G:
+			pfn = pud_pfn(*(pud_t *)kpte);
+			break;
+		default:
+			return;
+		}
+
+		psize = page_level_size(level);
+		pmask = page_level_mask(level);
+
+		kvm_sev_hypercall3(KVM_HC_PAGE_ENC_STATUS,
+				   pfn << PAGE_SHIFT, psize >> PAGE_SHIFT, enc);
+
+		vaddr_next = (vaddr & pmask) + psize;
+	}
+}
+
 static void __init __set_clr_pte_enc(pte_t *kpte, int level, bool enc)
 {
 	pgprot_t old_prot, new_prot;
@@ -252,12 +293,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;
 
@@ -308,6 +350,7 @@ static int __init early_set_memory_enc_dec(unsigned long vaddr,
 
 	ret = 0;
 
+	set_memory_enc_dec_hypercall(start, size, enc);
 out:
 	__flush_tlb_all();
 	return ret;
diff --git a/arch/x86/mm/pageattr.c b/arch/x86/mm/pageattr.c
index 4c570612e24e..b1a68879f66d 100644
--- a/arch/x86/mm/pageattr.c
+++ b/arch/x86/mm/pageattr.c
@@ -25,6 +25,7 @@
 #include <asm/proto.h>
 #include <asm/pat.h>
 #include <asm/set_memory.h>
+#include <asm/mem_encrypt.h>
 
 #include "mm_internal.h"
 
@@ -2019,6 +2020,12 @@ int set_memory_global(unsigned long addr, int numpages)
 				    __pgprot(_PAGE_GLOBAL), 0);
 }
 
+void __attribute__((weak)) set_memory_enc_dec_hypercall(unsigned long addr,
+							unsigned long size,
+							bool enc)
+{
+}
+
 static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc)
 {
 	struct cpa_data cpa;
@@ -2059,6 +2066,14 @@ static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc)
 	 */
 	cpa_flush(&cpa, 0);
 
+	/*
+	 * When SEV is active, notify hypervisor that a given memory range is mapped
+	 * encrypted or decrypted. Hypervisor will use this information during
+	 * the VM migration.
+	 */
+	if (sev_active())
+		set_memory_enc_dec_hypercall(addr, numpages << PAGE_SHIFT, enc);
+
 	return ret;
 }
 
-- 
2.17.1


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

* Re: [RFC PATCH v1 00/10] Add AMD SEV guest live migration support
  2019-04-24 16:09 [RFC PATCH v1 00/10] Add AMD SEV guest live migration support Singh, Brijesh
                   ` (9 preceding siblings ...)
  2019-04-24 16:10 ` [RFC PATCH v1 10/10] mm: x86: Invoke hypercall when page encryption status is changed Singh, Brijesh
@ 2019-04-24 19:15 ` Steve Rutherford
  2019-04-24 21:32   ` Singh, Brijesh
  10 siblings, 1 reply; 27+ messages in thread
From: Steve Rutherford @ 2019-04-24 19:15 UTC (permalink / raw)
  To: Singh, Brijesh
  Cc: kvm, qemu-devel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
	Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Borislav Petkov, Lendacky, Thomas, x86,
	linux-kernel

On Wed, Apr 24, 2019 at 9:10 AM Singh, Brijesh <brijesh.singh@amd.com> wrote:
>
> The series add support for AMD SEV guest live migration commands. To protect the
> confidentiality of an SEV protected guest memory while in transit we need to
> use the SEV commands defined in SEV API spec [1].
>
> SEV guest VMs have the concept of private and shared memory. Private memory
> is encrypted with the guest-specific key, while shared memory may be encrypted
> with hypervisor key. The commands provided by the SEV FW are meant to be used
> for the private memory only. The patch series introduces a new hypercall.
> The guest OS can use this hypercall to notify the page encryption status.
> If the page is encrypted with guest specific-key then we use SEV command during
> the migration. If page is not encrypted then fallback to default.
>
> The patch adds a new ioctl KVM_GET_PAGE_ENC_BITMAP. The ioctl can be used
> by the qemu to get the page encrypted bitmap. Qemu can consult this bitmap
> during the migration to know whether the page is encrypted.
>
> [1] https://developer.amd.com/wp-content/resources/55766.PDF
>
> The series is tested with the Qemu, I am in process of cleaning
> up the Qemu code and will submit soon.
>
> While implementing the migration I stumbled on the follow question:
>
> - Since there is a guest OS changes required to support the migration,
>   so how do we know whether guest OS is updated? Should we extend KVM
>   capabilities/feature bits to check this?
>
> TODO:
>  - add an ioctl to build encryption bitmap. The encryption bitmap is built during
>    the guest bootup/execution. We should provide an ioctl so that destination
>    can build the bitmap as it receives the pages.
>  - reset the bitmap on guest reboot.
>
> The complete tree with patch is available at:
> https://github.com/codomania/kvm/tree/sev-migration-rfc-v1
>
> 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: "Radim Krčmář" <rkrcmar@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
>
> Brijesh Singh (10):
>   KVM: SVM: Add KVM_SEV SEND_START command
>   KVM: SVM: Add KVM_SEND_UPDATE_DATA command
>   KVM: SVM: Add KVM_SEV_SEND_FINISH command
>   KVM: SVM: Add support for KVM_SEV_RECEIVE_START command
>   KVM: SVM: Add KVM_SEV_RECEIVE_UPDATE_DATA command
>   KVM: SVM: Add KVM_SEV_RECEIVE_FINISH command
>   KVM: x86: Add AMD SEV specific Hypercall3
>   KVM: X86: Introduce KVM_HC_PAGE_ENC_STATUS hypercall
>   KVM: x86: Introduce KVM_GET_PAGE_ENC_BITMAP ioctl
>   mm: x86: Invoke hypercall when page encryption status is changed
>
>  .../virtual/kvm/amd-memory-encryption.rst     | 116 ++++
>  Documentation/virtual/kvm/hypercalls.txt      |  14 +
>  arch/x86/include/asm/kvm_host.h               |   3 +
>  arch/x86/include/asm/kvm_para.h               |  12 +
>  arch/x86/include/asm/mem_encrypt.h            |   3 +
>  arch/x86/kvm/svm.c                            | 560 +++++++++++++++++-
>  arch/x86/kvm/vmx/vmx.c                        |   1 +
>  arch/x86/kvm/x86.c                            |  17 +
>  arch/x86/mm/mem_encrypt.c                     |  45 +-
>  arch/x86/mm/pageattr.c                        |  15 +
>  include/uapi/linux/kvm.h                      |  51 ++
>  include/uapi/linux/kvm_para.h                 |   1 +
>  12 files changed, 834 insertions(+), 4 deletions(-)
>
> --
> 2.17.1
>

What's the back-of-the-envelope marginal cost of transferring a 16kB
region from one host to another? I'm interested in what the end to end
migration perf changes look like for this. If you have measured
migration perf, I'm interested in that also.

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

* Re: [RFC PATCH v1 00/10] Add AMD SEV guest live migration support
  2019-04-24 19:15 ` [RFC PATCH v1 00/10] Add AMD SEV guest live migration support Steve Rutherford
@ 2019-04-24 21:32   ` Singh, Brijesh
       [not found]     ` <CABayD+fy5+QNU8YWsVrfd6jyvPo3AWCBgR-V8iWKzZkWxQY=zA@mail.gmail.com>
  0 siblings, 1 reply; 27+ messages in thread
From: Singh, Brijesh @ 2019-04-24 21:32 UTC (permalink / raw)
  To: Steve Rutherford
  Cc: Singh, Brijesh, kvm, qemu-devel, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Borislav Petkov, Lendacky, Thomas, x86,
	linux-kernel



On 4/24/19 2:15 PM, Steve Rutherford wrote:
> On Wed, Apr 24, 2019 at 9:10 AM Singh, Brijesh <brijesh.singh@amd.com> wrote:
>>
>> The series add support for AMD SEV guest live migration commands. To protect the
>> confidentiality of an SEV protected guest memory while in transit we need to
>> use the SEV commands defined in SEV API spec [1].
>>
>> SEV guest VMs have the concept of private and shared memory. Private memory
>> is encrypted with the guest-specific key, while shared memory may be encrypted
>> with hypervisor key. The commands provided by the SEV FW are meant to be used
>> for the private memory only. The patch series introduces a new hypercall.
>> The guest OS can use this hypercall to notify the page encryption status.
>> If the page is encrypted with guest specific-key then we use SEV command during
>> the migration. If page is not encrypted then fallback to default.
>>
>> The patch adds a new ioctl KVM_GET_PAGE_ENC_BITMAP. The ioctl can be used
>> by the qemu to get the page encrypted bitmap. Qemu can consult this bitmap
>> during the migration to know whether the page is encrypted.
>>
>> [1] https://developer.amd.com/wp-content/resources/55766.PDF
>>
>> The series is tested with the Qemu, I am in process of cleaning
>> up the Qemu code and will submit soon.
>>
>> While implementing the migration I stumbled on the follow question:
>>
>> - Since there is a guest OS changes required to support the migration,
>>    so how do we know whether guest OS is updated? Should we extend KVM
>>    capabilities/feature bits to check this?
>>
>> TODO:
>>   - add an ioctl to build encryption bitmap. The encryption bitmap is built during
>>     the guest bootup/execution. We should provide an ioctl so that destination
>>     can build the bitmap as it receives the pages.
>>   - reset the bitmap on guest reboot.
>>
>> The complete tree with patch is available at:
>> https://github.com/codomania/kvm/tree/sev-migration-rfc-v1
>>
>> 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: "Radim Krčmář" <rkrcmar@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
>>
>> Brijesh Singh (10):
>>    KVM: SVM: Add KVM_SEV SEND_START command
>>    KVM: SVM: Add KVM_SEND_UPDATE_DATA command
>>    KVM: SVM: Add KVM_SEV_SEND_FINISH command
>>    KVM: SVM: Add support for KVM_SEV_RECEIVE_START command
>>    KVM: SVM: Add KVM_SEV_RECEIVE_UPDATE_DATA command
>>    KVM: SVM: Add KVM_SEV_RECEIVE_FINISH command
>>    KVM: x86: Add AMD SEV specific Hypercall3
>>    KVM: X86: Introduce KVM_HC_PAGE_ENC_STATUS hypercall
>>    KVM: x86: Introduce KVM_GET_PAGE_ENC_BITMAP ioctl
>>    mm: x86: Invoke hypercall when page encryption status is changed
>>
>>   .../virtual/kvm/amd-memory-encryption.rst     | 116 ++++
>>   Documentation/virtual/kvm/hypercalls.txt      |  14 +
>>   arch/x86/include/asm/kvm_host.h               |   3 +
>>   arch/x86/include/asm/kvm_para.h               |  12 +
>>   arch/x86/include/asm/mem_encrypt.h            |   3 +
>>   arch/x86/kvm/svm.c                            | 560 +++++++++++++++++-
>>   arch/x86/kvm/vmx/vmx.c                        |   1 +
>>   arch/x86/kvm/x86.c                            |  17 +
>>   arch/x86/mm/mem_encrypt.c                     |  45 +-
>>   arch/x86/mm/pageattr.c                        |  15 +
>>   include/uapi/linux/kvm.h                      |  51 ++
>>   include/uapi/linux/kvm_para.h                 |   1 +
>>   12 files changed, 834 insertions(+), 4 deletions(-)
>>
>> --
>> 2.17.1
>>
> 
> What's the back-of-the-envelope marginal cost of transferring a 16kB
> region from one host to another? I'm interested in what the end to end
> migration perf changes look like for this. If you have measured
> migration perf, I'm interested in that also.
> 

I have not done a complete performance analysis yet! From the qemu
QMP prompt (query-migration) I am getting ~8mbps throughput from
one host to another (this is with 4kb regions). I have been told
that increasing the transfer size from 4kb -> 16kb may not give a
huge performance gain because at FW level they still operating
on 4kb blocks. There is possibility that future FW updates may
give a bit better performance on 16kb size.

-Brijesh

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

* Re: [RFC PATCH v1 00/10] Add AMD SEV guest live migration support
       [not found]     ` <CABayD+fy5+QNU8YWsVrfd6jyvPo3AWCBgR-V8iWKzZkWxQY=zA@mail.gmail.com>
@ 2019-04-25  2:15       ` Singh, Brijesh
  0 siblings, 0 replies; 27+ messages in thread
From: Singh, Brijesh @ 2019-04-25  2:15 UTC (permalink / raw)
  To: Steve Rutherford
  Cc: Singh, Brijesh, kvm, qemu-devel, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Borislav Petkov, Lendacky, Thomas, x86,
	linux-kernel


On 4/24/19 7:18 PM, Steve Rutherford wrote:
> Do you mean MiB/s, MB/s or Mb/s? Since you are talking about network
> speeds, sometimes these get conflated.

It's megabits/sec. The QMP query-migration command shows the throughput
in Mbits/s. It includes PSP command execution and the network write.
Most of the time is spent in PSP FW. I have not performed raw PSP
command benchmark yet but I believe SEV FW 0.17 may reproduce up to
12Mbits/s. I will update thread after I finish the further performance
breakdown.

-Brijesh


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

* Re: [RFC PATCH v1 01/10] KVM: SVM: Add KVM_SEV SEND_START command
  2019-04-24 16:09 ` [RFC PATCH v1 01/10] KVM: SVM: Add KVM_SEV SEND_START command Singh, Brijesh
@ 2019-04-26 14:10   ` Borislav Petkov
  2019-04-26 14:29     ` Singh, Brijesh
  0 siblings, 1 reply; 27+ messages in thread
From: Borislav Petkov @ 2019-04-26 14:10 UTC (permalink / raw)
  To: Singh, Brijesh
  Cc: kvm, qemu-devel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
	Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Lendacky, Thomas, x86, linux-kernel

On Wed, Apr 24, 2019 at 04:09:59PM +0000, Singh, Brijesh wrote:
> The command is used to create an outgoing SEV guest encryption context.
> 
> 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: "Radim Krčmář" <rkrcmar@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
> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> ---
>  .../virtual/kvm/amd-memory-encryption.rst     |  24 +++++
>  arch/x86/kvm/svm.c                            | 101 ++++++++++++++++++
>  include/uapi/linux/kvm.h                      |  12 +++
>  3 files changed, 137 insertions(+)
> 
> diff --git a/Documentation/virtual/kvm/amd-memory-encryption.rst b/Documentation/virtual/kvm/amd-memory-encryption.rst
> index 659bbc093b52..340ac4f87321 100644
> --- a/Documentation/virtual/kvm/amd-memory-encryption.rst
> +++ b/Documentation/virtual/kvm/amd-memory-encryption.rst
> @@ -238,6 +238,30 @@ Returns: 0 on success, -negative on error
>                  __u32 trans_len;
>          };
>  
> +10. KVM_SEV_SEND_START
> +----------------------
> +
> +The KVM_SEV_SEND_START command can be used by the hypervisor to create an
> +outgoing guest encryption context.
> +
> +Parameters (in): struct kvm_sev_send_start
> +
> +Returns: 0 on success, -negative on error
> +
> +::
> +        struct kvm_sev_send_start {
> +                __u32 policy;                 /* guest policy */
> +
> +                __u64 pdh_cert_uaddr;         /* platform Diffie-Hellman certificate */
> +                __u32 pdh_cert_len;
> +
> +                __u64 plat_cert_uaddr;        /* platform certificate chain */
> +                __u32 plat_cert_len;
> +
> +                __u64 amd_cert_uaddr;         /* AMD certificate */
> +                __u32 amd_cert_len;

        __u64 session_uaddr;
        __u32 session_len;

too, right?

> +        };
> +
>  References
>  ==========
>  
> diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
> index 406b558abfef..4c2a225ba546 100644
> --- a/arch/x86/kvm/svm.c
> +++ b/arch/x86/kvm/svm.c
> @@ -6955,6 +6955,104 @@ static int sev_launch_secret(struct kvm *kvm, struct kvm_sev_cmd *argp)
>  	return ret;
>  }
>  
> +static int sev_send_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
> +{
> +	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
> +	void *amd_cert = NULL, *session_data = NULL;
> +	void *pdh_cert = NULL, *plat_cert = NULL;
> +	struct sev_data_send_start *data = NULL;
> +	struct kvm_sev_send_start params;
> +	int ret;
> +
> +	if (!sev_guest(kvm))
> +		return -ENOTTY;
> +
> +	if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data,
> +				sizeof(struct kvm_sev_send_start)))
> +		return -EFAULT;
> +
> +	data = kzalloc(sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	/* userspace wants to query the session length */
> +	if (!params.session_len)
> +		goto cmd;
> +
> +	if (!params.pdh_cert_uaddr || !params.pdh_cert_len ||
> +	    !params.session_uaddr)
> +		return -EINVAL;
> +
> +	/* copy the certificate blobs from userspace */
> +	pdh_cert = psp_copy_user_blob(params.pdh_cert_uaddr, params.pdh_cert_len);
> +	if (IS_ERR(pdh_cert)) {
> +		ret = PTR_ERR(pdh_cert);
> +		goto e_free;
> +	}
> +
> +	data->pdh_cert_address = __psp_pa(pdh_cert);
> +	data->pdh_cert_len = params.pdh_cert_len;
> +
> +	plat_cert = psp_copy_user_blob(params.plat_cert_uaddr, params.plat_cert_len);
> +	if (IS_ERR(plat_cert)) {
> +		ret = PTR_ERR(plat_cert);
> +		goto e_free_pdh;
> +	}
> +
> +	data->plat_cert_address = __psp_pa(plat_cert);
> +	data->plat_cert_len = params.plat_cert_len;
> +
> +	amd_cert = psp_copy_user_blob(params.amd_cert_uaddr, params.amd_cert_len);
> +	if (IS_ERR(amd_cert)) {
> +		ret = PTR_ERR(amd_cert);
> +		goto e_free_plat_cert;
> +	}
> +
> +	data->amd_cert_address = __psp_pa(amd_cert);
> +	data->amd_cert_len = params.amd_cert_len;
> +
> +	ret = -ENOMEM;
> +	session_data = kmalloc(params.session_len, GFP_KERNEL);

If the user is supposed to query the session length first, you could
save it in a global variable perhaps and use that value instead of
trusting the user to give you the correct one in params.session_len for
the allocation...

> +	if (!session_data)
> +		goto e_free_amd_cert;
> +
> +	data->session_address = __psp_pa(session_data);
> +	data->session_len = params.session_len;
> +cmd:
> +	data->handle = sev->handle;
> +	ret = sev_issue_cmd(kvm, SEV_CMD_SEND_START, data, &argp->error);
> +
> +	/* if we queried the session length, FW responded with expected data */

<--- ... here you have the session length from the fw.

-- 
Regards/Gruss,
    Boris.

Good mailing practices for 400: avoid top-posting and trim the reply.

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

* Re: [RFC PATCH v1 01/10] KVM: SVM: Add KVM_SEV SEND_START command
  2019-04-26 14:10   ` Borislav Petkov
@ 2019-04-26 14:29     ` Singh, Brijesh
  2019-04-26 20:43       ` Borislav Petkov
  0 siblings, 1 reply; 27+ messages in thread
From: Singh, Brijesh @ 2019-04-26 14:29 UTC (permalink / raw)
  To: Borislav Petkov
  Cc: Singh, Brijesh, kvm, qemu-devel, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Lendacky, Thomas, x86, linux-kernel



On 4/26/19 9:10 AM, Borislav Petkov wrote:
> On Wed, Apr 24, 2019 at 04:09:59PM +0000, Singh, Brijesh wrote:
>> The command is used to create an outgoing SEV guest encryption context.
>>
>> 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: "Radim Krčmář" <rkrcmar@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
>> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
>> ---
>>   .../virtual/kvm/amd-memory-encryption.rst     |  24 +++++
>>   arch/x86/kvm/svm.c                            | 101 ++++++++++++++++++
>>   include/uapi/linux/kvm.h                      |  12 +++
>>   3 files changed, 137 insertions(+)
>>
>> diff --git a/Documentation/virtual/kvm/amd-memory-encryption.rst b/Documentation/virtual/kvm/amd-memory-encryption.rst
>> index 659bbc093b52..340ac4f87321 100644
>> --- a/Documentation/virtual/kvm/amd-memory-encryption.rst
>> +++ b/Documentation/virtual/kvm/amd-memory-encryption.rst
>> @@ -238,6 +238,30 @@ Returns: 0 on success, -negative on error
>>                   __u32 trans_len;
>>           };
>>   
>> +10. KVM_SEV_SEND_START
>> +----------------------
>> +
>> +The KVM_SEV_SEND_START command can be used by the hypervisor to create an
>> +outgoing guest encryption context.
>> +
>> +Parameters (in): struct kvm_sev_send_start
>> +
>> +Returns: 0 on success, -negative on error
>> +
>> +::
>> +        struct kvm_sev_send_start {
>> +                __u32 policy;                 /* guest policy */
>> +
>> +                __u64 pdh_cert_uaddr;         /* platform Diffie-Hellman certificate */
>> +                __u32 pdh_cert_len;
>> +
>> +                __u64 plat_cert_uaddr;        /* platform certificate chain */
>> +                __u32 plat_cert_len;
>> +
>> +                __u64 amd_cert_uaddr;         /* AMD certificate */
>> +                __u32 amd_cert_len;
> 
>          __u64 session_uaddr;
>          __u32 session_len;
> 
> too, right?


Ah good catch, I will fix in next rev. thanks


> 
>> +        };
>> +
>>   References
>>   ==========
>>   
>> diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
>> index 406b558abfef..4c2a225ba546 100644
>> --- a/arch/x86/kvm/svm.c
>> +++ b/arch/x86/kvm/svm.c
>> @@ -6955,6 +6955,104 @@ static int sev_launch_secret(struct kvm *kvm, struct kvm_sev_cmd *argp)
>>   	return ret;
>>   }
>>   
>> +static int sev_send_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
>> +{
>> +	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
>> +	void *amd_cert = NULL, *session_data = NULL;
>> +	void *pdh_cert = NULL, *plat_cert = NULL;
>> +	struct sev_data_send_start *data = NULL;
>> +	struct kvm_sev_send_start params;
>> +	int ret;
>> +
>> +	if (!sev_guest(kvm))
>> +		return -ENOTTY;
>> +
>> +	if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data,
>> +				sizeof(struct kvm_sev_send_start)))
>> +		return -EFAULT;
>> +
>> +	data = kzalloc(sizeof(*data), GFP_KERNEL);
>> +	if (!data)
>> +		return -ENOMEM;
>> +
>> +	/* userspace wants to query the session length */
>> +	if (!params.session_len)
>> +		goto cmd;
>> +
>> +	if (!params.pdh_cert_uaddr || !params.pdh_cert_len ||
>> +	    !params.session_uaddr)
>> +		return -EINVAL;
>> +
>> +	/* copy the certificate blobs from userspace */
>> +	pdh_cert = psp_copy_user_blob(params.pdh_cert_uaddr, params.pdh_cert_len);
>> +	if (IS_ERR(pdh_cert)) {
>> +		ret = PTR_ERR(pdh_cert);
>> +		goto e_free;
>> +	}
>> +
>> +	data->pdh_cert_address = __psp_pa(pdh_cert);
>> +	data->pdh_cert_len = params.pdh_cert_len;
>> +
>> +	plat_cert = psp_copy_user_blob(params.plat_cert_uaddr, params.plat_cert_len);
>> +	if (IS_ERR(plat_cert)) {
>> +		ret = PTR_ERR(plat_cert);
>> +		goto e_free_pdh;
>> +	}
>> +
>> +	data->plat_cert_address = __psp_pa(plat_cert);
>> +	data->plat_cert_len = params.plat_cert_len;
>> +
>> +	amd_cert = psp_copy_user_blob(params.amd_cert_uaddr, params.amd_cert_len);
>> +	if (IS_ERR(amd_cert)) {
>> +		ret = PTR_ERR(amd_cert);
>> +		goto e_free_plat_cert;
>> +	}
>> +
>> +	data->amd_cert_address = __psp_pa(amd_cert);
>> +	data->amd_cert_len = params.amd_cert_len;
>> +
>> +	ret = -ENOMEM;
>> +	session_data = kmalloc(params.session_len, GFP_KERNEL);
> 
> If the user is supposed to query the session length first, you could
> save it in a global variable perhaps and use that value instead of
> trusting the user to give you the correct one in params.session_len for
> the allocation...
> 

Yes that's doable but I am afraid that caching the value may lead us to
wrong path and also divergence from the SEV API spec. The spec says the
returned length is a minimum length but its possible that caller can
give a bigger buffer and FW will still work with it.


>> +	if (!session_data)
>> +		goto e_free_amd_cert;
>> +
>> +	data->session_address = __psp_pa(session_data);
>> +	data->session_len = params.session_len;
>> +cmd:
>> +	data->handle = sev->handle;
>> +	ret = sev_issue_cmd(kvm, SEV_CMD_SEND_START, data, &argp->error);
>> +
>> +	/* if we queried the session length, FW responded with expected data */
> 
> <--- ... here you have the session length from the fw.
> 

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

* Re: [RFC PATCH v1 02/10] KVM: SVM: Add KVM_SEND_UPDATE_DATA command
  2019-04-24 16:10 ` [RFC PATCH v1 02/10] KVM: SVM: Add KVM_SEND_UPDATE_DATA command Singh, Brijesh
@ 2019-04-26 20:31   ` Lendacky, Thomas
  2019-04-29 16:54     ` Singh, Brijesh
  0 siblings, 1 reply; 27+ messages in thread
From: Lendacky, Thomas @ 2019-04-26 20:31 UTC (permalink / raw)
  To: Singh, Brijesh, kvm
  Cc: qemu-devel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
	Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Borislav Petkov, x86, linux-kernel

On 4/24/19 11:10 AM, Singh, Brijesh wrote:
> The command is used for encrypting the guest memory region using the encryption
> context created with KVM_SEV_SEND_START.
> 
> 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: "Radim Krčmář" <rkrcmar@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
> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> ---
>  .../virtual/kvm/amd-memory-encryption.rst     |  23 ++++
>  arch/x86/kvm/svm.c                            | 128 +++++++++++++++++-
>  include/uapi/linux/kvm.h                      |   9 ++
>  3 files changed, 157 insertions(+), 3 deletions(-)
> 
> diff --git a/Documentation/virtual/kvm/amd-memory-encryption.rst b/Documentation/virtual/kvm/amd-memory-encryption.rst
> index 340ac4f87321..a0208e171489 100644
> --- a/Documentation/virtual/kvm/amd-memory-encryption.rst
> +++ b/Documentation/virtual/kvm/amd-memory-encryption.rst
> @@ -262,6 +262,29 @@ Returns: 0 on success, -negative on error
>                  __u32 amd_cert_len;
>          };
>  
> +11. KVM_SEV_SEND_UPDATE_DATA
> +----------------------------
> +
> +The KVM_SEV_SEND_UPDATE_DATA command can be used by the hypervisor to encrypt the
> +outgoing guest memory region with encryption context creating using KVM_SEV_SEND_START.

with the encryption context created using...

> +
> +Parameters (in): struct kvm_sev_send_update_data
> +
> +Returns: 0 on success, -negative on error
> +
> +::
> +
> +        struct kvm_sev_launch_send_update_data {
> +                __u64 hdr_uaddr;        /* userspace address containing the packet header */
> +                __u32 hdr_len;
> +
> +                __u64 guest_uaddr;      /* the source memory region to be encrypted */
> +                __u32 guest_len;
> +
> +                __u64 trans_uaddr;      /* the destition memory region  */
> +                __u32 trans_len;
> +        };
> +
>  References
>  ==========
>  
> diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
> index 4c2a225ba546..a1cfd36d6195 100644
> --- a/arch/x86/kvm/svm.c
> +++ b/arch/x86/kvm/svm.c
> @@ -418,6 +418,7 @@ enum {
>  
>  static unsigned int max_sev_asid;
>  static unsigned int min_sev_asid;
> +static unsigned long me_mask;

sev_me_mask ?

>  static unsigned long *sev_asid_bitmap;
>  #define __sme_page_pa(x) __sme_set(page_to_pfn(x) << PAGE_SHIFT)
>  
> @@ -1216,15 +1217,21 @@ static int avic_ga_log_notifier(u32 ga_tag)
>  static __init int sev_hardware_setup(void)
>  {
>  	struct sev_user_data_status *status;
> +	int eax, ebx;
>  	int rc;
>  
> -	/* Maximum number of encrypted guests supported simultaneously */
> -	max_sev_asid = cpuid_ecx(0x8000001F);
> +	/*
> +	 * Query the memory encryption information.
> +	 *  EBX:  Bit 0:5 Pagetable bit position used to indicate encryption (aka Cbit).
> +	 *  ECX:  Maximum number of encrypted guests supported simultaneously.
> +	 *  EDX:  Minimum ASID value that should be used for SEV guest.
> +	 */
> +	cpuid(0x8000001f, &eax, &ebx, &max_sev_asid, &min_sev_asid);
>  
>  	if (!max_sev_asid)
>  		return 1;
>  
> -	/* Minimum ASID value that should be used for SEV guest */
> +	me_mask = 1UL << (ebx & 0x3f);
>  	min_sev_asid = cpuid_edx(0x8000001F);

You can remove this since you obtained it with the cpuid() call above.

>  
>  	/* Initialize SEV ASID bitmap */
> @@ -7053,6 +7060,118 @@ static int sev_send_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
>  	return ret;
>  }
>  
> +static int sev_send_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)
> +{
> +	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
> +	struct sev_data_send_update_data *data;
> +	struct kvm_sev_send_update_data params;
> +	void *hdr = NULL, *trans_data = NULL;
> +	struct page **guest_page = NULL;
> +	unsigned long n;
> +	int ret, offset;
> +
> +	if (!sev_guest(kvm))
> +		return -ENOTTY;
> +
> +	if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data,
> +			sizeof(struct kvm_sev_send_update_data)))
> +		return -EFAULT;
> +
> +	data = kzalloc(sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	/* userspace wants to query either header or trans length */
> +	if (!params.trans_len || !params.hdr_len)
> +		goto cmd;
> +
> +	ret = -EINVAL;
> +	if (!params.trans_uaddr || !params.guest_uaddr ||
> +	    !params.guest_len || !params.hdr_uaddr)
> +		goto e_free;
> +
> +	/* Check if we are crossing the page boundry */
> +	ret = -EINVAL;
> +	offset = params.guest_uaddr & (PAGE_SIZE - 1);
> +	if ((params.guest_len + offset > PAGE_SIZE))
> +		goto e_free;
> +
> +	ret = -ENOMEM;
> +	hdr = kmalloc(params.hdr_len, GFP_KERNEL);
> +	if (!hdr)
> +		goto e_free;
> +
> +	data->hdr_address = __psp_pa(hdr);
> +	data->hdr_len = params.hdr_len;
> +
> +	ret = -ENOMEM;
> +	trans_data = kmalloc(params.trans_len, GFP_KERNEL);
> +	if (!trans_data)
> +		goto e_free;
> +
> +	data->trans_address = __psp_pa(trans_data);
> +	data->trans_len = params.trans_len;
> +
> +	/* Pin guest memory */
> +	ret = -EFAULT;
> +	guest_page = sev_pin_memory(kvm, params.guest_uaddr & PAGE_MASK,
> +				    PAGE_SIZE, &n, 0);
> +	if (!guest_page)
> +		goto e_free;
> +
> +	data->guest_address = __sme_page_pa(guest_page[0]) + offset;

If the C-bit needs to be set regardless below, then you don't need the
__sme version of this.

> +	data->guest_len = params.guest_len;
> +
> +	/*
> +	 * The SEND_UPDATE_DATA command requires C-bit to be always set.
> +	 * The __sme_page_pa() takes care of setting the C-bit only when SME
> +	 * is enabled on the host. But we need to set the C-bit regarless of

regardless

Thanks,
Tom

> +	 * the SME state.
> +	 */
> +	data->guest_address |= me_mask;
> +
> +	/* flush the caches to ensure that DRAM has recent contents */
> +	sev_clflush_pages(guest_page, 1);
> +
> +cmd:
> +	data->handle = sev->handle;
> +	ret = sev_issue_cmd(kvm, SEV_CMD_SEND_UPDATE_DATA, data, &argp->error);
> +
> +	/* userspace asked for header or trans length and FW responded with data */
> +	if (!params.trans_len || !params.hdr_len) {
> +		params.hdr_len = data->hdr_len;
> +		params.trans_len = data->trans_len;
> +		goto done;
> +	}
> +
> +	if (ret)
> +		goto e_unpin;
> +
> +	/* copy transport buffer to user space */
> +	if (copy_to_user((void __user *)(uintptr_t)params.trans_uaddr,
> +			 trans_data, params.trans_len)) {
> +		ret = -EFAULT;
> +		goto e_unpin;
> +	}
> +
> +	/* copy packet header to userspace */
> +	if (copy_to_user((void __user *)(uintptr_t)params.hdr_uaddr, hdr, params.hdr_len))
> +		ret = -EFAULT;
> +
> +e_unpin:
> +	sev_unpin_memory(kvm, guest_page, n);
> +done:
> +	if (copy_to_user((void __user *)(uintptr_t)argp->data, &params,
> +			sizeof(struct kvm_sev_send_update_data)))
> +		ret = -EFAULT;
> +e_free:
> +	kfree(data);
> +	kfree(trans_data);
> +	kfree(hdr);
> +
> +	return ret;
> +}
> +
>  static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
>  {
>  	struct kvm_sev_cmd sev_cmd;
> @@ -7097,6 +7216,9 @@ static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
>  	case KVM_SEV_SEND_START:
>  		r = sev_send_start(kvm, &sev_cmd);
>  		break;
> +	case KVM_SEV_SEND_UPDATE_DATA:
> +		r = sev_send_update_data(kvm, &sev_cmd);
> +		break;
>  	default:
>  		r = -EINVAL;
>  		goto out;
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index f425418bec13..0bee91bba329 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -1532,6 +1532,15 @@ struct kvm_sev_send_start {
>  	__u32 session_len;
>  };
>  
> +struct kvm_sev_send_update_data {
> +	__u64 hdr_uaddr;
> +	__u32 hdr_len;
> +	__u64 guest_uaddr;
> +	__u32 guest_len;
> +	__u64 trans_uaddr;
> +	__u32 trans_len;
> +};
> +
>  #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)
> 

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

* Re: [RFC PATCH v1 01/10] KVM: SVM: Add KVM_SEV SEND_START command
  2019-04-26 14:29     ` Singh, Brijesh
@ 2019-04-26 20:43       ` Borislav Petkov
  2019-04-29 15:01         ` Singh, Brijesh
  0 siblings, 1 reply; 27+ messages in thread
From: Borislav Petkov @ 2019-04-26 20:43 UTC (permalink / raw)
  To: Singh, Brijesh
  Cc: kvm, qemu-devel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
	Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Lendacky, Thomas, x86, linux-kernel

On Fri, Apr 26, 2019 at 02:29:31PM +0000, Singh, Brijesh wrote:
> Yes that's doable but I am afraid that caching the value may lead us to
> wrong path and also divergence from the SEV API spec. The spec says the
> returned length is a minimum length but its possible that caller can
> give a bigger buffer and FW will still work with it.

Does the caller even have a valid reason to give a bigger buffer len?

I mean I'm still thinking defensively here but maybe the only thing that
would happen here with a bigger buffer is if the kmalloc() would fail,
leading to eventual failure of the migration.

If the code limits the allocation to some sane max length, the migration
won't fail even if userspace gives it too big values...

-- 
Regards/Gruss,
    Boris.

Good mailing practices for 400: avoid top-posting and trim the reply.

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

* Re: [RFC PATCH v1 04/10] KVM: SVM: Add support for KVM_SEV_RECEIVE_START command
  2019-04-24 16:10 ` [RFC PATCH v1 04/10] KVM: SVM: Add support for KVM_SEV_RECEIVE_START command Singh, Brijesh
@ 2019-04-26 21:08   ` Lendacky, Thomas
  0 siblings, 0 replies; 27+ messages in thread
From: Lendacky, Thomas @ 2019-04-26 21:08 UTC (permalink / raw)
  To: Singh, Brijesh, kvm
  Cc: qemu-devel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
	Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Borislav Petkov, x86, linux-kernel

On 4/24/19 11:10 AM, Singh, Brijesh wrote:
> The command is used to create encryption context for the incoming

create the encryption context for an incoming

> SEV guest. The encryption context can be later unused by the hypervisor

can be later used by

> to import the incoming data into the SEV guest memory space.
> 
> 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: "Radim Krčmář" <rkrcmar@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
> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> ---
>  .../virtual/kvm/amd-memory-encryption.rst     | 29 +++++++
>  arch/x86/kvm/svm.c                            | 80 +++++++++++++++++++
>  include/uapi/linux/kvm.h                      |  9 +++
>  3 files changed, 118 insertions(+)
> 
> diff --git a/Documentation/virtual/kvm/amd-memory-encryption.rst b/Documentation/virtual/kvm/amd-memory-encryption.rst
> index 006832256ae3..acdff2454649 100644
> --- a/Documentation/virtual/kvm/amd-memory-encryption.rst
> +++ b/Documentation/virtual/kvm/amd-memory-encryption.rst
> @@ -293,6 +293,35 @@ issued by the hypervisor to delete the encryption context.
>  
>  Returns: 0 on success, -negative on error
>  
> +13. KVM_SEV_RECEIVE_START
> +------------------------
> +
> +The KVM_SEV_RECEIVE_START command is used for creating the memory encryption
> +context for an incoming SEV guest. To create the encryption context, user must

the user must

Thanks,
Tom

> +provide a guest policy, the platform public Diffie-Hellman (PDH) key and session
> +information.
> +
> +Parameters: struct  kvm_sev_receive_start (in/out)
> +
> +Returns: 0 on success, -negative on error
> +
> +::
> +
> +        struct kvm_sev_receive_start {
> +                __u32 handle;           /* if zero then firmware creates a new handle */
> +                __u32 policy;           /* guest's policy */
> +
> +                __u64 pdh_uaddr;         /* userspace address pointing to the PDH key */
> +                __u32 dh_len;
> +
> +                __u64 session_addr;     /* userspace address which points to the guest session information */
> +                __u32 session_len;
> +        };
> +
> +On success, the 'handle' field contains a new handle and on error, a negative value.
> +
> +For more details, see SEV spec Section 6.12.
> +
>  References
>  ==========
>  
> diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
> index 263f3c7deae7..a7dcf19baefb 100644
> --- a/arch/x86/kvm/svm.c
> +++ b/arch/x86/kvm/svm.c
> @@ -7192,6 +7192,83 @@ static int sev_send_finish(struct kvm *kvm, struct kvm_sev_cmd *argp)
>  	return ret;
>  }
>  
> +static int sev_receive_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
> +{
> +	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
> +	struct sev_data_receive_start *start;
> +	struct kvm_sev_receive_start params;
> +	int *error = &argp->error;
> +	void *session_data = NULL;
> +	void *pdh_data = NULL;
> +	int ret;
> +
> +	if (!sev_guest(kvm))
> +		return -ENOTTY;
> +
> +	/* Get parameter from the user */
> +	if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data,
> +			sizeof(struct kvm_sev_receive_start)))
> +		return -EFAULT;
> +
> +	if (!params.pdh_uaddr || !params.pdh_len ||
> +	    !params.session_uaddr || !params.session_len)
> +		return -EINVAL;
> +
> +	start = kzalloc(sizeof(*start), GFP_KERNEL);
> +	if (!start)
> +		return -ENOMEM;
> +
> +	start->handle = params.handle;
> +	start->policy = params.policy;
> +
> +	pdh_data = psp_copy_user_blob(params.pdh_uaddr, params.pdh_len);
> +	if (IS_ERR(pdh_data)) {
> +		ret = PTR_ERR(pdh_data);
> +		goto e_free;
> +	}
> +
> +	start->pdh_cert_address = __psp_pa(pdh_data);
> +	start->pdh_cert_len = params.pdh_len;
> +
> +	session_data = psp_copy_user_blob(params.session_uaddr, params.session_len);
> +	if (IS_ERR(session_data)) {
> +		ret = PTR_ERR(session_data);
> +		goto e_free_pdh;
> +	}
> +
> +	start->session_address = __psp_pa(session_data);
> +	start->session_len = params.session_len;
> +
> +	/* create memory encryption context */
> +	ret = __sev_issue_cmd(argp->sev_fd, SEV_CMD_RECEIVE_START, start, error);
> +	if (ret)
> +		goto e_free_session;
> +
> +	/* Bind ASID to this guest */
> +	ret = sev_bind_asid(kvm, start->handle, error);
> +	if (ret)
> +		goto e_free_session;
> +
> +	params.handle = start->handle;
> +	if (copy_to_user((void __user *)(uintptr_t)argp->data,
> +			 &params, sizeof(struct kvm_sev_receive_start))) {
> +		ret = -EFAULT;
> +		sev_unbind_asid(kvm, start->handle);
> +		goto e_free_session;
> +	}
> +
> +	sev->handle = start->handle;
> +	sev->fd = argp->sev_fd;
> +
> +e_free_session:
> +	kfree(session_data);
> +e_free_pdh:
> +	kfree(pdh_data);
> +e_free:
> +	kfree(start);
> +	return ret;
> +}
> +
>  static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
>  {
>  	struct kvm_sev_cmd sev_cmd;
> @@ -7242,6 +7319,9 @@ static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
>  	case KVM_SEV_SEND_FINISH:
>  		r = sev_send_finish(kvm, &sev_cmd);
>  		break;
> +	case KVM_SEV_RECEIVE_START:
> +		r = sev_receive_start(kvm, &sev_cmd);
> +		break;
>  	default:
>  		r = -EINVAL;
>  		goto out;
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index 0bee91bba329..fee75bf1fd90 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -1541,6 +1541,15 @@ struct kvm_sev_send_update_data {
>  	__u32 trans_len;
>  };
>  
> +struct kvm_sev_receive_start {
> +	__u32 handle;
> +	__u32 policy;
> +	__u64 pdh_uaddr;
> +	__u32 pdh_len;
> +	__u64 session_uaddr;
> +	__u32 session_len;
> +};
> +
>  #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)
> 

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

* Re: [RFC PATCH v1 05/10] KVM: SVM: Add KVM_SEV_RECEIVE_UPDATE_DATA command
  2019-04-24 16:10 ` [RFC PATCH v1 05/10] KVM: SVM: Add KVM_SEV_RECEIVE_UPDATE_DATA command Singh, Brijesh
@ 2019-04-26 21:11   ` Lendacky, Thomas
  0 siblings, 0 replies; 27+ messages in thread
From: Lendacky, Thomas @ 2019-04-26 21:11 UTC (permalink / raw)
  To: Singh, Brijesh, kvm
  Cc: qemu-devel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
	Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Borislav Petkov, x86, linux-kernel

On 4/24/19 11:10 AM, Singh, Brijesh wrote:
> The command is used for copying the incoming buffer into the
> SEV guest memory space.
> 
> 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: "Radim Krčmář" <rkrcmar@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
> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> ---
>  .../virtual/kvm/amd-memory-encryption.rst     | 24 ++++++
>  arch/x86/kvm/svm.c                            | 84 +++++++++++++++++++
>  include/uapi/linux/kvm.h                      |  9 ++
>  3 files changed, 117 insertions(+)
> 
> diff --git a/Documentation/virtual/kvm/amd-memory-encryption.rst b/Documentation/virtual/kvm/amd-memory-encryption.rst
> index acdff2454649..b9c3dc02f344 100644
> --- a/Documentation/virtual/kvm/amd-memory-encryption.rst
> +++ b/Documentation/virtual/kvm/amd-memory-encryption.rst
> @@ -322,6 +322,30 @@ On success, the 'handle' field contains a new handle and on error, a negative va
>  
>  For more details, see SEV spec Section 6.12.
>  
> +14. KVM_SEV_RECEIVE_UPDATE_DATA
> +----------------------------
> +
> +The KVM_SEV_RECEIVE_UPDATE_DATA command can be used by the hypervisor to copy
> +the incoming buffers into the guest memory region with encryption context
> +created during the KVM_SEV_RECEIVE_START.
> +
> +Parameters (in): struct kvm_sev_receive_update_data
> +
> +Returns: 0 on success, -negative on error
> +
> +::
> +
> +        struct kvm_sev_launch_receive_update_data {
> +                __u64 hdr_uaddr;        /* userspace address containing the packet header */
> +                __u32 hdr_len;
> +
> +                __u64 guest_uaddr;      /* the destination guest memory region */
> +                __u32 guest_len;
> +
> +                __u64 trans_uaddr;      /* the incoming buffer memory region  */
> +                __u32 trans_len;
> +        };
> +
>  References
>  ==========
>  
> diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
> index a7dcf19baefb..c81cac09c5af 100644
> --- a/arch/x86/kvm/svm.c
> +++ b/arch/x86/kvm/svm.c
> @@ -7269,6 +7269,87 @@ static int sev_receive_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
>  	return ret;
>  }
>  
> +static int sev_receive_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)
> +{
> +	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
> +	struct kvm_sev_receive_update_data params;
> +	struct sev_data_receive_update_data *data;
> +	void *hdr = NULL, *trans = NULL;
> +	struct page **guest_page;
> +	unsigned long n;
> +	int ret, offset;
> +
> +	if (!sev_guest(kvm))
> +		return -EINVAL;
> +
> +	if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data,
> +			sizeof(struct kvm_sev_receive_update_data)))
> +		return -EFAULT;
> +
> +	if (!params.hdr_uaddr || !params.hdr_len ||
> +	    !params.guest_uaddr || !params.guest_len ||
> +	    !params.trans_uaddr || !params.trans_len)
> +		return -EINVAL;
> +
> +	/* Check if we are crossing the page boundry */
> +	offset = params.guest_uaddr & (PAGE_SIZE - 1);
> +	if ((params.guest_len + offset > PAGE_SIZE))
> +		return -EINVAL;
> +
> +	data = kzalloc(sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	hdr = psp_copy_user_blob(params.hdr_uaddr, params.hdr_len);
> +	if (IS_ERR(hdr)) {
> +		ret = PTR_ERR(hdr);
> +		goto e_free;
> +	}
> +
> +	data->hdr_address = __psp_pa(hdr);
> +	data->hdr_len = params.hdr_len;
> +
> +	trans = psp_copy_user_blob(params.trans_uaddr, params.trans_len);
> +	if (IS_ERR(trans)) {
> +		ret = PTR_ERR(trans);
> +		goto e_free;
> +	}
> +
> +	data->trans_address = __psp_pa(trans);
> +	data->trans_len = params.trans_len;
> +
> +	/* Pin guest memory */
> +	ret = -EFAULT;
> +	guest_page = sev_pin_memory(kvm, params.guest_uaddr & PAGE_MASK,
> +				    PAGE_SIZE, &n, 0);
> +	if (!guest_page)
> +		goto e_free;
> +
> +	data->guest_address = __sme_page_pa(guest_page[0]) + offset;

Same comment here as in patch 02. No need to use the __sme version if
you're going to unconditionally set it below.

Thanks,
Tom

> +	data->guest_len = params.guest_len;
> +
> +	/*
> +	 * The RECEIVE_UPDATE_DATA command requires C-bit to be always set.
> +	 * The __sme_page_pa() takes care of setting the C-bit only when SME
> +	 * is enabled on the host. But we need to set the C-bit regarless of
> +	 * the SME state.
> +	 */
> +	data->guest_address |= me_mask;
> +
> +	/* flush the caches to ensure that DRAM has recent contents */
> +	sev_clflush_pages(guest_page, n);
> +
> +	data->handle = sev->handle;
> +	ret = sev_issue_cmd(kvm, SEV_CMD_RECEIVE_UPDATE_DATA, data, &argp->error);
> +
> +	sev_unpin_memory(kvm, guest_page, n);
> +e_free:
> +	kfree(data);
> +	kfree(hdr);
> +	kfree(trans);
> +	return ret;
> +}
> +
>  static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
>  {
>  	struct kvm_sev_cmd sev_cmd;
> @@ -7322,6 +7403,9 @@ static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
>  	case KVM_SEV_RECEIVE_START:
>  		r = sev_receive_start(kvm, &sev_cmd);
>  		break;
> +	case KVM_SEV_RECEIVE_UPDATE_DATA:
> +		r = sev_receive_update_data(kvm, &sev_cmd);
> +		break;
>  	default:
>  		r = -EINVAL;
>  		goto out;
> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
> index fee75bf1fd90..07e058a3ec11 100644
> --- a/include/uapi/linux/kvm.h
> +++ b/include/uapi/linux/kvm.h
> @@ -1550,6 +1550,15 @@ struct kvm_sev_receive_start {
>  	__u32 session_len;
>  };
>  
> +struct kvm_sev_receive_update_data {
> +	__u64 hdr_uaddr;
> +	__u32 hdr_len;
> +	__u64 guest_uaddr;
> +	__u32 guest_len;
> +	__u64 trans_uaddr;
> +	__u32 trans_len;
> +};
> +
>  #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)
> 

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

* Re: [RFC PATCH v1 06/10] KVM: SVM: Add KVM_SEV_RECEIVE_FINISH command
  2019-04-24 16:10 ` [RFC PATCH v1 06/10] KVM: SVM: Add KVM_SEV_RECEIVE_FINISH command Singh, Brijesh
@ 2019-04-26 21:11   ` Lendacky, Thomas
  0 siblings, 0 replies; 27+ messages in thread
From: Lendacky, Thomas @ 2019-04-26 21:11 UTC (permalink / raw)
  To: Singh, Brijesh, kvm
  Cc: qemu-devel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
	Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Borislav Petkov, x86, linux-kernel

On 4/24/19 11:10 AM, Singh, Brijesh wrote:
> The command finalize the guest receiving process and make the SEV guest
> ready for the execution.
> 
> 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: "Radim Krčmář" <rkrcmar@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
> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> ---
>  .../virtual/kvm/amd-memory-encryption.rst     |  8 +++++++
>  arch/x86/kvm/svm.c                            | 23 +++++++++++++++++++
>  2 files changed, 31 insertions(+)
> 
> diff --git a/Documentation/virtual/kvm/amd-memory-encryption.rst b/Documentation/virtual/kvm/amd-memory-encryption.rst
> index b9c3dc02f344..72c45f93abd7 100644
> --- a/Documentation/virtual/kvm/amd-memory-encryption.rst
> +++ b/Documentation/virtual/kvm/amd-memory-encryption.rst
> @@ -346,6 +346,14 @@ Returns: 0 on success, -negative on error
>                  __u32 trans_len;
>          };
>  
> +15. KVM_SEV_RECEIVE_FINISH
> +------------------------
> +
> +After completion of the migration flow, the KVM_SEV_RECEIVE_FINISH command can be
> +issued by the hypervisor to make the guest ready for the execution.

for execution.

Thanks,
Tom

> +
> +Returns: 0 on success, -negative on error
> +
>  References
>  ==========
>  
> diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
> index c81cac09c5af..74b57ab742ad 100644
> --- a/arch/x86/kvm/svm.c
> +++ b/arch/x86/kvm/svm.c
> @@ -7350,6 +7350,26 @@ static int sev_receive_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)
>  	return ret;
>  }
>  
> +static int sev_receive_finish(struct kvm *kvm, struct kvm_sev_cmd *argp)
> +{
> +	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
> +	struct sev_data_receive_finish *data;
> +	int ret;
> +
> +	if (!sev_guest(kvm))
> +		return -ENOTTY;
> +
> +	data = kzalloc(sizeof(*data), GFP_KERNEL);
> +	if (!data)
> +		return -ENOMEM;
> +
> +	data->handle = sev->handle;
> +	ret = sev_issue_cmd(kvm, SEV_CMD_RECEIVE_FINISH, data, &argp->error);
> +
> +	kfree(data);
> +	return ret;
> +}
> +
>  static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
>  {
>  	struct kvm_sev_cmd sev_cmd;
> @@ -7406,6 +7426,9 @@ static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
>  	case KVM_SEV_RECEIVE_UPDATE_DATA:
>  		r = sev_receive_update_data(kvm, &sev_cmd);
>  		break;
> +	case KVM_SEV_RECEIVE_FINISH:
> +		r = sev_receive_finish(kvm, &sev_cmd);
> +		break;
>  	default:
>  		r = -EINVAL;
>  		goto out;
> 

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

* Re: [RFC PATCH v1 08/10] KVM: X86: Introduce KVM_HC_PAGE_ENC_STATUS hypercall
  2019-04-24 16:10 ` [RFC PATCH v1 08/10] KVM: X86: Introduce KVM_HC_PAGE_ENC_STATUS hypercall Singh, Brijesh
@ 2019-04-26 21:39   ` Lendacky, Thomas
  2019-05-03 14:25     ` Singh, Brijesh
  0 siblings, 1 reply; 27+ messages in thread
From: Lendacky, Thomas @ 2019-04-26 21:39 UTC (permalink / raw)
  To: Singh, Brijesh, kvm
  Cc: qemu-devel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
	Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Borislav Petkov, x86, linux-kernel

On 4/24/19 11:10 AM, Singh, Brijesh wrote:
> The hypercall can be used by the SEV guest to notify the page encryption

This hyercall is used by the SEV guest to notify a change in the page...

> status to the hypervisor. The hypercall should be invoked only when
> the encryption attribute is changed from encrypted -> decrypted and vice
> versa. By default all the guest pages should be considered encrypted.

By default all guest page are considered

> 
> 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: "Radim Krčmář" <rkrcmar@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
> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
> ---
>  Documentation/virtual/kvm/hypercalls.txt | 14 +++++
>  arch/x86/include/asm/kvm_host.h          |  2 +
>  arch/x86/kvm/svm.c                       | 69 ++++++++++++++++++++++++
>  arch/x86/kvm/vmx/vmx.c                   |  1 +
>  arch/x86/kvm/x86.c                       |  5 ++
>  include/uapi/linux/kvm_para.h            |  1 +
>  6 files changed, 92 insertions(+)
> 
> diff --git a/Documentation/virtual/kvm/hypercalls.txt b/Documentation/virtual/kvm/hypercalls.txt
> index da24c138c8d1..ecd44e488679 100644
> --- a/Documentation/virtual/kvm/hypercalls.txt
> +++ b/Documentation/virtual/kvm/hypercalls.txt
> @@ -141,3 +141,17 @@ a0 corresponds to the APIC ID in the third argument (a2), bit 1
>  corresponds to the APIC ID a2+1, and so on.
>  
>  Returns the number of CPUs to which the IPIs were delivered successfully.
> +
> +7. KVM_HC_PAGE_ENC_STATUS
> +-------------------------
> +Architecture: x86
> +Status: active
> +Purpose: Notify the encryption status changes in guest page table (SEV guest)
> +
> +a0: the guest physical address of the start page
> +a1: the number of pages
> +a2: set or clear the encryption attribute

a2: encryption attribute

> +
> +   Where:
> +	* 1: Encryption attribute is set
> +	* 0: Encryption attribute is cleared
> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
> index a9d03af34030..adb0ca035b97 100644
> --- a/arch/x86/include/asm/kvm_host.h
> +++ b/arch/x86/include/asm/kvm_host.h
> @@ -1196,6 +1196,8 @@ struct kvm_x86_ops {
>  	uint16_t (*nested_get_evmcs_version)(struct kvm_vcpu *vcpu);
>  
>  	bool (*need_emulation_on_page_fault)(struct kvm_vcpu *vcpu);
> +	int (*page_enc_status_hc)(struct kvm *kvm, unsigned long gpa,
> +				  unsigned long sz, unsigned long mode);
>  };
>  
>  struct kvm_arch_async_pf {
> diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
> index 74b57ab742ad..f024f208b052 100644
> --- a/arch/x86/kvm/svm.c
> +++ b/arch/x86/kvm/svm.c
> @@ -138,6 +138,8 @@ struct kvm_sev_info {
>  	int fd;			/* SEV device fd */
>  	unsigned long pages_locked; /* Number of pages locked */
>  	struct list_head regions_list;  /* List of registered regions */
> +	unsigned long *page_enc_bmap;
> +	unsigned long page_enc_bmap_size;
>  };
>  
>  struct kvm_svm {
> @@ -1911,6 +1913,8 @@ static void sev_vm_destroy(struct kvm *kvm)
>  
>  	sev_unbind_asid(kvm, sev->handle);
>  	sev_asid_free(kvm);
> +
> +	kvfree(sev->page_enc_bmap);
>  }
>  
>  static void avic_vm_destroy(struct kvm *kvm)
> @@ -7370,6 +7374,69 @@ static int sev_receive_finish(struct kvm *kvm, struct kvm_sev_cmd *argp)
>  	return ret;
>  }
>  
> +static int sev_resize_page_enc_bitmap(struct kvm *kvm, unsigned long new_size)
> +{
> +	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
> +	unsigned long *map;
> +	unsigned long sz;
> +
> +	if (sev->page_enc_bmap_size >= new_size)
> +		return 0;
> +
> +	sz = ALIGN(new_size, BITS_PER_LONG) / 8;
> +
> +	if (sz > PAGE_SIZE)
> +		map = vmalloc(sz);
> +	else
> +		map = kmalloc(sz, GFP_KERNEL);

Any reason this can't always be vmalloc()?

> +
> +	if (!map) {
> +		pr_err_once("Failed to allocate decrypted bitmap size %lx\n", sz);
> +		return 1;

Should this be -ENOMEM?

> +	}
> +
> +	/* mark the page encrypted (by default) */
> +	memset(map, 0xff, sz);
> +
> +	bitmap_copy(map, sev->page_enc_bmap, sev->page_enc_bmap_size);
> +	kvfree(sev->page_enc_bmap);
> +
> +	sev->page_enc_bmap = map;
> +	sev->page_enc_bmap_size = new_size;
> +
> +	return 0;
> +}
> +
> +static int svm_page_enc_status_hc(struct kvm *kvm, unsigned long gpa,
> +				  unsigned long npages, unsigned long enc)
> +{
> +	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
> +	gfn_t gfn_start, gfn_end;
> +	int r;

int ret; ?  "r" at first confused me.

> +
> +	if (!npages)
> +		return 0;
> +
> +	gfn_start = gpa_to_gfn(gpa);
> +	gfn_end = gfn_start + npages;
> +
> +	mutex_lock(&kvm->lock);
> +
> +	r = 1;
> +	if (sev_resize_page_enc_bitmap(kvm, gfn_end))

ret = sev_resize_...
if (ret)

> +		goto unlock;
> +
> +	if (enc)
> +		__bitmap_set(sev->page_enc_bmap, gfn_start, gfn_end - gfn_start);
> +	else
> +		__bitmap_clear(sev->page_enc_bmap, gfn_start, gfn_end - gfn_start);
> +
> +	r = 0;

If you do the above, this is not needed.

Thanks,
Tom

> +unlock:
> +	mutex_unlock(&kvm->lock);
> +	return r;
> +}
> +
>  static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
>  {
>  	struct kvm_sev_cmd sev_cmd;
> @@ -7711,6 +7778,8 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
>  	.nested_get_evmcs_version = nested_get_evmcs_version,
>  
>  	.need_emulation_on_page_fault = svm_need_emulation_on_page_fault,
> +
> +	.page_enc_status_hc = svm_page_enc_status_hc
>  };
>  
>  static int __init svm_init(void)
> diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
> index b4e7d645275a..9c814e560e0f 100644
> --- a/arch/x86/kvm/vmx/vmx.c
> +++ b/arch/x86/kvm/vmx/vmx.c
> @@ -7731,6 +7731,7 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = {
>  	.get_vmcs12_pages = NULL,
>  	.nested_enable_evmcs = NULL,
>  	.need_emulation_on_page_fault = vmx_need_emulation_on_page_fault,
> +	.page_enc_status_hc = NULL,
>  };
>  
>  static void vmx_cleanup_l1d_flush(void)
> diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
> index a0d1fc80ac5a..dea644be5992 100644
> --- a/arch/x86/kvm/x86.c
> +++ b/arch/x86/kvm/x86.c
> @@ -7141,6 +7141,11 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
>  	case KVM_HC_SEND_IPI:
>  		ret = kvm_pv_send_ipi(vcpu->kvm, a0, a1, a2, a3, op_64_bit);
>  		break;
> +	case KVM_HC_PAGE_ENC_STATUS:
> +		ret = -KVM_ENOSYS;
> +		if (kvm_x86_ops->page_enc_status_hc)
> +			ret = kvm_x86_ops->page_enc_status_hc(vcpu->kvm, a0, a1, a2);
> +		break;
>  	default:
>  		ret = -KVM_ENOSYS;
>  		break;
> diff --git a/include/uapi/linux/kvm_para.h b/include/uapi/linux/kvm_para.h
> index 6c0ce49931e5..3dc9e579f4f9 100644
> --- a/include/uapi/linux/kvm_para.h
> +++ b/include/uapi/linux/kvm_para.h
> @@ -28,6 +28,7 @@
>  #define KVM_HC_MIPS_CONSOLE_OUTPUT	8
>  #define KVM_HC_CLOCK_PAIRING		9
>  #define KVM_HC_SEND_IPI		10
> +#define KVM_HC_PAGE_ENC_STATUS		11
>  
>  /*
>   * hypercalls use architecture specific
> 

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

* Re: [RFC PATCH v1 01/10] KVM: SVM: Add KVM_SEV SEND_START command
  2019-04-26 20:43       ` Borislav Petkov
@ 2019-04-29 15:01         ` Singh, Brijesh
  2019-04-29 16:36           ` Borislav Petkov
  0 siblings, 1 reply; 27+ messages in thread
From: Singh, Brijesh @ 2019-04-29 15:01 UTC (permalink / raw)
  To: Borislav Petkov
  Cc: Singh, Brijesh, kvm, qemu-devel, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Lendacky, Thomas, x86, linux-kernel



On 4/26/19 3:43 PM, Borislav Petkov wrote:
> On Fri, Apr 26, 2019 at 02:29:31PM +0000, Singh, Brijesh wrote:
>> Yes that's doable but I am afraid that caching the value may lead us to
>> wrong path and also divergence from the SEV API spec. The spec says the
>> returned length is a minimum length but its possible that caller can
>> give a bigger buffer and FW will still work with it.
> 
> Does the caller even have a valid reason to give a bigger buffer len?
> 


Practically I don't see any reason why caller would do that but
theoretically it can. If we cache the len then we also need to consider
adding another flag to hint whether userspace ever requested length.
e.g an application can compute the length of session blob by looking at
the API version and spec and may never query the length.


> I mean I'm still thinking defensively here but maybe the only thing that
> would happen here with a bigger buffer is if the kmalloc() would fail,
> leading to eventual failure of the migration.
> 
> If the code limits the allocation to some sane max length, the migration
> won't fail even if userspace gives it too big values...
> 

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

* Re: [RFC PATCH v1 01/10] KVM: SVM: Add KVM_SEV SEND_START command
  2019-04-29 15:01         ` Singh, Brijesh
@ 2019-04-29 16:36           ` Borislav Petkov
  2019-04-29 16:43             ` Singh, Brijesh
  0 siblings, 1 reply; 27+ messages in thread
From: Borislav Petkov @ 2019-04-29 16:36 UTC (permalink / raw)
  To: Singh, Brijesh
  Cc: kvm, qemu-devel, Thomas Gleixner, Ingo Molnar, H. Peter Anvin,
	Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Lendacky, Thomas, x86, linux-kernel

On Mon, Apr 29, 2019 at 03:01:24PM +0000, Singh, Brijesh wrote:
> Practically I don't see any reason why caller would do that but
> theoretically it can. If we cache the len then we also need to consider
> adding another flag to hint whether userspace ever requested length.
> e.g an application can compute the length of session blob by looking at
> the API version and spec and may never query the length.
> 
> > I mean I'm still thinking defensively here but maybe the only thing that
> > would happen here with a bigger buffer is if the kmalloc() would fail,
> > leading to eventual failure of the migration.
> > 
> > If the code limits the allocation to some sane max length, the migration
> > won't fail even if userspace gives it too big values...

So what about this? Limiting to a sane length...

-- 
Regards/Gruss,
    Boris.

Good mailing practices for 400: avoid top-posting and trim the reply.

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

* Re: [RFC PATCH v1 01/10] KVM: SVM: Add KVM_SEV SEND_START command
  2019-04-29 16:36           ` Borislav Petkov
@ 2019-04-29 16:43             ` Singh, Brijesh
  0 siblings, 0 replies; 27+ messages in thread
From: Singh, Brijesh @ 2019-04-29 16:43 UTC (permalink / raw)
  To: Borislav Petkov
  Cc: Singh, Brijesh, kvm, qemu-devel, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Lendacky, Thomas, x86, linux-kernel



On 4/29/19 11:36 AM, Borislav Petkov wrote:
> So what about this? Limiting to a sane length...

Sure, we have defined a SEV_FW_BLOB_MAX_SIZE and can use it to limit
the blob copy size. I will do this in next rev. thanks

-Brijesh

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

* Re: [RFC PATCH v1 02/10] KVM: SVM: Add KVM_SEND_UPDATE_DATA command
  2019-04-26 20:31   ` Lendacky, Thomas
@ 2019-04-29 16:54     ` Singh, Brijesh
  0 siblings, 0 replies; 27+ messages in thread
From: Singh, Brijesh @ 2019-04-29 16:54 UTC (permalink / raw)
  To: Lendacky, Thomas, kvm
  Cc: Singh, Brijesh, qemu-devel, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Borislav Petkov, x86, linux-kernel



On 4/26/19 3:31 PM, Lendacky, Thomas wrote:
...

>>   
>>   static unsigned int max_sev_asid;
>>   static unsigned int min_sev_asid;
>> +static unsigned long me_mask;
> 
> sev_me_mask ?
> 

Agreed.

>>   static unsigned long *sev_asid_bitmap;
>>   #define __sme_page_pa(x) __sme_set(page_to_pfn(x) << PAGE_SHIFT)
>>   
>> @@ -1216,15 +1217,21 @@ static int avic_ga_log_notifier(u32 ga_tag)
>>   static __init int sev_hardware_setup(void)
>>   {
>>   	struct sev_user_data_status *status;
>> +	int eax, ebx;
>>   	int rc;
>>   
>> -	/* Maximum number of encrypted guests supported simultaneously */
>> -	max_sev_asid = cpuid_ecx(0x8000001F);
>> +	/*
>> +	 * Query the memory encryption information.
>> +	 *  EBX:  Bit 0:5 Pagetable bit position used to indicate encryption (aka Cbit).
>> +	 *  ECX:  Maximum number of encrypted guests supported simultaneously.
>> +	 *  EDX:  Minimum ASID value that should be used for SEV guest.
>> +	 */
>> +	cpuid(0x8000001f, &eax, &ebx, &max_sev_asid, &min_sev_asid);
>>   
>>   	if (!max_sev_asid)
>>   		return 1;
>>   
>> -	/* Minimum ASID value that should be used for SEV guest */
>> +	me_mask = 1UL << (ebx & 0x3f);
>>   	min_sev_asid = cpuid_edx(0x8000001F);
> 
> You can remove this since you obtained it with the cpuid() call above.
> 

I thought I removed it but.. I will take care in next rev.

>>   
>>   	/* Initialize SEV ASID bitmap */
>> @@ -7053,6 +7060,118 @@ static int sev_send_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
>>   	return ret;
>>   }
>>   
>> +static int sev_send_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp)
>> +{
>> +	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
>> +	struct sev_data_send_update_data *data;
>> +	struct kvm_sev_send_update_data params;
>> +	void *hdr = NULL, *trans_data = NULL;
>> +	struct page **guest_page = NULL;
>> +	unsigned long n;
>> +	int ret, offset;
>> +
>> +	if (!sev_guest(kvm))
>> +		return -ENOTTY;
>> +
>> +	if (copy_from_user(&params, (void __user *)(uintptr_t)argp->data,
>> +			sizeof(struct kvm_sev_send_update_data)))
>> +		return -EFAULT;
>> +
>> +	data = kzalloc(sizeof(*data), GFP_KERNEL);
>> +	if (!data)
>> +		return -ENOMEM;
>> +
>> +	/* userspace wants to query either header or trans length */
>> +	if (!params.trans_len || !params.hdr_len)
>> +		goto cmd;
>> +
>> +	ret = -EINVAL;
>> +	if (!params.trans_uaddr || !params.guest_uaddr ||
>> +	    !params.guest_len || !params.hdr_uaddr)
>> +		goto e_free;
>> +
>> +	/* Check if we are crossing the page boundry */
>> +	ret = -EINVAL;
>> +	offset = params.guest_uaddr & (PAGE_SIZE - 1);
>> +	if ((params.guest_len + offset > PAGE_SIZE))
>> +		goto e_free;
>> +
>> +	ret = -ENOMEM;
>> +	hdr = kmalloc(params.hdr_len, GFP_KERNEL);
>> +	if (!hdr)
>> +		goto e_free;
>> +
>> +	data->hdr_address = __psp_pa(hdr);
>> +	data->hdr_len = params.hdr_len;
>> +
>> +	ret = -ENOMEM;
>> +	trans_data = kmalloc(params.trans_len, GFP_KERNEL);
>> +	if (!trans_data)
>> +		goto e_free;
>> +
>> +	data->trans_address = __psp_pa(trans_data);
>> +	data->trans_len = params.trans_len;
>> +
>> +	/* Pin guest memory */
>> +	ret = -EFAULT;
>> +	guest_page = sev_pin_memory(kvm, params.guest_uaddr & PAGE_MASK,
>> +				    PAGE_SIZE, &n, 0);
>> +	if (!guest_page)
>> +		goto e_free;
>> +
>> +	data->guest_address = __sme_page_pa(guest_page[0]) + offset;
> 
> If the C-bit needs to be set regardless below, then you don't need the
> __sme version of this.
> 

Noted.


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

* Re: [RFC PATCH v1 08/10] KVM: X86: Introduce KVM_HC_PAGE_ENC_STATUS hypercall
  2019-04-26 21:39   ` Lendacky, Thomas
@ 2019-05-03 14:25     ` Singh, Brijesh
  0 siblings, 0 replies; 27+ messages in thread
From: Singh, Brijesh @ 2019-05-03 14:25 UTC (permalink / raw)
  To: Lendacky, Thomas, kvm
  Cc: Singh, Brijesh, qemu-devel, Thomas Gleixner, Ingo Molnar,
	H. Peter Anvin, Paolo Bonzini, Radim Krčmář,
	Joerg Roedel, Borislav Petkov, x86, linux-kernel



On 4/26/19 4:39 PM, Lendacky, Thomas wrote:
> On 4/24/19 11:10 AM, Singh, Brijesh wrote:
>> The hypercall can be used by the SEV guest to notify the page encryption
> 
> This hyercall is used by the SEV guest to notify a change in the page...
> 
>> status to the hypervisor. The hypercall should be invoked only when
>> the encryption attribute is changed from encrypted -> decrypted and vice
>> versa. By default all the guest pages should be considered encrypted.
> 
> By default all guest page are considered
> 
>>
>> 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: "Radim Krčmář" <rkrcmar@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
>> Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
>> ---
>>   Documentation/virtual/kvm/hypercalls.txt | 14 +++++
>>   arch/x86/include/asm/kvm_host.h          |  2 +
>>   arch/x86/kvm/svm.c                       | 69 ++++++++++++++++++++++++
>>   arch/x86/kvm/vmx/vmx.c                   |  1 +
>>   arch/x86/kvm/x86.c                       |  5 ++
>>   include/uapi/linux/kvm_para.h            |  1 +
>>   6 files changed, 92 insertions(+)
>>
>> diff --git a/Documentation/virtual/kvm/hypercalls.txt b/Documentation/virtual/kvm/hypercalls.txt
>> index da24c138c8d1..ecd44e488679 100644
>> --- a/Documentation/virtual/kvm/hypercalls.txt
>> +++ b/Documentation/virtual/kvm/hypercalls.txt
>> @@ -141,3 +141,17 @@ a0 corresponds to the APIC ID in the third argument (a2), bit 1
>>   corresponds to the APIC ID a2+1, and so on.
>>   
>>   Returns the number of CPUs to which the IPIs were delivered successfully.
>> +
>> +7. KVM_HC_PAGE_ENC_STATUS
>> +-------------------------
>> +Architecture: x86
>> +Status: active
>> +Purpose: Notify the encryption status changes in guest page table (SEV guest)
>> +
>> +a0: the guest physical address of the start page
>> +a1: the number of pages
>> +a2: set or clear the encryption attribute
> 
> a2: encryption attribute
> 
>> +
>> +   Where:
>> +	* 1: Encryption attribute is set
>> +	* 0: Encryption attribute is cleared
>> diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
>> index a9d03af34030..adb0ca035b97 100644
>> --- a/arch/x86/include/asm/kvm_host.h
>> +++ b/arch/x86/include/asm/kvm_host.h
>> @@ -1196,6 +1196,8 @@ struct kvm_x86_ops {
>>   	uint16_t (*nested_get_evmcs_version)(struct kvm_vcpu *vcpu);
>>   
>>   	bool (*need_emulation_on_page_fault)(struct kvm_vcpu *vcpu);
>> +	int (*page_enc_status_hc)(struct kvm *kvm, unsigned long gpa,
>> +				  unsigned long sz, unsigned long mode);
>>   };
>>   
>>   struct kvm_arch_async_pf {
>> diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
>> index 74b57ab742ad..f024f208b052 100644
>> --- a/arch/x86/kvm/svm.c
>> +++ b/arch/x86/kvm/svm.c
>> @@ -138,6 +138,8 @@ struct kvm_sev_info {
>>   	int fd;			/* SEV device fd */
>>   	unsigned long pages_locked; /* Number of pages locked */
>>   	struct list_head regions_list;  /* List of registered regions */
>> +	unsigned long *page_enc_bmap;
>> +	unsigned long page_enc_bmap_size;
>>   };
>>   
>>   struct kvm_svm {
>> @@ -1911,6 +1913,8 @@ static void sev_vm_destroy(struct kvm *kvm)
>>   
>>   	sev_unbind_asid(kvm, sev->handle);
>>   	sev_asid_free(kvm);
>> +
>> +	kvfree(sev->page_enc_bmap);
>>   }
>>   
>>   static void avic_vm_destroy(struct kvm *kvm)
>> @@ -7370,6 +7374,69 @@ static int sev_receive_finish(struct kvm *kvm, struct kvm_sev_cmd *argp)
>>   	return ret;
>>   }
>>   
>> +static int sev_resize_page_enc_bitmap(struct kvm *kvm, unsigned long new_size)
>> +{
>> +	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
>> +	unsigned long *map;
>> +	unsigned long sz;
>> +
>> +	if (sev->page_enc_bmap_size >= new_size)
>> +		return 0;
>> +
>> +	sz = ALIGN(new_size, BITS_PER_LONG) / 8;
>> +
>> +	if (sz > PAGE_SIZE)
>> +		map = vmalloc(sz);
>> +	else
>> +		map = kmalloc(sz, GFP_KERNEL);
> 
> Any reason this can't always be vmalloc()?
> 

Yes, we can use vmalloc() unconditionally. The bitmap size will be
mostly greater than PAGE_SIZE hence the above is useless anyway.


>> +
>> +	if (!map) {
>> +		pr_err_once("Failed to allocate decrypted bitmap size %lx\n", sz);
>> +		return 1;
> 
> Should this be -ENOMEM?
> 
>> +	}
>> +
>> +	/* mark the page encrypted (by default) */
>> +	memset(map, 0xff, sz);
>> +
>> +	bitmap_copy(map, sev->page_enc_bmap, sev->page_enc_bmap_size);
>> +	kvfree(sev->page_enc_bmap);
>> +
>> +	sev->page_enc_bmap = map;
>> +	sev->page_enc_bmap_size = new_size;
>> +
>> +	return 0;
>> +}
>> +
>> +static int svm_page_enc_status_hc(struct kvm *kvm, unsigned long gpa,
>> +				  unsigned long npages, unsigned long enc)
>> +{
>> +	struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
>> +	gfn_t gfn_start, gfn_end;
>> +	int r;
> 
> int ret; ?  "r" at first confused me.


I will fix it in next rev.


> 
>> +
>> +	if (!npages)
>> +		return 0;
>> +
>> +	gfn_start = gpa_to_gfn(gpa);
>> +	gfn_end = gfn_start + npages;
>> +
>> +	mutex_lock(&kvm->lock);
>> +
>> +	r = 1;
>> +	if (sev_resize_page_enc_bitmap(kvm, gfn_end))
> 
> ret = sev_resize_...
> if (ret)
> 
>> +		goto unlock;
>> +
>> +	if (enc)
>> +		__bitmap_set(sev->page_enc_bmap, gfn_start, gfn_end - gfn_start);
>> +	else
>> +		__bitmap_clear(sev->page_enc_bmap, gfn_start, gfn_end - gfn_start);
>> +
>> +	r = 0;
> 
> If you do the above, this is not needed.
> 

Yes agreed. thanks

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

end of thread, other threads:[~2019-05-03 14:25 UTC | newest]

Thread overview: 27+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2019-04-24 16:09 [RFC PATCH v1 00/10] Add AMD SEV guest live migration support Singh, Brijesh
2019-04-24 16:09 ` [RFC PATCH v1 01/10] KVM: SVM: Add KVM_SEV SEND_START command Singh, Brijesh
2019-04-26 14:10   ` Borislav Petkov
2019-04-26 14:29     ` Singh, Brijesh
2019-04-26 20:43       ` Borislav Petkov
2019-04-29 15:01         ` Singh, Brijesh
2019-04-29 16:36           ` Borislav Petkov
2019-04-29 16:43             ` Singh, Brijesh
2019-04-24 16:10 ` [RFC PATCH v1 02/10] KVM: SVM: Add KVM_SEND_UPDATE_DATA command Singh, Brijesh
2019-04-26 20:31   ` Lendacky, Thomas
2019-04-29 16:54     ` Singh, Brijesh
2019-04-24 16:10 ` [RFC PATCH v1 03/10] KVM: SVM: Add KVM_SEV_SEND_FINISH command Singh, Brijesh
2019-04-24 16:10 ` [RFC PATCH v1 04/10] KVM: SVM: Add support for KVM_SEV_RECEIVE_START command Singh, Brijesh
2019-04-26 21:08   ` Lendacky, Thomas
2019-04-24 16:10 ` [RFC PATCH v1 05/10] KVM: SVM: Add KVM_SEV_RECEIVE_UPDATE_DATA command Singh, Brijesh
2019-04-26 21:11   ` Lendacky, Thomas
2019-04-24 16:10 ` [RFC PATCH v1 06/10] KVM: SVM: Add KVM_SEV_RECEIVE_FINISH command Singh, Brijesh
2019-04-26 21:11   ` Lendacky, Thomas
2019-04-24 16:10 ` [RFC PATCH v1 07/10] KVM: x86: Add AMD SEV specific Hypercall3 Singh, Brijesh
2019-04-24 16:10 ` [RFC PATCH v1 08/10] KVM: X86: Introduce KVM_HC_PAGE_ENC_STATUS hypercall Singh, Brijesh
2019-04-26 21:39   ` Lendacky, Thomas
2019-05-03 14:25     ` Singh, Brijesh
2019-04-24 16:10 ` [RFC PATCH v1 09/10] KVM: x86: Introduce KVM_GET_PAGE_ENC_BITMAP ioctl Singh, Brijesh
2019-04-24 16:10 ` [RFC PATCH v1 10/10] mm: x86: Invoke hypercall when page encryption status is changed Singh, Brijesh
2019-04-24 19:15 ` [RFC PATCH v1 00/10] Add AMD SEV guest live migration support Steve Rutherford
2019-04-24 21:32   ` Singh, Brijesh
     [not found]     ` <CABayD+fy5+QNU8YWsVrfd6jyvPo3AWCBgR-V8iWKzZkWxQY=zA@mail.gmail.com>
2019-04-25  2:15       ` Singh, Brijesh

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).