From patchwork Tue Nov 1 15:53:00 2016 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Brijesh Singh X-Patchwork-Id: 9407569 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 D254760585 for ; Tue, 1 Nov 2016 16:01:53 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id C258129A5B for ; Tue, 1 Nov 2016 16:01:53 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id B6A7F29A61; Tue, 1 Nov 2016 16:01:53 +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 181CC29A5B for ; Tue, 1 Nov 2016 16:01:52 +0000 (UTC) Received: from localhost ([::1]:48886 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1c1bVX-0003UP-Ar for patchwork-qemu-devel@patchwork.kernel.org; Tue, 01 Nov 2016 12:01:51 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:57283) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1c1bND-0005CQ-AC for qemu-devel@nongnu.org; Tue, 01 Nov 2016 11:53:18 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1c1bN8-0003j1-Rl for qemu-devel@nongnu.org; Tue, 01 Nov 2016 11:53:15 -0400 Received: from mail-sn1nam02on0058.outbound.protection.outlook.com ([104.47.36.58]:43456 helo=NAM02-SN1-obe.outbound.protection.outlook.com) by eggs.gnu.org with esmtps (TLS1.0:RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1c1bN8-0003iu-IQ for qemu-devel@nongnu.org; Tue, 01 Nov 2016 11:53:10 -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=rM+J5MXxgOd5pZxPshjv0YTdsn2nYaEe96imhoGDazY=; b=s0H5pJeJrZ2gu/X2RkBoGb4B5EZ+rfMvYf+tnASpsivLI09Nfkp36HB6IS+xLVTG6UCmtW2NxrKr5NL3vX6i7+KND8ONJEp9f9oToCd0/YXPwFHSo3HkaooAaGsGXMPJPBXgo0iGpASl0f1xxaQ+0BWXzCZgz/OAYX6qc+AleoI= Authentication-Results: spf=none (sender IP is ) smtp.mailfrom=brijesh.singh@amd.com; Received: from [127.0.1.1] (165.204.77.1) by BY2PR12MB0661.namprd12.prod.outlook.com (10.163.113.150) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384_P384) id 15.1.693.12; Tue, 1 Nov 2016 15:53:05 +0000 From: Brijesh Singh To: , , , , , , , , , Date: Tue, 1 Nov 2016 11:53:00 -0400 Message-ID: <147801558020.18237.18202763050547452134.stgit@brijesh-build-machine> In-Reply-To: <147801550845.18237.12915616525154608660.stgit@brijesh-build-machine> References: <147801550845.18237.12915616525154608660.stgit@brijesh-build-machine> User-Agent: StGit/0.17.1-dirty MIME-Version: 1.0 X-Originating-IP: [165.204.77.1] X-ClientProxiedBy: BN6PR17CA0038.namprd17.prod.outlook.com (10.175.189.24) To BY2PR12MB0661.namprd12.prod.outlook.com (10.163.113.150) X-MS-Office365-Filtering-Correlation-Id: 745d03c0-bc12-448f-25ec-08d4026f2c15 X-Microsoft-Exchange-Diagnostics: 1; BY2PR12MB0661; 2:9FgOBpzSJnQAr0tvgK/sOl6Mw/WrpC9ve6iaY8L7DeaV3PpODunUeM9BaBojFzcPzoxfN/8Ya9CuxgKFfHzL9Wiex1HFkujQI2Sh4s0TWr8wvir4DGbaS2St03ZQSury8BxFa8wb7LiLOpK0x9qbArE8lJbnz/D1GHb6RE77RewGMosLvCv71B/Edss3oM0/Ui3/5tCvyplm9RAyeFU99w==; 3:qb8Lywjfm038nZbkJ9keH2VT1nhX6ddLZPSGWU2PK/Nurz7vqZtWla6YPu7u6d5otaVbodEYSrUozz9AJ7LSjjaRln4kOzp4gDfWmi/XLCP0EKYpdWeKdAx/I13LTPcGUaGuDJhFuftCJg9fdaVExQ== X-Microsoft-Antispam: UriScan:;BCL:0;PCL:0;RULEID:;SRVR:BY2PR12MB0661; X-Microsoft-Exchange-Diagnostics: 1; BY2PR12MB0661; 25:TzXg8RcVwnzG5R2UDL2t/9jVaDJ5wk4/Ctms7CFSXOF2i0CgA4bL1WG4Z60tnshdQytyGghuCE2TfyLwAsgU/DUuzQL5cTx0WQk9w4lS8fZ5U5rqW+AYzkXT8ZEiuKVL8gxUef6gthSS22YqDR7UDiGJdc0C61oiFrwv9J/fZNGdeEUVPGSmlKbx23MJhE55UrAXkRcUZIEb2dI/vXdIb0qh0ngxaRDTxCMZaLbxicpexWwWvsQ+2vIO08F4RLs0J/vMAnn8Z+Y5I4Any13pIcE9ywLBSS0nCBw5A8Kr94rbb1JkH8kHZPgzDEQcaS4RBTZ9r/ohAC4a9P2HnpsdWwIWQ0E8DGTatixNVR2DFTmK8MSDbuAX2B3QOgR/52vDr1GV5s91lkyXZwrLHEEWCZGFYhqvFmH5vrjChTeHudyou3z5dOqBqdK1LMGDRn8m1I1WFq2vCXv6eyZ9RoIlRqK+09k0clcmx+DrgpQMIBshGSaOMbAOqXCLXWNOWrNpfQE6iF5ASKGLS/qJlm5wpCJ3IABzSKhKhseJFLWyuXGea6gCEOkv6GexslhdfMNQLj/drGtqoD7ERK941UcBygz67yxd6CThCQ9hKfFnT3nR+DSgfRjO0ecL1y2E6A9EcMdnn0Hef3jhNcpT/3WYJ+sCMsKx9T8gInnZtuEKKhD5YKpTARgnzh8PjeX2xCSuLdMS/IdkOe6r1+ysf7GtHakrSULBVQbeW5ICPV5+m5Tm75UmLb7KnpqkWqCP7aHhSKEfx1uSHr9LsDFIdWFxOLlUP0IMdhlZ/xlpQFxdplUunEyzh6rd6AdpCdFfs/HepcZILFxU82Bne6T8mlSOrmeyoLXbYNcLvdYWK2e2sYg= X-Microsoft-Exchange-Diagnostics: 1; BY2PR12MB0661; 31:706Q+2uoVknOZbc1uwJ+UdLFZ8c+b7pna0Ud7fMbXKXA7E5zRb4WKo2MnWFfQvmp+pzfXiFlYEGU+Yv/AEW8gmBr0VA6G16M41Gsm7CgpugUmlGzzI2HGQTvtT7fINxlJf2CQeqEcrKgvg9CHNr0Zf0niGAogJaLRkmaylvS6gaCiWpWlLRxKAwqASPrIQiL6qS0PHwttrs04tn5f+Xk3TGamvc4ehvISV0FzPZuvxxFYgxhpoEN8azFh4tSzL8L2pWrUWd1BN3ISPAGzsjpQg==; 20:UpQEhDEi2mesft8fg4OAkagqUfITq34RjgKcBzsizZf13ngoHcpywGiFNQGgCOnRlBVfvr3hK91h6XB20grcm2q/yYmnkWRqqq+D7SCfkoDnU0rBkv70HzJSH3JFYkmeXSnof3dLfC4ABr9ggpPRbqUJ+Cjk8wGLBNmMgs/LyzfGESchCUMRYtFxUuZS/2saaI1FDsObs3nefSS6nCiYvs63ZJD0ocpRihhuhL/lT4hXPb6MawTNKMntFy6E/4UFNjnSbc2i4r5Lb90sK/y5K6RcUajpIgbc+Gxx0a42hWLDxCHrb76UbWah2GaKynCOGgb074i5uPXsd1n6COc9eXrVsYCketliSJ687W9pkLNZKJtlai/PJlB1JAP7Bp2GwGWwXgMAtnGq2hKxBTkbBsZWCPM2QFxg4lhBbYzpx0KhEdjCr2pevZ14qWcj7q9NUDqkBbCorjxUS5LrXy2XuYOroo2BO2EseuY/DAIButpOn+LxPxdvTGDKUUZ+5sCy 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)(10201501046)(3002001)(6055026); SRVR:BY2PR12MB0661; BCL:0; PCL:0; RULEID:; SRVR:BY2PR12MB0661; X-Microsoft-Exchange-Diagnostics: 1; BY2PR12MB0661; 4:5WP/x3wgKEJ1/zCnMrUt3u2dZ6MbZgtuKMQNKEnhr/3mFQssAUIMXDpORuaNsaNwGgy1cpbZl3zfhuShOY6Y1ygu8hsGzXOYjzyQ8vSPbSYUxD+v8SQHH7608raBVXzLMwLOOKIFathXCwmDFuennJ4R1zrng78mfU744TWAybpsQc977pvdeFnEmKnI06ypvKcuocoGEZzeALOAJR62D6qZVJ6NXDtJ5GhFtYV7gJF1f25ELe+aenwjfF81gyQl2EPMwV0zdgRBq6ttNYhI2e08vaCUkfkFpunNsAEuUZ3WfhvWkzBgIbiJWcoYIgWsZsqr5CcWpCdPfwEhkXDC8CAxQmMn7gzqsEDU9lC7WowvOCP5L51wRoDn7XEkNyGN732HsHarGeCbtb+ldqP+JyRkQoBM+ITLYv490fC8b3oluTU2BW4FkydFZqrErJzXG4anVk/h0ZhfKPnrie8mUNvRs7mfiKtDTJCuKal8hjkIB0SAMFX0IGJaoYdGDjhk X-Forefront-PRVS: 01136D2D90 X-Forefront-Antispam-Report: SFV:NSPM; SFS:(10009020)(4630300001)(6049001)(6009001)(7916002)(199003)(15404003)(189002)(229853001)(86362001)(8676002)(2950100002)(19580405001)(19580395003)(5660300001)(81156014)(81166006)(97736004)(105586002)(76176999)(54356999)(33716001)(106356001)(5001770100001)(101416001)(9686002)(68736007)(586003)(3846002)(103116003)(6116002)(23676002)(6666003)(2906002)(4326007)(230700001)(7416002)(2201001)(305945005)(42186005)(7736002)(92566002)(50466002)(33646002)(189998001)(66066001)(47776003)(7846002)(4001350100001)(15975445007)(77096005)(1720100001)(50986999)(83506001)(921003)(1121003)(217873001); DIR:OUT; SFP:1101; SCL:1; SRVR:BY2PR12MB0661; 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?MTtCWTJQUjEyTUIwNjYxOzIzOmhGUzE0RUNETHQzdTBPcG1OS2E1ME9xWElp?= =?utf-8?B?cm9xY3BYTTlzNEl0dHRNNHh3Qk94VnV1VGtZQmt6eWI0QVhGY2ZJaVFnQnlq?= =?utf-8?B?OXU1bmtBY0pLUC9BaEhrc25ub2NNZXYyckc3NG1qTms3c25xZjJWRTdDdUti?= =?utf-8?B?YlY5WThFYlI3UWUyTXlnQzhiN3pzRlEwZFZnZVhDQTRPNGRHZml6NnJnOTJU?= =?utf-8?B?alFnVUVEcndCNTRRc0pYK25MSHEzVWNlNzZBOHJWTDVWODlMVmxid2dNekFs?= =?utf-8?B?S3IyWjV3TzUySmM4dnBxY2N2aEkrV3M1bEdsaFpJOG1XTWFLckZVdEFBS3B3?= =?utf-8?B?dmRUQzlnQ1ZkbjMxZXZXemxuNkxTSEh5Z2N0dFBFc0JLczRjMldQNE1COXpT?= =?utf-8?B?Y21vSmVuSUhlNHBTbHp2ODFPU3Z4SUQxamtUOVpxU003SFIvUUZQVUtuc3Bo?= =?utf-8?B?ck53Tndqblo4UnRXUFY0ZGdaek5mRnFpZnhkdmdLUDFMdEdDYVB2OEZVNDRL?= =?utf-8?B?eFFmTi9qWXpKUmd6WUx3NTgwc2ZKMm5RdXBSbUZVdjVieGppbTRHdUpWWXI5?= =?utf-8?B?N2JnSFEzakZtMnBTU3dXM09HdlJkVFVaYjVBWUNqS3RMYXV4dHcwQ2hCTlFT?= =?utf-8?B?MjdPbWVDclhZNG9PL1R1N2htSHZ4cVgvU3llRXlkSkNyUmh3UzUrVkxUUklT?= =?utf-8?B?WGxIbEVyRUZWaFp2U2dxZ1pJU0k2K1YvK1JxdHRGTGJlclZ5YkxjalZaZTRU?= =?utf-8?B?a2RCRVg4d1BiZHFORmtWVGxkVGlCTDlCTUlhdHF3MmUwUGxzOWJPRkdOZW1J?= =?utf-8?B?MldaWHJGOVFSSUtjZktacHFUNnl3dkFZRCsvTFF1U3JraEk1UG1lWXNkU01V?= =?utf-8?B?aTgxUVp4SXd5RGQ4a0gzbDhFTStxYlJSMzlmOEhGS3BLSVlERExqZ1M0SHha?= =?utf-8?B?b3JsSlZOa1N3OHkybzNXSjdYMCtBTWlqd1lxTWh6VUdaRllYaVNaZlpmUDlQ?= =?utf-8?B?ZmxUUi9selRtUXJNQlpITmgxZHkxUFR4Sm1WeVdVOUlOWWt1d1krMS9Ia1hq?= =?utf-8?B?cUJ6N2o0SHpoNTBJY2lULzJmQ1RTRXJ6OUF3TmNmOVA3U3JBYTluN2hQMlNy?= =?utf-8?B?RTdaM0lTK1RQYjNvZEEyVlFvaTFFTVkxb3V5enQ2RVZKOVRvdnl6TGRpUUp5?= =?utf-8?B?Y3RTTElUYjBFNlpTS245dkEwNzBkLytMdjdBSzlTYjVyV2pFUW1HaTJ1aXBR?= =?utf-8?B?TXBGMnQzRXM1dnJHVTdLNldGKysxSVZvdDhaTS9sZmRQWFpQR0dWRk54MURr?= =?utf-8?B?TUlEK2VuWWpvZWtMUWFXelRUbVEyUC8yTWxmQmQrRS9WQ0k1WTd4WGVackYx?= =?utf-8?B?N0ZHaS80OXJHZVFSSUZrOVQ4RFVxOC82RjErTStzN2N1ZGVSN0NMZUxZMWM0?= =?utf-8?B?azF4U1U4RnpvcEVMSjZZbVA4azRKbk50WUE0T1NYbUJUc0hkODFmb1ZzblNs?= =?utf-8?B?NW52djBGb0dsdGRaQlowYUJsRW9MM3RkSzdxSzE5UkdzdERqVGFaRmVPbndi?= =?utf-8?B?d0Q5SlZmUUdFbUt6bFVHcDNWUEwzVjl3VVlJakZwT1lTTDRONDF4MWRPdUkv?= =?utf-8?B?SVkwTERIL285Y1FMcklTK1F1Q0Q0OVN6M1prUGZFbzM4MEE3amZaSHNLMCsz?= =?utf-8?B?TlB1TWhKaWJCazZFVWdDTmhJZ254RmV5SmZ4cklPU2VUdnBVMzJJL092ZjlN?= =?utf-8?B?b3ZUS2thcFVFOEswN2wwQldEOFdBa1pvcDlydW5BMVg5K3NyVldoRTBPVFd0?= =?utf-8?B?cjQzcndrNWhGWFN0aGM3Ym56bDhZcUI3Yjc2dWZpaC9YN2lpRnVvd1ZjNmZH?= =?utf-8?Q?J/NMFOXJM2U=3D?= X-Microsoft-Exchange-Diagnostics: 1; BY2PR12MB0661; 6:lp/8jFG52zFSY/AZSmLxsP/GtO2uExwjX5YIqQHpSNrk+c8tB7nkwzFFFnHUC7XFifHjWTYH16Xei6w0yL862rhfDa8IGp7kotfYJjwKR5f7o0C3O15s7K9j0Z0GsQM7jv48vtpXIK/4BIH48pG+sVd0QaR7m6JF3wUGo/60EvhurWWSNgEajVOiMuQGRq90qNiiGjCLglJLg0ry9kXfcHrRZ+sBH+5iJh/y1vRjvX+yVRkAHVrzjpFZLvc3eV6cxys+Xi+l5qjreCbuwlVqIMkx9R6CYyXCdZNeRBNvDXK07TMaSPvj5TB8hD+6pvTMKZIjcaBAZg1tVd41zPTxyjjHrdTKc86ggHGOwhFSyAU=; 5:ZO+zvwcp1KyFO8UPvtHGDom1TaCM3Ae8fuEmRrrESJTVD+4vrTuahDdEG14Pzurvf8rd9AfAGfGjN+jywkkl6z5rB7+754xDkFgbOgG2RtKo4UGUN5dT/qObVwd9fghTl08yIMoOx0aSEmt7tSur8w==; 24:RvleJ/VNstPx9CcwmxtTET2r6EqkWO0hm91N3AXNL4vmNIqPvAgnF1CJ+OiVjESobVdUwuYGsBWnsHBMt6KoVhUkLGeO35LlIKfYkx4GYPg= SpamDiagnosticOutput: 1:99 SpamDiagnosticMetadata: NSPM X-Microsoft-Exchange-Diagnostics: 1; BY2PR12MB0661; 7:FwLDx04N+gr9UP6SU21c41B4k0m5WFF+fXu2+8spyUQsq9kZtN3zLRN4NF5wJb/xufNFmNcbBKQrKyvWi6uq/HZEmPtUGbNZcQKqWyLmjo5enwrFQOb3LFFkkHhqXcDl9IHVkKhzyk9c0VV+aFiXs7OJ3eqZKIYuuA2cc3AlSenJ7qIyv1u5kMS77j8Q4LmVeLPGn2XEaswc0EksH53NmrbS5AIxRVvbSlgdwh0Y05MeBJm45S4EasNGiAW+7TBds2DD6+NYdvSxNkMv5k3fEyFhjDHZymL9D9KP+Il6XJFGtLt1uEy8UX9VNxagVCUoT0PGaPzbfLFH9NruDTtD7JVG84Pb56NZw5lDc2xpPqI=; 20:Dd1R4orj5dmTOwt1CuIOSY1+mTD/1KzxRo4E8u3a523Jr6E/istDfxG/urjVPUU+TYhu4zllPoXRJhfXceJBWuEazoXmvXm4ynKHfSBSwbwpM88PtuKdpwvylSsiCvBdiLvhATjs9hqSlNPh+uVDgW+ooEuWVxshXbLqSrUn3477Y6lGMrM2L2f7wLS9mKzPBZiVdZvB/H3kdWYupNVEIs6PIikmzAD8QFI1M/3Smj2r2TxtN6zTO2K00opwULKS X-OriginatorOrg: amd.com X-MS-Exchange-CrossTenant-OriginalArrivalTime: 01 Nov 2016 15:53:05.5449 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-Transport-CrossTenantHeadersStamped: BY2PR12MB0661 X-detected-operating-system: by eggs.gnu.org: Windows 7 or 8 [fuzzy] X-Received-From: 104.47.36.58 Subject: [Qemu-devel] [RFC PATCH v3 07/18] 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: , Cc: brijesh.ksingh@gmail.com 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: - sev-launch-info: provides the properties to set/get parameters used to boot SEV guest from unencrypted boot images. 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 owners PDH key provided through this object. - sev-guest: a top level object to transition a guest into SEV-enabled e.g to launch SEV guest from unencrypted boot images # $QEMU \ -object sev-launch-info,id=launch0,nonce=abcd,pub-dh-qx=1234 \ -object sev-guest,id,sev0 \ -object security-policy,id=secure0,memory-encryption=sev0 \ -machine ....,security-policy=secure0 Signed-off-by: Brijesh Singh --- Makefile.target | 2 docs/amd-memory-encryption.txt | 153 +++++++++++++++++ include/sysemu/sev.h | 112 +++++++++++++ kvm-all.c | 26 +++ qemu-options.hx | 34 ++++ sev.c | 350 ++++++++++++++++++++++++++++++++++++++++ 6 files changed, 676 insertions(+), 1 deletion(-) 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 7a5080e..004c3cd 100644 --- a/Makefile.target +++ b/Makefile.target @@ -137,7 +137,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..682f8e9 --- /dev/null +++ b/docs/amd-memory-encryption.txt @@ -0,0 +1,153 @@ +Secure Encrypted Virtualization (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 Secure +Processor firmware which exposes commands for these tasks. + +At highest level the SEV key management APIs are divided into two sections: + +* Platform management commands +* Guest management commands + +In this doc we will focus on Guest management commands. + +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 deployment of SEV guest: the guest owner and +the platform owner. For example, in a cloud environment, the platform owner +would be cloud vendor and the guest owner would be the user that wishes to run +their workload in the cloud. + +1. Guest Management Commands +----------------------------- + +The guest management commands provide the support for common guest lifecycle +events. These events include launching, running, snapshotting, migrating and +decommission guest. The guest management commands are issued through +KVM_SEV_ISSUE_CMD ioctl. + +1.1 Launch + +When a guest is launched, its memory must first be encrypted using guest owners +key before SEV can be enabled in hardware. There are two types of launches: + +1.1.1 unencrypted + +Boot images (such as bios, kernel, initrd) provided by the guest owner to +bootstrap the guest is unencrypted. The firmware provides interfaces to +bootstrap the memory encryption for this purpose: LAUNCH_START, LAUNCH_UPDATE, +and LAUNCH_FINISH. These three commands together generate a fresh memory +encryption key for the guest, encrypt guest memory and provide an attestation +of the successful launch. + +LAUNCH_START is called first to create a guest context within the firmware. +To create this context, qemu user must provide guest's security policy, guest +owners public Diffie-Hellman key (P-256 defined in section D.1.2.3 of +[FIPS 186-4]) and nonce. The guest security policy is a 4-byte data structure +containing several flags that restrict what the hypervisor can do on the running +SEV guest. The guest security policy should be provided by the guest owner, any +changes in policy by hypervisor would result in the wrong measurement. The policy +is applied to the lifetime of the guest. Guest owners public diffie-hellman (pdh) +key is used to establish a cryptographic session with the guest owner to +negotiate keys used for attestation. If the hypervisor requests this guest to +share key with another SEV guest then hypervisor must set 'key-sharing' and +'handle' in LAUNCH_START command. The key sharing is permitted only if guest +policy allows it. + +LAUNCH_UPDATE encrypts the memory region using the cryptographic context created +via LAUNCH_START command. If required this command can be called multiple times +to encrypt different memory regions. The command also calculates the measurement +of the memory contents as it encrypts. + +LAUNCH_FINISH command finalizes the guest launch and generates measurement. +This measurement is a signature of the memory contents that can be sent to the +guest owner as an attestation that the memory was encrypted correctly by the +firmware. The guest owner may wait to provide the guest confidential information +until it can verify the attestation measurement. Since the guest owner knows the +initial contents of the guest at boot, the attestation measurement can be +verified by comparing it to what the guest owner expects. + +SEV support can be enabled via 'memory-encryption' parameters defined in +security-policy object. If memory-encryption is enabled, then hypervisor +uses MemoryRegionReadWriteOps callbacks to access guest memory. + +Before vm_start, rom_reset copies boot images from internal rom to guest memory +as shown below. + + +----------------------+ + | qemu_system_reset | + +----------------------+ + | + | + V + +-----------------------------+ + | rom_reset (loader.c) | + +-----------------------------+ + | | | + +-------------------+ | +-----------------+ + | | | + V V V + +--------------+ +------------------+ +----------------+ + | LAUNCH_START | | memory_rom_write | | LAUNCH_FINISH | + +--------------+ +------------------+ +----------------+ + | + | + V + +------------------+ + | LAUNCH_UPDATE | + +------------------+ + +Input to LAUNCH_START command can be provided through the properties defined in +'sev-launch-info' object. + +e.g to launch SEV guest from unencrypted boot images + +# ${QEMU} \ + -object sev-launch-info,id=launch0,dh-pub-qx=abcd,dh-pub-qy=1234,nonce=1234\ + -object sev-guest,id=sev0\ + -object security-policy,id=mypolicy,memory-encryption=sev0\ + -machine ...,security-policy=mypolicy + +e.g launch this SEV guest using another SEV guest key (key sharing) + +# ${QEMU} \ + -object sev-launch-info,id=launch0,key-sharing=on,handle=1234\ + -object sev-guest,id=sev0\ + -object security-policy,id=mypolicy,memory-encryption=sev0\ + -machine ...,security-policy=mypolicy + +1.1.2 pre-encrypted + +1.2 Snapshot + +1.3 Restore + +1.4 Live Migration + +1.5 Debugging + +Since memory contents of SEV guest is encrypted hence hypervisor access to the +guest memory will get a cipher text. If guest policy allows debugging, then +hypervisor is allowed to access guest memory. Hypervisor can use DEBUG_DECRYPT +command to decrypt guest memory region for debug purposes. Similarly hypervisor +can use DEBUG_ENCRYPT command to write into guest memory. + +2. References +----------------- + +AMD Memory Encryption whitepaper: +http://amd-dev.wpengine.netdna-cdn.com/wordpress/media/2013/12/AMD_Memory_Encryption_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 diff --git a/include/sysemu/sev.h b/include/sysemu/sev.h new file mode 100644 index 0000000..5ca39d1 --- /dev/null +++ b/include/sysemu/sev.h @@ -0,0 +1,112 @@ +/* + * 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_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 a SEV + * guest from unnencrypted boot images. SEV will encrypt the boot images using + * guest owner's key before launching the guest. + * + * # $QEMU -object sev-launch-info,id=launch0,dh-pub-qx=abcd \ + * .... + */ +struct QSevLaunchInfo { + Object parent_obj; + char *nonce; + char *dh_pub_qx; + char *dh_pub_qy; +}; + +struct QSevLaunchInfoClass { + ObjectClass parent_class; +}; + +#define TYPE_QSEV_GUEST_INFO "sev-guest" +#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 is used for creating a SEV guest. + * + * e.g to launch a SEV guest from unencrypted boot images + * + * # $QEMU -object sev-launch-info,id=launch0 \ + * -object sev-guest,id=sev0 \ + * -object security-policy,id=secure0,memory-encryption=sev0 \ + * -machine ...security-policy=secure0 + */ +struct QSevGuestInfo { + Object parent_obj; + + QSevLaunchInfo *launch_info; +}; + +struct QSevGuestInfoClass { + ObjectClass parent_class; +}; + +struct SEVState { + uint8_t state; + QSevGuestInfo *sev_info; +}; + +typedef struct SEVState SEVState; + +enum { + INVALID_TYPE = 0, + USE_LAUNCH_INFO, + USE_RECEIVE_INFO +}; + +enum { + SEV_STATE_INVALID = 0, + SEV_STATE_LAUNCHING, + SEV_STATE_RECEIVING, + SEV_STATE_SENDING, + SEV_STATE_RUNNING +}; + +bool sev_enabled(void); +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_debug_ops(void *handle, MemoryRegion *mr); +int sev_guest_mem_dec(void *handle, uint8_t *dst, + const uint8_t *src, uint32_t len); +int sev_guest_mem_enc(void *handle, uint8_t *dst, + const uint8_t *src, uint32_t len); + +#endif + diff --git a/kvm-all.c b/kvm-all.c index 86c810e..e712b96 100644 --- a/kvm-all.c +++ b/kvm-all.c @@ -37,6 +37,7 @@ #include "trace.h" #include "hw/irq.h" #include "sysemu/security-policy.h" +#include "sysemu/sev.h" #include "hw/boards.h" @@ -1818,6 +1819,31 @@ 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 */ + kvm_state->ehandle = sev_guest_init(id); + if (!kvm_state->ehandle) { + fprintf(stderr, + "failed to initialize 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_debug_ops = sev_guest_set_debug_ops; + kvm_state->mem_encrypt_dec = sev_guest_mem_dec; + kvm_state->mem_encrypt_enc = sev_guest_mem_enc; + 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 7a65015..1c1f93d 100644 --- a/qemu-options.hx +++ b/qemu-options.hx @@ -4048,6 +4048,40 @@ can be set to the unquie ID of memory encryption object. On AMD processor, memory encryption is supported via 'sev-guest' object. +@item -object sev-guest,id=@var{id} + +Create a Secure Encrypted Virtualization (SEV) guest object, which be used to +provide the memory encryption support on AMD processors. + +e.g to launch a SEV guest +@example + # $QEMU \ + -object sev-launch-info,id=launch0 \ + -object sev-guest-info,id=sev0 \ + -object security-policy,id=secure0-guest,memory-encryption=sev0 \ + -machine ...,security-policy=secure0 +@end example + +@item -object sev-launch-info,id=@var{id}[,nonce=@var{string}][,dh-pub-qx=@var{string}][,dh-pub-qy=@var{string}] + +Create a SEV launch info object, which can be used to pass various parameters +required to boot SEV guest from unencrypted boot images. +The id parameter is a unique ID that should be used in sev-guest-info object +when creating a unencrypted SEV guest. + +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. + +e.g to launch SEV guest from unencrypted boot images +@example + # $QEMU \ + -object sev-launch-info,id=launch0,nonce=abcd \ + -object sev-guest,id=sev0 \ +@end example + +@end table ETEXI diff --git a/sev.c b/sev.c new file mode 100644 index 0000000..487dba6 --- /dev/null +++ b/sev.c @@ -0,0 +1,350 @@ +/* + * 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 "sysemu/sysemu.h" +#include "trace.h" + +#define DEBUG_SEV +#ifdef DEBUG_SEV +#define DPRINTF(fmt, ...) \ + do { fprintf(stdout, fmt, ## __VA_ARGS__); } while (0) +#else +#define DPRINTF(fmt, ...) \ + do { } while (0) +#endif + +static MemoryRegionRAMReadWriteOps sev_ops; +static bool sev_allowed; + +static void +qsev_guest_finalize(Object *obj) +{ +} + +static void +qsev_guest_class_init(ObjectClass *oc, void *data) +{ +} + +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 void +qsev_guest_init(Object *obj) +{ + QSevGuestInfo *sev = QSEV_GUEST_INFO(obj); + + object_property_add_link(obj, "launch", TYPE_QSEV_LAUNCH_INFO, + (Object **)&sev->launch_info, + object_property_allow_set_link, + OBJ_PROP_LINK_UNREF_ON_RELEASE, NULL); +} + +/* 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, + .instance_init = qsev_guest_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + +static void +qsev_launch_finalize(Object *obj) +{ +} + +static char * +qsev_launch_get_nonce(Object *obj, Error **errp) +{ + QSevLaunchInfo *launch = QSEV_LAUNCH_INFO(obj); + + return g_strdup(launch->nonce); +} + +static void +qsev_launch_set_nonce(Object *obj, const char *value, Error **errp) +{ + QSevLaunchInfo *launch = QSEV_LAUNCH_INFO(obj); + + launch->nonce = g_strdup(value); +} + +static char * +qsev_launch_get_dh_pub_qx(Object *obj, Error **errp) +{ + QSevLaunchInfo *launch = QSEV_LAUNCH_INFO(obj); + + return g_strdup(launch->dh_pub_qx); +} + +static void +qsev_launch_set_dh_pub_qx(Object *obj, const char *value, Error **errp) +{ + QSevLaunchInfo *launch = QSEV_LAUNCH_INFO(obj); + + launch->dh_pub_qx = g_strdup(value); +} + +static char * +qsev_launch_get_dh_pub_qy(Object *obj, Error **errp) +{ + QSevLaunchInfo *launch = QSEV_LAUNCH_INFO(obj); + + return g_strdup(launch->dh_pub_qy); +} + +static void +qsev_launch_set_dh_pub_qy(Object *obj, const char *value, Error **errp) +{ + QSevLaunchInfo *launch = QSEV_LAUNCH_INFO(obj); + + launch->dh_pub_qy = g_strdup(value); +} + +static void +qsev_launch_class_init(ObjectClass *oc, void *data) +{ + 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 void +qsev_launch_init(Object *obj) +{ +} + +/* 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, + .instance_init = qsev_launch_init, + .interfaces = (InterfaceInfo[]) { + { TYPE_USER_CREATABLE }, + { } + } +}; + + +static int +sev_launch_start(SEVState *s) +{ + return 0; +} + +static int +sev_launch_finish(SEVState *s) +{ + return 0; +} + +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 && s->state != SEV_STATE_INVALID); + + 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 && s->state != SEV_STATE_INVALID); + + return 0; +} + +static int +sev_get_launch_type(SEVState *s) +{ + QSevGuestInfo *sev_info = s->sev_info; + + /* if QSevLaunchInfo is set then we are configured to use + * launch_info object. + */ + if (object_property_get_link(OBJECT(sev_info), "launch", &error_abort)) { + return USE_LAUNCH_INFO; + } + + return INVALID_TYPE; +} + +void * +sev_guest_init(const char *id) +{ + Object *obj; + SEVState *s; + + s = g_malloc0(sizeof(SEVState)); + if (!s) { + return NULL; + } + + s->sev_info = lookup_sev_guest_info(id); + if (!s->sev_info) { + fprintf(stderr, "'%s' not a valid '%s' object\n", + id, TYPE_QSEV_GUEST_INFO); + goto err; + } + + obj = object_resolve_path_type("", TYPE_QSEV_LAUNCH_INFO, NULL); + if (obj) { + object_property_set_link(OBJECT(s->sev_info), obj, "launch", + &error_abort); + } + + sev_allowed = true; + return s; +err: + g_free(s); + return NULL; +} + +int +sev_guest_launch_start(void *handle) +{ + SEVState *s = (SEVState *)handle; + + assert(s != NULL); + + /* If we are in prelaunch state then create memory encryption context based + * on the sev launch object created by user. + */ + if (runstate_check(RUN_STATE_PRELAUNCH)) { + if (sev_get_launch_type(s) == USE_LAUNCH_INFO) { + return sev_launch_start(s); + } + } + + return 1; +} + +int +sev_guest_launch_finish(void *handle) +{ + SEVState *s = (SEVState *)handle; + + assert(s != NULL); + + if (s->state == SEV_STATE_LAUNCHING) { + return sev_launch_finish(s); + } + + return 1; +} + +void +sev_guest_set_debug_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_debug_ops(mr, &sev_ops); +} + +int +sev_guest_mem_dec(void *handle, uint8_t *dst, const uint8_t *src, uint32_t len) +{ + SEVState *s = (SEVState *)handle; + + assert(s != NULL && s->state != SEV_STATE_INVALID); + + /* use SEV debug command to decrypt memory */ + return 1; +} + +int +sev_guest_mem_enc(void *handle, uint8_t *dst, const uint8_t *src, uint32_t len) +{ + SEVState *s = (SEVState *)handle; + + assert(s != NULL && s->state != SEV_STATE_INVALID); + + /* use SEV debug command to decrypt memory */ + return 1; +} + +bool +sev_enabled(void) +{ + return sev_allowed; +} + +static void +sev_policy_register_types(void) +{ + type_register_static(&qsev_guest_info); + type_register_static(&qsev_launch_info); +} + +type_init(sev_policy_register_types);