* [PATCH v5 00/14] Add AMD SEV guest live migration support
@ 2020-03-30 1:32 Ashish Kalra
2020-03-30 1:33 ` [PATCH v5 01/14] KVM: SVM: Add KVM_SEV SEND_START command Ashish Kalra
` (13 more replies)
0 siblings, 14 replies; 16+ messages in thread
From: Ashish Kalra @ 2020-03-30 1:32 UTC (permalink / raw)
To: pbonzini
Cc: tglx, mingo, hpa, joro, bp, thomas.lendacky, x86, kvm,
linux-kernel, rientjes, srutherford, luto, brijesh.singh
From: Ashish Kalra <ashish.kalra@amd.com>
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 new ioctls KVM_{SET,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
Changes since v4:
- Host support has been added to extend KVM capabilities/feature bits to
include a new KVM_FEATURE_SEV_LIVE_MIGRATION, which the guest can
query for host-side support for SEV live migration and a new custom MSR
MSR_KVM_SEV_LIVE_MIG_EN is added for guest to enable the SEV live
migration feature.
- Ensure that _bss_decrypted section is marked as decrypted in the
page encryption bitmap.
- Fixing KVM_GET_PAGE_ENC_BITMAP ioctl to return the correct bitmap
as per the number of pages being requested by the user. Ensure that
we only copy bmap->num_pages bytes in the userspace buffer, if
bmap->num_pages is not byte aligned we read the trailing bits
from the userspace and copy those bits as is. This fixes guest
page(s) corruption issues observed after migration completion.
- Add kexec support for SEV Live Migration to reset the host's
page encryption bitmap related to kernel specific page encryption
status settings before we load a new kernel by kexec. We cannot
reset the complete page encryption bitmap here as we need to
retain the UEFI/OVMF firmware specific settings.
Changes since v3:
- Rebasing to mainline and testing.
- Adding a new KVM_PAGE_ENC_BITMAP_RESET ioctl, which resets the
page encryption bitmap on a guest reboot event.
- Adding a more reliable sanity check for GPA range being passed to
the hypercall to ensure that guest MMIO ranges are also marked
in the page encryption bitmap.
Changes since v2:
- reset the page encryption bitmap on vcpu reboot
Changes since v1:
- Add support to share the page encryption between the source and target
machine.
- Fix review feedbacks from Tom Lendacky.
- Add check to limit the session blob length.
- Update KVM_GET_PAGE_ENC_BITMAP icotl to use the base_gfn instead of
the memory slot when querying the bitmap.
Ashish Kalra (3):
KVM: x86: Introduce KVM_PAGE_ENC_BITMAP_RESET ioctl
KVM: x86: Introduce new KVM_FEATURE_SEV_LIVE_MIGRATION feature &
Custom MSR.
KVM: x86: Add kexec support for SEV Live Migration.
Brijesh Singh (11):
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
KVM: x86: Introduce KVM_SET_PAGE_ENC_BITMAP ioctl
.../virt/kvm/amd-memory-encryption.rst | 120 +++
Documentation/virt/kvm/api.rst | 62 ++
Documentation/virt/kvm/cpuid.rst | 4 +
Documentation/virt/kvm/hypercalls.rst | 15 +
Documentation/virt/kvm/msr.rst | 10 +
arch/x86/include/asm/kvm_host.h | 10 +
arch/x86/include/asm/kvm_para.h | 12 +
arch/x86/include/asm/paravirt.h | 6 +
arch/x86/include/asm/paravirt_types.h | 2 +
arch/x86/include/uapi/asm/kvm_para.h | 5 +
arch/x86/kernel/kvm.c | 32 +
arch/x86/kernel/paravirt.c | 1 +
arch/x86/kvm/cpuid.c | 3 +-
arch/x86/kvm/svm.c | 698 +++++++++++++++++-
arch/x86/kvm/vmx/vmx.c | 1 +
arch/x86/kvm/x86.c | 43 ++
arch/x86/mm/mem_encrypt.c | 69 +-
arch/x86/mm/pat/set_memory.c | 7 +
include/linux/psp-sev.h | 8 +-
include/uapi/linux/kvm.h | 53 ++
include/uapi/linux/kvm_para.h | 1 +
21 files changed, 1152 insertions(+), 10 deletions(-)
--
2.17.1
^ permalink raw reply [flat|nested] 16+ messages in thread
* [PATCH v5 01/14] KVM: SVM: Add KVM_SEV SEND_START command
2020-03-30 1:32 [PATCH v5 00/14] Add AMD SEV guest live migration support Ashish Kalra
@ 2020-03-30 1:33 ` Ashish Kalra
2020-03-30 1:34 ` [PATCH v5 02/14] KVM: SVM: Add KVM_SEND_UPDATE_DATA command Ashish Kalra
` (12 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: Ashish Kalra @ 2020-03-30 1:33 UTC (permalink / raw)
To: pbonzini
Cc: tglx, mingo, hpa, joro, bp, thomas.lendacky, x86, kvm,
linux-kernel, rientjes, srutherford, luto, brijesh.singh
From: Brijesh Singh <Brijesh.Singh@amd.com>
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
Reviewed-by: Steve Rutherford <srutherford@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
---
.../virt/kvm/amd-memory-encryption.rst | 27 ++++
arch/x86/kvm/svm.c | 128 ++++++++++++++++++
include/linux/psp-sev.h | 8 +-
include/uapi/linux/kvm.h | 12 ++
4 files changed, 171 insertions(+), 4 deletions(-)
diff --git a/Documentation/virt/kvm/amd-memory-encryption.rst b/Documentation/virt/kvm/amd-memory-encryption.rst
index c3129b9ba5cb..4fd34fc5c7a7 100644
--- a/Documentation/virt/kvm/amd-memory-encryption.rst
+++ b/Documentation/virt/kvm/amd-memory-encryption.rst
@@ -263,6 +263,33 @@ 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_certs_uadr; /* platform certificate chain */
+ __u32 plat_certs_len;
+
+ __u64 amd_certs_uaddr; /* AMD certificate */
+ __u32 amd_cert_len;
+
+ __u64 session_uaddr; /* Guest session information */
+ __u32 session_len;
+ };
+
References
==========
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 50d1ebafe0b3..63d172e974ad 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -7149,6 +7149,131 @@ static int sev_launch_secret(struct kvm *kvm, struct kvm_sev_cmd *argp)
return ret;
}
+/* Userspace wants to query session length. */
+static int
+__sev_send_start_query_session_length(struct kvm *kvm, struct kvm_sev_cmd *argp,
+ struct kvm_sev_send_start *params)
+{
+ struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+ struct sev_data_send_start *data;
+ int ret;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
+ if (data == NULL)
+ return -ENOMEM;
+
+ data->handle = sev->handle;
+ ret = sev_issue_cmd(kvm, SEV_CMD_SEND_START, data, &argp->error);
+
+ 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;
+
+ kfree(data);
+ 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;
+ struct sev_data_send_start *data;
+ struct kvm_sev_send_start params;
+ void *amd_certs, *session_data;
+ void *pdh_cert, *plat_certs;
+ int ret;
+
+ if (!sev_guest(kvm))
+ return -ENOTTY;
+
+ if (copy_from_user(¶ms, (void __user *)(uintptr_t)argp->data,
+ sizeof(struct kvm_sev_send_start)))
+ return -EFAULT;
+
+ /* if session_len is zero, userspace wants to query the session length */
+ if (!params.session_len)
+ return __sev_send_start_query_session_length(kvm, argp,
+ ¶ms);
+
+ /* some sanity checks */
+ if (!params.pdh_cert_uaddr || !params.pdh_cert_len ||
+ !params.session_uaddr || params.session_len > SEV_FW_BLOB_MAX_SIZE)
+ return -EINVAL;
+
+ /* allocate the memory to hold the session data blob */
+ session_data = kmalloc(params.session_len, GFP_KERNEL_ACCOUNT);
+ if (!session_data)
+ return -ENOMEM;
+
+ /* 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_session;
+ }
+
+ plat_certs = psp_copy_user_blob(params.plat_certs_uaddr,
+ params.plat_certs_len);
+ if (IS_ERR(plat_certs)) {
+ ret = PTR_ERR(plat_certs);
+ goto e_free_pdh;
+ }
+
+ amd_certs = psp_copy_user_blob(params.amd_certs_uaddr,
+ params.amd_certs_len);
+ if (IS_ERR(amd_certs)) {
+ ret = PTR_ERR(amd_certs);
+ goto e_free_plat_cert;
+ }
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
+ if (data == NULL) {
+ ret = -ENOMEM;
+ goto e_free_amd_cert;
+ }
+
+ /* populate the FW SEND_START field with system physical address */
+ data->pdh_cert_address = __psp_pa(pdh_cert);
+ data->pdh_cert_len = params.pdh_cert_len;
+ data->plat_certs_address = __psp_pa(plat_certs);
+ data->plat_certs_len = params.plat_certs_len;
+ data->amd_certs_address = __psp_pa(amd_certs);
+ data->amd_certs_len = params.amd_certs_len;
+ data->session_address = __psp_pa(session_data);
+ data->session_len = params.session_len;
+ data->handle = sev->handle;
+
+ ret = sev_issue_cmd(kvm, SEV_CMD_SEND_START, data, &argp->error);
+
+ if (ret)
+ goto e_free;
+
+ if (copy_to_user((void __user *)(uintptr_t) params.session_uaddr,
+ session_data, params.session_len)) {
+ ret = -EFAULT;
+ goto e_free;
+ }
+
+ params.policy = data->policy;
+ params.session_len = data->session_len;
+ if (copy_to_user((void __user *)(uintptr_t)argp->data, ¶ms,
+ sizeof(struct kvm_sev_send_start)))
+ ret = -EFAULT;
+
+e_free:
+ kfree(data);
+e_free_amd_cert:
+ kfree(amd_certs);
+e_free_plat_cert:
+ kfree(plat_certs);
+e_free_pdh:
+ kfree(pdh_cert);
+e_free_session:
+ kfree(session_data);
+ return ret;
+}
+
static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
{
struct kvm_sev_cmd sev_cmd;
@@ -7193,6 +7318,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/linux/psp-sev.h b/include/linux/psp-sev.h
index 5167bf2bfc75..9f63b9d48b63 100644
--- a/include/linux/psp-sev.h
+++ b/include/linux/psp-sev.h
@@ -323,11 +323,11 @@ struct sev_data_send_start {
u64 pdh_cert_address; /* In */
u32 pdh_cert_len; /* In */
u32 reserved1;
- u64 plat_cert_address; /* In */
- u32 plat_cert_len; /* In */
+ u64 plat_certs_address; /* In */
+ u32 plat_certs_len; /* In */
u32 reserved2;
- u64 amd_cert_address; /* In */
- u32 amd_cert_len; /* In */
+ u64 amd_certs_address; /* In */
+ u32 amd_certs_len; /* In */
u32 reserved3;
u64 session_address; /* In */
u32 session_len; /* In/Out */
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index 4b95f9a31a2f..17bef4c245e1 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1558,6 +1558,18 @@ struct kvm_sev_dbg {
__u32 len;
};
+struct kvm_sev_send_start {
+ __u32 policy;
+ __u64 pdh_cert_uaddr;
+ __u32 pdh_cert_len;
+ __u64 plat_certs_uaddr;
+ __u32 plat_certs_len;
+ __u64 amd_certs_uaddr;
+ __u32 amd_certs_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] 16+ messages in thread
* [PATCH v5 02/14] KVM: SVM: Add KVM_SEND_UPDATE_DATA command
2020-03-30 1:32 [PATCH v5 00/14] Add AMD SEV guest live migration support Ashish Kalra
2020-03-30 1:33 ` [PATCH v5 01/14] KVM: SVM: Add KVM_SEV SEND_START command Ashish Kalra
@ 2020-03-30 1:34 ` Ashish Kalra
2020-03-30 1:34 ` [PATCH v5 03/14] KVM: SVM: Add KVM_SEV_SEND_FINISH command Ashish Kalra
` (11 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: Ashish Kalra @ 2020-03-30 1:34 UTC (permalink / raw)
To: pbonzini
Cc: tglx, mingo, hpa, joro, bp, thomas.lendacky, x86, kvm,
linux-kernel, rientjes, srutherford, luto, brijesh.singh
From: Brijesh Singh <Brijesh.Singh@amd.com>
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
Reviewed-by : Steve Rutherford <srutherford@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
---
.../virt/kvm/amd-memory-encryption.rst | 24 ++++
arch/x86/kvm/svm.c | 136 +++++++++++++++++-
include/uapi/linux/kvm.h | 9 ++
3 files changed, 165 insertions(+), 4 deletions(-)
diff --git a/Documentation/virt/kvm/amd-memory-encryption.rst b/Documentation/virt/kvm/amd-memory-encryption.rst
index 4fd34fc5c7a7..f46817ef7019 100644
--- a/Documentation/virt/kvm/amd-memory-encryption.rst
+++ b/Documentation/virt/kvm/amd-memory-encryption.rst
@@ -290,6 +290,30 @@ Returns: 0 on success, -negative on error
__u32 session_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 the 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 63d172e974ad..8561c47cc4f9 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -428,6 +428,7 @@ static DECLARE_RWSEM(sev_deactivate_lock);
static DEFINE_MUTEX(sev_bitmap_lock);
static unsigned int max_sev_asid;
static unsigned int min_sev_asid;
+static unsigned long sev_me_mask;
static unsigned long *sev_asid_bitmap;
static unsigned long *sev_reclaim_asid_bitmap;
#define __sme_page_pa(x) __sme_set(page_to_pfn(x) << PAGE_SHIFT)
@@ -1232,16 +1233,22 @@ static int avic_ga_log_notifier(u32 ga_tag)
static __init int sev_hardware_setup(void)
{
struct sev_user_data_status *status;
+ u32 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 */
- min_sev_asid = cpuid_edx(0x8000001F);
+ sev_me_mask = 1UL << (ebx & 0x3f);
/* Initialize SEV ASID bitmaps */
sev_asid_bitmap = bitmap_zalloc(max_sev_asid, GFP_KERNEL);
@@ -7274,6 +7281,124 @@ static int sev_send_start(struct kvm *kvm, struct kvm_sev_cmd *argp)
return ret;
}
+/* Userspace wants to query either header or trans length. */
+static int
+__sev_send_update_data_query_lengths(struct kvm *kvm, struct kvm_sev_cmd *argp,
+ struct kvm_sev_send_update_data *params)
+{
+ struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+ struct sev_data_send_update_data *data;
+ int ret;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL_ACCOUNT);
+ if (!data)
+ return -ENOMEM;
+
+ data->handle = sev->handle;
+ ret = sev_issue_cmd(kvm, SEV_CMD_SEND_UPDATE_DATA, data, &argp->error);
+
+ params->hdr_len = data->hdr_len;
+ params->trans_len = data->trans_len;
+
+ if (copy_to_user((void __user *)(uintptr_t)argp->data, params,
+ sizeof(struct kvm_sev_send_update_data)))
+ ret = -EFAULT;
+
+ kfree(data);
+ 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, *trans_data;
+ struct page **guest_page;
+ unsigned long n;
+ int ret, offset;
+
+ if (!sev_guest(kvm))
+ return -ENOTTY;
+
+ if (copy_from_user(¶ms, (void __user *)(uintptr_t)argp->data,
+ sizeof(struct kvm_sev_send_update_data)))
+ return -EFAULT;
+
+ /* userspace wants to query either header or trans length */
+ if (!params.trans_len || !params.hdr_len)
+ return __sev_send_update_data_query_lengths(kvm, argp, ¶ms);
+
+ if (!params.trans_uaddr || !params.guest_uaddr ||
+ !params.guest_len || !params.hdr_uaddr)
+ return -EINVAL;
+
+
+ /* Check if we are crossing the page boundary */
+ offset = params.guest_uaddr & (PAGE_SIZE - 1);
+ if ((params.guest_len + offset > PAGE_SIZE))
+ return -EINVAL;
+
+ /* Pin guest memory */
+ guest_page = sev_pin_memory(kvm, params.guest_uaddr & PAGE_MASK,
+ PAGE_SIZE, &n, 0);
+ if (!guest_page)
+ return -EFAULT;
+
+ /* allocate memory for header and transport buffer */
+ ret = -ENOMEM;
+ hdr = kmalloc(params.hdr_len, GFP_KERNEL_ACCOUNT);
+ if (!hdr)
+ goto e_unpin;
+
+ trans_data = kmalloc(params.trans_len, GFP_KERNEL_ACCOUNT);
+ if (!trans_data)
+ goto e_free_hdr;
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ goto e_free_trans_data;
+
+ data->hdr_address = __psp_pa(hdr);
+ data->hdr_len = params.hdr_len;
+ data->trans_address = __psp_pa(trans_data);
+ data->trans_len = params.trans_len;
+
+ /* The SEND_UPDATE_DATA command requires C-bit to be always set. */
+ data->guest_address = (page_to_pfn(guest_page[0]) << PAGE_SHIFT) +
+ offset;
+ data->guest_address |= sev_me_mask;
+ data->guest_len = params.guest_len;
+ data->handle = sev->handle;
+
+ ret = sev_issue_cmd(kvm, SEV_CMD_SEND_UPDATE_DATA, data, &argp->error);
+
+ if (ret)
+ goto e_free;
+
+ /* 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. */
+ ret = copy_to_user((void __user *)(uintptr_t)params.hdr_uaddr, hdr,
+ params.hdr_len);
+
+e_free:
+ kfree(data);
+e_free_trans_data:
+ kfree(trans_data);
+e_free_hdr:
+ kfree(hdr);
+e_unpin:
+ sev_unpin_memory(kvm, guest_page, n);
+
+ return ret;
+}
+
static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
{
struct kvm_sev_cmd sev_cmd;
@@ -7321,6 +7446,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 17bef4c245e1..d9dc81bb9c55 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1570,6 +1570,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] 16+ messages in thread
* [PATCH v5 03/14] KVM: SVM: Add KVM_SEV_SEND_FINISH command
2020-03-30 1:32 [PATCH v5 00/14] Add AMD SEV guest live migration support Ashish Kalra
2020-03-30 1:33 ` [PATCH v5 01/14] KVM: SVM: Add KVM_SEV SEND_START command Ashish Kalra
2020-03-30 1:34 ` [PATCH v5 02/14] KVM: SVM: Add KVM_SEND_UPDATE_DATA command Ashish Kalra
@ 2020-03-30 1:34 ` Ashish Kalra
2020-03-30 1:34 ` [PATCH v5 04/14] KVM: SVM: Add support for KVM_SEV_RECEIVE_START command Ashish Kalra
` (10 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: Ashish Kalra @ 2020-03-30 1:34 UTC (permalink / raw)
To: pbonzini
Cc: tglx, mingo, hpa, joro, bp, thomas.lendacky, x86, kvm,
linux-kernel, rientjes, srutherford, luto, brijesh.singh
From: Brijesh Singh <Brijesh.Singh@amd.com>
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
Reviewed-by: Steve Rutherford <srutherford@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
---
.../virt/kvm/amd-memory-encryption.rst | 8 +++++++
arch/x86/kvm/svm.c | 23 +++++++++++++++++++
2 files changed, 31 insertions(+)
diff --git a/Documentation/virt/kvm/amd-memory-encryption.rst b/Documentation/virt/kvm/amd-memory-encryption.rst
index f46817ef7019..a45dcb5f8687 100644
--- a/Documentation/virt/kvm/amd-memory-encryption.rst
+++ b/Documentation/virt/kvm/amd-memory-encryption.rst
@@ -314,6 +314,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 8561c47cc4f9..71a4cb3b817d 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -7399,6 +7399,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;
@@ -7449,6 +7469,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] 16+ messages in thread
* [PATCH v5 04/14] KVM: SVM: Add support for KVM_SEV_RECEIVE_START command
2020-03-30 1:32 [PATCH v5 00/14] Add AMD SEV guest live migration support Ashish Kalra
` (2 preceding siblings ...)
2020-03-30 1:34 ` [PATCH v5 03/14] KVM: SVM: Add KVM_SEV_SEND_FINISH command Ashish Kalra
@ 2020-03-30 1:34 ` Ashish Kalra
2020-03-30 1:35 ` [PATCH v5 05/14] KVM: SVM: Add KVM_SEV_RECEIVE_UPDATE_DATA command Ashish Kalra
` (9 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: Ashish Kalra @ 2020-03-30 1:34 UTC (permalink / raw)
To: pbonzini
Cc: tglx, mingo, hpa, joro, bp, thomas.lendacky, x86, kvm,
linux-kernel, rientjes, srutherford, luto, brijesh.singh
From: Brijesh Singh <Brijesh.Singh@amd.com>
The command is used to create the encryption context for an incoming
SEV guest. The encryption context can be later used 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
Reviewed-by: Steve Rutherford <srutherford@google.com>
Signed-off-by: Brijesh Singh <brijesh.singh@amd.com>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
---
.../virt/kvm/amd-memory-encryption.rst | 29 +++++++
arch/x86/kvm/svm.c | 81 +++++++++++++++++++
include/uapi/linux/kvm.h | 9 +++
3 files changed, 119 insertions(+)
diff --git a/Documentation/virt/kvm/amd-memory-encryption.rst b/Documentation/virt/kvm/amd-memory-encryption.rst
index a45dcb5f8687..ef1f1f3a5b40 100644
--- a/Documentation/virt/kvm/amd-memory-encryption.rst
+++ b/Documentation/virt/kvm/amd-memory-encryption.rst
@@ -322,6 +322,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, the 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 71a4cb3b817d..038b47685733 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -7419,6 +7419,84 @@ 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;
+ void *pdh_data;
+ int ret;
+
+ if (!sev_guest(kvm))
+ return -ENOTTY;
+
+ /* Get parameter from the userspace */
+ if (copy_from_user(¶ms, (void __user *)(uintptr_t)argp->data,
+ sizeof(struct kvm_sev_receive_start)))
+ return -EFAULT;
+
+ /* some sanity checks */
+ if (!params.pdh_uaddr || !params.pdh_len ||
+ !params.session_uaddr || !params.session_len)
+ return -EINVAL;
+
+ pdh_data = psp_copy_user_blob(params.pdh_uaddr, params.pdh_len);
+ if (IS_ERR(pdh_data))
+ return PTR_ERR(pdh_data);
+
+ 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;
+ }
+
+ ret = -ENOMEM;
+ start = kzalloc(sizeof(*start), GFP_KERNEL);
+ if (!start)
+ goto e_free_session;
+
+ start->handle = params.handle;
+ start->policy = params.policy;
+ start->pdh_cert_address = __psp_pa(pdh_data);
+ start->pdh_cert_len = params.pdh_len;
+ 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;
+
+ /* Bind ASID to this guest */
+ ret = sev_bind_asid(kvm, start->handle, error);
+ if (ret)
+ goto e_free;
+
+ params.handle = start->handle;
+ if (copy_to_user((void __user *)(uintptr_t)argp->data,
+ ¶ms, sizeof(struct kvm_sev_receive_start))) {
+ ret = -EFAULT;
+ sev_unbind_asid(kvm, start->handle);
+ goto e_free;
+ }
+
+ sev->handle = start->handle;
+ sev->fd = argp->sev_fd;
+
+e_free:
+ kfree(start);
+e_free_session:
+ kfree(session_data);
+e_free_pdh:
+ kfree(pdh_data);
+
+ return ret;
+}
+
static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
{
struct kvm_sev_cmd sev_cmd;
@@ -7472,6 +7550,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 d9dc81bb9c55..74764b9db5fa 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1579,6 +1579,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] 16+ messages in thread
* [PATCH v5 05/14] KVM: SVM: Add KVM_SEV_RECEIVE_UPDATE_DATA command
2020-03-30 1:32 [PATCH v5 00/14] Add AMD SEV guest live migration support Ashish Kalra
` (3 preceding siblings ...)
2020-03-30 1:34 ` [PATCH v5 04/14] KVM: SVM: Add support for KVM_SEV_RECEIVE_START command Ashish Kalra
@ 2020-03-30 1:35 ` Ashish Kalra
2020-03-30 1:35 ` [PATCH v5 06/14] KVM: SVM: Add KVM_SEV_RECEIVE_FINISH command Ashish Kalra
` (8 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: Ashish Kalra @ 2020-03-30 1:35 UTC (permalink / raw)
To: pbonzini
Cc: tglx, mingo, hpa, joro, bp, thomas.lendacky, x86, kvm,
linux-kernel, rientjes, srutherford, luto, brijesh.singh
From: Brijesh Singh <Brijesh.Singh@amd.com>
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>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
---
.../virt/kvm/amd-memory-encryption.rst | 24 ++++++
arch/x86/kvm/svm.c | 79 +++++++++++++++++++
include/uapi/linux/kvm.h | 9 +++
3 files changed, 112 insertions(+)
diff --git a/Documentation/virt/kvm/amd-memory-encryption.rst b/Documentation/virt/kvm/amd-memory-encryption.rst
index ef1f1f3a5b40..554aa33a99cc 100644
--- a/Documentation/virt/kvm/amd-memory-encryption.rst
+++ b/Documentation/virt/kvm/amd-memory-encryption.rst
@@ -351,6 +351,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 038b47685733..5fc5355536d7 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -7497,6 +7497,82 @@ 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(¶ms, (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 boundary */
+ offset = params.guest_uaddr & (PAGE_SIZE - 1);
+ if ((params.guest_len + offset > PAGE_SIZE))
+ return -EINVAL;
+
+ hdr = psp_copy_user_blob(params.hdr_uaddr, params.hdr_len);
+ if (IS_ERR(hdr))
+ return PTR_ERR(hdr);
+
+ trans = psp_copy_user_blob(params.trans_uaddr, params.trans_len);
+ if (IS_ERR(trans)) {
+ ret = PTR_ERR(trans);
+ goto e_free_hdr;
+ }
+
+ ret = -ENOMEM;
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data)
+ goto e_free_trans;
+
+ data->hdr_address = __psp_pa(hdr);
+ data->hdr_len = params.hdr_len;
+ 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;
+
+ /* The RECEIVE_UPDATE_DATA command requires C-bit to be always set. */
+ data->guest_address = (page_to_pfn(guest_page[0]) << PAGE_SHIFT) +
+ offset;
+ data->guest_address |= sev_me_mask;
+ data->guest_len = params.guest_len;
+ 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);
+e_free_trans:
+ kfree(trans);
+e_free_hdr:
+ kfree(hdr);
+
+ return ret;
+}
+
static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
{
struct kvm_sev_cmd sev_cmd;
@@ -7553,6 +7629,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 74764b9db5fa..4e80c57a3182 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1588,6 +1588,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] 16+ messages in thread
* [PATCH v5 06/14] KVM: SVM: Add KVM_SEV_RECEIVE_FINISH command
2020-03-30 1:32 [PATCH v5 00/14] Add AMD SEV guest live migration support Ashish Kalra
` (4 preceding siblings ...)
2020-03-30 1:35 ` [PATCH v5 05/14] KVM: SVM: Add KVM_SEV_RECEIVE_UPDATE_DATA command Ashish Kalra
@ 2020-03-30 1:35 ` Ashish Kalra
2020-03-30 1:35 ` [PATCH v5 07/14] KVM: x86: Add AMD SEV specific Hypercall3 Ashish Kalra
` (7 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: Ashish Kalra @ 2020-03-30 1:35 UTC (permalink / raw)
To: pbonzini
Cc: tglx, mingo, hpa, joro, bp, thomas.lendacky, x86, kvm,
linux-kernel, rientjes, srutherford, luto, brijesh.singh
From: Brijesh Singh <Brijesh.Singh@amd.com>
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>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
---
.../virt/kvm/amd-memory-encryption.rst | 8 +++++++
arch/x86/kvm/svm.c | 23 +++++++++++++++++++
2 files changed, 31 insertions(+)
diff --git a/Documentation/virt/kvm/amd-memory-encryption.rst b/Documentation/virt/kvm/amd-memory-encryption.rst
index 554aa33a99cc..93cd95d9a6c0 100644
--- a/Documentation/virt/kvm/amd-memory-encryption.rst
+++ b/Documentation/virt/kvm/amd-memory-encryption.rst
@@ -375,6 +375,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 execution.
+
+Returns: 0 on success, -negative on error
+
References
==========
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index 5fc5355536d7..7c2721e18b06 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -7573,6 +7573,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;
@@ -7632,6 +7652,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] 16+ messages in thread
* [PATCH v5 07/14] KVM: x86: Add AMD SEV specific Hypercall3
2020-03-30 1:32 [PATCH v5 00/14] Add AMD SEV guest live migration support Ashish Kalra
` (5 preceding siblings ...)
2020-03-30 1:35 ` [PATCH v5 06/14] KVM: SVM: Add KVM_SEV_RECEIVE_FINISH command Ashish Kalra
@ 2020-03-30 1:35 ` Ashish Kalra
2020-03-30 1:36 ` [PATCH v5 08/14] KVM: X86: Introduce KVM_HC_PAGE_ENC_STATUS hypercall Ashish Kalra
` (6 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: Ashish Kalra @ 2020-03-30 1:35 UTC (permalink / raw)
To: pbonzini
Cc: tglx, mingo, hpa, joro, bp, thomas.lendacky, x86, kvm,
linux-kernel, rientjes, srutherford, luto, brijesh.singh
From: Brijesh Singh <Brijesh.Singh@amd.com>
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>
Signed-off-by: Ashish Kalra <ashish.kalra@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 9b4df6eaa11a..6c09255633a4 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] 16+ messages in thread
* [PATCH v5 08/14] KVM: X86: Introduce KVM_HC_PAGE_ENC_STATUS hypercall
2020-03-30 1:32 [PATCH v5 00/14] Add AMD SEV guest live migration support Ashish Kalra
` (6 preceding siblings ...)
2020-03-30 1:35 ` [PATCH v5 07/14] KVM: x86: Add AMD SEV specific Hypercall3 Ashish Kalra
@ 2020-03-30 1:36 ` Ashish Kalra
2020-03-30 1:36 ` [PATCH v5 09/14] KVM: x86: Introduce KVM_GET_PAGE_ENC_BITMAP ioctl Ashish Kalra
` (5 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: Ashish Kalra @ 2020-03-30 1:36 UTC (permalink / raw)
To: pbonzini
Cc: tglx, mingo, hpa, joro, bp, thomas.lendacky, x86, kvm,
linux-kernel, rientjes, srutherford, luto, brijesh.singh
From: Brijesh Singh <Brijesh.Singh@amd.com>
This hypercall is used by the SEV guest to notify a change in 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 guest pages are 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>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
---
Documentation/virt/kvm/hypercalls.rst | 15 +++++
arch/x86/include/asm/kvm_host.h | 2 +
arch/x86/kvm/svm.c | 94 +++++++++++++++++++++++++++
arch/x86/kvm/vmx/vmx.c | 1 +
arch/x86/kvm/x86.c | 6 ++
include/uapi/linux/kvm_para.h | 1 +
6 files changed, 119 insertions(+)
diff --git a/Documentation/virt/kvm/hypercalls.rst b/Documentation/virt/kvm/hypercalls.rst
index dbaf207e560d..ff5287e68e81 100644
--- a/Documentation/virt/kvm/hypercalls.rst
+++ b/Documentation/virt/kvm/hypercalls.rst
@@ -169,3 +169,18 @@ a0: destination APIC ID
:Usage example: When sending a call-function IPI-many to vCPUs, yield if
any of the IPI target vCPUs was preempted.
+
+
+8. 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: 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 98959e8cd448..90718fa3db47 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1267,6 +1267,8 @@ struct kvm_x86_ops {
bool (*apic_init_signal_blocked)(struct kvm_vcpu *vcpu);
int (*enable_direct_tlbflush)(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 7c2721e18b06..6c924df1b7b7 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -136,6 +136,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 {
@@ -1991,6 +1993,9 @@ static void sev_vm_destroy(struct kvm *kvm)
sev_unbind_asid(kvm, sev->handle);
sev_asid_free(sev->asid);
+
+ kvfree(sev->page_enc_bmap);
+ sev->page_enc_bmap = NULL;
}
static void avic_vm_destroy(struct kvm *kvm)
@@ -7593,6 +7598,93 @@ 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;
+
+ map = vmalloc(sz);
+ if (!map) {
+ pr_err_once("Failed to allocate encrypted bitmap size %lx\n",
+ sz);
+ return -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 ret;
+
+ if (!sev_guest(kvm))
+ return -EINVAL;
+
+ if (!npages)
+ return 0;
+
+ gfn_start = gpa_to_gfn(gpa);
+ gfn_end = gfn_start + npages;
+
+ /* out of bound access error check */
+ if (gfn_end <= gfn_start)
+ return -EINVAL;
+
+ /* lets make sure that gpa exist in our memslot */
+ pfn_start = gfn_to_pfn(kvm, gfn_start);
+ pfn_end = gfn_to_pfn(kvm, gfn_end);
+
+ if (is_error_noslot_pfn(pfn_start) && !is_noslot_pfn(pfn_start)) {
+ /*
+ * Allow guest MMIO range(s) to be added
+ * to the page encryption bitmap.
+ */
+ return -EINVAL;
+ }
+
+ if (is_error_noslot_pfn(pfn_end) && !is_noslot_pfn(pfn_end)) {
+ /*
+ * Allow guest MMIO range(s) to be added
+ * to the page encryption bitmap.
+ */
+ return -EINVAL;
+ }
+
+ mutex_lock(&kvm->lock);
+ ret = sev_resize_page_enc_bitmap(kvm, gfn_end);
+ 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);
+
+unlock:
+ mutex_unlock(&kvm->lock);
+ return ret;
+}
+
static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
{
struct kvm_sev_cmd sev_cmd;
@@ -7995,6 +8087,8 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
.need_emulation_on_page_fault = svm_need_emulation_on_page_fault,
.apic_init_signal_blocked = svm_apic_init_signal_blocked,
+
+ .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 079d9fbf278e..f68e76ee7f9c 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -8001,6 +8001,7 @@ static struct kvm_x86_ops vmx_x86_ops __ro_after_init = {
.nested_get_evmcs_version = NULL,
.need_emulation_on_page_fault = vmx_need_emulation_on_page_fault,
.apic_init_signal_blocked = vmx_apic_init_signal_blocked,
+ .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 cf95c36cb4f4..68428eef2dde 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -7564,6 +7564,12 @@ int kvm_emulate_hypercall(struct kvm_vcpu *vcpu)
kvm_sched_yield(vcpu->kvm, a0);
ret = 0;
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 8b86609849b9..847b83b75dc8 100644
--- a/include/uapi/linux/kvm_para.h
+++ b/include/uapi/linux/kvm_para.h
@@ -29,6 +29,7 @@
#define KVM_HC_CLOCK_PAIRING 9
#define KVM_HC_SEND_IPI 10
#define KVM_HC_SCHED_YIELD 11
+#define KVM_HC_PAGE_ENC_STATUS 12
/*
* hypercalls use architecture specific
--
2.17.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v5 09/14] KVM: x86: Introduce KVM_GET_PAGE_ENC_BITMAP ioctl
2020-03-30 1:32 [PATCH v5 00/14] Add AMD SEV guest live migration support Ashish Kalra
` (7 preceding siblings ...)
2020-03-30 1:36 ` [PATCH v5 08/14] KVM: X86: Introduce KVM_HC_PAGE_ENC_STATUS hypercall Ashish Kalra
@ 2020-03-30 1:36 ` Ashish Kalra
2020-03-30 1:36 ` [PATCH v5 10/14] mm: x86: Invoke hypercall when page encryption status is changed Ashish Kalra
` (4 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: Ashish Kalra @ 2020-03-30 1:36 UTC (permalink / raw)
To: pbonzini
Cc: tglx, mingo, hpa, joro, bp, thomas.lendacky, x86, kvm,
linux-kernel, rientjes, srutherford, luto, brijesh.singh
From: Brijesh Singh <Brijesh.Singh@amd.com>
The ioctl can be used to retrieve page encryption bitmap for a given
gfn range.
Return the correct bitmap as per the number of pages being requested
by the user. Ensure that we only copy bmap->num_pages bytes in the
userspace buffer, if bmap->num_pages is not byte aligned we read
the trailing bits from the userspace and copy those bits as is.
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>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
---
Documentation/virt/kvm/api.rst | 27 +++++++++++++
arch/x86/include/asm/kvm_host.h | 2 +
arch/x86/kvm/svm.c | 71 +++++++++++++++++++++++++++++++++
arch/x86/kvm/x86.c | 12 ++++++
include/uapi/linux/kvm.h | 12 ++++++
5 files changed, 124 insertions(+)
diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index ebd383fba939..8ad800ebb54f 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -4648,6 +4648,33 @@ This ioctl resets VCPU registers and control structures according to
the clear cpu reset definition in the POP. However, the cpu is not put
into ESA mode. This reset is a superset of the initial reset.
+4.125 KVM_GET_PAGE_ENC_BITMAP (vm ioctl)
+---------------------------------------
+
+:Capability: basic
+:Architectures: x86
+:Type: vm ioctl
+:Parameters: struct kvm_page_enc_bitmap (in/out)
+:Returns: 0 on success, -1 on error
+
+/* for KVM_GET_PAGE_ENC_BITMAP */
+struct kvm_page_enc_bitmap {
+ __u64 start_gfn;
+ __u64 num_pages;
+ union {
+ void __user *enc_bitmap; /* one bit per page */
+ __u64 padding2;
+ };
+};
+
+The encrypted VMs have concept of private and shared pages. The private
+page is encrypted with the guest-specific key, while shared page may
+be encrypted with the hypervisor key. The KVM_GET_PAGE_ENC_BITMAP can
+be used to get the bitmap indicating whether the guest page is private
+or shared. The bitmap can be used during the guest migration, if the page
+is private then userspace need to use SEV migration commands to transmit
+the page.
+
5. The kvm_run structure
========================
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 90718fa3db47..27e43e3ec9d8 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1269,6 +1269,8 @@ struct kvm_x86_ops {
int (*enable_direct_tlbflush)(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 6c924df1b7b7..c417b1bfb5bf 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -7685,6 +7685,76 @@ static int svm_page_enc_status_hc(struct kvm *kvm, unsigned long gpa,
return ret;
}
+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;
+ unsigned long sz, i, sz_bytes;
+ unsigned long *bitmap;
+ int ret, n;
+
+ if (!sev_guest(kvm))
+ return -ENOTTY;
+
+ gfn_start = bmap->start_gfn;
+ gfn_end = gfn_start + bmap->num_pages;
+
+ sz = ALIGN(bmap->num_pages, BITS_PER_LONG) / BITS_PER_BYTE;
+ bitmap = kmalloc(sz, GFP_KERNEL);
+ if (!bitmap)
+ return -ENOMEM;
+
+ /* by default all pages are marked encrypted */
+ memset(bitmap, 0xff, sz);
+
+ 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;
+
+ n = bmap->num_pages % BITS_PER_BYTE;
+ sz_bytes = ALIGN(bmap->num_pages, BITS_PER_BYTE) / BITS_PER_BYTE;
+
+ /*
+ * Return the correct bitmap as per the number of pages being
+ * requested by the user. Ensure that we only copy bmap->num_pages
+ * bytes in the userspace buffer, if bmap->num_pages is not byte
+ * aligned we read the trailing bits from the userspace and copy
+ * those bits as is.
+ */
+
+ if (n) {
+ unsigned char *bitmap_kernel = (unsigned char *)bitmap;
+ unsigned char bitmap_user;
+ unsigned long offset, mask;
+
+ offset = bmap->num_pages / BITS_PER_BYTE;
+ if (copy_from_user(&bitmap_user, bmap->enc_bitmap + offset,
+ sizeof(unsigned char)))
+ goto out;
+
+ mask = GENMASK(n - 1, 0);
+ bitmap_user &= ~mask;
+ bitmap_kernel[offset] &= mask;
+ bitmap_kernel[offset] |= bitmap_user;
+ }
+
+ if (copy_to_user(bmap->enc_bitmap, bitmap, sz_bytes))
+ 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;
@@ -8089,6 +8159,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
.apic_init_signal_blocked = svm_apic_init_signal_blocked,
.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 68428eef2dde..3c3fea4e20b5 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -5226,6 +5226,18 @@ long kvm_arch_vm_ioctl(struct file *filp,
case KVM_SET_PMU_EVENT_FILTER:
r = kvm_vm_ioctl_set_pmu_event_filter(kvm, argp);
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 4e80c57a3182..db1ebf85e177 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -500,6 +500,16 @@ struct kvm_dirty_log {
};
};
+/* for KVM_GET_PAGE_ENC_BITMAP */
+struct kvm_page_enc_bitmap {
+ __u64 start_gfn;
+ __u64 num_pages;
+ union {
+ void __user *enc_bitmap; /* one bit per page */
+ __u64 padding2;
+ };
+};
+
/* for KVM_CLEAR_DIRTY_LOG */
struct kvm_clear_dirty_log {
__u32 slot;
@@ -1478,6 +1488,8 @@ struct kvm_enc_region {
#define KVM_S390_NORMAL_RESET _IO(KVMIO, 0xc3)
#define KVM_S390_CLEAR_RESET _IO(KVMIO, 0xc4)
+#define KVM_GET_PAGE_ENC_BITMAP _IOW(KVMIO, 0xc5, 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] 16+ messages in thread
* [PATCH v5 10/14] mm: x86: Invoke hypercall when page encryption status is changed
2020-03-30 1:32 [PATCH v5 00/14] Add AMD SEV guest live migration support Ashish Kalra
` (8 preceding siblings ...)
2020-03-30 1:36 ` [PATCH v5 09/14] KVM: x86: Introduce KVM_GET_PAGE_ENC_BITMAP ioctl Ashish Kalra
@ 2020-03-30 1:36 ` Ashish Kalra
2020-03-30 2:37 ` kbuild test robot
2020-03-30 1:37 ` [PATCH v5 11/14] KVM: x86: Introduce KVM_SET_PAGE_ENC_BITMAP ioctl Ashish Kalra
` (3 subsequent siblings)
13 siblings, 1 reply; 16+ messages in thread
From: Ashish Kalra @ 2020-03-30 1:36 UTC (permalink / raw)
To: pbonzini
Cc: tglx, mingo, hpa, joro, bp, thomas.lendacky, x86, kvm,
linux-kernel, rientjes, srutherford, luto, brijesh.singh
From: Brijesh Singh <Brijesh.Singh@amd.com>
Invoke a hypercall when a memory region is changed from encrypted ->
decrypted and vice versa. Hypervisor 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>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
---
arch/x86/include/asm/paravirt.h | 6 +++
arch/x86/include/asm/paravirt_types.h | 2 +
arch/x86/kernel/paravirt.c | 1 +
arch/x86/mm/mem_encrypt.c | 57 ++++++++++++++++++++++++++-
arch/x86/mm/pat/set_memory.c | 7 ++++
5 files changed, 72 insertions(+), 1 deletion(-)
diff --git a/arch/x86/include/asm/paravirt.h b/arch/x86/include/asm/paravirt.h
index 694d8daf4983..aa296af5d393 100644
--- a/arch/x86/include/asm/paravirt.h
+++ b/arch/x86/include/asm/paravirt.h
@@ -78,6 +78,12 @@ static inline void paravirt_arch_exit_mmap(struct mm_struct *mm)
PVOP_VCALL1(mmu.exit_mmap, mm);
}
+static inline void page_encryption_changed(unsigned long vaddr, int npages,
+ bool enc)
+{
+ PVOP_VCALL3(mmu.page_encryption_changed, vaddr, npages, enc);
+}
+
#ifdef CONFIG_PARAVIRT_XXL
static inline void load_sp0(unsigned long sp0)
{
diff --git a/arch/x86/include/asm/paravirt_types.h b/arch/x86/include/asm/paravirt_types.h
index 732f62e04ddb..03bfd515c59c 100644
--- a/arch/x86/include/asm/paravirt_types.h
+++ b/arch/x86/include/asm/paravirt_types.h
@@ -215,6 +215,8 @@ struct pv_mmu_ops {
/* Hook for intercepting the destruction of an mm_struct. */
void (*exit_mmap)(struct mm_struct *mm);
+ void (*page_encryption_changed)(unsigned long vaddr, int npages,
+ bool enc);
#ifdef CONFIG_PARAVIRT_XXL
struct paravirt_callee_save read_cr2;
diff --git a/arch/x86/kernel/paravirt.c b/arch/x86/kernel/paravirt.c
index c131ba4e70ef..840c02b23aeb 100644
--- a/arch/x86/kernel/paravirt.c
+++ b/arch/x86/kernel/paravirt.c
@@ -367,6 +367,7 @@ struct paravirt_patch_template pv_ops = {
(void (*)(struct mmu_gather *, void *))tlb_remove_page,
.mmu.exit_mmap = paravirt_nop,
+ .mmu.page_encryption_changed = paravirt_nop,
#ifdef CONFIG_PARAVIRT_XXL
.mmu.read_cr2 = __PV_IS_CALLEE_SAVE(native_read_cr2),
diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c
index f4bd4b431ba1..c9800fa811f6 100644
--- a/arch/x86/mm/mem_encrypt.c
+++ b/arch/x86/mm/mem_encrypt.c
@@ -19,6 +19,7 @@
#include <linux/kernel.h>
#include <linux/bitops.h>
#include <linux/dma-mapping.h>
+#include <linux/kvm_para.h>
#include <asm/tlbflush.h>
#include <asm/fixmap.h>
@@ -29,6 +30,7 @@
#include <asm/processor-flags.h>
#include <asm/msr.h>
#include <asm/cmdline.h>
+#include <asm/kvm_para.h>
#include "mm_internal.h"
@@ -196,6 +198,47 @@ void __init sme_early_init(void)
swiotlb_force = SWIOTLB_FORCE;
}
+static void set_memory_enc_dec_hypercall(unsigned long vaddr, int npages,
+ bool enc)
+{
+ unsigned long sz = npages << PAGE_SHIFT;
+ 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;
@@ -253,12 +296,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;
@@ -313,6 +357,8 @@ static int __init early_set_memory_enc_dec(unsigned long vaddr,
ret = 0;
+ set_memory_enc_dec_hypercall(start, PAGE_ALIGN(size) >> PAGE_SHIFT,
+ enc);
out:
__flush_tlb_all();
return ret;
@@ -451,6 +497,15 @@ void __init mem_encrypt_init(void)
if (sev_active())
static_branch_enable(&sev_enable_key);
+#ifdef CONFIG_PARAVIRT
+ /*
+ * With SEV, we need to make a hypercall when page encryption state is
+ * changed.
+ */
+ if (sev_active())
+ pv_ops.mmu.page_encryption_changed = set_memory_enc_dec_hypercall;
+#endif
+
pr_info("AMD %s active\n",
sev_active() ? "Secure Encrypted Virtualization (SEV)"
: "Secure Memory Encryption (SME)");
diff --git a/arch/x86/mm/pat/set_memory.c b/arch/x86/mm/pat/set_memory.c
index c4aedd00c1ba..86b7804129fc 100644
--- a/arch/x86/mm/pat/set_memory.c
+++ b/arch/x86/mm/pat/set_memory.c
@@ -26,6 +26,7 @@
#include <asm/proto.h>
#include <asm/memtype.h>
#include <asm/set_memory.h>
+#include <asm/paravirt.h>
#include "../mm_internal.h"
@@ -1987,6 +1988,12 @@ static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc)
*/
cpa_flush(&cpa, 0);
+ /* Notify hypervisor that a given memory range is mapped encrypted
+ * or decrypted. The hypervisor will use this information during the
+ * VM migration.
+ */
+ page_encryption_changed(addr, numpages, enc);
+
return ret;
}
--
2.17.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v5 11/14] KVM: x86: Introduce KVM_SET_PAGE_ENC_BITMAP ioctl
2020-03-30 1:32 [PATCH v5 00/14] Add AMD SEV guest live migration support Ashish Kalra
` (9 preceding siblings ...)
2020-03-30 1:36 ` [PATCH v5 10/14] mm: x86: Invoke hypercall when page encryption status is changed Ashish Kalra
@ 2020-03-30 1:37 ` Ashish Kalra
2020-03-30 1:37 ` [PATCH v5 12/14] KVM: x86: Introduce KVM_PAGE_ENC_BITMAP_RESET ioctl Ashish Kalra
` (2 subsequent siblings)
13 siblings, 0 replies; 16+ messages in thread
From: Ashish Kalra @ 2020-03-30 1:37 UTC (permalink / raw)
To: pbonzini
Cc: tglx, mingo, hpa, joro, bp, thomas.lendacky, x86, kvm,
linux-kernel, rientjes, srutherford, luto, brijesh.singh
From: Brijesh Singh <Brijesh.Singh@amd.com>
The ioctl can be used to set page encryption bitmap for an
incoming guest.
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>
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
---
Documentation/virt/kvm/api.rst | 22 +++++++++++++++++
arch/x86/include/asm/kvm_host.h | 2 ++
arch/x86/kvm/svm.c | 42 +++++++++++++++++++++++++++++++++
arch/x86/kvm/x86.c | 12 ++++++++++
include/uapi/linux/kvm.h | 1 +
5 files changed, 79 insertions(+)
diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 8ad800ebb54f..4d1004a154f6 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -4675,6 +4675,28 @@ or shared. The bitmap can be used during the guest migration, if the page
is private then userspace need to use SEV migration commands to transmit
the page.
+4.126 KVM_SET_PAGE_ENC_BITMAP (vm ioctl)
+---------------------------------------
+
+:Capability: basic
+:Architectures: x86
+:Type: vm ioctl
+:Parameters: struct kvm_page_enc_bitmap (in/out)
+:Returns: 0 on success, -1 on error
+
+/* for KVM_SET_PAGE_ENC_BITMAP */
+struct kvm_page_enc_bitmap {
+ __u64 start_gfn;
+ __u64 num_pages;
+ union {
+ void __user *enc_bitmap; /* one bit per page */
+ __u64 padding2;
+ };
+};
+
+During the guest live migration the outgoing guest exports its page encryption
+bitmap, the KVM_SET_PAGE_ENC_BITMAP can be used to build the page encryption
+bitmap for an incoming guest.
5. The kvm_run structure
========================
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 27e43e3ec9d8..d30f770aaaea 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1271,6 +1271,8 @@ struct kvm_x86_ops {
unsigned long sz, unsigned long mode);
int (*get_page_enc_bitmap)(struct kvm *kvm,
struct kvm_page_enc_bitmap *bmap);
+ int (*set_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 c417b1bfb5bf..e7fa196f3de1 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -7755,6 +7755,47 @@ static int svm_get_page_enc_bitmap(struct kvm *kvm,
return ret;
}
+static int svm_set_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;
+ unsigned long *bitmap;
+ unsigned long sz, i;
+ int ret;
+
+ if (!sev_guest(kvm))
+ return -ENOTTY;
+
+ gfn_start = bmap->start_gfn;
+ gfn_end = gfn_start + bmap->num_pages;
+
+ sz = ALIGN(bmap->num_pages, BITS_PER_LONG) / 8;
+ bitmap = kmalloc(sz, GFP_KERNEL);
+ if (!bitmap)
+ return -ENOMEM;
+
+ ret = -EFAULT;
+ if (copy_from_user(bitmap, bmap->enc_bitmap, sz))
+ goto out;
+
+ mutex_lock(&kvm->lock);
+ ret = sev_resize_page_enc_bitmap(kvm, gfn_end);
+ if (ret)
+ goto unlock;
+
+ i = gfn_start;
+ for_each_clear_bit_from(i, bitmap, (gfn_end - gfn_start))
+ clear_bit(i + gfn_start, sev->page_enc_bmap);
+
+ ret = 0;
+unlock:
+ mutex_unlock(&kvm->lock);
+out:
+ kfree(bitmap);
+ return ret;
+}
+
static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
{
struct kvm_sev_cmd sev_cmd;
@@ -8160,6 +8201,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
.page_enc_status_hc = svm_page_enc_status_hc,
.get_page_enc_bitmap = svm_get_page_enc_bitmap,
+ .set_page_enc_bitmap = svm_set_page_enc_bitmap,
};
static int __init svm_init(void)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 3c3fea4e20b5..05e953b2ec61 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -5238,6 +5238,18 @@ long kvm_arch_vm_ioctl(struct file *filp,
r = kvm_x86_ops->get_page_enc_bitmap(kvm, &bitmap);
break;
}
+ case KVM_SET_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->set_page_enc_bitmap)
+ r = kvm_x86_ops->set_page_enc_bitmap(kvm, &bitmap);
+ break;
+ }
default:
r = -ENOTTY;
}
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index db1ebf85e177..b4b01d47e568 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1489,6 +1489,7 @@ struct kvm_enc_region {
#define KVM_S390_CLEAR_RESET _IO(KVMIO, 0xc4)
#define KVM_GET_PAGE_ENC_BITMAP _IOW(KVMIO, 0xc5, struct kvm_page_enc_bitmap)
+#define KVM_SET_PAGE_ENC_BITMAP _IOW(KVMIO, 0xc6, struct kvm_page_enc_bitmap)
/* Secure Encrypted Virtualization command */
enum sev_cmd_id {
--
2.17.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v5 12/14] KVM: x86: Introduce KVM_PAGE_ENC_BITMAP_RESET ioctl
2020-03-30 1:32 [PATCH v5 00/14] Add AMD SEV guest live migration support Ashish Kalra
` (10 preceding siblings ...)
2020-03-30 1:37 ` [PATCH v5 11/14] KVM: x86: Introduce KVM_SET_PAGE_ENC_BITMAP ioctl Ashish Kalra
@ 2020-03-30 1:37 ` Ashish Kalra
2020-03-30 1:37 ` [PATCH v5 13/14] KVM: x86: Introduce new KVM_FEATURE_SEV_LIVE_MIGRATION feature & Custom MSR Ashish Kalra
2020-03-30 1:38 ` [PATCH v5 14/14] KVM: x86: Add kexec support for SEV Live Migration Ashish Kalra
13 siblings, 0 replies; 16+ messages in thread
From: Ashish Kalra @ 2020-03-30 1:37 UTC (permalink / raw)
To: pbonzini
Cc: tglx, mingo, hpa, joro, bp, thomas.lendacky, x86, kvm,
linux-kernel, rientjes, srutherford, luto, brijesh.singh
From: Ashish Kalra <ashish.kalra@amd.com>
This ioctl can be used by the application to reset the page
encryption bitmap managed by the KVM driver. A typical usage
for this ioctl is on VM reboot, on reboot, we must reinitialize
the bitmap.
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
---
Documentation/virt/kvm/api.rst | 13 +++++++++++++
arch/x86/include/asm/kvm_host.h | 1 +
arch/x86/kvm/svm.c | 16 ++++++++++++++++
arch/x86/kvm/x86.c | 6 ++++++
include/uapi/linux/kvm.h | 1 +
5 files changed, 37 insertions(+)
diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 4d1004a154f6..a11326ccc51d 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -4698,6 +4698,19 @@ During the guest live migration the outgoing guest exports its page encryption
bitmap, the KVM_SET_PAGE_ENC_BITMAP can be used to build the page encryption
bitmap for an incoming guest.
+4.127 KVM_PAGE_ENC_BITMAP_RESET (vm ioctl)
+-----------------------------------------
+
+:Capability: basic
+:Architectures: x86
+:Type: vm ioctl
+:Parameters: none
+:Returns: 0 on success, -1 on error
+
+The KVM_PAGE_ENC_BITMAP_RESET is used to reset the guest's page encryption
+bitmap during guest reboot and this is only done on the guest's boot vCPU.
+
+
5. The kvm_run structure
========================
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index d30f770aaaea..a96ef6338cd2 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1273,6 +1273,7 @@ struct kvm_x86_ops {
struct kvm_page_enc_bitmap *bmap);
int (*set_page_enc_bitmap)(struct kvm *kvm,
struct kvm_page_enc_bitmap *bmap);
+ int (*reset_page_enc_bitmap)(struct kvm *kvm);
};
struct kvm_arch_async_pf {
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index e7fa196f3de1..d74773573811 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -7796,6 +7796,21 @@ static int svm_set_page_enc_bitmap(struct kvm *kvm,
return ret;
}
+static int svm_reset_page_enc_bitmap(struct kvm *kvm)
+{
+ struct kvm_sev_info *sev = &to_kvm_svm(kvm)->sev_info;
+
+ if (!sev_guest(kvm))
+ return -ENOTTY;
+
+ mutex_lock(&kvm->lock);
+ /* by default all pages should be marked encrypted */
+ if (sev->page_enc_bmap_size)
+ bitmap_fill(sev->page_enc_bmap, sev->page_enc_bmap_size);
+ mutex_unlock(&kvm->lock);
+ return 0;
+}
+
static int svm_mem_enc_op(struct kvm *kvm, void __user *argp)
{
struct kvm_sev_cmd sev_cmd;
@@ -8202,6 +8217,7 @@ static struct kvm_x86_ops svm_x86_ops __ro_after_init = {
.page_enc_status_hc = svm_page_enc_status_hc,
.get_page_enc_bitmap = svm_get_page_enc_bitmap,
.set_page_enc_bitmap = svm_set_page_enc_bitmap,
+ .reset_page_enc_bitmap = svm_reset_page_enc_bitmap,
};
static int __init svm_init(void)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 05e953b2ec61..2127ed937f53 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -5250,6 +5250,12 @@ long kvm_arch_vm_ioctl(struct file *filp,
r = kvm_x86_ops->set_page_enc_bitmap(kvm, &bitmap);
break;
}
+ case KVM_PAGE_ENC_BITMAP_RESET: {
+ r = -ENOTTY;
+ if (kvm_x86_ops->reset_page_enc_bitmap)
+ r = kvm_x86_ops->reset_page_enc_bitmap(kvm);
+ break;
+ }
default:
r = -ENOTTY;
}
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index b4b01d47e568..0884a581fc37 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1490,6 +1490,7 @@ struct kvm_enc_region {
#define KVM_GET_PAGE_ENC_BITMAP _IOW(KVMIO, 0xc5, struct kvm_page_enc_bitmap)
#define KVM_SET_PAGE_ENC_BITMAP _IOW(KVMIO, 0xc6, struct kvm_page_enc_bitmap)
+#define KVM_PAGE_ENC_BITMAP_RESET _IO(KVMIO, 0xc7)
/* Secure Encrypted Virtualization command */
enum sev_cmd_id {
--
2.17.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v5 13/14] KVM: x86: Introduce new KVM_FEATURE_SEV_LIVE_MIGRATION feature & Custom MSR.
2020-03-30 1:32 [PATCH v5 00/14] Add AMD SEV guest live migration support Ashish Kalra
` (11 preceding siblings ...)
2020-03-30 1:37 ` [PATCH v5 12/14] KVM: x86: Introduce KVM_PAGE_ENC_BITMAP_RESET ioctl Ashish Kalra
@ 2020-03-30 1:37 ` Ashish Kalra
2020-03-30 1:38 ` [PATCH v5 14/14] KVM: x86: Add kexec support for SEV Live Migration Ashish Kalra
13 siblings, 0 replies; 16+ messages in thread
From: Ashish Kalra @ 2020-03-30 1:37 UTC (permalink / raw)
To: pbonzini
Cc: tglx, mingo, hpa, joro, bp, thomas.lendacky, x86, kvm,
linux-kernel, rientjes, srutherford, luto, brijesh.singh
From: Ashish Kalra <ashish.kalra@amd.com>
Add new KVM_FEATURE_SEV_LIVE_MIGRATION feature for guest to check
for host-side support for SEV live migration. Also add a new custom
MSR_KVM_SEV_LIVE_MIG_EN for guest to enable the SEV live migration
feature.
Also, ensure that _bss_decrypted section is marked as decrypted in the
page encryption bitmap.
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
---
Documentation/virt/kvm/cpuid.rst | 4 ++++
Documentation/virt/kvm/msr.rst | 10 ++++++++++
arch/x86/include/asm/kvm_host.h | 3 +++
arch/x86/include/uapi/asm/kvm_para.h | 5 +++++
arch/x86/kernel/kvm.c | 4 ++++
arch/x86/kvm/cpuid.c | 3 ++-
arch/x86/kvm/svm.c | 5 +++++
arch/x86/kvm/x86.c | 7 +++++++
arch/x86/mm/mem_encrypt.c | 14 +++++++++++++-
9 files changed, 53 insertions(+), 2 deletions(-)
diff --git a/Documentation/virt/kvm/cpuid.rst b/Documentation/virt/kvm/cpuid.rst
index 01b081f6e7ea..fcb191bb3016 100644
--- a/Documentation/virt/kvm/cpuid.rst
+++ b/Documentation/virt/kvm/cpuid.rst
@@ -86,6 +86,10 @@ KVM_FEATURE_PV_SCHED_YIELD 13 guest checks this feature bit
before using paravirtualized
sched yield.
+KVM_FEATURE_SEV_LIVE_MIGRATION 14 guest checks this feature bit
+ before enabling SEV live
+ migration feature.
+
KVM_FEATURE_CLOCSOURCE_STABLE_BIT 24 host will warn if no guest-side
per-cpu warps are expeced in
kvmclock
diff --git a/Documentation/virt/kvm/msr.rst b/Documentation/virt/kvm/msr.rst
index 33892036672d..7cd7786bbb03 100644
--- a/Documentation/virt/kvm/msr.rst
+++ b/Documentation/virt/kvm/msr.rst
@@ -319,3 +319,13 @@ data:
KVM guests can request the host not to poll on HLT, for example if
they are performing polling themselves.
+
+MSR_KVM_SEV_LIVE_MIG_EN:
+ 0x4b564d06
+
+ Control SEV Live Migration features.
+
+data:
+ Bit 0 enables (1) or disables (0) host-side SEV Live Migration feature.
+ Bit 1 enables (1) or disables (0) support for SEV Live Migration extensions.
+ All other bits are reserved.
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index a96ef6338cd2..ad5faaed43c0 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -780,6 +780,9 @@ struct kvm_vcpu_arch {
u64 msr_kvm_poll_control;
+ /* SEV Live Migration MSR (AMD only) */
+ u64 msr_kvm_sev_live_migration_flag;
+
/*
* Indicates the guest is trying to write a gfn that contains one or
* more of the PTEs used to translate the write itself, i.e. the access
diff --git a/arch/x86/include/uapi/asm/kvm_para.h b/arch/x86/include/uapi/asm/kvm_para.h
index 2a8e0b6b9805..d9d4953b42ad 100644
--- a/arch/x86/include/uapi/asm/kvm_para.h
+++ b/arch/x86/include/uapi/asm/kvm_para.h
@@ -31,6 +31,7 @@
#define KVM_FEATURE_PV_SEND_IPI 11
#define KVM_FEATURE_POLL_CONTROL 12
#define KVM_FEATURE_PV_SCHED_YIELD 13
+#define KVM_FEATURE_SEV_LIVE_MIGRATION 14
#define KVM_HINTS_REALTIME 0
@@ -50,6 +51,7 @@
#define MSR_KVM_STEAL_TIME 0x4b564d03
#define MSR_KVM_PV_EOI_EN 0x4b564d04
#define MSR_KVM_POLL_CONTROL 0x4b564d05
+#define MSR_KVM_SEV_LIVE_MIG_EN 0x4b564d06
struct kvm_steal_time {
__u64 steal;
@@ -122,4 +124,7 @@ struct kvm_vcpu_pv_apf_data {
#define KVM_PV_EOI_ENABLED KVM_PV_EOI_MASK
#define KVM_PV_EOI_DISABLED 0x0
+#define KVM_SEV_LIVE_MIGRATION_ENABLED (1 << 0)
+#define KVM_SEV_LIVE_MIGRATION_EXTENSIONS_SUPPORTED (1 << 1)
+
#endif /* _UAPI_ASM_X86_KVM_PARA_H */
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index 6efe0410fb72..8fcee0b45231 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -418,6 +418,10 @@ static void __init sev_map_percpu_data(void)
if (!sev_active())
return;
+ if (kvm_para_has_feature(KVM_FEATURE_SEV_LIVE_MIGRATION)) {
+ wrmsrl(MSR_KVM_SEV_LIVE_MIG_EN, KVM_SEV_LIVE_MIGRATION_ENABLED);
+ }
+
for_each_possible_cpu(cpu) {
__set_percpu_decrypted(&per_cpu(apf_reason, cpu), sizeof(apf_reason));
__set_percpu_decrypted(&per_cpu(steal_time, cpu), sizeof(steal_time));
diff --git a/arch/x86/kvm/cpuid.c b/arch/x86/kvm/cpuid.c
index b1c469446b07..74c8b2a7270c 100644
--- a/arch/x86/kvm/cpuid.c
+++ b/arch/x86/kvm/cpuid.c
@@ -716,7 +716,8 @@ static inline int __do_cpuid_func(struct kvm_cpuid_entry2 *entry, u32 function,
(1 << KVM_FEATURE_ASYNC_PF_VMEXIT) |
(1 << KVM_FEATURE_PV_SEND_IPI) |
(1 << KVM_FEATURE_POLL_CONTROL) |
- (1 << KVM_FEATURE_PV_SCHED_YIELD);
+ (1 << KVM_FEATURE_PV_SCHED_YIELD) |
+ (1 << KVM_FEATURE_SEV_LIVE_MIGRATION);
if (sched_info_on())
entry->eax |= (1 << KVM_FEATURE_STEAL_TIME);
diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c
index d74773573811..8c6839a97974 100644
--- a/arch/x86/kvm/svm.c
+++ b/arch/x86/kvm/svm.c
@@ -7632,12 +7632,17 @@ 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;
+ struct kvm_vcpu *vcpu = kvm->vcpus[0];
gfn_t gfn_start, gfn_end;
int ret;
if (!sev_guest(kvm))
return -EINVAL;
+ if (!(vcpu->arch.msr_kvm_sev_live_migration_flag &
+ KVM_SEV_LIVE_MIGRATION_ENABLED))
+ return -ENOTTY;
+
if (!npages)
return 0;
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 2127ed937f53..82867b8798f8 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -2880,6 +2880,10 @@ int kvm_set_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
vcpu->arch.msr_kvm_poll_control = data;
break;
+ case MSR_KVM_SEV_LIVE_MIG_EN:
+ vcpu->arch.msr_kvm_sev_live_migration_flag = data;
+ break;
+
case MSR_IA32_MCG_CTL:
case MSR_IA32_MCG_STATUS:
case MSR_IA32_MC0_CTL ... MSR_IA32_MCx_CTL(KVM_MAX_MCE_BANKS) - 1:
@@ -3126,6 +3130,9 @@ int kvm_get_msr_common(struct kvm_vcpu *vcpu, struct msr_data *msr_info)
case MSR_KVM_POLL_CONTROL:
msr_info->data = vcpu->arch.msr_kvm_poll_control;
break;
+ case MSR_KVM_SEV_LIVE_MIG_EN:
+ msr_info->data = vcpu->arch.msr_kvm_sev_live_migration_flag;
+ break;
case MSR_IA32_P5_MC_ADDR:
case MSR_IA32_P5_MC_TYPE:
case MSR_IA32_MCG_CAP:
diff --git a/arch/x86/mm/mem_encrypt.c b/arch/x86/mm/mem_encrypt.c
index c9800fa811f6..f6a841494845 100644
--- a/arch/x86/mm/mem_encrypt.c
+++ b/arch/x86/mm/mem_encrypt.c
@@ -502,8 +502,20 @@ void __init mem_encrypt_init(void)
* With SEV, we need to make a hypercall when page encryption state is
* changed.
*/
- if (sev_active())
+ if (sev_active()) {
+ unsigned long nr_pages;
+
pv_ops.mmu.page_encryption_changed = set_memory_enc_dec_hypercall;
+
+ /*
+ * Ensure that _bss_decrypted section is marked as decrypted in the
+ * page encryption bitmap.
+ */
+ nr_pages = DIV_ROUND_UP(__end_bss_decrypted - __start_bss_decrypted,
+ PAGE_SIZE);
+ set_memory_enc_dec_hypercall((unsigned long)__start_bss_decrypted,
+ nr_pages, 0);
+ }
#endif
pr_info("AMD %s active\n",
--
2.17.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* [PATCH v5 14/14] KVM: x86: Add kexec support for SEV Live Migration.
2020-03-30 1:32 [PATCH v5 00/14] Add AMD SEV guest live migration support Ashish Kalra
` (12 preceding siblings ...)
2020-03-30 1:37 ` [PATCH v5 13/14] KVM: x86: Introduce new KVM_FEATURE_SEV_LIVE_MIGRATION feature & Custom MSR Ashish Kalra
@ 2020-03-30 1:38 ` Ashish Kalra
13 siblings, 0 replies; 16+ messages in thread
From: Ashish Kalra @ 2020-03-30 1:38 UTC (permalink / raw)
To: pbonzini
Cc: tglx, mingo, hpa, joro, bp, thomas.lendacky, x86, kvm,
linux-kernel, rientjes, srutherford, luto, brijesh.singh
From: Ashish Kalra <ashish.kalra@amd.com>
Reset the host's page encryption bitmap related to kernel
specific page encryption status settings before we load a
new kernel by kexec. We cannot reset the complete
page encryption bitmap here as we need to retain the
UEFI/OVMF firmware specific settings.
Signed-off-by: Ashish Kalra <ashish.kalra@amd.com>
---
arch/x86/kernel/kvm.c | 28 ++++++++++++++++++++++++++++
1 file changed, 28 insertions(+)
diff --git a/arch/x86/kernel/kvm.c b/arch/x86/kernel/kvm.c
index 8fcee0b45231..ba6cce3c84af 100644
--- a/arch/x86/kernel/kvm.c
+++ b/arch/x86/kernel/kvm.c
@@ -34,6 +34,7 @@
#include <asm/hypervisor.h>
#include <asm/tlb.h>
#include <asm/cpuidle_haltpoll.h>
+#include <asm/e820/api.h>
static int kvmapf = 1;
@@ -357,6 +358,33 @@ static void kvm_pv_guest_cpu_reboot(void *unused)
*/
if (kvm_para_has_feature(KVM_FEATURE_PV_EOI))
wrmsrl(MSR_KVM_PV_EOI_EN, 0);
+ /*
+ * Reset the host's page encryption bitmap related to kernel
+ * specific page encryption status settings before we load a
+ * new kernel by kexec. NOTE: We cannot reset the complete
+ * page encryption bitmap here as we need to retain the
+ * UEFI/OVMF firmware specific settings.
+ */
+ if (kvm_para_has_feature(KVM_FEATURE_SEV_LIVE_MIGRATION) &&
+ (smp_processor_id() == 0)) {
+ unsigned long nr_pages;
+ int i;
+
+ for (i = 0; i < e820_table->nr_entries; i++) {
+ struct e820_entry *entry = &e820_table->entries[i];
+ unsigned long start_pfn, end_pfn;
+
+ if (entry->type != E820_TYPE_RAM)
+ continue;
+
+ start_pfn = entry->addr >> PAGE_SHIFT;
+ end_pfn = (entry->addr + entry->size) >> PAGE_SHIFT;
+ nr_pages = DIV_ROUND_UP(entry->size, PAGE_SIZE);
+
+ kvm_sev_hypercall3(KVM_HC_PAGE_ENC_STATUS,
+ entry->addr, nr_pages, 1);
+ }
+ }
kvm_pv_disable_apf();
kvm_disable_steal_time();
}
--
2.17.1
^ permalink raw reply related [flat|nested] 16+ messages in thread
* Re: [PATCH v5 10/14] mm: x86: Invoke hypercall when page encryption status is changed
2020-03-30 1:36 ` [PATCH v5 10/14] mm: x86: Invoke hypercall when page encryption status is changed Ashish Kalra
@ 2020-03-30 2:37 ` kbuild test robot
0 siblings, 0 replies; 16+ messages in thread
From: kbuild test robot @ 2020-03-30 2:37 UTC (permalink / raw)
To: Ashish Kalra
Cc: kbuild-all, pbonzini, tglx, mingo, hpa, joro, bp,
thomas.lendacky, x86, kvm, linux-kernel, rientjes, srutherford,
luto, brijesh.singh
[-- Attachment #1: Type: text/plain, Size: 3245 bytes --]
Hi Ashish,
I love your patch! Yet something to improve:
[auto build test ERROR on tip/x86/mm]
[also build test ERROR on v5.6]
[cannot apply to kvm/linux-next tip/x86/core next-20200327]
[if your patch is applied to the wrong git tree, please drop us a note to help
improve the system. BTW, we also suggest to use '--base' option to specify the
base tree in git format-patch, please see https://stackoverflow.com/a/37406982]
url: https://github.com/0day-ci/linux/commits/Ashish-Kalra/Add-AMD-SEV-guest-live-migration-support/20200330-094122
base: https://git.kernel.org/pub/scm/linux/kernel/git/tip/tip.git aa61ee7b9ee3cb84c0d3a842b0d17937bf024c46
config: i386-tinyconfig (attached as .config)
compiler: gcc-7 (Debian 7.5.0-5) 7.5.0
reproduce:
# save the attached .config to linux build tree
make ARCH=i386
If you fix the issue, kindly add following tag
Reported-by: kbuild test robot <lkp@intel.com>
All errors (new ones prefixed by >>):
arch/x86/mm/pat/set_memory.c: In function '__set_memory_enc_dec':
>> arch/x86/mm/pat/set_memory.c:1995:2: error: implicit declaration of function 'page_encryption_changed'; did you mean 'sme_encrypt_kernel'? [-Werror=implicit-function-declaration]
page_encryption_changed(addr, numpages, enc);
^~~~~~~~~~~~~~~~~~~~~~~
sme_encrypt_kernel
cc1: some warnings being treated as errors
vim +1995 arch/x86/mm/pat/set_memory.c
1950
1951 static int __set_memory_enc_dec(unsigned long addr, int numpages, bool enc)
1952 {
1953 struct cpa_data cpa;
1954 int ret;
1955
1956 /* Nothing to do if memory encryption is not active */
1957 if (!mem_encrypt_active())
1958 return 0;
1959
1960 /* Should not be working on unaligned addresses */
1961 if (WARN_ONCE(addr & ~PAGE_MASK, "misaligned address: %#lx\n", addr))
1962 addr &= PAGE_MASK;
1963
1964 memset(&cpa, 0, sizeof(cpa));
1965 cpa.vaddr = &addr;
1966 cpa.numpages = numpages;
1967 cpa.mask_set = enc ? __pgprot(_PAGE_ENC) : __pgprot(0);
1968 cpa.mask_clr = enc ? __pgprot(0) : __pgprot(_PAGE_ENC);
1969 cpa.pgd = init_mm.pgd;
1970
1971 /* Must avoid aliasing mappings in the highmem code */
1972 kmap_flush_unused();
1973 vm_unmap_aliases();
1974
1975 /*
1976 * Before changing the encryption attribute, we need to flush caches.
1977 */
1978 cpa_flush(&cpa, 1);
1979
1980 ret = __change_page_attr_set_clr(&cpa, 1);
1981
1982 /*
1983 * After changing the encryption attribute, we need to flush TLBs again
1984 * in case any speculative TLB caching occurred (but no need to flush
1985 * caches again). We could just use cpa_flush_all(), but in case TLB
1986 * flushing gets optimized in the cpa_flush() path use the same logic
1987 * as above.
1988 */
1989 cpa_flush(&cpa, 0);
1990
1991 /* Notify hypervisor that a given memory range is mapped encrypted
1992 * or decrypted. The hypervisor will use this information during the
1993 * VM migration.
1994 */
> 1995 page_encryption_changed(addr, numpages, enc);
1996
1997 return ret;
1998 }
1999
---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/kbuild-all@lists.01.org
[-- Attachment #2: .config.gz --]
[-- Type: application/gzip, Size: 7246 bytes --]
^ permalink raw reply [flat|nested] 16+ messages in thread
end of thread, other threads:[~2020-03-30 2:38 UTC | newest]
Thread overview: 16+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-03-30 1:32 [PATCH v5 00/14] Add AMD SEV guest live migration support Ashish Kalra
2020-03-30 1:33 ` [PATCH v5 01/14] KVM: SVM: Add KVM_SEV SEND_START command Ashish Kalra
2020-03-30 1:34 ` [PATCH v5 02/14] KVM: SVM: Add KVM_SEND_UPDATE_DATA command Ashish Kalra
2020-03-30 1:34 ` [PATCH v5 03/14] KVM: SVM: Add KVM_SEV_SEND_FINISH command Ashish Kalra
2020-03-30 1:34 ` [PATCH v5 04/14] KVM: SVM: Add support for KVM_SEV_RECEIVE_START command Ashish Kalra
2020-03-30 1:35 ` [PATCH v5 05/14] KVM: SVM: Add KVM_SEV_RECEIVE_UPDATE_DATA command Ashish Kalra
2020-03-30 1:35 ` [PATCH v5 06/14] KVM: SVM: Add KVM_SEV_RECEIVE_FINISH command Ashish Kalra
2020-03-30 1:35 ` [PATCH v5 07/14] KVM: x86: Add AMD SEV specific Hypercall3 Ashish Kalra
2020-03-30 1:36 ` [PATCH v5 08/14] KVM: X86: Introduce KVM_HC_PAGE_ENC_STATUS hypercall Ashish Kalra
2020-03-30 1:36 ` [PATCH v5 09/14] KVM: x86: Introduce KVM_GET_PAGE_ENC_BITMAP ioctl Ashish Kalra
2020-03-30 1:36 ` [PATCH v5 10/14] mm: x86: Invoke hypercall when page encryption status is changed Ashish Kalra
2020-03-30 2:37 ` kbuild test robot
2020-03-30 1:37 ` [PATCH v5 11/14] KVM: x86: Introduce KVM_SET_PAGE_ENC_BITMAP ioctl Ashish Kalra
2020-03-30 1:37 ` [PATCH v5 12/14] KVM: x86: Introduce KVM_PAGE_ENC_BITMAP_RESET ioctl Ashish Kalra
2020-03-30 1:37 ` [PATCH v5 13/14] KVM: x86: Introduce new KVM_FEATURE_SEV_LIVE_MIGRATION feature & Custom MSR Ashish Kalra
2020-03-30 1:38 ` [PATCH v5 14/14] KVM: x86: Add kexec support for SEV Live Migration Ashish Kalra
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).