diff options
Diffstat (limited to 'meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71-e3000/0078-KVM-SVM-Add-support-for-SEV-DEBUG_DECRYPT-command.patch')
-rw-r--r-- | meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71-e3000/0078-KVM-SVM-Add-support-for-SEV-DEBUG_DECRYPT-command.patch | 202 |
1 files changed, 202 insertions, 0 deletions
diff --git a/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71-e3000/0078-KVM-SVM-Add-support-for-SEV-DEBUG_DECRYPT-command.patch b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71-e3000/0078-KVM-SVM-Add-support-for-SEV-DEBUG_DECRYPT-command.patch new file mode 100644 index 00000000..5f7419db --- /dev/null +++ b/meta-amd-bsp/recipes-kernel/linux/linux-yocto-4.14.71-e3000/0078-KVM-SVM-Add-support-for-SEV-DEBUG_DECRYPT-command.patch @@ -0,0 +1,202 @@ +From b087a322574fc94f760c1150b344191996543733 Mon Sep 17 00:00:00 2001 +From: Brijesh Singh <brijesh.singh@amd.com> +Date: Mon, 4 Dec 2017 10:57:37 -0600 +Subject: [PATCH 78/95] KVM: SVM: Add support for SEV DEBUG_DECRYPT command +MIME-Version: 1.0 +Content-Type: text/plain; charset=UTF-8 +Content-Transfer-Encoding: 8bit + +The command is used for decrypting a guest memory region for debug +purposes. + +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> +Reviewed-by: Borislav Petkov <bp@suse.de> +Signed-off-by: Sudheesh Mavila <sudheesh.mavila@amd.com> +--- + arch/x86/kvm/svm.c | 152 +++++++++++++++++++++++++++++++++++++++++++++++++++++ + 1 file changed, 152 insertions(+) + +diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c +index f9eb8fa..9c5962a 100755 +--- a/arch/x86/kvm/svm.c ++++ b/arch/x86/kvm/svm.c +@@ -6269,6 +6269,155 @@ static int sev_guest_status(struct kvm *kvm, struct kvm_sev_cmd *argp) + return ret; + } + ++static int __sev_issue_dbg_cmd(struct kvm *kvm, unsigned long src, ++ unsigned long dst, int size, ++ int *error, bool enc) ++{ ++ struct kvm_sev_info *sev = &kvm->arch.sev_info; ++ struct sev_data_dbg *data; ++ int ret; ++ ++ data = kzalloc(sizeof(*data), GFP_KERNEL); ++ if (!data) ++ return -ENOMEM; ++ ++ data->handle = sev->handle; ++ data->dst_addr = dst; ++ data->src_addr = src; ++ data->len = size; ++ ++ ret = sev_issue_cmd(kvm, ++ enc ? SEV_CMD_DBG_ENCRYPT : SEV_CMD_DBG_DECRYPT, ++ data, error); ++ kfree(data); ++ return ret; ++} ++ ++static int __sev_dbg_decrypt(struct kvm *kvm, unsigned long src_paddr, ++ unsigned long dst_paddr, int sz, int *err) ++{ ++ int offset; ++ ++ /* ++ * Its safe to read more than we are asked, caller should ensure that ++ * destination has enough space. ++ */ ++ src_paddr = round_down(src_paddr, 16); ++ offset = src_paddr & 15; ++ sz = round_up(sz + offset, 16); ++ ++ return __sev_issue_dbg_cmd(kvm, src_paddr, dst_paddr, sz, err, false); ++} ++ ++static int __sev_dbg_decrypt_user(struct kvm *kvm, unsigned long paddr, ++ unsigned long __user dst_uaddr, ++ unsigned long dst_paddr, ++ int size, int *err) ++{ ++ struct page *tpage = NULL; ++ int ret, offset; ++ ++ /* if inputs are not 16-byte then use intermediate buffer */ ++ if (!IS_ALIGNED(dst_paddr, 16) || ++ !IS_ALIGNED(paddr, 16) || ++ !IS_ALIGNED(size, 16)) { ++ tpage = (void *)alloc_page(GFP_KERNEL); ++ if (!tpage) ++ return -ENOMEM; ++ ++ dst_paddr = __sme_page_pa(tpage); ++ } ++ ++ ret = __sev_dbg_decrypt(kvm, paddr, dst_paddr, size, err); ++ if (ret) ++ goto e_free; ++ ++ if (tpage) { ++ offset = paddr & 15; ++ if (copy_to_user((void __user *)(uintptr_t)dst_uaddr, ++ page_address(tpage) + offset, size)) ++ ret = -EFAULT; ++ } ++ ++e_free: ++ if (tpage) ++ __free_page(tpage); ++ ++ return ret; ++} ++ ++static int sev_dbg_crypt(struct kvm *kvm, struct kvm_sev_cmd *argp, bool dec) ++{ ++ unsigned long vaddr, vaddr_end, next_vaddr; ++ unsigned long dst_vaddr, dst_vaddr_end; ++ struct page **src_p, **dst_p; ++ struct kvm_sev_dbg debug; ++ unsigned long n; ++ int ret, size; ++ ++ if (!sev_guest(kvm)) ++ return -ENOTTY; ++ ++ if (copy_from_user(&debug, (void __user *)(uintptr_t)argp->data, sizeof(debug))) ++ return -EFAULT; ++ ++ vaddr = debug.src_uaddr; ++ size = debug.len; ++ vaddr_end = vaddr + size; ++ dst_vaddr = debug.dst_uaddr; ++ dst_vaddr_end = dst_vaddr + size; ++ ++ for (; vaddr < vaddr_end; vaddr = next_vaddr) { ++ int len, s_off, d_off; ++ ++ /* lock userspace source and destination page */ ++ src_p = sev_pin_memory(kvm, vaddr & PAGE_MASK, PAGE_SIZE, &n, 0); ++ if (!src_p) ++ return -EFAULT; ++ ++ dst_p = sev_pin_memory(kvm, dst_vaddr & PAGE_MASK, PAGE_SIZE, &n, 1); ++ if (!dst_p) { ++ sev_unpin_memory(kvm, src_p, n); ++ return -EFAULT; ++ } ++ ++ /* ++ * The DBG_{DE,EN}CRYPT commands will perform {dec,en}cryption of the ++ * memory content (i.e it will write the same memory region with C=1). ++ * It's possible that the cache may contain the data with C=0, i.e., ++ * unencrypted so invalidate it first. ++ */ ++ sev_clflush_pages(src_p, 1); ++ sev_clflush_pages(dst_p, 1); ++ ++ /* ++ * Since user buffer may not be page aligned, calculate the ++ * offset within the page. ++ */ ++ s_off = vaddr & ~PAGE_MASK; ++ d_off = dst_vaddr & ~PAGE_MASK; ++ len = min_t(size_t, (PAGE_SIZE - s_off), size); ++ ++ ret = __sev_dbg_decrypt_user(kvm, ++ __sme_page_pa(src_p[0]) + s_off, ++ dst_vaddr, ++ __sme_page_pa(dst_p[0]) + d_off, ++ len, &argp->error); ++ ++ sev_unpin_memory(kvm, src_p, 1); ++ sev_unpin_memory(kvm, dst_p, 1); ++ ++ if (ret) ++ goto err; ++ ++ next_vaddr = vaddr + len; ++ dst_vaddr = dst_vaddr + len; ++ size -= len; ++ } ++err: ++ return ret; ++} ++ + static int svm_mem_enc_op(struct kvm *kvm, void __user *argp) + { + struct kvm_sev_cmd sev_cmd; +@@ -6301,6 +6450,9 @@ static int svm_mem_enc_op(struct kvm *kvm, void __user *argp) + case KVM_SEV_GUEST_STATUS: + r = sev_guest_status(kvm, &sev_cmd); + break; ++ case KVM_SEV_DBG_DECRYPT: ++ r = sev_dbg_crypt(kvm, &sev_cmd, true); ++ break; + default: + r = -EINVAL; + goto out; +-- +2.7.4 + |