From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S933698AbdKAWD3 (ORCPT ); Wed, 1 Nov 2017 18:03:29 -0400 Received: from mail-bn3nam01on0059.outbound.protection.outlook.com ([104.47.33.59]:44352 "EHLO NAM01-BN3-obe.outbound.protection.outlook.com" rhost-flags-OK-OK-OK-FAIL) by vger.kernel.org with ESMTP id S933409AbdKAVR0 (ORCPT ); Wed, 1 Nov 2017 17:17:26 -0400 Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=brijesh.singh@amd.com; From: Brijesh Singh To: kvm@vger.kernel.org, linux-kernel@vger.kernel.org Cc: bp@alien8.de, Brijesh Singh , Thomas Gleixner , Ingo Molnar , "H. Peter Anvin" , Paolo Bonzini , =?UTF-8?q?Radim=20Kr=C4=8Dm=C3=A1=C5=99?= , Joerg Roedel , Borislav Petkov , Tom Lendacky , x86@kernel.org Subject: [Part2 PATCH v7 28/38] KVM: SVM: Add support for KVM_SEV_LAUNCH_UPDATE_DATA command Date: Wed, 1 Nov 2017 16:16:13 -0500 Message-Id: <20171101211623.71496-29-brijesh.singh@amd.com> X-Mailer: git-send-email 2.9.5 In-Reply-To: <20171101211623.71496-1-brijesh.singh@amd.com> References: <20171101211623.71496-1-brijesh.singh@amd.com> MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-Originating-IP: [165.204.78.1] X-ClientProxiedBy: DM5PR06CA0064.namprd06.prod.outlook.com (2603:10b6:3:37::26) To DM2PR12MB0155.namprd12.prod.outlook.com (2a01:111:e400:50ce::18) X-MS-PublicTrafficType: Email X-MS-Office365-Filtering-Correlation-Id: d452cd52-8e29-407f-9c27-08d5216de16d X-MS-Office365-Filtering-HT: Tenant X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:(22001)(48565401081)(4534020)(4602075)(2017052603199);SRVR:DM2PR12MB0155; X-Microsoft-Exchange-Diagnostics: 1;DM2PR12MB0155;3:ttaRkUV0kwPL0/AWvDq0tvBaxzgAkGdNfNankkb+Sbl3DiPZPwW50Grf4M7jpxVdcM+t1kveggW8vVSMcdE4+MdRFUelTTSoOS08Uv7af79qH8QTJDf3x/eihTKjTCIPz54EYXiM2/clvRPCa9NUtL92H0cT1DTsELbbMdpzNqYx/PtjfDfa3OY965lUrHtAZnXU2IDocGzWeYdCeXo31fSs5jXOh+po1Nhj3c53fODpVZt+ioKyrNkvanQ5kE1c;25:k9nacO8Rqtu3KFFlzGGxl2jVmDowyHHSHTGFL8m16V5QhY0U7yBNTbnDAK/zTXHUNf9wmYenKcvK2iwmSHC7c4fJiF8rVqv6YGnvcCZMYMLpqxjOJwGDqOLG3m5pcyV5tM3sSaBF9IszHSAPzEqocxMoweFUveWSMzu6BMorCJ3Ye/nR/jNAukICQC0a7H9icJ4rUwYil1oTbYQL2zT0AC63m050oMg+7HZWT1YoQ2OuzBkoGMqYG5H2SqN9BPBEw+qRWCaMKsXc1oujuZfuhesfEbSuV4hiDGGLY7LpVk2O9ZZMJRKPxsV3xEGtE7PT06ntHWIPHggzj2+RZBp9VA==;31:VieKsSEp9xE86EOy2dVd6C2cq3eovfmanNn/VIckmR/8CGZZzAcYMj97RatEs2XHKK0SEzjYBv0Uj2pxGpHLCe3ajQ43lw30PwuCSEXWgkeSIwC6/xd62521CBt19yFreDo0Z6tWk/3EmL1Kb93xvOESmV/xWvyhNGiT8ggFwsrL+OOXsThHhJ4wacmIgYphHrhqaJf82SgyFjRF2Mx++XdBCkS4zUEecQ7d4sCN61I= X-MS-TrafficTypeDiagnostic: DM2PR12MB0155: X-Microsoft-Exchange-Diagnostics: 1;DM2PR12MB0155;20:T9+6RDM5pDk+1Aw1VJ2x6RGgeRRUPp58TWV31uhmNXLli4l8tdY3fWyU3iTLBvjb/1ap6UQkLXtR8oL8FCtWiU+A9A/wS3mHWYLHAosSebBhflUFb2cgK3wynF1ht0r/YeTDpWAqAm1oXtdFifxSdSX8kumCLHqzmSSvSiQHWiNIGzOq2u/XbQksZAe917WpCGGpfjIqPH13W08AWLnnuNP/s/On7CY9lL+xmh2SC1u6Tr6rBKYD4ZvDBaL77LXzRJyiQIrp0Jw8oZL+JzqkbXwjvIEPES4afnpQ+sGprcs6nKFgu22Z8hZCZbPjDTh0uYvK0TMcntt6IoWBXTnbR6amKWuLwIp4UR4bPOdpbCj5Eyb3A2Im4sMa+8cJGjt9ee3Z9TJboiMzMTJ3c10xJVBvsC/N4CbonzrJ9YJL6c51NORNHZZVIN1KcLJdOZTvVohnLBjgsFDi2Nn/BxUBfEmh0wZiUAeujUee/KFvUQSnlhNz3oWZJIZnfD4sevJM;4:yu0Txs6OGHX9F6D8vmJmcSEzgu65Wb6x0rw/Kqi9xj2PgN3YSqt6vMb3L8MONXDmuwn9PMgdPNePx59di6N4NMgDqOSGgaMfEVxyvQtiya0mL8f/R4qX2Fz00e9/NVgw0pY/LiooO1BfdNyRV8i2Y7uFztoqeWstDy21kTYPtP4UZ6Fib2GO/qu15ldzriWdK2c68Zun693xl0UK+MR0LamJUbW8pmvxvkMdPOFiZO38lDcze2IXEgdWr5IC1Sgm+OVYAw3m4x6qFzcjeJ/HEraqtPvgedPJcAC+DHI7PeSeElOY4kPkWB8eVMettdhjY/OYe7VY+T83mW6DAx7HnA== X-Exchange-Antispam-Report-Test: UriScan:(9452136761055)(767451399110); X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-CFA-Test: BCL:0;PCL:0;RULEID:(100000700101)(100105000095)(100000701101)(100105300095)(100000702101)(100105100095)(6040450)(2401047)(8121501046)(5005006)(100000703101)(100105400095)(3231020)(10201501046)(93006095)(93001095)(3002001)(6055026)(6041248)(20161123560025)(20161123555025)(20161123564025)(201703131423075)(201702281528075)(201703061421075)(201703061406153)(20161123562025)(20161123558100)(6072148)(201708071742011)(100000704101)(100105200095)(100000705101)(100105500095);SRVR:DM2PR12MB0155;BCL:0;PCL:0;RULEID:(100000800101)(100110000095)(100000801101)(100110300095)(100000802101)(100110100095)(100000803101)(100110400095)(100000804101)(100110200095)(100000805101)(100110500095);SRVR:DM2PR12MB0155; X-Forefront-PRVS: 0478C23FE0 X-Forefront-Antispam-Report: SFV:NSPM;SFS:(10009020)(6009001)(39860400002)(376002)(346002)(189002)(199003)(1076002)(6116002)(97736004)(66066001)(50466002)(3846002)(25786009)(4326008)(54906003)(316002)(8676002)(47776003)(36756003)(23676003)(50986999)(478600001)(7416002)(81156014)(81166006)(105586002)(53416004)(53936002)(189998001)(106356001)(2906002)(16526018)(2870700001)(76176999)(33646002)(305945005)(7736002)(86362001)(5660300001)(6486002)(101416001)(50226002)(68736007)(8936002)(2950100002)(6666003);DIR:OUT;SFP:1101;SCL:1;SRVR:DM2PR12MB0155;H:wsp141597wss.amd.com;FPR:;SPF:None;PTR:InfoNoRecords;MX:1;A:1;LANG:en; X-Microsoft-Exchange-Diagnostics: =?utf-8?B?MTtETTJQUjEyTUIwMTU1OzIzOnBtd3duZENzYkxyY2N3aWgvSXhOWXNGcW1H?= =?utf-8?B?dXBwZmx0MWxOVFFsVTNmQnpwMldHYWtLZ2tmbDBuc3FEdTJoelprMzlJVW5C?= =?utf-8?B?S2o2UkxWSGZxWGgzMi9EUXpsRUE1ZHNiQytSblBrSXJLR1doTkhxcjZ1U3do?= =?utf-8?B?WGViUlp0WTAyQXFjZ2kxVTQzU2RZZW9IaElKa0pNOGVia0tQZzBvNXFzTTBV?= =?utf-8?B?Qi9EbXZHR01UVW9ob0QrZjNBWGozUFBML0Y1UnlNaURFS0RpeFUxOE1VeCtj?= =?utf-8?B?bmxrckJSVGRYQTVMck1rbXhqZ2lvSFFHZjBEYkdMYjdxS2FkQmlqWXI0cHhS?= =?utf-8?B?ZWpycnFEeFFZUFBDczJ6U0thM2o3UGo1WEl0LzhZU0wrQ0xwV0h1ek9hR2Yy?= =?utf-8?B?b2diWUZUVE13K3F6M2RCTTkrMGtWVC9zd3pQVStGcitJYVYvaStZZUh2YVRM?= =?utf-8?B?RjlKYTFYSEk1RTZqY01EeUJKZW9sc0tyWmZxN3V0NFJYWitITjRHbmt5VUU4?= =?utf-8?B?dDh2ZjFTajBncVVpbk94SVV1M2s5bTlWbVhYWnF1QlpWc0lTb1dybjlMcHNZ?= =?utf-8?B?eHZmODYrSEdZWjVCNktNTU8xc1NneWJkUHBBR0ZIT1Y0Q0krcnFQWkRYSzRv?= =?utf-8?B?bHlzeXR1V0poTjZBRXlTNGFkd3A3ckVpUTZzM2R6YThoa1N2dzd5ZmtMSjdH?= =?utf-8?B?bVhvYmZQVU95QzB5T0NNc3lkMHdXNGlMeFRBSXlQVFlwQ0FmUklKTCtML1NW?= =?utf-8?B?OFV1UHhycEtvMmkzSk81c0s2aC83ZVM0bTJHVDQ3Z1padlI0YmNJbWM0eUxv?= =?utf-8?B?ZEN6R0o2VzFkNkgzQWZLSTJ4SWM1Y2I5WEdJWURibXJiMFgxMnN0eEZlS3VS?= =?utf-8?B?L1R5cktaUHN6SW1hWGxjMTdNVitXSit6cHMvclBXTENwUU9TUmpTaTNHbU1X?= =?utf-8?B?eXFIbnpQcTBVaVFPVUNWaWJsZEN3cHFjRWVoK0U3OEtmTmxxbzhJbThDaWo2?= =?utf-8?B?ZThyTWx4Y29OT082b0F5aG9DMHBESnVEbkRaNWU5SC9JV0plQjlFUlNpRVIz?= =?utf-8?B?SjMyNkg1VHlrditlckU0dzAwU1JqSDYzaVp0dU45cXNoZ0hoM2hwTmVIblMv?= =?utf-8?B?R2NXaEhQWVhyY3Z1VTBoMllVRkVBdlRJWWZMQXM0ZnVMN1JlRGtGZThqY2N4?= =?utf-8?B?UEZPR1o4OXFkMGZNbE1iRjY1eWI0dmxZV3ROLzN0Z0RNNzNpUjJab2ZlTXBD?= =?utf-8?B?NWh4Z3JDV2ZBajJUS3JrN3VTY1BGOU41NXJXT0RjWi9pSlJhY3NZZEdoTUNK?= =?utf-8?B?MHk1a0E1L0hVY3BOVWpib002SEFwN2tRZ2dRNEdxKytDMHB3VlkvT3ZOblJZ?= =?utf-8?B?bDVzYTRaemEwTVdEU2VoVGhCZitQdm55d3hQakVvRUNIamMxbnk5ZFJPcDVx?= =?utf-8?Q?gS6hmS0vXoPXjPNDHOd0eE43PqP?= X-Microsoft-Exchange-Diagnostics: 1;DM2PR12MB0155;6:Any5EMa30/Dtcu9wP/VrSq0DuDITHSIDY5gAY5+LcHrwAf9rQ0FV06UpliGamBcw/q8INO7wveORy8yvg5UwwXLYAsBhhYRDmn/iJpE7me/EGMGNwGwn3CQmXjNhXS9ANNfHI1FJrhVQiEU1TmiRn/HrTFegkWVBBefHsFd/a8TbwaC/rfKbkK4mENqRQjgK/QWdoITU3Ga90Ugzmk1cjkQqxHucquN1J6N0ujXzXwlH7yDdW9VScQh5+5JHz5pPmkVkw0xmYQekGTo9OFp1yLwW9+cAfM+uNPiq6XfOi6PYDhkWh5rK9wLI6IyjuMsE6xzKx53OEQRT0FolK3QLNHaEJyBFa7694EQvCQ8jkPg=;5:JiXXikRnL+cQXKK3hX+WaMuSudr9GjEqWvb9iAnUsbhNcYUohfc9EKRHhm08t+Xp+I4zvec0XTcwT/LosP2oVaPZvFZRqexA1Cg+NTEnrdoDlRwX47nPaOXgvGJVjJohtabnbHmJ2Cyt//3q5Be84NuBwHKDuQU8kIe4nzoHtjg=;24:r/f5Hk4l92PHuLM5oLxjPTrJHtH3MSy0eoNp3wOJrH8DbqHb4qVxVj5ErfTqR/P0z8rtsuO6/bxgcCb4Vybme+MBH83f99f3cgG3Q+/mRzk=;7:oz0mp6LLDynUm8TZ5KV93bcqDSWSX+4CosUcfzZe94xxh3L7CUqFdIljQBBjAeA8Febo4MOZHF9f5KyD/DQYYUW3gWXhAsiinlsBiw3nHZz+tyclT3MxOrO7GCdlAgTzAmg74yo6z9Zf4ySyVhkGecAdb8liD4Q4I19o5pdpsNSGzGrOuhIkRjDeVTf5wimVIFGhG12z1XLbaWkrvshEC0Rh5JeeVDyvlzEhtjsRrU6txrb5gWWP54yJZJLjGzUV SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1;DM2PR12MB0155;20:slSzo6qMZMeVUpxnrNUTRnlMeyvb4dw3fAG5snBLvKR0jN5d7nc5IIk+bXzbbrMTl/EXrvOTl9qC9tZf9tzfe/g7OAiCiqkCQkQ8nfqTLwyHJ5/pKbwBDoWsYHiuASxItioycddAz7J0VIoMLMycTEtWjmzzCM6IPuOTbPoy6XfP6FPPEmGm2HNbvBINzukLtCecMhW8pIxI/D5VB6h+Kcy0tAkZqpdX83WbdV5ZO3fps53haOVy6S5BjA8cdv/E X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Nov 2017 21:16:55.5939 (UTC) X-MS-Exchange-CrossTenant-Network-Message-Id: d452cd52-8e29-407f-9c27-08d5216de16d X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 3dd8961f-e488-4e60-8e11-a82d994e183d X-MS-Exchange-Transport-CrossTenantHeadersStamped: DM2PR12MB0155 Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org The command is used for encrypting the guest memory region using the VM encryption key (VEK) created during KVM_SEV_LAUNCH_START. Cc: Thomas Gleixner Cc: Ingo Molnar Cc: "H. Peter Anvin" Cc: Paolo Bonzini Cc: "Radim Krčmář" Cc: Joerg Roedel Cc: Borislav Petkov Cc: Tom Lendacky Cc: x86@kernel.org Cc: kvm@vger.kernel.org Cc: linux-kernel@vger.kernel.org Improvements-by: Borislav Petkov Signed-off-by: Brijesh Singh Reviewed-by: Borislav Petkov --- arch/x86/include/asm/kvm_host.h | 1 + arch/x86/kvm/svm.c | 191 +++++++++++++++++++++++++++++++++++++++- 2 files changed, 190 insertions(+), 2 deletions(-) diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h index f2654486b9a6..924ce807c76c 100644 --- a/arch/x86/include/asm/kvm_host.h +++ b/arch/x86/include/asm/kvm_host.h @@ -752,6 +752,7 @@ struct kvm_sev_info { unsigned int asid; /* ASID used for this guest */ unsigned int handle; /* SEV firmware handle */ int fd; /* SEV device fd */ + unsigned long pages_locked; /* Number of pages locked */ }; struct kvm_arch { diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 56df6d64359b..f400753a37a8 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include #include @@ -330,6 +332,7 @@ enum { static unsigned int max_sev_asid; static unsigned long *sev_asid_bitmap; +#define __sme_page_pa(x) __sme_set(page_to_pfn(x) << PAGE_SHIFT) static inline bool svm_sev_enabled(void) { @@ -1547,6 +1550,83 @@ static void sev_unbind_asid(struct kvm *kvm, unsigned int handle) kfree(decommission); } +static struct page **sev_pin_memory(struct kvm *kvm, unsigned long uaddr, + unsigned long ulen, unsigned long *n, + int write) +{ + struct kvm_sev_info *sev = &kvm->arch.sev_info; + unsigned long npages, npinned, size; + unsigned long locked, lock_limit; + struct page **pages; + int first, last; + + /* Calculate number of pages. */ + first = (uaddr & PAGE_MASK) >> PAGE_SHIFT; + last = ((uaddr + ulen - 1) & PAGE_MASK) >> PAGE_SHIFT; + npages = (last - first + 1); + + locked = sev->pages_locked + npages; + lock_limit = rlimit(RLIMIT_MEMLOCK) >> PAGE_SHIFT; + if (locked > lock_limit && !capable(CAP_IPC_LOCK)) { + pr_err("SEV: %lu locked pages exceed the lock limit of %lu.\n", locked, lock_limit); + return NULL; + } + + /* Avoid using vmalloc for smaller buffers. */ + size = npages * sizeof(struct page *); + if (size > PAGE_SIZE) + pages = vmalloc(size); + else + pages = kmalloc(size, GFP_KERNEL); + + if (!pages) + return NULL; + + /* Pin the user virtual address. */ + npinned = get_user_pages_fast(uaddr, npages, write ? FOLL_WRITE : 0, pages); + if (npinned != npages) { + pr_err("SEV: Failure locking %lu pages.\n", npages); + goto err; + } + + *n = npages; + sev->pages_locked = locked; + + return pages; + +err: + if (npinned > 0) + release_pages(pages, npinned, 0); + + kvfree(pages); + return NULL; +} + +static void sev_unpin_memory(struct kvm *kvm, struct page **pages, + unsigned long npages) +{ + struct kvm_sev_info *sev = &kvm->arch.sev_info; + + release_pages(pages, npages, 0); + kvfree(pages); + sev->pages_locked -= npages; +} + +static void sev_clflush_pages(struct page *pages[], unsigned long npages) +{ + uint8_t *page_virtual; + unsigned long i; + + if (npages == 0 || pages == NULL) + return; + + for (i = 0; i < npages; i++) { + page_virtual = kmap_atomic(pages[i]); + clflush_cache_range(page_virtual, PAGE_SIZE); + kunmap_atomic(page_virtual); + } +} + static void sev_vm_destroy(struct kvm *kvm) { struct kvm_sev_info *sev = &kvm->arch.sev_info; @@ -5636,7 +5716,7 @@ static int sev_bind_asid(struct kvm *kvm, unsigned int handle, int *error) return ret; } -static int sev_issue_cmd(int fd, int id, void *data, int *error) +static int __sev_issue_cmd(int fd, int id, void *data, int *error) { struct fd f; int ret; @@ -5651,6 +5731,13 @@ static int sev_issue_cmd(int fd, int id, void *data, int *error) return ret; } +static int sev_issue_cmd(struct kvm *kvm, int id, void *data, int *error) +{ + struct kvm_sev_info *sev = &kvm->arch.sev_info; + + return __sev_issue_cmd(sev->fd, id, data, error); +} + static int sev_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp) { struct kvm_sev_info *sev = &kvm->arch.sev_info; @@ -5698,7 +5785,7 @@ static int sev_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp) start->policy = params.policy; /* create memory encryption context */ - ret = sev_issue_cmd(argp->sev_fd, SEV_CMD_LAUNCH_START, start, error); + ret = __sev_issue_cmd(argp->sev_fd, SEV_CMD_LAUNCH_START, start, error); if (ret) goto e_free_session; @@ -5727,6 +5814,103 @@ static int sev_launch_start(struct kvm *kvm, struct kvm_sev_cmd *argp) return ret; } +static int get_num_contig_pages(int idx, struct page **inpages, + unsigned long npages) +{ + unsigned long paddr, next_paddr; + int i = idx + 1, pages = 1; + + /* find the number of contiguous pages starting from idx */ + paddr = __sme_page_pa(inpages[idx]); + while (i < npages) { + next_paddr = __sme_page_pa(inpages[i++]); + if ((paddr + PAGE_SIZE) == next_paddr) { + pages++; + paddr = next_paddr; + continue; + } + break; + } + + return pages; +} + +static int sev_launch_update_data(struct kvm *kvm, struct kvm_sev_cmd *argp) +{ + unsigned long vaddr, vaddr_end, next_vaddr, npages, size; + struct kvm_sev_info *sev = &kvm->arch.sev_info; + struct kvm_sev_launch_update_data params; + struct sev_data_launch_update_data *data; + struct page **inpages; + int i, ret, pages; + + if (!sev_guest(kvm)) + return -ENOTTY; + + if (copy_from_user(¶ms, (void __user *)(uintptr_t)argp->data, sizeof(params))) + return -EFAULT; + + data = kzalloc(sizeof(*data), GFP_KERNEL); + if (!data) + return -ENOMEM; + + vaddr = params.uaddr; + size = params.len; + vaddr_end = vaddr + size; + + /* Lock the user memory. */ + inpages = sev_pin_memory(kvm, vaddr, size, &npages, 1); + if (!inpages) { + ret = -ENOMEM; + goto e_free; + } + + /* + * The LAUNCH_UPDATE command will perform in-place encryption 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(inpages, npages); + + for (i = 0; vaddr < vaddr_end; vaddr = next_vaddr, i += pages) { + int offset, len; + + /* + * If the user buffer is not page-aligned, calculate the offset + * within the page. + */ + offset = vaddr & (PAGE_SIZE - 1); + + /* Calculate the number of pages that can be encrypted in one go. */ + pages = get_num_contig_pages(i, inpages, npages); + + len = min_t(size_t, ((pages * PAGE_SIZE) - offset), size); + + data->handle = sev->handle; + data->len = len; + data->address = __sme_page_pa(inpages[i]) + offset; + ret = sev_issue_cmd(kvm, SEV_CMD_LAUNCH_UPDATE_DATA, data, &argp->error); + if (ret) + goto e_unpin; + + size -= len; + next_vaddr = vaddr + len; + } + +e_unpin: + /* content of memory is updated, mark pages dirty */ + for (i = 0; i < npages; i++) { + set_page_dirty_lock(inpages[i]); + mark_page_accessed(inpages[i]); + } + /* unlock the user pages */ + sev_unpin_memory(kvm, inpages, npages); +e_free: + kfree(data); + return ret; +} + static int svm_mem_enc_op(struct kvm *kvm, void __user *argp) { struct kvm_sev_cmd sev_cmd; @@ -5747,6 +5931,9 @@ static int svm_mem_enc_op(struct kvm *kvm, void __user *argp) case KVM_SEV_LAUNCH_START: r = sev_launch_start(kvm, &sev_cmd); break; + case KVM_SEV_LAUNCH_UPDATE_DATA: + r = sev_launch_update_data(kvm, &sev_cmd); + break; default: r = -EINVAL; goto out; -- 2.9.5