From patchwork Thu Sep 22 14:52:49 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Brijesh Singh X-Patchwork-Id: 9345547 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 39A30607D0 for ; Thu, 22 Sep 2016 15:29:04 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 2444E2ABB4 for ; Thu, 22 Sep 2016 15:29:04 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 183722ABB7; Thu, 22 Sep 2016 15:29:04 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-6.8 required=2.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_HI,T_DKIM_INVALID autolearn=ham version=3.3.1 Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) (using TLSv1 with cipher AES256-SHA (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 17CF72ABB4 for ; Thu, 22 Sep 2016 15:29:01 +0000 (UTC) Received: from localhost ([::1]:50426 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bn5vo-0005wq-59 for patchwork-qemu-devel@patchwork.kernel.org; Thu, 22 Sep 2016 11:29:00 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:45934) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bn5N0-0000oU-Ir for qemu-devel@nongnu.org; Thu, 22 Sep 2016 10:53:07 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1bn5Mu-0007kK-Dg for qemu-devel@nongnu.org; Thu, 22 Sep 2016 10:53:01 -0400 Received: from mail-sn1nam02on0040.outbound.protection.outlook.com ([104.47.36.40]:4848 helo=NAM02-SN1-obe.outbound.protection.outlook.com) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1bn5Mt-0007kE-TQ for qemu-devel@nongnu.org; Thu, 22 Sep 2016 10:52:56 -0400 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=amdcloud.onmicrosoft.com; s=selector1-amd-com; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version; bh=0U5WB4G3/12bloT2FveRNPHWsbGpslj/97WRJ7sh9lI=; b=rZS7qcO3b2mpTLDygSjiAXIf3iTRTVfu/PEccHl1w9cWxEx6E6wx5Of/s5LfJcGynPyk60FkB9dtgFHVY36Bnd2pZtO98wNIrl2HO+AWvuXF3HvqCERGM1LxlkG7mkCbet0CD3LwS/1MoEaxWJY6fHhekCA/Aaw2qqT6dFrB48g= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=brijesh.singh@amd.com; Received: from [127.0.1.1] (165.204.77.1) by CY1PR12MB0665.namprd12.prod.outlook.com (10.163.238.150) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.629.8; Thu, 22 Sep 2016 14:52:52 +0000 From: Brijesh Singh To: , , , , , , , , Date: Thu, 22 Sep 2016 10:52:49 -0400 Message-ID: <147455596937.8519.6403549430047219068.stgit@brijesh-build-machine> In-Reply-To: <147455590865.8519.11191009507297313736.stgit@brijesh-build-machine> References: <147455590865.8519.11191009507297313736.stgit@brijesh-build-machine> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-Originating-IP: [165.204.77.1] X-ClientProxiedBy: BN6PR03CA0060.namprd03.prod.outlook.com (10.173.137.22) To CY1PR12MB0665.namprd12.prod.outlook.com (10.163.238.150) X-MS-Office365-Filtering-Correlation-Id: 1ab44353-17ac-414e-9ad6-08d3e2f821de X-Microsoft-Exchange-Diagnostics: 1; CY1PR12MB0665; 2:t5HtO5UGdXtIN+FclbrLwaA7B0tr4V9akU2RGLWIn+rN3+glGXK1RxT/VAFzm5n8Jmu1tSzzlQ2e8A3AgSDspEybHdl7hTL1LayaRjo8fpTZWwIgzxoppfw4DSP3Ju8s9A7XmVNLckkh3RZKXMXudwr/Pn7P61YPElUvaqY2CrA5WXzpLFy58MPY8OwHr7HX; 3:GsDDC40vsBVFqup03W8CCF6jfE+sQwHkYH+RJSve5Nv2+x13vKk9LDXvo5fwD3BGvZ3Yx+mD7ifyBvGgshMvrqNzxqo5VEl7We6Fjyrr4GXjpXXnVIzUIIGBYJ7XZeAd; 25:16yWCBSRdeXdz6SwETFJsS1pb8SmiGVUckmd2qLo5q+RJ0Js0/iNLKZt/CuED04J1F10O7i0ng9VQwxk2QayVg5AnTU2rGiYbxJfDhBCckxvuLrxZt0KEpdNMVgV7b1ym5gBSXfMGGkXjmRJqDxg5cAFhce5xn66oS5OGqLWiouycqd+jx0C2iqy7bWVS5HKswzElqDBkMR6umDNif5QLAr2KHu5QcYJ7J6a3ofSFGI6id89Dn+Otw2JBC/mUlIWHnpl/hcN/TkTWe1yHrmF+Dgol/FJHqO1Ielsa2+6MqCwMxc+UkveZOi/XWVKd4MJT1qnQRtwSAUENQ8B/SKrfJa0egfIrRQ4+O2pak946LzfFFCFQe58LNEXeWzfLCYQr2mmSTNKtMug0B/k2oiByftskOAwjuvET1zIzUznvOw= X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:CY1PR12MB0665; X-Microsoft-Exchange-Diagnostics: 1; CY1PR12MB0665; 31:1jkq/GTN7hQSVg+w5/MDPTt+PXaz4R2OdD0ru4PsldahVSb0TVn+ElOkc4XZ77rGU+rQLHPRFzAaiEHo4EmyEcYcGdxoBM8cNZ3pjpFOJY+cqGY6EIKjs1SUTapnqgFA5mkkmJibTEipimYU89dKfY0ssTBWt9dcj7GnjDvEfgc1TJNuxb1LMjkObheFP6HETr73kcpR78Il2POrKVtpuGkvTulSOVAUNz7vsTG4Ypg=; 20:mommbIJe4ro6sbtx+Nsu/C/8Od0BiJXEHBMmq8GWhskxtzajwQHiP7qhH0Ev0na1XUcbH00Mxey/vgNC1hy1mYn82ueXZcgsuucS3GPEWzSSylpBJiE65KqDEFFeO7ZlQEUEofg6neNNLrVkzaM2y/g7i5ZWMJQe7CQczsV+iLcoicx/ii0nEEBSWe3dcI9nFzfEPZP+QLgdGaxG7LBPQY3wUFiYeH49Xeaf8q3mh1JC6GRZ6Ql4zdmFE4yTubjP6lJJUV3u2FDhsum/aKtbnaq0tZijQAqPsqXm+vLqahSf6i+sYFNvHgcvWghcECZtiurDqLng8mQCgd+5ut7wsNe7XIIM1LXlXUEsTTdHzlVHQcUUitPvTDCmW0QkQ5eX+oDu+qim+ib8pla1Nqya3ng3DFFcp6OZCghcLwfRTZCkBi/ZICffuMJ0xsSR3Bsw0BdaiULw2QZjmxQxamxp4iZPXHoObD3cvuyfeF/3+Rq/q8fFqa94c07bT0xDZ0dg X-Microsoft-Antispam-PRVS: X-Exchange-Antispam-Report-Test: UriScan:(192374486261705)(767451399110); X-Exchange-Antispam-Report-CFA-Test: BCL:0; PCL:0; RULEID:(6040176)(601004)(2401047)(5005006)(8121501046)(3002001)(10201501046)(6055026); SRVR:CY1PR12MB0665; BCL:0; PCL:0; RULEID:; SRVR:CY1PR12MB0665; X-Microsoft-Exchange-Diagnostics: 1; CY1PR12MB0665; 4:M80aoSlZ0fNa5AVQE1xhQrXZ3XjfTxlb9tnif3Z/91h30K4KD7UMujmidZSMAgyR8s3UUYogPO5Vbo8cD4fzVFHeUw50lmvEU+S6ZKspfBOPkGMNr1qQL7QTG4CDF3x16wiDjrcaeR493Eg2g/tkUJZ+r0Ftt9GK3MDkuYw/PvqPoDTPZeILBzQrMA1KpNAdh94Pf/KqOlVPc5/0ny5nLLyeLvn+NA+WkG5Fxarheaof8Ldtu4LFEGzaymqZL3TlR7B4ALUf5n32fgrQpmCB5w4QIfKBDuJJ4Oy6U/AXZKTxc2QOwK9SYD/wBZaFU3Q7Aihvwj+6I4jJiqAe+grZFOgXaqUSKHKNlcuOjvnLov3jRS+03kzdiVI7xDg/Ib8m4mho9lHs1z74ObPwV6SIDPFhHbeh3Dbh8UzagcezAJg9WiKyrJxLnsZndTGZwB48SyJU/zum3E7Yy/Z1M9Lo/n/r1QwfN09FzpcoweoJHcY= X-Forefront-PRVS: 0073BFEF03 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(4630300001)(6049001)(6009001)(7916002)(199003)(189002)(77096005)(229853001)(103116003)(19580395003)(1720100001)(305945005)(47776003)(33716001)(19580405001)(23676002)(105586002)(189998001)(7736002)(83506001)(33646002)(92566002)(8676002)(230700001)(106356001)(81156014)(107886002)(6116002)(9686002)(81166006)(76176999)(2201001)(97736004)(5001770100001)(42186005)(86362001)(68736007)(2906002)(50986999)(66066001)(3846002)(54356999)(5660300001)(50466002)(101416001)(4001350100001)(2950100001)(7846002)(15975445007)(586003)(217873001)(559001)(579004); DIR:OUT; SFP:1101; SCL:1; SRVR:CY1PR12MB0665; H:[127.0.1.1]; FPR:; SPF:None; PTR:InfoNoRecords; A:1; MX:1; LANG:en; Received-SPF: None (protection.outlook.com: amd.com does not designate permitted sender hosts) X-Microsoft-Exchange-Diagnostics: =?utf-8?B?MTtDWTFQUjEyTUIwNjY1OzIzOlpNSlk1NjVRVGtZMlFmWDFvT3pWVVZyK3FN?= =?utf-8?B?MkhxbVRETnJ1YlJEclUwY1dOTTh4WTRnQllsU0JKalBlU2NnVVRIcnM2YnNE?= =?utf-8?B?SjBQQVkrcktyU3hRVlE5MXlkT3lzVkY5T3Z0dDFOQmVUZEFIY214OGpKc2RE?= =?utf-8?B?WlBLeml1b2tHd2Rod3V3UHdjVFRmc25mN1NYRW81dU9xQjFaTXN2TmJaUTlG?= =?utf-8?B?SXlUcDJMZHpLV0hmaS9BcldDejY5cnJ6LzJRWldCK3JkWVVsdmVydmlpQVNY?= =?utf-8?B?SWgwMFI1QVB3bVBJczZpaTByMy8rUU1OQ2JZbExrUWxiT2Uxd3RVM1ZLL1pP?= =?utf-8?B?TkpUbEJMSHZKb2d0bmRXOHpibnZadzFiamZWZ3lLM1pmbFdYdUdOR0lzaWFY?= =?utf-8?B?WDdJeE03cElHZDVGNlpCcHFYdG5HWXFFYzF6Q2NpcDBFMkJtYzVQQmNjbXY3?= =?utf-8?B?SEtIQktHMUdPMXo5RGcwSmZXOWZKN1BWbkcrNjRndy9aakVwVWlxTmk4NU5W?= =?utf-8?B?dDhrb0ZHd0lSbFo1eTlmZ0JOUTJnckYrSWUvR1JHSFJrdWVJSXAwT2lkNWJh?= =?utf-8?B?bllyblZTZy9YY0Jhd3g3UlRqU2ZSVldTa3N6bE92WDJVOE4zbEJ3UTF4Z3Rp?= =?utf-8?B?SXZkSnExNjhzSXlRbmlvMm1FTkZxbXVQcTJKamlUTDBWekNBY2hvaUsrSGg1?= =?utf-8?B?Yzlndjd5U0xyNTVZV3NQWHpjb2Y3S1R6WEFlN2FEMVBHN2tQTk5Ud3lXVk9m?= =?utf-8?B?UGgyaHpqbmFDVXhDdFFEVlJTb08yRmM1Q3dtalRkYlEycnQ3SzFBK1FGQ2xN?= =?utf-8?B?aHVuUlFWL0psVk0yd2VzbERDVEV6aGpmT2JDdFRHa21ZaTM3VnNuRHV6aVVR?= =?utf-8?B?QzMyT05sbWgwWG5UejhiRi9JOCt5YmdKT0Fhd1JTa2V0TEV4dzRoVk44OVlX?= =?utf-8?B?VUlTV0t2b0dDTW9RK2xtVWFBdkxPeitXMDNHaEcvOFRxRlA3NENnN1dDWUJv?= =?utf-8?B?VndOSFE2cytlaWlQZDMyUzI2VVFDeUlYekZ3OHBncFIwWjZDczhETnRON215?= =?utf-8?B?S01TckVtdnlZSU0vemdzcVh3aVAyT3E5T0d3ZkxqaHIzQUp1dWxVcXdpS3U5?= =?utf-8?B?UlRBcGtKWkY5MHd5NEtCVGVsd01HOHFITmF2dnArcUtMME9rWHFpWmJmdzFj?= =?utf-8?B?MVlZbXJsOFlSZUpnaUlIcnE1cVk1RXdWTExLSzFrZHBQU3Frc3J6TnpjMnNy?= =?utf-8?B?OHo2c256TXhvdzUrWlBLSGtYSkt2cm1mc2lNRzFDZkRRT2hPbFFVV0pZY2Jq?= =?utf-8?B?ZDlWeVM2R2lKL2dhYU8vMUhmVEFqRVlLN2tIekYzcktNQjA2MC9YeVM2Uzg5?= =?utf-8?B?SDArM3JyQkhPaloveW1tSzV5cmowbTRLYmhPSkF4M2JvNDAwSnR6UTFUd3FF?= =?utf-8?B?K25XbElSVnZkU1EzdVFXa0xpa1BQRXdLSXlySlQ5ZHF0ZllsK0xHd3lRdzln?= =?utf-8?B?SWdMaUZtdFVEYi9jdGhYM0hWUE1raW5TS2xnOHZ5M0JZUjlST2w2ZHJieVNs?= =?utf-8?B?cmhJNW0vS2lBb0RKOW9OTnZzaENpUU5mSGsxYUs2VHNKSDJUUjBod2RkY0Ex?= =?utf-8?B?bTJ2NVdOellJUVBXMVo3TG9DTUZpWHh6bnFzZzl0SGJ2Ry9JeEdsUmZDdkU5?= =?utf-8?B?djYrSGpIZExuTThDZnhHU2FBbHJzd09TZ3REakYyQTdQTWhQRjRLcG45OFc4?= =?utf-8?Q?vEeUiE1N/CPjBMSpakbtCZLfe2hlGM8S7dTk4=3D?= X-Microsoft-Exchange-Diagnostics: 1; CY1PR12MB0665; 6:7wboQWIynV3by8H5UGlScMCbQdhc9zYrdakfbeO3JcHdkVIJrF2xPdIHKi9C64/3eNSnjcuE7P0LQoETYNffCVSBMhkk+nq2YWZ85RlOmjXnGBbN7gcu+tsJ51ZD9TOUH98H0Mehp6JA677YU7OW/Hu7zZFmveW6NUgB53eosj4UmlH+KN0PY/zytDXpdX/OT1RibNfbsnVqWhkE7JhzZILNS3t/WRlLYc5WjFopVlPYuoprXeNoic4IqLqKa9fYd4viZcNWfS3nzKmQ9A6/1piCqpWg7mAAw2NdVSl0skbim41EqaTWGksH1852nh+EWyTDxTQ6Me7cJtPOmTrexA==; 5:s6Tln8TEMCqYiWzkCZHbStj7kyn/hhPNeTJlezM0u5OjfGQJes+yFuKnncBwoInUHyoWRD8xOubg+F2v+hexRDRB4m2r9QYUwPqJRY8LtHXilc1S2dcPNqOqXTUkzObfz3rP/XT/zSgmjtJWQ0jn4A==; 24:O+v2C/prYOXtA3SC/J7HnwRJkS5Dglr/Gn4p0SkOGelVX9i9fRS6Bg/izsStWUMv6NF0XtexG5TmLSns8Y8M8QhTVBwjIZXcu0Si136YBfY=; 7:OBD+YH3VQyXxToVB/TRh1/p9Mc+X2mBHD9hPg7JV2Env/tfqBzqwtpWUI8kr9lWtKH2dKiKfouDYwyxlOa4fTd+DwFuKQnFUmB3tvVbBjkkG7gx92zcU+QoF105pEu1ipGHRiMBAkR5TzSgmwV7rij5jW2eXdjleYP8wO5q2h6XmIfGzJ4vsYNweOajAfhY+Ag8zUabbqHyGaqKe5i7m7lkfeUiVHeNac5Gw3sgU9xBI0axWmcp4CjvdWr3xoxvmTqCMUDyTmStiKyvnISZICO2kw+zHuwDOVetmgUi+SQ/ABuqn1e6tNpku69T+/zgS SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; CY1PR12MB0665; 20:C2kAQY00micVZrc7DcEfRMWsk+o9wryE/znMNuX1BJMjotRuodUBERnXVAkXX6hr1XTLEIES+kHEzOoR7JZo/kQ0V+TEm2WP3Zt11EkGqAKrlgpxBo8xQIVqbk7iPtY1PYrzvkUfLGtFJIxOkovK/3zn90uvbS1UEkmW9pzwLI+EwC+jz80MIcokszbDNbs8l1s7nZ04PLLKzZGTFdpV71ClQwrJNBuLDWh05XqbZrhQ9fE88UJbshWJNJohJvbR X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 22 Sep 2016 14:52:52.5756 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: CY1PR12MB0665 X-detected-operating-system: by eggs.gnu.org: Windows 7 or 8 [fuzzy] X-Received-From: 104.47.36.40 Subject: [Qemu-devel] [RFC PATCH v2 06/16] sev: add Secure Encrypted Virtulization (SEV) support X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: qemu-devel-bounces+patchwork-qemu-devel=patchwork.kernel.org@nongnu.org Sender: "Qemu-devel" X-Virus-Scanned: ClamAV using ClamSMTP This patch adds the initial support required to integrate Secure Encrypted Virtualization (SEV) feature. SEV is an extension to the existing AMD-V technology found on AMD processors. The SEV feature allows the memory contents of a virtual machine to be transparently encrypted with a key unique to the guest VM. In QEMU command line, SEV can be enabled via memory-encryption property defined in security-policy object. The patch adds the following new objects to pass various SEV specific parameters required to launch and migrate the SEV guest. - sev-launch-info: provides the properties to set/get parameters required to launch unencrypted SEV guest. In this mode the OS images (kernel, initrd and bios) provides by guest owner are unencrypted. The SEV guest boot process would encrypt the images using the guest owner's key. to launch unencrypted SEV guest: # $QEMU \ -object sev-launch-info,id=launch0,flags.ks=off \ -object sev-guest-info,id,sev0,launch=launch0 \ -object security-policy,id=secure0,memory-encryption=sev0 \ -machine ....,security-policy=secure0 - sev-receive-info: provides the properties to set/get parameters required to launch encrypted SEV guest. In this mode the boot images received from the guest owner are pre-encrypted with owners transport keys. The SEV guest boot process would re-encrypt the images using guest owner's key. to launch encrypted SEV guest: # $QEMU \ -object sev-receive-info,id=launch0,flags.ks=off \ -object sev-guest-info,id=sev0,launch=launch0 \ -object security-policy,id=secure0,memory-encryption=sev0 \ -machine ....,security-policy=secure0 - sev-policy-info: provides properties to get/set SEV specific policy parameters required by SEV launch and migrate objects. e.g to disable key share during encrypted launch. # $QEMU \ -object sev-policy-info,id=policy0,ks=off \ -object sev-launch-info,id=sev0,policy=policy0 \ ..... sev-policy should be provided by the guest owner. - sev-guest-info: provides properties to set SEV guest launch object id used during guest launch. to use encrypted guest launch # $QEMU \ -object sev-receive-info,id=launch0 \ -object sev-send-info,id=send0 \ -object sev-guest-info,id=sev0,launch=launch0,send=send0 \ ..... Signed-off-by: Brijesh Singh --- Makefile.target | 2 docs/amd-memory-encryption.txt | 260 ++++++++++ include/sysemu/kvm.h | 6 include/sysemu/sev.h | 208 ++++++++ kvm-all.c | 71 +++ qemu-options.hx | 106 ++++ sev.c | 1074 ++++++++++++++++++++++++++++++++++++++++ 7 files changed, 1725 insertions(+), 2 deletions(-) create mode 100644 docs/amd-memory-encryption.txt create mode 100644 include/sysemu/sev.h create mode 100644 sev.c diff --git a/Makefile.target b/Makefile.target index a440bcb..74ad204 100644 --- a/Makefile.target +++ b/Makefile.target @@ -136,7 +136,7 @@ ifdef CONFIG_SOFTMMU obj-y += arch_init.o cpus.o monitor.o gdbstub.o balloon.o ioport.o numa.o obj-y += qtest.o bootdevice.o obj-y += hw/ -obj-$(CONFIG_KVM) += kvm-all.o +obj-$(CONFIG_KVM) += kvm-all.o sev.o obj-y += memory.o cputlb.o obj-y += memory_mapping.o obj-y += dump.o diff --git a/docs/amd-memory-encryption.txt b/docs/amd-memory-encryption.txt new file mode 100644 index 0000000..ab2fdfb --- /dev/null +++ b/docs/amd-memory-encryption.txt @@ -0,0 +1,260 @@ +Secure Encrypted Virtalization (SEV) is a feature found on AMD processors. + +SEV feature allows the memory contents of a virtual machine (VM) to be +transparently encrypted with a key unique to the guest VM. The memory +controller contains a high performance encryption engine which can be +programmed with multiple keys for used by different VMs in the system. +The programming and management of these keys is handled by the AMD Platform +Secure Processor (PSP) firmware which exposes commands for these tasks. The +SEV commands can be send via KVM_SEV_ISSUE_CMD ioctl. + +SEV is capable of supporting both light-weight virtual containers as well as +conventional VM within an enterprise cloud environment. In either case, +there are two parties concerned in the deloplyment of SEV guest: the guest +owner and the platform owner. For example, in a cloud envrionment, the +platform owner would be cloud vendor and the guest owner would be the user +that wishes to run their workload in the cloud. + +Guest owners wish to protect the confidentiality of the data running within +their guests. While they trust the platform owner to provide the infrastrcuture +to run their guest, they benefit from reducing their risk exposure to +vulnerablities within that infrastruture. The SEV feature encrypts the content +of the memory of the guest and provides additional assurance that it was +encrypted properly. The encryption of memory places an additional burden +on attackers within the operational envrionment who may have already obtained +some illicit access to the guest's memory through a vulnerability in the +hypervisor or other supporting enterprise softwares. + +Platform owners wish to provide such protection to guest owners, but also must +manage the computing resources efficiently and effectively. Resource allocation +need to be fluid and their customers data must be safely backed up in case +of failure. The SEV feature has been developed to be sensitive to this +requirement; it integrates into the conventional guest life cycle surrounding +guest launching, migration, and snapshotting. + +The following links provide additional detail: + +AMD Memory Encryption whitepaper: + http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2013/12/AMD_Memory_Encryptio \ +n_Whitepaper_v7-Public.pdf + +Secure Encrypted Virutualization Key Management: +http://support.amd.com/TechDocs/55766_SEV-KM API_Spec.pdf + +KVM Forum slides: +http://www.linux-kvm.org/images/7/74/02x08A-Thomas_Lendacky-AMDs_Virtualizatoin_Memory_Encryption_Technology.pdf + +AMD64 Architecture Programmer's Manual: + http://support.amd.com/TechDocs/24593.pdf + SME is section 7.10 + SEV is section 15.34 + +1. API description +----------------- + +SEV provides the following command via KVM_SEV_ISSUE_CMD ioctl to launch, +migrate and snapshot a SEV-enabled guest. + +1.0 LAUNCH_START (KVM_SEV_LAUNCH_START) + +The command is used to prepare a guest for the transition into SEV-enabled +mode. + +Parameters: struct kvm_sev_launch_start +Returns: 0 on success; -1 on error. + +/* for LAUNCH_START */ +struct kvm_sev_launch_start { + /* If KS is set; share key with guest reference by this handle */ + u32 handle; + + /* Bit 0 (KS) key sharing is enabled */ + u32 flags; + + /* Guest launch policy (see 1.5 for details) + u32 policy; + + /* The Qx and Qy parameter of the owner's ECDH public key */ + u8 dh_pub_qx[32], dh_pub_qy[32]; + + /* A nonce generated by the guest owner */ + u8 nonce[16]; +} + +The firmware creates a new launch context and generate a new VM Encryption Key +(VEK) - a 128-bit AES-128 key used to encrypt the memory of the guest. The key +is loaded into memory controller by the firmware. + +1.1 LAUNCH_UPDATE (KVM_SEV_LAUNCH_UPDATE) + +The command is used to encrypt the guest memory region specified using the VEK +loaded during LAUNCH_START. + +Parameters: struct kvm_sev_launch_update +Returns: 0 on success; -1 on error + +/* for LAUNCH_UPDATE */ +struct kvm_sev_launch_update { + /* host virtual address to encrypt */ + u64 address; + + /* length of memory region to encrypt */ + u32 len; +} + +The firmware will perform the inline encryption of memory region and launch +measurement will be updated with the contents of the memor region. + +1.2 LAUNCH_FINISH (KVM_SEV_LAUNCH_FINISH) + +The command is used to finalize the SEV guest launch process and get the +measurement of encrypted contents. + +Parameters: struct kvm_sev_launch_update +Returns: 0 on success; -1 on error + +/* for LAUNCH_FINISH */ +struct kvm_sev_launch_finish { + /* contains measurement of memory encrypted via LAUNCH_UPDATE */ + u8 measurement[32]; +} + +After hypervisor has finished encrypting the guest's memory (via LAUNCH_UPDATE), +the hypervisor concludes the launch operation. The measurement value returned +from the LAUNCH_FINISH command can be handed to the guest owner to verify that +guest is launched successfully. + +1.3 GUEST_STATUS (KVM_SEV_GUEST_STATUS) + +The command returns the current SEV guest status. + +Parameters: struct kvm_sev_guest_status +Returns: 0 on success; -1 on error + +/* for GUEST_STATUS */ +struct kvm_sev_guest_status { + /* guest handle */ + u32 handle; + + /* guest policy */ + u32 policy; + + /* guest state (see state enum) */ + u8 state; +}; + +/* for SEV guest state */ +GuestState { + STATE_INVALID = 0, + STATE_LAUNCHING, + STATE_RECEIVING, + STATE_SENDING, + STATE_RUNNING, +}; + +1.4 DBG_DECRYPT (KVM_SEV_DBG_DECRYPT) + +The command is used to decrypt a page of guest memory for debug. + +Parameters: struct kvm_sev_dbg_decrypt +Returns: 0 on success; -1 on error + +/* DGB_DECRYPT */ +struct kvm_sev_dbg_decrypt { + /* virtual address of memory region to debug from */ + u64 src_address; + + /* virtual address of memory region to write decrypted contents into */ + u64 dst_address; + + /* length of memory region */ + u32 length; +} + +1.4 DBG_ENCRYPT (KVM_SEV_DBG_ENCRYPT) + +The command is used to encrypt a page of guest memory for debug. + +Parameters: struct kvm_sev_dbg_encrypt +Returns: 0 on success; -1 on error + +/* DGB_ENCRYPT */ +struct kvm_sev_dbg_encrypt { + /* virtual address of memory region to debug from */ + u64 src_address; + + /* virtual address of memory region to write encrypted contents into */ + u64 dst_address; + + /* length of memory region */ + u32 length; +} + +1.5 SEV Policy + +Firmware maintain a guest policy provided by the guest owner. This policy is +enforced by the firmware and restricts what configuration and operational +command can be performed on the SEV guest by the hypervisor. For instance, +if debug is off then hypervisor will not able to decrypt guest memory using +DBG_DECRYPT commands. + +The policy is 4-byte structure with the following field + +Bit 0 (debug) - Debugging of the guest is disallowed when set +Bit 1 (ks) - Sharing keys with other guests is disallowed when set +Bit 2 (reserved) - must be set to 1 +Bit 3 (nosend) - Sending the guest to another platform is disallowed when set +Bit 4 (domain) - The guest must not be transmitted to another platform that is not in the domain when set +Bit 5 (sev) - The guest must not be transmitted to another platform that is not SEV capable when set. +Bit 15:6 (reserved) +Bit 16:24 (fw_major) - The guest must not be transmitted to another platform that is not SEV capable when set. +Bit 25:31 (fw_minor) - The guest must not be transmitted to another platform that is not SEV capable when set. + +2. QEMU command line +-------------------- + +SEV support can be enabled through 'memory-encryption' parameters defined in +security-policy object. + +The following objects can be used to provide SEV guest parameters. + +2.0 sev-launch-info + +The object can be used to provide various parameters required to launch an +unencrypted SEV guest. A unencrypted guest means that OS images (bios, kernel +and initrd) received from guest owner are unencrypted and SEV guest should +encrypt it using the LAUNCH command. + +e.g to launch an unencrypted SEV guest + +# $QEMU \ + -object sev-launch-info,id=launch0,flags.ks=off,dh-pub-qx=zzzz \ + -object sev-guest-info,id=sev0,launch=launch0 \ + -object security-policy,id=secure0,memory-encryption=sev0 \ + -machine ...,security-policy=secure0 + +2.1 sev-policy-info + +The object can be used to provide the guest policy for sev-launch-info object + +e.g to launch a unencrypted SEV guest which does not allow the guest to be +send to another platform (i.e disable migration) + +# $QEMU \ + -object sev-policy-info,id=policy0,nosend=on \ + -object sev-launch-info,id=launch0,policy=policy0 \ + .... + +2.2 sev-guest-info + +The object provides the properties to set the SEV guest launch and send id to +use during SEV guest creation and migration. + +e.g to use sev-launch-info object id during SEV guest creation + +# $QEMU \ + -object sev-launch-info,id=launch0 \ + -object sev-guest-info,id=sev0,launch=launch0 \ + -object security-policy,id=secure0,memory-encryption=sev0 \ + .... + diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index c9c2436..16c14f4 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -56,6 +56,7 @@ extern bool kvm_ioeventfd_any_length_allowed; #if defined CONFIG_KVM || !defined NEED_CPU_H #define kvm_enabled() (kvm_allowed) + /** * kvm_irqchip_in_kernel: * @@ -217,6 +218,11 @@ int kvm_has_intx_set_mask(void); int kvm_init_vcpu(CPUState *cpu); int kvm_cpu_exec(CPUState *cpu); int kvm_destroy_vcpu(CPUState *cpu); +bool kvm_memory_encryption_enabled(void); +int kvm_memory_encryption_start(void); +int kvm_memory_encryption_finish(void); +void *kvm_memory_encryption_get_handle(void); +void kvm_memory_encryption_set_memory_region(MemoryRegion *mr); #ifdef NEED_CPU_H #include "cpu.h" diff --git a/include/sysemu/sev.h b/include/sysemu/sev.h new file mode 100644 index 0000000..534390b --- /dev/null +++ b/include/sysemu/sev.h @@ -0,0 +1,208 @@ +/* + * QEMU Secure Encrypted Virutualization (SEV) support + * + * Copyright: Advanced Micro Devices, 2016 + * + * Authors: + * Brijesh Singh + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#ifndef QEMU_SEV_H +#define QEMU_SEV_H + +#include + +#include "qom/object.h" +#include "qapi/error.h" +#include "sysemu/kvm.h" + +#define TYPE_QSEV_GUEST_INFO "sev-guest-info" +#define QSEV_GUEST_INFO(obj) \ + OBJECT_CHECK(QSevGuestInfo, (obj), TYPE_QSEV_GUEST_INFO) + +typedef struct QSevGuestInfo QSevGuestInfo; +typedef struct QSevGuestInfoClass QSevGuestInfoClass; + +/** + * QSevGuestInfo: + * + * The QSevGuestInfo object provides the guest launch and migration ID + * when memory encryption support is enabled in security-policy. + * + * The QSevGuestInfo object provides two properties: + * - launch: should be set to SEV guest launch object ID + * - send: should be set to SEV guest send object ID + * + * e.g to launch a unencrypted SEV guest + * + * # $QEMU -object sev-launch-info,id=launch0,flags.ks=off \ + * -object sev-migrate-send,id=send0 \ + * -object sev-guest-info,id=sev0,launch=launch0 send=send0 \ + * -object security-policy,id=secure0,memory-encryption=sev0 \ + * -machine ...security-policy=secure0 + */ +struct QSevGuestInfo { + Object parent_obj; + + char *launch; + char *send; +}; + +struct QSevGuestInfoClass { + ObjectClass parent_class; +}; + +#define TYPE_QSEV_POLICY_INFO "sev-policy-info" +#define QSEV_POLICY_INFO(obj) \ + OBJECT_CHECK(QSevPolicyInfo, (obj), TYPE_QSEV_POLICY_INFO) + +typedef struct QSevPolicyInfo QSevPolicyInfo; +typedef struct QSevPolicyInfoClass QSevPolicyInfoClass; + +/** + * QSevPolicyInfo: + * + * The QSevPolicyInfo object provides the SEV guest policy parameters used + * in launch and send commands. + * + * # $QEMU -object sev-policy-info,id=policy0,debug=on,ks=on,nosend=off \ + * -object sev-launch-info,id=launch0,flag.ks=on,policy=policy0\ + * .... + */ +struct QSevPolicyInfo { + Object parent_obj; + bool debug; + bool ks; + bool nosend; + bool domain; + bool sev; + uint8_t fw_major; + uint8_t fw_minor; +}; + +struct QSevPolicyInfoClass { + ObjectClass parent_class; +}; + +#define TYPE_QSEV_LAUNCH_INFO "sev-launch-info" +#define QSEV_LAUNCH_INFO(obj) \ + OBJECT_CHECK(QSevLaunchInfo, (obj), TYPE_QSEV_LAUNCH_INFO) + +typedef struct QSevLaunchInfo QSevLaunchInfo; +typedef struct QSevLaunchInfoClass QSevLaunchInfoClass; + +/** + * QSevLaunchInfo: + * + * The QSevLaunchInfo object provides parameters to launch an unencrypted + * sev guest. A unencrypted guest launch means that the guest owners + * provided OS images (kernel, initrd and bios) are unencrypted and SEV + * would encrypt the images using guest owner's key creating using the + * launch parameters. + * + * # $QEMU -object sev-policy,debug=on,ks=on,nosend=off,id=policy1 \ + * -object sev-launch-info,flag.ks=on,policy=policy1,id=sev \ + * -object sev-guest-info,launch=sev,id=secure-guest \ + * .... + */ +struct QSevLaunchInfo { + Object parent_obj; + uint32_t handle; + bool flags_ks; + char *policy_id; + uint8_t nonce[16]; + uint8_t dh_pub_qx[32]; + uint8_t dh_pub_qy[32]; +}; + +struct QSevLaunchInfoClass { + ObjectClass parent_class; +}; + +#define TYPE_QSEV_RECEIVE_INFO "sev-receive-info" +#define QSEV_RECEIVE_INFO(obj) \ + OBJECT_CHECK(QSevReceiveInfo, (obj), TYPE_QSEV_RECEIVE_INFO) + +typedef struct QSevReceiveInfo QSevReceiveInfo; +typedef struct QSevReceiveInfoClass QSevReceiveInfoClass; + +/** + * QSevReceiveInfo: + * + * The QSevReceiveInfo object provides parameters to launch a pre-encrypted + * sev guest or receive the guest during migration. In this mode the images + * received from the remote is encrypted using transport key, SEV guest would + * re-encrypt the data using the owner's key creating using the parameters + * specified in this object. + * + * # $QEMU \ + * -object sev-receive-info,id=launch0,wrapped-tek=xxxx,ten=xxxx \ + * -object sev-guest,sev=0,launch=launch0 \ + * ..... + * + */ + +struct QSevReceiveInfo { + Object parent_obj; + uint32_t handle; + bool flags_ks; + char *policy_id; + uint8_t nonce[16]; + uint8_t dh_pub_qx[32]; + uint8_t dh_pub_qy[32]; + uint8_t policy_measure[32]; + uint8_t wrapped_tek[24]; + uint8_t wrapped_tik[24]; + uint8_t ten[24]; +}; + +struct QSevReceiveInfoClass { + ObjectClass parent_class; +}; + +enum SevLaunchMode { + SEV_LAUNCH_INVALID = 0, + SEV_LAUNCH_UNENCRYPTED, + SEV_LAUNCH_ENCRYPTED +}; + +enum SevState { + SEV_STATE_INVALID = 0, + SEV_STATE_LAUNCHING, + SEV_STATE_RECEIVING, + SEV_STATE_SENDING, + SEV_STATE_RUNNING +}; + +struct SEVState { + char *launch_id; + char *sev_info_id; + + uint8_t mode; + uint8_t state; + struct kvm_sev_launch_start *launch_start; + struct kvm_sev_launch_update *launch_update; + struct kvm_sev_launch_finish *launch_finish; + struct kvm_sev_receive_start *recv_start; + struct kvm_sev_receive_update *recv_update; + struct kvm_sev_receive_finish *recv_finish; + struct kvm_sev_send_start *send_start; + struct kvm_sev_send_update *send_update; + struct kvm_sev_send_finish *send_finish; +}; + +typedef struct SEVState SEVState; + +bool sev_enabled(void); +bool has_sev_guest_policy(const char *keyid); +void *sev_guest_init(const char *keyid); +int sev_guest_launch_start(void *handle); +int sev_guest_launch_finish(void *handle); +void sev_guest_set_ops(void *handle, MemoryRegion *mr); + +#endif + diff --git a/kvm-all.c b/kvm-all.c index ebf35b0..bb5da88 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -36,6 +36,8 @@ #include "qemu/event_notifier.h" #include "trace.h" #include "hw/irq.h" +#include "sysemu/security-policy.h" +#include "sysemu/sev.h" #include "hw/boards.h" @@ -101,6 +103,12 @@ struct KVMState #endif KVMMemoryListener memory_listener; QLIST_HEAD(, KVMParkedVcpu) kvm_parked_vcpus; + + /* memory encryption support */ + void *mem_encrypt_handle; + int (*mem_encrypt_start)(void *handle); + int (*mem_encrypt_finish)(void *handle); + void (*mem_encrypt_ops)(void *handle, MemoryRegion *mr); }; KVMState *kvm_state; @@ -126,6 +134,42 @@ static const KVMCapabilityInfo kvm_required_capabilites[] = { KVM_CAP_LAST_INFO }; +bool kvm_memory_encryption_enabled(void) +{ + return kvm_state->mem_encrypt_handle ? true : false; +} + +int kvm_memory_encryption_start(void) +{ + if (kvm_state->mem_encrypt_start) { + return kvm_state->mem_encrypt_start(kvm_state->mem_encrypt_handle); + } + + return -1; +} + +int kvm_memory_encryption_finish(void) +{ + if (kvm_state->mem_encrypt_finish) { + return kvm_state->mem_encrypt_finish(kvm_state->mem_encrypt_handle); + } + + return -1; +} + +void kvm_memory_encryption_set_memory_region(MemoryRegion *mr) +{ + if (kvm_state->mem_encrypt_ops) { + return kvm_state->mem_encrypt_ops(kvm_state->mem_encrypt_handle, + mr); + } +} + +void *kvm_memory_encryption_get_handle(void) +{ + return kvm_state->mem_encrypt_handle; +} + int kvm_get_max_memslots(void) { KVMState *s = KVM_STATE(current_machine->accelerator); @@ -1745,6 +1789,33 @@ static int kvm_init(MachineState *ms) kvm_state = s; + if (ms->security_policy) { + char *id; + + /* if security-policy is enabled then check whether memory encryption + * property is defined. If so, enable hardware memory encryption. + */ + id = security_policy_get_memory_encryption_id(ms->security_policy); + if (id) { + + /* check if its SEV guest policy */ + if (has_sev_guest_policy(id)) { + kvm_state->mem_encrypt_handle = sev_guest_init(id); + if (!kvm_state->mem_encrypt_handle) { + fprintf(stderr, + "failed to initialize Secure Encrypted" + " Virutalization (SEV) guest\n"); + goto err; + } + kvm_state->mem_encrypt_start = sev_guest_launch_start; + kvm_state->mem_encrypt_finish = sev_guest_launch_finish; + kvm_state->mem_encrypt_ops = sev_guest_set_ops; + } + + g_free(id); + } + } + if (kvm_eventfds_allowed) { s->memory_listener.listener.eventfd_add = kvm_mem_ioeventfd_add; s->memory_listener.listener.eventfd_del = kvm_mem_ioeventfd_del; diff --git a/qemu-options.hx b/qemu-options.hx index b90d6da..7362452 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -3985,7 +3985,111 @@ can be set to the unquie ID of memory encryption object. On AMD processor, memory encryption is supported via 'sev-guest-info' object. -@end table +@item -object sev-guest-info,id=@var{id},launch=@var{id}[,send=@var{id}] + +Create a Secure Encrypted Virtualization (SEV) guest object, which be used to +provide the memory encryption support on AMD processors. The id paramerter is +a unique ID that should be used in security-policy object when creating the +SEV-enabled guest. + +When creating a SEV guest, 'launch' parameter should be set to the unquire ID +from SEV launch object. + +e.g to launch a SEV guest +@example + # $QEMU \ + -object sev-launch-info,id=launch0 \ + -object sev-guest-info,id=sev0,launch=launch0 \ + -object security-policy,id=secure0-guest,memory-encryption=sev0 \ + -machine ...,security-policy=secure0 +@end example + +@item -object sev-launch-info,id=@var{id}[,flags.ks=@var{bool}][,policy=@var{id}][,nonce=@var{string}][,dh-pub-qx=@var{string}][,dh-pub-qy=@var{string}][,handle=@var{int}] + +Create a SEV launch info object, which can be used to pass various parameters +required to transition an unencrypted guest into SEV-enabled mode. +The id parameter is a unique ID that should be used in sev-guest-info object +when creating a unencrypted SEV guest. + +The 'flags.ks' parameter should be set when guest owner has requested the key +sharing with other guests. + +The 'nonce' parameter should be set with a nonce generated by guest owner. + +The 'dh-pub-qx' and 'dh-pub-qy' parameters should be set with guest owners +ECDH public key. + +The 'policy' parameter should be set to unique ID created from 'sev-policy-info'. + +e.g to launch a unencrypted SEV guest +@example + # $QEMU \ + -object sev-launch-info,id=launch0,flags.ks=off,nonce=xxxx \ + -object sev-guest-info,id=sev0,launch=launch0 \ +@end example + +@item -object sev-receive-info,id=@var{id},measurement=@var{string}[,flags.ks=@var{bool}][,policy=@var{id}][,nonce=@var{string}][,dh-pub-qx=@var{string}][,dh-pub-qy=@var{string}][,handle=@var{int}][,wrapped-tek=@var{string}][,wrapped-tik=@var{string}][,ten=@var{string}] + +Create a SEV guest receive info object, which can be used to pass various +parameters required to receive a encrypted guest. The object can be used for +both when launching a pre-encrypted guest or receiving a migration. +The id parameter is a unique ID that should be used in sev-guest-info object +when creating a encrypted SEV guest. + +The 'flags.ks' parameter should be set when guest owner has requested the key +sharing with other guests. + +The 'nonce' parameter should be set with a nonce generated by guest owner. + +The 'dh-pub-qx' and 'dh-pub-qy' parameters should be set with guest owners +ECDH public key. + +The 'policy' parameter should be set to unique ID created from 'sev-policy-info. + +The 'wrapped-tek' parameter should be set with transport encryption key. + +The 'wrapped-tik' parameter should be set with transport identity key. + +The 'ten' parameter should be set with transport encryption nonce. + +The 'measurement' should be set with measurement of transported guest. + +e.g to launch a encrypted SEV guest +@example + # $QEMU \ + -object sev-receive-info,id=launch0,flags.ks=off,nonce=xxxx \ + -object sev-guest-info,id=sev0,launch=launch0 \ +@end example + +@item -object sev-policy-info,id=@var{id}[,debug=@var{bool}][,ks=@var{bool}][,nosend=@var{bool}][,domain=@var{bool}][,sev=@var{bool}][,fw-major=@var{int}][,fw-minor=@var{int}] + +Create SEV guest policy object, which can be used to pass the guest policy +during SEV guest creation and migration. The id parameter is a unqiue ID that +should be used in SEV launch and send objects. + +The SEV guest policy should be provided by the guest owner. + +debug: should be set if guest owner allows the debugging + +ks: should be set when guest owner allows sharing the key with other guest + +nosend: should be set when guest owner does not allow the platform to be + migrated to remote location. + +domain: should be set when guest owner does not allow platform to be transmitted + to another location that is not in the domain. + +sev: should be set when guest should not be transmitted to non SEV platform. + +fw_major/minor: guest should not be transmitted to another platform with a + lower firmware version. + +e.g to create a policy +@example + # $QEMU \ + -object sev-policy-info,id=policy0,debug=on,ks=off \ + -object sev-launch-info,id=launch0,policy=policy0 \ +@end example ETEXI diff --git a/sev.c b/sev.c new file mode 100644 index 0000000..226ad76 --- /dev/null +++ b/sev.c @@ -0,0 +1,1074 @@ +/* + * QEMU SEV support + * + * Copyright Advanced Micro Devices 2016 + * + * Author: + * Brijesh Singh + * + * This work is licensed under the terms of the GNU GPL, version 2 or later. + * See the COPYING file in the top-level directory. + * + */ + +#include "qemu/osdep.h" +#include "qapi/error.h" +#include "qom/object_interfaces.h" +#include "qemu/base64.h" +#include "sysemu/kvm.h" +#include "sysemu/sev.h" +#include "trace.h" + +#define DEBUG_SEV +#ifdef DEBUG_SEV +#define DPRINTF(fmt, ...) \ + do { fprintf(stderr, fmt, ## __VA_ARGS__); } while (0) +#else +#define DPRINTF(fmt, ...) \ + do { } while (0) +#endif + +static MemoryRegionRAMReadWriteOps sev_ops; +static bool sev_allowed; + +static void +DPRINTF_U8_PTR(const char *msg, uint8_t *ptr, int count) +{ + int i; + + DPRINTF("%s = ", msg); + for (i = 0; i < count; i++) { + DPRINTF("%02hhx", ptr[i]); + } + DPRINTF("\n"); +} + +static void +str_to_uint8_ptr(const char *str, uint8_t *ptr, int count) +{ + int i = 0; + + while (*str && i != count) { + sscanf(str, "%2hhx", &ptr[i]); + str += 2; + i++; + } +} + +static char * +uint8_ptr_to_str(uint8_t *ptr, int count) +{ + char *str = g_malloc0(count); + + return memcpy(str, ptr, count); +} + +static Object * +get_object_by_id(const char *id) +{ + Object *obj; + + obj = object_resolve_path_component( + object_get_objects_root(), id); + if (!obj) { + return NULL; + } + + return obj; + +} + +static bool +qsev_policy_get_debug(Object *obj, Error **errp) +{ + QSevPolicyInfo *policy = QSEV_POLICY_INFO(obj); + + return policy->debug; +} + +static void +qsev_policy_set_debug(Object *obj, bool value, Error **errp) +{ + QSevPolicyInfo *policy = QSEV_POLICY_INFO(obj); + + policy->debug = value; +} + +static bool +qsev_policy_get_ks(Object *obj, Error **errp) +{ + QSevPolicyInfo *policy = QSEV_POLICY_INFO(obj); + + return policy->ks; +} + +static void +qsev_policy_set_ks(Object *obj, bool value, Error **errp) +{ + QSevPolicyInfo *policy = QSEV_POLICY_INFO(obj); + + policy->ks = value; +} + +static bool +qsev_policy_get_nosend(Object *obj, Error **errp) +{ + QSevPolicyInfo *policy = QSEV_POLICY_INFO(obj); + + return policy->nosend; +} + +static void +qsev_policy_set_nosend(Object *obj, bool value, Error **errp) +{ + QSevPolicyInfo *policy = QSEV_POLICY_INFO(obj); + + policy->nosend = value; +} + +static bool +qsev_policy_get_domain(Object *obj, Error **errp) +{ + QSevPolicyInfo *policy = QSEV_POLICY_INFO(obj); + + return policy->domain; +} + +static void +qsev_policy_set_domain(Object *obj, bool value, Error **errp) +{ + QSevPolicyInfo *policy = QSEV_POLICY_INFO(obj); + + policy->domain = value; +} + +static bool +qsev_policy_get_sev(Object *obj, Error **errp) +{ + QSevPolicyInfo *policy = QSEV_POLICY_INFO(obj); + + return policy->sev; +} + +static void +qsev_policy_set_sev(Object *obj, bool value, Error **errp) +{ + QSevPolicyInfo *policy = QSEV_POLICY_INFO(obj); + + policy->sev = value; +} + +static void +qsev_policy_get_fw_major(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + QSevPolicyInfo *policy = QSEV_POLICY_INFO(obj); + uint8_t value = policy->fw_major; + + visit_type_uint8(v, name, &value, errp); +} + +static void +qsev_policy_set_fw_major(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + QSevPolicyInfo *policy = QSEV_POLICY_INFO(obj); + Error *error = NULL; + uint8_t value; + + visit_type_uint8(v, name, &value, &error); + if (error) { + return; + } + + policy->fw_major = value; +} + +static void +qsev_policy_get_fw_minor(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + QSevPolicyInfo *policy = QSEV_POLICY_INFO(obj); + uint8_t value = policy->fw_minor; + + visit_type_uint8(v, name, &value, errp); +} + +static void +qsev_policy_set_fw_minor(Object *obj, Visitor *v, + const char *name, void *opaque, + Error **errp) +{ + QSevPolicyInfo *policy = QSEV_POLICY_INFO(obj); + Error *error = NULL; + uint8_t value; + + visit_type_uint8(v, name, &value, &error); + if (error) { + return; + } + + policy->fw_minor = value; +} + +static void +qsev_policy_class_init(ObjectClass *oc, void *data) +{ + object_class_property_add_bool(oc, "debug", + qsev_policy_get_debug, + qsev_policy_set_debug, + NULL); + object_class_property_set_description(oc, "debug", + "Set on/off if debugging is allowed on this guest", + NULL); + + object_class_property_add_bool(oc, "ks", + qsev_policy_get_ks, + qsev_policy_set_ks, + NULL); + object_class_property_set_description(oc, "ks", + "Set on/off if guest is allowed to share key with others.", + NULL); + + object_class_property_add_bool(oc, "nosend", + qsev_policy_get_nosend, + qsev_policy_set_nosend, + NULL); + object_class_property_set_description(oc, "nosend", + "Set on/off if sending guest to anoter platform is allowed", + NULL); + + object_class_property_add_bool(oc, "domain", + qsev_policy_get_domain, + qsev_policy_set_domain, + NULL); + object_class_property_set_description(oc, "domain", + "Set on/off if guest should not be transmitted to another platform that is not in the same domain.", + NULL); + + object_class_property_add_bool(oc, "sev", + qsev_policy_get_sev, + qsev_policy_set_sev, + NULL); + object_class_property_set_description(oc, "domain", + "Set on/off if guest should not be transmitted to another non SEV platform", + NULL); + + object_class_property_add(oc, "fw_major", "uint8", + qsev_policy_get_fw_major, + qsev_policy_set_fw_major, + NULL, NULL, NULL); + object_class_property_set_description(oc, "fw_major", + "guest must not be transmitted to another platform with a lower firmware version", + NULL); + object_class_property_add(oc, "fw_minor", "uint8", + qsev_policy_get_fw_minor, + qsev_policy_set_fw_minor, + NULL, NULL, NULL); + object_class_property_set_description(oc, "fw_minor", + "guest must not be transmitted to another platform with a lower firmware version", + NULL); +} + +static void +qsev_policy_finalize(Object *obj) +{ +} + +static QSevPolicyInfo * +lookup_sev_policy_info(const char *id) +{ + QSevPolicyInfo *policy; + Object *obj = get_object_by_id(id); + + if (!obj) { + return NULL; + } + + policy = (QSevPolicyInfo *) + object_dynamic_cast(obj, + TYPE_QSEV_POLICY_INFO); + if (!policy) { + return NULL; + } + + return policy; +} + +static uint32_t +sev_policy_get_value(const char *id) +{ + uint32_t val = 0; + QSevPolicyInfo *policy = lookup_sev_policy_info(id); + + if (!policy) { + return 0; + } + + val = policy->debug; + val |= policy->ks << 1; + val |= (1 << 2); + val |= policy->nosend << 3; + val |= policy->domain << 4; + val |= policy->sev << 5; + val |= policy->fw_major << 16; + val |= policy->fw_minor << 24; + + return val; +} + +/* qsev policy */ +static const TypeInfo qsev_policy_info = { + .parent = TYPE_OBJECT, + .name = TYPE_QSEV_POLICY_INFO, + .instance_size = sizeof(QSevPolicyInfo), + .instance_finalize = qsev_policy_finalize, + .class_size = sizeof(QSevPolicyInfoClass), + .class_init = qsev_policy_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + +static char * +qsev_guest_get_launch_id(Object *obj, Error **errp) +{ + QSevGuestInfo *sev_info = QSEV_GUEST_INFO(obj); + + return g_strdup(sev_info->launch); +} + +static void +qsev_guest_set_launch_id(Object *obj, const char *value, Error **errp) +{ + QSevGuestInfo *sev_info = QSEV_GUEST_INFO(obj); + + sev_info->launch = g_strdup(value); +} + +static char * +qsev_guest_get_send_id(Object *obj, Error **errp) +{ + QSevGuestInfo *sev_info = QSEV_GUEST_INFO(obj); + + return g_strdup(sev_info->send); +} + +static void +qsev_guest_set_send_id(Object *obj, const char *value, Error **errp) +{ + QSevGuestInfo *sev_info = QSEV_GUEST_INFO(obj); + + sev_info->send = g_strdup(value); +} + +static void +qsev_guest_finalize(Object *obj) +{ + QSevGuestInfo *sev_info = QSEV_GUEST_INFO(obj); + + g_free(sev_info->launch); + g_free(sev_info->send); +} + +static void +qsev_guest_class_init(ObjectClass *oc, void *data) +{ + object_class_property_add_str(oc, "launch", + qsev_guest_get_launch_id, + qsev_guest_set_launch_id, + NULL); + object_class_property_set_description(oc, "launch", + "Set the launch object id to use", NULL); + object_class_property_add_str(oc, "send", + qsev_guest_get_send_id, + qsev_guest_set_send_id, + NULL); + object_class_property_set_description(oc, "send", + "Set the send object id to use when migrating the guest", NULL); +} + +static QSevGuestInfo * +lookup_sev_guest_info(const char *id) +{ + Object *obj; + QSevGuestInfo *info; + + obj = object_resolve_path_component( + object_get_objects_root(), id); + if (!obj) { + return NULL; + } + + info = (QSevGuestInfo *) + object_dynamic_cast(obj, TYPE_QSEV_GUEST_INFO); + if (!info) { + return NULL; + } + + return info; +} + +static uint8_t +sev_guest_info_get_mode(const char *id) +{ + uint8_t ret = SEV_LAUNCH_INVALID; + Object *obj; + + obj = get_object_by_id(id); + if (object_dynamic_cast(obj, TYPE_QSEV_LAUNCH_INFO)) { + ret = SEV_LAUNCH_UNENCRYPTED; + } else if (object_dynamic_cast(obj, TYPE_QSEV_RECEIVE_INFO)) { + ret = SEV_LAUNCH_ENCRYPTED; + } + + return ret; +} + +/* sev guest info */ +static const TypeInfo qsev_guest_info = { + .parent = TYPE_OBJECT, + .name = TYPE_QSEV_GUEST_INFO, + .instance_size = sizeof(QSevGuestInfo), + .instance_finalize = qsev_guest_finalize, + .class_size = sizeof(QSevGuestInfoClass), + .class_init = qsev_guest_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + +static void +qsev_launch_finalize(Object *obj) +{ +} + +static char * +qsev_launch_get_policy_id(Object *obj, Error **errp) +{ + QSevLaunchInfo *sev_info = QSEV_LAUNCH_INFO(obj); + + return g_strdup(sev_info->policy_id); +} + +static void +qsev_launch_set_policy_id(Object *obj, const char *value, Error **errp) +{ + QSevLaunchInfo *sev_info = QSEV_LAUNCH_INFO(obj); + + sev_info->policy_id = g_strdup(value); +} + +static bool +qsev_launch_get_flags_ks(Object *obj, Error **errp) +{ + QSevLaunchInfo *launch = QSEV_LAUNCH_INFO(obj); + + return launch->flags_ks; +} + +static void +qsev_launch_set_flags_ks(Object *obj, bool value, Error **errp) +{ + QSevLaunchInfo *launch = QSEV_LAUNCH_INFO(obj); + + launch->flags_ks = value; +} + +static char * +qsev_launch_get_nonce(Object *obj, Error **errp) +{ + char *value, *str; + QSevLaunchInfo *launch = QSEV_LAUNCH_INFO(obj); + + str = uint8_ptr_to_str(launch->nonce, sizeof(launch->nonce)); + value = g_strdup(str); + g_free(str); + + return value; +} + +static void +qsev_launch_set_nonce(Object *obj, const char *value, Error **errp) +{ + QSevLaunchInfo *launch = QSEV_LAUNCH_INFO(obj); + + str_to_uint8_ptr(value, launch->nonce, sizeof(launch->nonce)); +} + +static char * +qsev_launch_get_dh_pub_qx(Object *obj, Error **errp) +{ + char *value, *str; + QSevLaunchInfo *launch = QSEV_LAUNCH_INFO(obj); + + str = uint8_ptr_to_str(launch->dh_pub_qx, sizeof(launch->dh_pub_qx)); + value = g_strdup(str); + g_free(str); + + return value; +} + +static void +qsev_launch_set_dh_pub_qx(Object *obj, const char *value, Error **errp) +{ + QSevLaunchInfo *launch = QSEV_LAUNCH_INFO(obj); + + str_to_uint8_ptr(value, launch->dh_pub_qx, + sizeof(launch->dh_pub_qx)); +} + +static char * +qsev_launch_get_dh_pub_qy(Object *obj, Error **errp) +{ + char *value, *str; + QSevLaunchInfo *launch = QSEV_LAUNCH_INFO(obj); + + str = uint8_ptr_to_str(launch->dh_pub_qy, sizeof(launch->dh_pub_qy)); + value = g_strdup(str); + g_free(str); + + return value; +} + +static void +qsev_launch_set_dh_pub_qy(Object *obj, const char *value, Error **errp) +{ + QSevLaunchInfo *launch = QSEV_LAUNCH_INFO(obj); + + str_to_uint8_ptr(value, launch->dh_pub_qy, + sizeof(launch->dh_pub_qy)); +} + +static void +qsev_launch_class_init(ObjectClass *oc, void *data) +{ + object_class_property_add_bool(oc, "flags.ks", + qsev_launch_get_flags_ks, + qsev_launch_set_flags_ks, + NULL); + object_class_property_set_description(oc, "flags.ks", + "Set on/off if key sharing with other guests is allowed", + NULL); + + object_class_property_add_str(oc, "policy", + qsev_launch_get_policy_id, + qsev_launch_set_policy_id, + NULL); + object_class_property_set_description(oc, "policy", + "Set the guest owner's sev-policy id", NULL); + + object_class_property_add_str(oc, "nonce", + qsev_launch_get_nonce, + qsev_launch_set_nonce, + NULL); + object_class_property_set_description(oc, "nonce", + "a nonce provided by guest owner", NULL); + + object_class_property_add_str(oc, "dh-pub-qx", + qsev_launch_get_dh_pub_qx, + qsev_launch_set_dh_pub_qx, + NULL); + object_class_property_set_description(oc, "dh-pub-qx", + "Qx parameter of owner's ECDH public key", NULL); + + object_class_property_add_str(oc, "dh-pub-qy", + qsev_launch_get_dh_pub_qy, + qsev_launch_set_dh_pub_qy, + NULL); + object_class_property_set_description(oc, "dh-pub-qy", + "Qy parameter of owner's ECDH public key", NULL); +} + +static uint8_t +sev_launch_info_get_flags(QSevLaunchInfo *launch) +{ + uint8_t flags = launch->flags_ks; + + return flags; +} + +static QSevLaunchInfo * +lookup_sev_launch_info(const char *id) +{ + Object *obj; + QSevLaunchInfo *info; + + obj = object_resolve_path_component( + object_get_objects_root(), id); + if (!obj) { + return NULL; + } + + info = (QSevLaunchInfo *) + object_dynamic_cast(obj, TYPE_QSEV_LAUNCH_INFO); + if (!info) { + return NULL; + } + + return info; +} + +static int +sev_launch_info_get_params(const char *id, + struct kvm_sev_launch_start **s, + struct kvm_sev_launch_update **u, + struct kvm_sev_launch_finish **f) +{ + QSevLaunchInfo *info; + struct kvm_sev_launch_start *start; + struct kvm_sev_launch_finish *finish; + + info = lookup_sev_launch_info(id); + if (!info) { + return -1; + } + + start = g_malloc0(sizeof(*start)); + start->flags = sev_launch_info_get_flags(info); + start->policy = sev_policy_get_value(info->policy_id); + memcpy(start->nonce, info->nonce, sizeof(info->nonce)); + memcpy(start->dh_pub_qx, info->dh_pub_qx, sizeof(info->dh_pub_qx)); + memcpy(start->dh_pub_qy, info->dh_pub_qy, sizeof(info->dh_pub_qy)); + + finish = g_malloc0(sizeof(*finish)); + + DPRINTF("sev-launch\n"); + DPRINTF(" flags: %#x\n", start->flags); + DPRINTF(" policy: %#x\n", start->policy); + DPRINTF_U8_PTR(" dh_pub_qx", start->dh_pub_qx, sizeof(start->dh_pub_qx)); + DPRINTF_U8_PTR(" dh_pub_qy", start->dh_pub_qy, sizeof(start->dh_pub_qy)); + DPRINTF_U8_PTR(" nonce", start->nonce, sizeof(start->nonce)); + + *s = start; + *u = g_malloc(sizeof(struct kvm_sev_launch_update)); + *f = finish; + + return 0; +} + +/* unencrypted guest launch */ +static const TypeInfo qsev_launch_info = { + .parent = TYPE_OBJECT, + .name = TYPE_QSEV_LAUNCH_INFO, + .instance_size = sizeof(QSevLaunchInfo), + .instance_finalize = qsev_launch_finalize, + .class_size = sizeof(QSevLaunchInfoClass), + .class_init = qsev_launch_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + +static void +qsev_receive_finalize(Object *obj) +{ +} + +static char * +qsev_receive_get_policy_id(Object *obj, Error **errp) +{ + QSevReceiveInfo *sev_info = QSEV_RECEIVE_INFO(obj); + + return g_strdup(sev_info->policy_id); +} + +static void +qsev_receive_set_policy_id(Object *obj, const char *value, Error **errp) +{ + QSevReceiveInfo *sev_info = QSEV_RECEIVE_INFO(obj); + + sev_info->policy_id = g_strdup(value); +} + +static bool +qsev_receive_get_flags_ks(Object *obj, Error **errp) +{ + QSevReceiveInfo *receive = QSEV_RECEIVE_INFO(obj); + + return receive->flags_ks; +} + +static void +qsev_receive_set_flags_ks(Object *obj, bool value, Error **errp) +{ + QSevReceiveInfo *receive = QSEV_RECEIVE_INFO(obj); + + receive->flags_ks = value; +} + +static char * +qsev_receive_get_nonce(Object *obj, Error **errp) +{ + char *value, *str; + QSevReceiveInfo *receive = QSEV_RECEIVE_INFO(obj); + + str = uint8_ptr_to_str(receive->nonce, sizeof(receive->nonce)); + value = g_strdup(str); + g_free(str); + + return value; +} + +static void +qsev_receive_set_nonce(Object *obj, const char *value, Error **errp) +{ + QSevReceiveInfo *receive = QSEV_RECEIVE_INFO(obj); + + str_to_uint8_ptr(value, receive->nonce, sizeof(receive->nonce)); +} + +static char * +qsev_receive_get_dh_pub_qx(Object *obj, Error **errp) +{ + char *value, *str; + QSevReceiveInfo *receive = QSEV_RECEIVE_INFO(obj); + + str = uint8_ptr_to_str(receive->dh_pub_qx, sizeof(receive->dh_pub_qx)); + value = g_strdup(str); + g_free(str); + + return value; +} + +static void +qsev_receive_set_dh_pub_qx(Object *obj, const char *value, Error **errp) +{ + QSevReceiveInfo *receive = QSEV_RECEIVE_INFO(obj); + + str_to_uint8_ptr(value, receive->dh_pub_qx, + sizeof(receive->dh_pub_qx)); +} + +static char * +qsev_receive_get_dh_pub_qy(Object *obj, Error **errp) +{ + char *value, *str; + QSevReceiveInfo *receive = QSEV_RECEIVE_INFO(obj); + + str = uint8_ptr_to_str(receive->dh_pub_qy, sizeof(receive->dh_pub_qy)); + value = g_strdup(str); + g_free(str); + + return value; +} + +static void +qsev_receive_set_dh_pub_qy(Object *obj, const char *value, Error **errp) +{ + QSevReceiveInfo *receive = QSEV_RECEIVE_INFO(obj); + + str_to_uint8_ptr(value, receive->dh_pub_qy, + sizeof(receive->dh_pub_qy)); +} + +static char * +qsev_receive_get_ten(Object *obj, Error **errp) +{ + char *value, *str; + QSevReceiveInfo *receive = QSEV_RECEIVE_INFO(obj); + + str = uint8_ptr_to_str(receive->ten, sizeof(receive->ten)); + value = g_strdup(str); + g_free(str); + + return value; +} + +static void +qsev_receive_set_ten(Object *obj, const char *value, Error **errp) +{ + QSevReceiveInfo *receive = QSEV_RECEIVE_INFO(obj); + + str_to_uint8_ptr(value, receive->ten, + sizeof(receive->ten)); +} + +static char * +qsev_receive_get_wrapped_tik(Object *obj, Error **errp) +{ + char *value, *str; + QSevReceiveInfo *receive = QSEV_RECEIVE_INFO(obj); + + str = uint8_ptr_to_str(receive->wrapped_tik, sizeof(receive->wrapped_tik)); + value = g_strdup(str); + g_free(str); + + return value; +} + +static void +qsev_receive_set_wrapped_tik(Object *obj, const char *value, Error **errp) +{ + QSevReceiveInfo *receive = QSEV_RECEIVE_INFO(obj); + + str_to_uint8_ptr(value, receive->wrapped_tik, + sizeof(receive->wrapped_tik)); +} + +static char * +qsev_receive_get_wrapped_tek(Object *obj, Error **errp) +{ + char *value, *str; + QSevReceiveInfo *receive = QSEV_RECEIVE_INFO(obj); + + str = uint8_ptr_to_str(receive->wrapped_tek, sizeof(receive->wrapped_tek)); + value = g_strdup(str); + g_free(str); + + return value; +} + +static void +qsev_receive_set_wrapped_tek(Object *obj, const char *value, Error **errp) +{ + QSevReceiveInfo *receive = QSEV_RECEIVE_INFO(obj); + + str_to_uint8_ptr(value, receive->wrapped_tek, + sizeof(receive->wrapped_tek)); +} + +static void +qsev_receive_class_init(ObjectClass *oc, void *data) +{ + object_class_property_add_bool(oc, "flags.ks", + qsev_receive_get_flags_ks, + qsev_receive_set_flags_ks, + NULL); + object_class_property_set_description(oc, "flags.ks", + "Set on/off if key sharing with other guests is allowed", + NULL); + + object_class_property_add_str(oc, "policy", + qsev_receive_get_policy_id, + qsev_receive_set_policy_id, + NULL); + object_class_property_set_description(oc, "policy", + "Set the guest origin sev-policy id", NULL); + + object_class_property_add_str(oc, "nonce", + qsev_receive_get_nonce, + qsev_receive_set_nonce, + NULL); + object_class_property_set_description(oc, "nonce", + "a nonce provided by origin", NULL); + + object_class_property_add_str(oc, "dh-pub-qx", + qsev_receive_get_dh_pub_qx, + qsev_receive_set_dh_pub_qx, + NULL); + object_class_property_set_description(oc, "dh-pub-qx", + "Qx parameter of origin ECDH public key", NULL); + + object_class_property_add_str(oc, "dh-pub-qy", + qsev_receive_get_dh_pub_qy, + qsev_receive_set_dh_pub_qy, + NULL); + object_class_property_set_description(oc, "dh-pub-qy", + "Qy parameter of origin ECDH public key", NULL); + + object_class_property_add_str(oc, "ten", + qsev_receive_get_ten, + qsev_receive_set_ten, + NULL); + object_class_property_set_description(oc, "ten", + "Set transport encryption nonce", NULL); + + object_class_property_add_str(oc, "wrapped-tik", + qsev_receive_get_wrapped_tik, + qsev_receive_set_wrapped_tik, + NULL); + object_class_property_set_description(oc, "wrapped-tik", + "The wrapped transport identity key", NULL); + + object_class_property_add_str(oc, "wrapped-tek", + qsev_receive_get_wrapped_tek, + qsev_receive_set_wrapped_tek, + NULL); + object_class_property_set_description(oc, "wrapped-tek", + "The wrapped transport encryption key", NULL); +} + +/* pre-encrypted guest launch */ +static const TypeInfo qsev_receive_info = { + .parent = TYPE_OBJECT, + .name = TYPE_QSEV_RECEIVE_INFO, + .instance_size = sizeof(QSevReceiveInfo), + .instance_finalize = qsev_receive_finalize, + .class_size = sizeof(QSevReceiveInfoClass), + .class_init = qsev_receive_class_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + +static int +sev_launch_start(SEVState *s) +{ + int ret; + + ret = sev_launch_info_get_params(s->launch_id, &s->launch_start, + &s->launch_update, &s->launch_finish); + if (ret < 0) { + return -1; + } + + // add the command to launch guest in next patches + return 0; +} + +static int +sev_launch_finish(SEVState *s) +{ + // add the command to finalize the launch in next patches + return 0; +} + +/** + * Function returns 'true' if id is a valid QSevGuestInfo object. + */ +bool +has_sev_guest_policy(const char *id) +{ + return lookup_sev_guest_info(id) ? true : false; +} + +void * +sev_guest_init(const char *id) +{ + int ret; + SEVState *s; + QSevGuestInfo *sev_info; + + s = g_malloc0(sizeof(SEVState)); + if (!s) { + return NULL; + } + + sev_info = lookup_sev_guest_info(id); + if (!sev_info) { + fprintf(stderr, "'%s' not a valid '%s' object\n", + id, TYPE_QSEV_GUEST_INFO); + goto err; + } + + s->mode = sev_guest_info_get_mode(sev_info->launch); + if (s->mode == SEV_LAUNCH_INVALID) { + fprintf(stderr, "'%s' invalid sev launch id\n", sev_info->launch); + goto err; + } + + s->sev_info_id = g_strdup(id); + s->launch_id = g_strdup(sev_info->launch); + + /* now launch the guest */ + ret = sev_guest_launch_start(s); + if (ret < 0) { + goto err; + } + + sev_allowed = true; + return s; +err: + g_free(s); + + return NULL; +} + +int +sev_guest_launch_start(void *handle) +{ + SEVState *s = (SEVState *)handle; + + if (s->state == SEV_STATE_RUNNING) { + return 0; + } + + if (s->mode == SEV_LAUNCH_UNENCRYPTED) { + return sev_launch_start(s); + } else if (s->mode == SEV_LAUNCH_ENCRYPTED) { + // use receive_info commands + } + + return -1; +} + +int +sev_guest_launch_finish(void *handle) +{ + SEVState *s = (SEVState *)handle; + + if (s->state == SEV_STATE_RUNNING) { + return 0; + } + + if (s->state == SEV_STATE_LAUNCHING) { + return sev_launch_finish(s); + // use launch_finish commands + } else if (s->state == SEV_STATE_RECEIVING) { + // use receive_finish commands + } else { + return -1; + } + + return -1; +} + +static int +sev_mem_write(uint8_t *dst, const uint8_t *src, uint32_t len, MemTxAttrs attrs) +{ + SEVState *s = kvm_memory_encryption_get_handle(); + + assert(s != NULL); + + // fill in the code in next patches + return 0; +} + +static int +sev_mem_read(uint8_t *dst, const uint8_t *src, uint32_t len, MemTxAttrs attrs) +{ + SEVState *s = kvm_memory_encryption_get_handle(); + + assert(s != NULL); + + // fill in the code in next patches + return 0; +} + +void +sev_guest_set_ops(void *handle, MemoryRegion *mr) +{ + SEVState *s = (SEVState *)handle; + + assert(s != NULL); + + sev_ops.read = sev_mem_read; + sev_ops.write = sev_mem_write; + + memory_region_set_ram_ops(mr, &sev_ops); +} + +bool +sev_enabled(void) +{ + return sev_allowed; +} + +static void +sev_policy_register_types(void) +{ + type_register_static(&qsev_guest_info); + type_register_static(&qsev_policy_info); + type_register_static(&qsev_launch_info); + type_register_static(&qsev_receive_info); +} + +type_init(sev_policy_register_types);