From patchwork Mon Feb 13 11:59:08 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Huang, Kai" X-Patchwork-Id: 13138297 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5C034C636D7 for ; Mon, 13 Feb 2023 12:00:21 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id EDFA76B0074; Mon, 13 Feb 2023 07:00:20 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id E68C86B0075; Mon, 13 Feb 2023 07:00:20 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id CE2B96B0078; Mon, 13 Feb 2023 07:00:20 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0014.hostedemail.com [216.40.44.14]) by kanga.kvack.org (Postfix) with ESMTP id B7CD96B0074 for ; Mon, 13 Feb 2023 07:00:20 -0500 (EST) Received: from smtpin15.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay05.hostedemail.com (Postfix) with ESMTP id 3A77A4175F for ; Mon, 13 Feb 2023 12:00:20 +0000 (UTC) X-FDA: 80462125800.15.6ADE4E2 Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by imf14.hostedemail.com (Postfix) with ESMTP id CB82610002C for ; Mon, 13 Feb 2023 12:00:17 +0000 (UTC) Authentication-Results: imf14.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b="TLEJrUg/"; spf=pass (imf14.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1676289618; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=Ip0oMz2jOEenkcraaNJSgJNrAK3sP+BIFTa74KSFMhQ=; b=S5wFXn/tM4JkguHOdU53xlTWIYl78J1ocRslRp5cSnp7IGQYzeK1UiFf3X5BlEPcYcfQBH 6PRR/aGZJPxFch02jW9qfzhl+sueEOND5ZkR+D1pJQnvLSBjHDaS8n08Jw1CX1VF2Uxijh 5AYG/IS2QpAAud5W02XsLMbG6tzNg8s= ARC-Authentication-Results: i=1; imf14.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b="TLEJrUg/"; spf=pass (imf14.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1676289618; a=rsa-sha256; cv=none; b=LnYc3/XaTQ8fqZmfH6V6ULi04FG7ZOPUPeEG/wIz/HsBuz5FR81JyK2D/2g7988UTGeScn kkN5AcwWl7eMCbqeXrA1RrIjEsRZCOOR9SaUhd9PVp/eXb6NB7OtL566aVXSkmqNc9Zsib U4WTcB5XE20IWRj5jkQjz8N+EP/wPas= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1676289617; x=1707825617; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=QEso+vBOOoVux/wtjNoZkk+xLB3AIptATSZNTVaGYfg=; b=TLEJrUg/CZcZE2QzVS+AhOWYkyAQTzzZNh7twhou09OFQX7Xnm3AX7Mx jkBFukoVjO90gybjj5A34AB1isf930QcZcipzdHsOhebMLCSQjoql3ebQ 5ZOvaoHs3HgJSymed6hpgg+ZS+KHZrg6/hV4HmuJZz8xrK/tVpLNfSeTA ztaVzC2mfFM+TTAw46lnXQav74OEPAd+3/qCZgMwRQfxUNhbK1clgf10q 1nKPZkXf9WceWJoqL1oB6ckgKEqz7uzkE5ZZbVCQBr8254DX688N0MWVv Dn2NaolDdKFdkS+E2CYK0/gCbCXI8NKgk3Ros0Q3Hdr0213H6S4FujMSz w==; X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="358283041" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="358283041" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:00:17 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="701243098" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="701243098" Received: from wonger-mobl.amr.corp.intel.com (HELO khuang2-desk.gar.corp.intel.com) ([10.209.188.34]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:00:10 -0800 From: Kai Huang To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: linux-mm@kvack.org, dave.hansen@intel.com, peterz@infradead.org, tglx@linutronix.de, seanjc@google.com, pbonzini@redhat.com, dan.j.williams@intel.com, rafael.j.wysocki@intel.com, kirill.shutemov@linux.intel.com, ying.huang@intel.com, reinette.chatre@intel.com, len.brown@intel.com, tony.luck@intel.com, ak@linux.intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com, david@redhat.com, bagasdotme@gmail.com, sagis@google.com, imammedo@redhat.com, kai.huang@intel.com Subject: [PATCH v9 01/18] x86/tdx: Define TDX supported page sizes as macros Date: Tue, 14 Feb 2023 00:59:08 +1300 Message-Id: X-Mailer: git-send-email 2.39.1 In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Queue-Id: CB82610002C X-Stat-Signature: ez5omqh7e3jy16bqz8qgn96q153jgzox X-Rspam-User: X-Rspamd-Server: rspam08 X-HE-Tag: 1676289617-925041 X-HE-Meta: U2FsdGVkX1+nro/ipeiWAR/awqv3T4LApcvRiZeKwZQchDkVJ6TxgDaEaJ3LiPWcSbBMxJk0DND7D/wwRxykSeaYozkWgUqq0VGqEqIEquag4r5mYNTMddXhqgA1Qo8uqCDOTWkcgq5nk4h3PKdwkAllAiXSMiXiyRMYYCigHXF4J6lUVKNwqdxnDksNtASv3kN8OOvK6PUSm+imDLMFQG4mhixMpiD3xKBc4rAWwBTwFaHE6XnR8By/KJPNI2spCB4yPZzpsJ5oxIOdVwCJO30V7cj8yr+GJH+JjfJTCWQxClfsI6NBqWS9S/I+dgdnFe8mxYdWM1LClF3kY7C5O4HuA+HEWXfrMAcQuq7ZvfGUdLqXNZoYooEEyMTrJxwtgXOW+tvSPj1K4k3bkrGlR1nZM9yFHB/kcd38oeSJMG0ktVR2+dJYjoTX4A92F7WptrfeTL5zIb/aO/MVCe0q9BMcq9VH1zPvYiREkf8pltqwCc8eXp27kQMRMh+GgVKws1Hk3WDqLPMMeCOyOvWuxovirGMs8Ildw7xy9qsVmKagr/V6i/3Mv0/Lz/hGArscbK/6OVHW6u6pbEEQR124QGoqmUKDSXJUP1ulNbwLRWA3sUM6PMbz2HqDq2Tz8ccp4asrC8t1i/7DttsuukY53v8VsrZs/MpwvZQ4SegNIy1FjIRLWL3NbHhuJsNDa4jm2FUgXgZM5HYIqetaT+Hu+g0A0gmmdU40l/QFIG8oJwOi7F7ZbKpMrDsswxj3rVBQGMCNEkAONOyLTHf3cEqNinUi2K5GCD4I9QV9liHE29RwZG6ugrQuKFH6lOMy+IkNW01L5RmpPzvkH3S2FYh6/qQ7ylAMVLapPTwte81AbNPgoiZ7/cr6w7G74sgTuZS3UltGnVGOI9Cx74tAQzS+9aLtBob+4GDQb4VlejSG7gIwUhStCDhlzh1TbMG/cOmtNPxwKqKqlGp3VuVEPFu FQarajHA T0pNos96TkZYf8sJGzk3q6aD9oP8K3o5F9UbNmCI7cg86vFhXsZimtPSNdVhXAdfUPun1R2wzf5fsmspE1C1XuKzv/wCl9i0qtZUKCj7gdEMzSjtUrhwd7OMO8KwEJOHlLXfUlc151lAcsy3Icjr3n3AzSlJVSvwz5WcHMOdUKP1bG6k9OWhsxxSzr/TAcehnjML+EMpqwC00ECvLK778c2CXlA== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: TDX supports 4K, 2M and 1G page sizes. The corresponding values are defined by the TDX module spec and used as TDX module ABI. Currently, they are used in try_accept_one() when the TDX guest tries to accept a page. However currently try_accept_one() uses hard-coded magic values. Define TDX supported page sizes as macros and get rid of the hard-coded values in try_accept_one(). TDX host support will need to use them too. Signed-off-by: Kai Huang Reviewed-by: Kirill A. Shutemov Reviewed-by: Dave Hansen --- v8 -> v9: - Added Dave's Reviewed-by v7 -> v8: - Improved the comment of TDX supported page sizes macros (Dave) v6 -> v7: - Removed the helper to convert kernel page level to TDX page level. - Changed to use macro to define TDX supported page sizes. --- arch/x86/coco/tdx/tdx.c | 6 +++--- arch/x86/include/asm/tdx.h | 5 +++++ 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/arch/x86/coco/tdx/tdx.c b/arch/x86/coco/tdx/tdx.c index b593009b30ab..e27c3cd97fcb 100644 --- a/arch/x86/coco/tdx/tdx.c +++ b/arch/x86/coco/tdx/tdx.c @@ -777,13 +777,13 @@ static bool try_accept_one(phys_addr_t *start, unsigned long len, */ switch (pg_level) { case PG_LEVEL_4K: - page_size = 0; + page_size = TDX_PS_4K; break; case PG_LEVEL_2M: - page_size = 1; + page_size = TDX_PS_2M; break; case PG_LEVEL_1G: - page_size = 2; + page_size = TDX_PS_1G; break; default: return false; diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index 28d889c9aa16..25fd6070dc0b 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -20,6 +20,11 @@ #ifndef __ASSEMBLY__ +/* TDX supported page sizes from the TDX module ABI. */ +#define TDX_PS_4K 0 +#define TDX_PS_2M 1 +#define TDX_PS_1G 2 + /* * Used to gather the output registers values of the TDCALL and SEAMCALL * instructions when requesting services from the TDX module. From patchwork Mon Feb 13 11:59:09 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Huang, Kai" X-Patchwork-Id: 13138298 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 50111C636D7 for ; Mon, 13 Feb 2023 12:00:27 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 9D6416B0075; Mon, 13 Feb 2023 07:00:26 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 961156B0078; Mon, 13 Feb 2023 07:00:26 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 7D9536B007B; Mon, 13 Feb 2023 07:00:26 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0012.hostedemail.com [216.40.44.12]) by kanga.kvack.org (Postfix) with ESMTP id 679086B0075 for ; Mon, 13 Feb 2023 07:00:26 -0500 (EST) Received: from smtpin21.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay08.hostedemail.com (Postfix) with ESMTP id EBAB51416BF for ; Mon, 13 Feb 2023 12:00:25 +0000 (UTC) X-FDA: 80462126010.21.A80EA8C Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by imf14.hostedemail.com (Postfix) with ESMTP id A117C100010 for ; Mon, 13 Feb 2023 12:00:23 +0000 (UTC) Authentication-Results: imf14.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=i8b10z0u; spf=pass (imf14.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1676289624; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=MWLjb0eMdl3WAl7Xx9o7XjWXjlBG5EnOVzTN+nH9aYA=; b=bpzi3TjJKAUFB2Hv5wT4NtT6IgI3r2ez6Cty+yb3JBekuHmUZe1JaW1/PaZYYmuTQDV5K/ c859zYX6mUjo9K46EYm00a+EkGTCV04iaWuHS4/CbNgAW2gfimylf6gcwMAV2boMf/9953 oPv7p00kRl8RYexxss4eWelhZ1L4N3M= ARC-Authentication-Results: i=1; imf14.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=i8b10z0u; spf=pass (imf14.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1676289624; a=rsa-sha256; cv=none; b=XUztq04I2bHmHQhBLExV4aTN+f7Nh/rWhGSUqaQNpEUMsSWL21A1wv9HpYEOsqYVrOwePn iIYNouTCirHMchOk0jKQI8zMxXyhLdthLRHU42ZJWXDOwlevt8S80Sop6YKJgy3qucKrLX mITLgOeIWOyrRiW/UBk8JB0DLvyQsok= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1676289623; x=1707825623; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=9DkaKZwWOo0jCrvOqpLGFqKxtauaAnf7axqkLLshL0Q=; b=i8b10z0uIqZKO5MryRxu5D7BOYleLPNmT0XRvQiqX2z3vvfa1voMwTxW BFgaBk5ybh1FvXaqAtCaEe7SI2umUVLYOu04gbBx+3qG4WHqAknh2DAIs 3lu9HwZ9iClW49J4Px67Di+5OMKXhPkX970+nKsgu9+ne0si3oFo4ByaN NmJeoC3GRrytmnK91NjXgZV/SRSHDAb+DNg8XCsD3P9JqeANgvznL/XIj olUyJZaCpO1/lT8y4DTJYIfTPyRryy5p+dXjKhm4Kb4XK6dZuVKAE45tv J8qMs0gx+hGz5TPeDW3jGV6YQka3QjjgL+kHHGmgPUQkdsDFPLV7XQ74N A==; X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="358283064" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="358283064" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:00:23 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="701243154" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="701243154" Received: from wonger-mobl.amr.corp.intel.com (HELO khuang2-desk.gar.corp.intel.com) ([10.209.188.34]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:00:17 -0800 From: Kai Huang To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: linux-mm@kvack.org, dave.hansen@intel.com, peterz@infradead.org, tglx@linutronix.de, seanjc@google.com, pbonzini@redhat.com, dan.j.williams@intel.com, rafael.j.wysocki@intel.com, kirill.shutemov@linux.intel.com, ying.huang@intel.com, reinette.chatre@intel.com, len.brown@intel.com, tony.luck@intel.com, ak@linux.intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com, david@redhat.com, bagasdotme@gmail.com, sagis@google.com, imammedo@redhat.com, kai.huang@intel.com Subject: [PATCH v9 02/18] x86/virt/tdx: Detect TDX during kernel boot Date: Tue, 14 Feb 2023 00:59:09 +1300 Message-Id: X-Mailer: git-send-email 2.39.1 In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Queue-Id: A117C100010 X-Stat-Signature: 8oqxbpry3iqad46wsyfnpick9khwa7wf X-Rspam-User: X-Rspamd-Server: rspam08 X-HE-Tag: 1676289623-807570 X-HE-Meta: U2FsdGVkX1+3jIWkOzfyCxENqWHz4ZRIyW/0EKtu0NrsdjaLz0hOfYS2Qmiaoib8TQKUc7tmAAjG/IJQzZieabPF0kChGxTjJQc6NVAx980UCc4v9f00O2rYpEy8Y77wMpd56BeoJ07tpO31x9sjGepzF0a8AJm82qbf51jojulPN+U7RoYe/MXaj70OQpIXVQTVLO2pc9wOV1iv4cKunSesYFPJ4P5Fgpfj/trnh/4BEMz9rIdV6dqJnayYa/6mfdapLCfULuSe3tGZGq94OS/J9ByQ3QPagg3x2Js76jnECgE5yFnLWef+eyaGLItkFeUAoJANfEDkIOeZaB00YXnGjtw34FSeJIGdPltlF9/s53ydaBjiUkF843lZjMup+66M4E1UjKSZQzKmtNtuK2VHPmzcSu9O7GvcR6BnUFJsaFoRlvb3/qd4FxmLH8E339vhlHjn3N5DIkFT/haGCiBkyYTBeMnSsPVb8h07NwHrUmS+TAgG2wA0aA89zvDGH8cqxy0KTH8NGhbU2GypMryhCh5AhRnZJbhTjILyzCcx3ktjPNMulyx2oECqFo04qAdiMe6VPjR9tEYzcZg19VnXHOqh1WwgV98fMru4XSm3JPe4MZwZhMOU3a0w/fk3sipD+V9R5eNbivQufsiZO9i/WtCRFPoVK4Tqc4TMAvLKK1CJU6JjToDjEb+jmCJEvWtLVR3p0KJGpYWM/0aaQB7KslFnHfGAFKaZUitdZtCEYZ7p6orA7lhkixB9kDof7ZvAxnxpt3pBdrAFvD2op/NlrvmrKz9yG6eYCLexHIDtsDCC2A6DCDHB8wWVqk8nryzsN7PSPZ1sCz+beSLrq7k4JYbhfZo9KEngumF9aA6m8y/R3oSBQU+gJ6QY/jzeH6EhyNqWWkv7XCBLsYf9a4PGdCe79ZAV4LgGZy5lqPO6ewsup6W6sw8OvjPdiyMBEtXfE4dK3HQiDI1aK8Z RN+F0Rpb BOnDeRlp2olqNqLyqB8s3vxWN5GdRKTj91NXtLaS6uwu5JYXF1dcrG8nUGTWgbuyQMntcGLUkuBVFioEJesEJ6GCf+tQdiYGXUdXN/rDcxGuJyzGoAbzqdKyFURG2TOOLp3PyHTXL/ey/ghmW/poVYs+0Jsk6GEdUERRu6uH/cyZ3jFg= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: Intel Trust Domain Extensions (TDX) protects guest VMs from malicious host and certain physical attacks. A CPU-attested software module called 'the TDX module' runs inside a new isolated memory range as a trusted hypervisor to manage and run protected VMs. Pre-TDX Intel hardware has support for a memory encryption architecture called MKTME. The memory encryption hardware underpinning MKTME is also used for Intel TDX. TDX ends up "stealing" some of the physical address space from the MKTME architecture for crypto-protection to VMs. The BIOS is responsible for partitioning the "KeyID" space between legacy MKTME and TDX. The KeyIDs reserved for TDX are called 'TDX private KeyIDs' or 'TDX KeyIDs' for short. TDX doesn't trust the BIOS. During machine boot, TDX verifies the TDX private KeyIDs are consistently and correctly programmed by the BIOS across all CPU packages before it enables TDX on any CPU core. A valid TDX private KeyID range on BSP indicates TDX has been enabled by the BIOS, otherwise the BIOS is buggy. The TDX module is expected to be loaded by the BIOS when it enables TDX, but the kernel needs to properly initialize it before it can be used to create and run any TDX guests. The TDX module will be initialized by the KVM subsystem when KVM wants to use TDX. Add a new early_initcall(tdx_init) to detect the TDX by detecting TDX private KeyIDs. Also add a function to report whether TDX is enabled by the BIOS. Similar to AMD SME, kexec() will use it to determine whether cache flush is needed. The TDX module itself requires one TDX KeyID as the 'TDX global KeyID' to protect its metadata. Each TDX guest also needs a TDX KeyID for its own protection. Just use the first TDX KeyID as the global KeyID and leave the rest for TDX guests. If no TDX KeyID is left for TDX guests, disable TDX as initializing the TDX module alone is useless. To start to support TDX, create a new arch/x86/virt/vmx/tdx/tdx.c for TDX host kernel support. Add a new Kconfig option CONFIG_INTEL_TDX_HOST to opt-in TDX host kernel support (to distinguish with TDX guest kernel support). So far only KVM uses TDX. Make the new config option depend on KVM_INTEL. Signed-off-by: Kai Huang Reviewed-by: Kirill A. Shutemov --- v8 -> v9: - Moved MSR macro from local tdx.h to (Dave). - Moved reserving the TDX global KeyID from later patch to here. - Changed 'tdx_keyid_start' and 'nr_tdx_keyids' to 'tdx_guest_keyid_start' and 'tdx_nr_guest_keyids' to represent KeyIDs can be used by guest. (Dave) - Slight changelog update according to above changes. v7 -> v8: (address Dave's comments) - Improved changelog: - "KVM user" -> "The TDX module will be initialized by KVM when ..." - Changed "tdx_int" part to "Just say what this patch is doing" - Fixed the last sentence of "kexec()" paragraph - detect_tdx() -> record_keyid_partitioning() - Improved how to calculate tdx_keyid_start. - tdx_keyid_num -> nr_tdx_keyids. - Improved dmesg printing. - Add comment to clear_tdx(). v6 -> v7: - No change. v5 -> v6: - Removed SEAMRR detection to make code simpler. - Removed the 'default N' in the KVM_TDX_HOST Kconfig (Kirill). - Changed to use 'obj-y' in arch/x86/virt/vmx/tdx/Makefile (Kirill). --- arch/x86/Kconfig | 12 ++++ arch/x86/Makefile | 2 + arch/x86/include/asm/msr-index.h | 3 + arch/x86/include/asm/tdx.h | 7 +++ arch/x86/virt/Makefile | 2 + arch/x86/virt/vmx/Makefile | 2 + arch/x86/virt/vmx/tdx/Makefile | 2 + arch/x86/virt/vmx/tdx/tdx.c | 105 +++++++++++++++++++++++++++++++ 8 files changed, 135 insertions(+) create mode 100644 arch/x86/virt/Makefile create mode 100644 arch/x86/virt/vmx/Makefile create mode 100644 arch/x86/virt/vmx/tdx/Makefile create mode 100644 arch/x86/virt/vmx/tdx/tdx.c diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 3604074a878b..fc010973a6ff 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1952,6 +1952,18 @@ config X86_SGX If unsure, say N. +config INTEL_TDX_HOST + bool "Intel Trust Domain Extensions (TDX) host support" + depends on CPU_SUP_INTEL + depends on X86_64 + depends on KVM_INTEL + help + Intel Trust Domain Extensions (TDX) protects guest VMs from malicious + host and certain physical attacks. This option enables necessary TDX + support in host kernel to run protected VMs. + + If unsure, say N. + config EFI bool "EFI runtime service support" depends on ACPI diff --git a/arch/x86/Makefile b/arch/x86/Makefile index 9cf07322875a..972b5a64ce38 100644 --- a/arch/x86/Makefile +++ b/arch/x86/Makefile @@ -252,6 +252,8 @@ archheaders: libs-y += arch/x86/lib/ +core-y += arch/x86/virt/ + # drivers-y are linked after core-y drivers-$(CONFIG_MATH_EMULATION) += arch/x86/math-emu/ drivers-$(CONFIG_PCI) += arch/x86/pci/ diff --git a/arch/x86/include/asm/msr-index.h b/arch/x86/include/asm/msr-index.h index 37ff47552bcb..952374ddb167 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -512,6 +512,9 @@ #define MSR_RELOAD_PMC0 0x000014c1 #define MSR_RELOAD_FIXED_CTR0 0x00001309 +/* KeyID partitioning between MKTME and TDX */ +#define MSR_IA32_MKTME_KEYID_PARTITIONING 0x00000087 + /* * AMD64 MSRs. Not complete. See the architecture manual for a more * complete list. diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index 25fd6070dc0b..4dfe2e794411 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -94,5 +94,12 @@ static inline long tdx_kvm_hypercall(unsigned int nr, unsigned long p1, return -ENODEV; } #endif /* CONFIG_INTEL_TDX_GUEST && CONFIG_KVM_GUEST */ + +#ifdef CONFIG_INTEL_TDX_HOST +bool platform_tdx_enabled(void); +#else /* !CONFIG_INTEL_TDX_HOST */ +static inline bool platform_tdx_enabled(void) { return false; } +#endif /* CONFIG_INTEL_TDX_HOST */ + #endif /* !__ASSEMBLY__ */ #endif /* _ASM_X86_TDX_H */ diff --git a/arch/x86/virt/Makefile b/arch/x86/virt/Makefile new file mode 100644 index 000000000000..1e36502cd738 --- /dev/null +++ b/arch/x86/virt/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-y += vmx/ diff --git a/arch/x86/virt/vmx/Makefile b/arch/x86/virt/vmx/Makefile new file mode 100644 index 000000000000..feebda21d793 --- /dev/null +++ b/arch/x86/virt/vmx/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-$(CONFIG_INTEL_TDX_HOST) += tdx/ diff --git a/arch/x86/virt/vmx/tdx/Makefile b/arch/x86/virt/vmx/tdx/Makefile new file mode 100644 index 000000000000..93ca8b73e1f1 --- /dev/null +++ b/arch/x86/virt/vmx/tdx/Makefile @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: GPL-2.0-only +obj-y += tdx.o diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c new file mode 100644 index 000000000000..a600b5d0879d --- /dev/null +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -0,0 +1,105 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Copyright(c) 2023 Intel Corporation. + * + * Intel Trusted Domain Extensions (TDX) support + */ + +#define pr_fmt(fmt) "tdx: " fmt + +#include +#include +#include +#include +#include +#include +#include +#include + +static u32 tdx_global_keyid __ro_after_init; +static u32 tdx_guest_keyid_start __ro_after_init; +static u32 tdx_nr_guest_keyids __ro_after_init; + +/* + * Use tdx_global_keyid to indicate that TDX is uninitialized. + * This is used in TDX initialization error paths to take it from + * initialized -> uninitialized. + */ +static void __init clear_tdx(void) +{ + tdx_global_keyid = 0; +} + +static int __init record_keyid_partitioning(u32 *tdx_keyid_start, + u32 *nr_tdx_keyids) +{ + u32 _nr_mktme_keyids, _tdx_keyid_start, _nr_tdx_keyids; + int ret; + + /* + * IA32_MKTME_KEYID_PARTIONING: + * Bit [31:0]: Number of MKTME KeyIDs. + * Bit [63:32]: Number of TDX private KeyIDs. + */ + ret = rdmsr_safe(MSR_IA32_MKTME_KEYID_PARTITIONING, &_nr_mktme_keyids, + &_nr_tdx_keyids); + if (ret) + return -ENODEV; + + if (!_nr_tdx_keyids) + return -ENODEV; + + /* TDX KeyIDs start after the last MKTME KeyID. */ + _tdx_keyid_start = _nr_mktme_keyids + 1; + + *tdx_keyid_start = _tdx_keyid_start; + *nr_tdx_keyids = _nr_tdx_keyids; + + return 0; +} + +static int __init tdx_init(void) +{ + u32 tdx_keyid_start, nr_tdx_keyids; + int err; + + err = record_keyid_partitioning(&tdx_keyid_start, &nr_tdx_keyids); + if (err) + return err; + + pr_info("BIOS enabled: private KeyID range [%u, %u)\n", + tdx_keyid_start, tdx_keyid_start + nr_tdx_keyids); + + /* + * The TDX module itself requires one 'TDX global KeyID' to + * protect its metadata. Just use the first one. + */ + tdx_global_keyid = tdx_keyid_start; + tdx_keyid_start++; + nr_tdx_keyids--; + + /* + * If there's no more TDX KeyID left, KVM won't be able to run + * any TDX guest. Disable TDX in this case as initializing the + * TDX module alone is meaningless. + */ + if (!nr_tdx_keyids) { + pr_info("initialization failed: too few private KeyIDs available.\n"); + goto no_tdx; + } + + tdx_guest_keyid_start = tdx_keyid_start; + tdx_nr_guest_keyids = nr_tdx_keyids; + + return 0; +no_tdx: + clear_tdx(); + return -ENODEV; +} +early_initcall(tdx_init); + +/* Return whether the BIOS has enabled TDX */ +bool platform_tdx_enabled(void) +{ + return !!tdx_global_keyid; +} From patchwork Mon Feb 13 11:59:10 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Huang, Kai" X-Patchwork-Id: 13138299 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id D68E2C636D4 for ; Mon, 13 Feb 2023 12:00:32 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 5B8866B0073; Mon, 13 Feb 2023 07:00:32 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 541076B0078; Mon, 13 Feb 2023 07:00:32 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 3E1D56B007B; Mon, 13 Feb 2023 07:00:32 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0017.hostedemail.com [216.40.44.17]) by kanga.kvack.org (Postfix) with ESMTP id 2B4416B0073 for ; Mon, 13 Feb 2023 07:00:32 -0500 (EST) Received: from smtpin07.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay01.hostedemail.com (Postfix) with ESMTP id E80CE1C6ECC for ; Mon, 13 Feb 2023 12:00:31 +0000 (UTC) X-FDA: 80462126262.07.E72EBE4 Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by imf14.hostedemail.com (Postfix) with ESMTP id 7D6CA10000B for ; Mon, 13 Feb 2023 12:00:29 +0000 (UTC) Authentication-Results: imf14.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=mD3snYve; spf=pass (imf14.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1676289629; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=lXNxgBMaxsinrr+gptxYJ70KEXZVLvYppoPLl6ERppM=; b=MbYyJiOylx25V4DqIhTXUZfYpN2k2kbFvCYkeRMlkZhUwKtKPGhRyRxG0Oa5pvIjug4XB2 CjBmkVrx3MWFCou3vuQPz7NAgQDvewswSTGswhTOkJH4H5ST9Xc8kKaRTsPU8JnTeiOvKc TAgk43nHI1kmwF36Y4wN+9PxzRkEL6o= ARC-Authentication-Results: i=1; imf14.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=mD3snYve; spf=pass (imf14.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1676289629; a=rsa-sha256; cv=none; b=HGoUCKnST8WopIvmn9qDdOe4jNs/bodmWNrtAwhI+ik9oE578S2RmCk47wnzpia322Ssx5 FBUXv+CHc+PiSS+YUr7ab/SZInSwn96O44ZnTGnvGZll0N4yV/fbd7KVCWOmGpNqKiKOBC BtYbIBcQRdkHmkeeJ0c11TJV5OSM6lo= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1676289629; x=1707825629; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=6hl+bXXiRVGiGthCtAdZGGt9ykL2zfBjTabiMcyXn8o=; b=mD3snYve//FUv6cMYCTebvax4y0Evwyql0JA1zdLudf/0vkBGw3qDmRR SsWndmmZ//w9FlHD5F2IG7KA6BDXX8dVrpD8pEGDFXGg/C73geAHEC0zh WEHvTbXymT1gMEsRONXsLPh0SNfZRYeam4EY6WZ94UaXcR7YWSVSAdtNZ Lj/Zvr+rjYpq33W608xoqrcCUWyTWejYgIk/KwWqvepeHf8zu4Dn3SX6+ RgCCmWS16bM/OtqKErm/vjHvPOrkAD3Wai38wESjCsw8KtLLno9ssOrcc dgIBg5FchGRzS6xZmvyDneQ1YQ4+yhED7TLK+bbG+QjQKtbTGzsQKIneN w==; X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="358283087" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="358283087" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:00:28 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="701243202" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="701243202" Received: from wonger-mobl.amr.corp.intel.com (HELO khuang2-desk.gar.corp.intel.com) ([10.209.188.34]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:00:22 -0800 From: Kai Huang To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: linux-mm@kvack.org, dave.hansen@intel.com, peterz@infradead.org, tglx@linutronix.de, seanjc@google.com, pbonzini@redhat.com, dan.j.williams@intel.com, rafael.j.wysocki@intel.com, kirill.shutemov@linux.intel.com, ying.huang@intel.com, reinette.chatre@intel.com, len.brown@intel.com, tony.luck@intel.com, ak@linux.intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com, david@redhat.com, bagasdotme@gmail.com, sagis@google.com, imammedo@redhat.com, kai.huang@intel.com Subject: [PATCH v9 03/18] x86/virt/tdx: Make INTEL_TDX_HOST depend on X86_X2APIC Date: Tue, 14 Feb 2023 00:59:10 +1300 Message-Id: <5b4de9199779c07e2d432d1ea9aadafd0894503a.1676286526.git.kai.huang@intel.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Queue-Id: 7D6CA10000B X-Stat-Signature: bmhnztfy5tgq5jscig58444cjqut1fs8 X-Rspam-User: X-Rspamd-Server: rspam08 X-HE-Tag: 1676289629-530137 X-HE-Meta: U2FsdGVkX18AYDO+Lt78SdR44xp6Nq4u0Z6qD+m9shcH9eReuOWqajk/GjIVSE7hlH90gMwrvFpQcqHcbfK02K6W+GRryv5/8igWGFWUcnaT4XMO09nQ8hLWxY5gWYz1sGy64mMyKZ8OfVsm98SWWEwCIp9hLg0rozspZGkSU+W0/8X6gy1XC3zxnFdXLILT318kY9o3UaTs+NYXShuZewNeV7eqtHXGRJXZQERXUkwZvEIxgYlEepLvqxt2NZg3Ek0aH7H1+gPO4UPmwfRFz+Yh88ZKR5qaqCzBOtY1QqhC6EAwz1q30a+RCV9ZhIxnptVf0V0L30HBWuFp7jsTw0Jqt80L5AlcTnHIvt4HzxllVTuc+ZPdbBak5YgvmMWEcULhDoGH9D+vvAJNKPlEIhPx7HJ8TLEegZu473mdmh1IH5a/gFGTkgrQBkB0Vu1fBx2gCJsG3yRMLabpMcrvgp60ZvOtoUcPXDtnRhjbBxRVHmrr+YBkHzG0UXjZvjOJc36hwSQtrPh5GqrTaINUDRNwOdxBW/PdoHvVh55NFqUXG/5xU4JbMPbqI1Quh3hlrCIXFfhxtr1wmA2Qa8Gkdo+VhtNkkauhY8q24PjZ4JudOG1FaWTqcUWbWr6eERYqjL7Y36+q1CVin3Wnwt47Aos2ABzuYuFRxobMoWyly+iaA2NQwLQccuwSvXUtBb+tsFdCT8bgv82sB63nxdrOZukZ+x+mwXEdyzzLZq0pcWIdCAqRoHariPZMGUVIk2qlpSMMknolXFQrr9CqOjbaQSddKUXlM2izOaIjwpvYAJA25EYpY7CIUiS3TRQClB3+SLBF9YuvYXTmsCJgo/CJZwqbTU2iDAYU1rptsNTqGpWhla+wU93kiH/CJLQqqOE/1wn5TJVBql6/OspcaIIBYIXLeSVSJ9gnUQPC6xyCWybbU20FaXXV1LYvRGC/xEC1hv0wMldC82Z4LAB2zaq 6z+VoGev OxuGGgLEEHRjOv3abyKfuQZbCog91MzTi22xLxmjA9qWO1qUR16/h+nZRXj0hcE7lGgJzWq2xEK5JHd0MEGjlVhcux19mjk15VsXYgCTgLXwUjqeZFf+hxJKyIqXGqI64jYybf3HQ3t2dxqb1GEWxY5eUF/zlIlWF/YWQAj5DPz4DzPZdxPEz6XslGNvbD7BuejJVHiLxpJXt9NhXwRMm87+pR1V3fhvTH6LyaeNIkdo7kDyO59tad0W39gerxiBpheb23X50IJwqQ6wpmfjetbujRg== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: TDX capable platforms are locked to X2APIC mode and cannot fall back to the legacy xAPIC mode when TDX is enabled by the BIOS. TDX host support requires x2APIC. Make INTEL_TDX_HOST depend on X86_X2APIC. Link: https://lore.kernel.org/lkml/ba80b303-31bf-d44a-b05d-5c0f83038798@intel.com/ Signed-off-by: Kai Huang Reviewed-by: Dave Hansen --- v8 -> v9: - Added Dave's Reviewed-by. v7 -> v8: (Dave) - Only make INTEL_TDX_HOST depend on X86_X2APIC but removed other code - Rewrote the changelog. v6 -> v7: - Changed to use "Link" for the two lore links to get rid of checkpatch warning. --- arch/x86/Kconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index fc010973a6ff..6dd5d5586099 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1957,6 +1957,7 @@ config INTEL_TDX_HOST depends on CPU_SUP_INTEL depends on X86_64 depends on KVM_INTEL + depends on X86_X2APIC help Intel Trust Domain Extensions (TDX) protects guest VMs from malicious host and certain physical attacks. This option enables necessary TDX From patchwork Mon Feb 13 11:59:11 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Huang, Kai" X-Patchwork-Id: 13138300 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5092EC636D4 for ; Mon, 13 Feb 2023 12:00:37 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id DCE886B0078; Mon, 13 Feb 2023 07:00:36 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id D57506B007B; Mon, 13 Feb 2023 07:00:36 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id BA9BA6B007D; Mon, 13 Feb 2023 07:00:36 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0015.hostedemail.com [216.40.44.15]) by kanga.kvack.org (Postfix) with ESMTP id A35D56B0078 for ; Mon, 13 Feb 2023 07:00:36 -0500 (EST) Received: from smtpin26.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay08.hostedemail.com (Postfix) with ESMTP id 3A14C1416BF for ; Mon, 13 Feb 2023 12:00:36 +0000 (UTC) X-FDA: 80462126472.26.DD6513C Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by imf14.hostedemail.com (Postfix) with ESMTP id E9A0510002F for ; Mon, 13 Feb 2023 12:00:33 +0000 (UTC) Authentication-Results: imf14.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=MZsFwWgv; spf=pass (imf14.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1676289634; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=AmRrVSasjzh6ZoSPmYsV8MUExEdHMJRCzWhfEChqkX0=; b=UTxJyrfylc6dcLzOhoz40PMFe//tReykoV0Rc4FSXeNEWYkoET0HCYIhh/WB6MLxBE6wRD XWnQ1iL4MmRpFN8bYhXsKncZBFTqOY43fH8dIw6ajmSEouNjNMW2fP/B645WUuC6DkONQC W3GeXVVTxapXhz7ykWiETmZqzHwol34= ARC-Authentication-Results: i=1; imf14.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=MZsFwWgv; spf=pass (imf14.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1676289634; a=rsa-sha256; cv=none; b=asXjGhK/i8D+wWZCJhC8UJU6ZZjIiChCtD6UjL+LHa9qTmCMXrpctcLuunw+vCe38jUKAQ zThb0bu5zSg/ygkHs9/sTnevzinjn8B1626I2K5Xtu0/scUJpVYxWbIt+9qqoKu5UPZq+f B/ehGgx2xwpT+fpBWsiEoJGglROq/+c= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1676289634; x=1707825634; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=KCtFrPMXWCBUQiJLyRSETt1euQ8icZ6ARs1bRdXgsDc=; b=MZsFwWgvvfe4jREV07o5EHkHBVZxHB50Kjci3IciQnyBudMcaYTdE74H yf4YA9vLtWViKUaI739dCtK9GsERgnxlZSRfuVOWnEatkQ0zT81oqQ8GW YBHAgVSe6BY0KBhzkxlUDjNA93VxcvqOOzK98E7vRYg6+cgadWSWuRK+n hJZt+hPS/JrWoNMzcrI1LpbjhxDej/wmFNtSQv4y2EApyXRmwpqEIsw7C HYwkQhEbWfzUM3LoNxAr1R2shyx4x1xM9SjYMPK4jnoKvr2yBjj8OoQp3 XsaTtDyZMqH5a08DLZj9fQWNmOt7YLjVuJQ6krVdTeAo2NTt37BYla81O w==; X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="358283131" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="358283131" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:00:33 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="701243219" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="701243219" Received: from wonger-mobl.amr.corp.intel.com (HELO khuang2-desk.gar.corp.intel.com) ([10.209.188.34]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:00:28 -0800 From: Kai Huang To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: linux-mm@kvack.org, dave.hansen@intel.com, peterz@infradead.org, tglx@linutronix.de, seanjc@google.com, pbonzini@redhat.com, dan.j.williams@intel.com, rafael.j.wysocki@intel.com, kirill.shutemov@linux.intel.com, ying.huang@intel.com, reinette.chatre@intel.com, len.brown@intel.com, tony.luck@intel.com, ak@linux.intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com, david@redhat.com, bagasdotme@gmail.com, sagis@google.com, imammedo@redhat.com, kai.huang@intel.com Subject: [PATCH v9 04/18] x86/virt/tdx: Add skeleton to initialize TDX on demand Date: Tue, 14 Feb 2023 00:59:11 +1300 Message-Id: X-Mailer: git-send-email 2.39.1 In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Queue-Id: E9A0510002F X-Stat-Signature: qp33erx1d1oqtus36ukk8c4s8s8ew5jf X-Rspam-User: X-Rspamd-Server: rspam08 X-HE-Tag: 1676289633-997434 X-HE-Meta: U2FsdGVkX1/l/+QakJ/EVsfrTtiEaIscDvf54qqayOUwN9FNneVS/XP56QRo/2vqB9RelgpbL835VeXs0RQ5k5tVhqkTqI4w8umCNNxLy8eyTeLwu2ACNpx6YBKMvqFu54FJtBPcj2/ZWB6DnB/4EVAXbUm6oXkC6DXjKzJV3sRJ4C6c4j6Tol7huFiYrekyJBKJ5SBMe58Kcb3RQi4wcg0MQz/8KbmR65wU9qcjEkl3qi84vkifm9mh9wOJbEglZsYz/DJ8mBzpfE2Ofg7OfS5Kgprdw44n7NSwKzyywzZgDcU6SyS2kHFFhYNrKI8TO26TM52Bu4j+uNoXbN09c25+MimBlMr9+GwdSX0gjcjQsmCP1z3TWbLdXdUBskXDeMRdxf7fEgkOwobXzY5agooDFOu0fITvO/2TrwNGeOEfQZZ+J04X6zO3qQ1vIkamQMEfGdo0GLPqaIJmtkiQ4AzNAgaPeHTONLy3phqwpO5K+ehKYa0rIPKZiMrJUjAYdhffmnPLGqfbNALZ/4CVGOt3kF/sFtfJhdFRNWEn14HL+eWo19pBLv6IuII75lD3dsAPhyULS2U27RhDrOOCNAh+FO9dUjmRDIvlE6hfQmSBxw4vDnL1E4fHtk1tQFczz/092p18eAzhcYvEFyOw6SDxyPv/16ncFIGjtNWmB0iwiLNUBoek0QNYoU8D5gNSx9molJ1vcpM8EaQjLeQoSvG48ZeV9Narqqb4kF6XZhUAI1tL836Q2W6PjM7eMjQX+Kol8kqEqdz2OuOi2ICBxM2wHfK4VqMiQl9z0xK4OWGRRCNaucMkE8M1+WdltWLPeUrgUb9cjSCXa+0bBB+jABG6YnLy3Mtgy137BiShPhEgb+jcJVz2M8/d0IMHzCXYDuWxX30+LEFoUdgsFgfXELCJrvMB+zApEL185WsiFFuSaOPodcGP29T/++D+ccNKNTEpIVrb26n+XUz9RnO po7DO+VJ eJhgYXmJSAPkMFZV9liqRLXv9Ye1pfYrU+h5QD/QKo4emiIErAOr81c8dw1/jphEYThZhvsceNk8v7fiVlRA/bvjf0hiIeAEl4cOnuLUAkarIzn0/lhPL68IfXzImUi/DcPVX1OAZViBmwyMq3ZPlhtH43D1Ro2R8wWVFSdvTkRBPAaWlxv3eYhKQTECFGloTWp4ETX+26Jd1+bXLBJnP3u/5Yw== X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: Before the TDX module can be used to create and run TDX guests, it must be loaded and properly initialized. The TDX module is expected to be loaded by the BIOS, and to be initialized by the kernel. TDX introduces a new CPU mode: Secure Arbitration Mode (SEAM). The host kernel communicates with the TDX module via a new SEAMCALL instruction. The TDX module implements a set of SEAMCALL leaf functions to allow the host kernel to initialize it. The TDX module can be initialized only once in its lifetime. Instead of always initializing it at boot time, this implementation chooses an "on demand" approach to initialize TDX until there is a real need (e.g when requested by KVM). This approach has below pros: 1) It avoids consuming the memory that must be allocated by kernel and given to the TDX module as metadata (~1/256th of the TDX-usable memory), and also saves the CPU cycles of initializing the TDX module (and the metadata) when TDX is not used at all. 2) The TDX module design allows it to be updated while the system is running. The update procedure shares quite a few steps with this "on demand" initialization mechanism. The hope is that much of "on demand" mechanism can be shared with a future "update" mechanism. A boot-time TDX module implementation would not be able to share much code with the update mechanism. 3) Loading the TDX module requires VMX to be enabled. Currently, only the kernel KVM code mucks with VMX enabling. If the TDX module were to be initialized separately from KVM (like at boot), the boot code would need to be taught how to muck with VMX enabling and KVM would need to be taught how to cope with that. Making KVM itself responsible for TDX initialization lets the rest of the kernel stay blissfully unaware of VMX. Add a placeholder tdx_enable() to initialize the TDX module on demand. The TODO list will be pared down as functionality is added. Use a state machine protected by mutex to make sure the initialization will only be done once, as tdx_enable() can be called multiple times (i.e. KVM module can be reloaded) and be called concurrently by other kernel components in the future. Also introduce a local tdx.h to hold all TDX architectural and kernel defined structures and declarations used by module initialization. Signed-off-by: Kai Huang Reviewed-by: Chao Gao --- v8 -> v9: - Removed detailed TODO list in the changelog (Dave). - Added back steps to do module global initialization and per-cpu initialization in the TODO list comment. - Moved the 'enum tdx_module_status_t' from tdx.c to local tdx.h v7 -> v8: - Refined changelog (Dave). - Removed "all BIOS-enabled cpus" related code (Peter/Thomas/Dave). - Add a "TODO list" comment in init_tdx_module() to list all steps of initializing the TDX Module to tell the story (Dave). - Made tdx_enable() unverisally return -EINVAL, and removed nonsense comments (Dave). - Simplified __tdx_enable() to only handle success or failure. - TDX_MODULE_SHUTDOWN -> TDX_MODULE_ERROR - Removed TDX_MODULE_NONE (not loaded) as it is not necessary. - Improved comments (Dave). - Pointed out 'tdx_module_status' is software thing (Dave). v6 -> v7: - No change. v5 -> v6: - Added code to set status to TDX_MODULE_NONE if TDX module is not loaded (Chao) - Added Chao's Reviewed-by. - Improved comments around cpus_read_lock(). - v3->v5 (no feedback on v4): - Removed the check that SEAMRR and TDX KeyID have been detected on all present cpus. - Removed tdx_detect(). - Added num_online_cpus() to MADT-enabled CPUs check within the CPU hotplug lock and return early with error message. - Improved dmesg printing for TDX module detection and initialization. --- arch/x86/include/asm/tdx.h | 2 + arch/x86/virt/vmx/tdx/tdx.c | 89 +++++++++++++++++++++++++++++++++++++ arch/x86/virt/vmx/tdx/tdx.h | 12 +++++ 3 files changed, 103 insertions(+) create mode 100644 arch/x86/virt/vmx/tdx/tdx.h diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index 4dfe2e794411..4a3ee64c1ca7 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -97,8 +97,10 @@ static inline long tdx_kvm_hypercall(unsigned int nr, unsigned long p1, #ifdef CONFIG_INTEL_TDX_HOST bool platform_tdx_enabled(void); +int tdx_enable(void); #else /* !CONFIG_INTEL_TDX_HOST */ static inline bool platform_tdx_enabled(void) { return false; } +static inline int tdx_enable(void) { return -EINVAL; } #endif /* CONFIG_INTEL_TDX_HOST */ #endif /* !__ASSEMBLY__ */ diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index a600b5d0879d..f5a20d56097c 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -12,14 +12,20 @@ #include #include #include +#include #include #include #include +#include "tdx.h" static u32 tdx_global_keyid __ro_after_init; static u32 tdx_guest_keyid_start __ro_after_init; static u32 tdx_nr_guest_keyids __ro_after_init; +static enum tdx_module_status_t tdx_module_status; +/* Prevent concurrent attempts on TDX module initialization */ +static DEFINE_MUTEX(tdx_module_lock); + /* * Use tdx_global_keyid to indicate that TDX is uninitialized. * This is used in TDX initialization error paths to take it from @@ -103,3 +109,86 @@ bool platform_tdx_enabled(void) { return !!tdx_global_keyid; } + +static int init_tdx_module(void) +{ + /* + * TODO: + * + * - TDX module global initialization. + * - TDX module per-cpu initialization. + * - Get TDX module information and TDX-capable memory regions. + * - Build the list of TDX-usable memory regions. + * - Construct a list of "TD Memory Regions" (TDMRs) to cover + * all TDX-usable memory regions. + * - Configure the TDMRs and the global KeyID to the TDX module. + * - Configure the global KeyID on all packages. + * - Initialize all TDMRs. + * + * Return error before all steps are done. + */ + return -EINVAL; +} + +static int __tdx_enable(void) +{ + int ret; + + ret = init_tdx_module(); + if (ret) { + pr_err("initialization failed (%d)\n", ret); + tdx_module_status = TDX_MODULE_ERROR; + /* + * Just return one universal error code. + * For now the caller cannot recover anyway. + */ + return -EINVAL; + } + + pr_info("TDX module initialized.\n"); + tdx_module_status = TDX_MODULE_INITIALIZED; + + return 0; +} + +/** + * tdx_enable - Enable TDX to be ready to run TDX guests + * + * Initialize the TDX module to enable TDX. After this function, the TDX + * module is ready to create and run TDX guests. + * + * This function assumes all online cpus are already in VMX operation. + * This function can be called in parallel by multiple callers. + * + * Return 0 if TDX is enabled successfully, otherwise error. + */ +int tdx_enable(void) +{ + int ret; + + if (!platform_tdx_enabled()) { + pr_err_once("initialization failed: TDX is disabled.\n"); + return -EINVAL; + } + + mutex_lock(&tdx_module_lock); + + switch (tdx_module_status) { + case TDX_MODULE_UNKNOWN: + ret = __tdx_enable(); + break; + case TDX_MODULE_INITIALIZED: + /* Already initialized, great, tell the caller. */ + ret = 0; + break; + default: + /* Failed to initialize in the previous attempts */ + ret = -EINVAL; + break; + } + + mutex_unlock(&tdx_module_lock); + + return ret; +} +EXPORT_SYMBOL_GPL(tdx_enable); diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h new file mode 100644 index 000000000000..881cca276956 --- /dev/null +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#ifndef _X86_VIRT_TDX_H +#define _X86_VIRT_TDX_H + +/* Kernel defined TDX module status during module initialization. */ +enum tdx_module_status_t { + TDX_MODULE_UNKNOWN, + TDX_MODULE_INITIALIZED, + TDX_MODULE_ERROR +}; + +#endif From patchwork Mon Feb 13 11:59:12 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Huang, Kai" X-Patchwork-Id: 13138301 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 3FF0FC64EC4 for ; Mon, 13 Feb 2023 12:00:44 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id D32CD6B007B; Mon, 13 Feb 2023 07:00:43 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id CBAEA6B007D; Mon, 13 Feb 2023 07:00:43 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id B0D5E6B007E; Mon, 13 Feb 2023 07:00:43 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0010.hostedemail.com [216.40.44.10]) by kanga.kvack.org (Postfix) with ESMTP id A028E6B007B for ; Mon, 13 Feb 2023 07:00:43 -0500 (EST) Received: from smtpin10.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay05.hostedemail.com (Postfix) with ESMTP id 77C4A41766 for ; Mon, 13 Feb 2023 12:00:43 +0000 (UTC) X-FDA: 80462126766.10.8B2D677 Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by imf14.hostedemail.com (Postfix) with ESMTP id 17901100038 for ; Mon, 13 Feb 2023 12:00:40 +0000 (UTC) Authentication-Results: imf14.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=csePHMdj; spf=pass (imf14.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1676289641; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=USJBJsatxN2CH0j6RfogfQrlubGIwvddY3J4NQndNQU=; b=kbN0AFNdet/cUkPuRNtOGwExprFzQwxtpSTPIqfOTBCJgLWCYx9n4jyIqzbWbuUCRfrVud byBs8R1QwTuycvSVxv7qOq9OzjDCauBq0NS/woD2CVqODHEoGo0FxGxt3W6JBcuNWgmMMl sPsI6iHxpj2e9J9sVQ9ADSI+cmGNcwk= ARC-Authentication-Results: i=1; imf14.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=csePHMdj; spf=pass (imf14.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1676289641; a=rsa-sha256; cv=none; b=qKhKKAbuOltCdns0CLvUn78rBLvLM0khw1oC6MvzMhempwoKR1D5iDrdTkdWi6Gu69QCw/ l4MBjwXjCIbNNBW90gxRCFlFc/+44hxmYtvbqsXa9azFi63Xuz4gOBKZVEqnK78NmZ82+R /BonjFe3GRPKbKGIL+m4wepPm3vShGA= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1676289641; x=1707825641; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=mskoA6wmBALGpNDsQmfVYNazTJkiGatfzDIRABme0ow=; b=csePHMdj9qgsy0jx0xzHri/JXnFYNwxmybh1XOfHAK6cmIQIMbgVqZOo ncebNSp3FI18uGujULbFp5N7JWJ9ug4s8Tu728yN6UUKibKqOAO05dMOW BQObtlmL5mELBxmfvxDff5rxQ0DkXAyDsr6CpEAABqHaxHIAotOXFs9JM xjNeJJovlGZZcHkgCgwzzREhlZN+Tu6QcImjjk7C1CV2jSZJvmDVgryYt TDCRqIigUd9KJXXaPeToXs6MdDpVFTSyszFW5spEFXQRnHNmjZ8O7y6X3 VfQeqGvvgbfvA7Djw/i/N9bJTk1MgD/paj5fpKcQWudl7Hv08RmsvMdTg w==; X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="358283186" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="358283186" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:00:39 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="701243226" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="701243226" Received: from wonger-mobl.amr.corp.intel.com (HELO khuang2-desk.gar.corp.intel.com) ([10.209.188.34]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:00:33 -0800 From: Kai Huang To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: linux-mm@kvack.org, dave.hansen@intel.com, peterz@infradead.org, tglx@linutronix.de, seanjc@google.com, pbonzini@redhat.com, dan.j.williams@intel.com, rafael.j.wysocki@intel.com, kirill.shutemov@linux.intel.com, ying.huang@intel.com, reinette.chatre@intel.com, len.brown@intel.com, tony.luck@intel.com, ak@linux.intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com, david@redhat.com, bagasdotme@gmail.com, sagis@google.com, imammedo@redhat.com, kai.huang@intel.com Subject: [PATCH v9 05/18] x86/virt/tdx: Add SEAMCALL infrastructure Date: Tue, 14 Feb 2023 00:59:12 +1300 Message-Id: X-Mailer: git-send-email 2.39.1 In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Queue-Id: 17901100038 X-Stat-Signature: 67h5o5mhegt5q67ja5dtxrrmh4pdnemx X-Rspam-User: X-Rspamd-Server: rspam08 X-HE-Tag: 1676289640-527507 X-HE-Meta: U2FsdGVkX18hdH5wOCffS2C9xK3vH46V2YXlslU/h7+lMqbtgOogh+fN6I3COwxX/EIxhe36YQFnHnYiYSK1N4GgDv3J+zIBqiOYtkNAbJi66vTVFdAZfVTJP1P/c3PHaQlAidMgrpxeEumSQXMtvS5pQAYQWeiI4RyK+H8FZMaP4JsmFEqEuj1BzT9ItXPfcft9cxzxOdWKhng+9ppSgJcDoaEHKa5CijM5eZ8EtMhNgfGZhFxOEdkfq8AbUxuEnYblTkC/8tR3ZFIM25Y5ohVToSrT8EHulYKSLyLtXpJlLrxDnVGKLJXnLUPMlaDyJpRXoXWo5aTmTUPncNItOY7Dg1EmsI/dslm5iCp1HUtLSIvaSo8cKLvZumx7+MkeEsUb8UShelcr/Kvd8eTzCLc51MkmaN1bUSxoebt5zHVB7EgKSrMDKJlh/HagoHpzqzcjrjJfM/rVcRnRs70jyvU4khnp5LywHy8RR7vCesN2BxNNCRm30xaXzqdYKOWeiNLkRPT51uZ8a2P6BoxnIhXXM1N8N7eMJ5Ed3kSWUqBhZ024/ijf/nf7M8IV0PZnx1Wz0mMSyp5T43Tm70FqoGVwkkK9dsqg7LD2nqnF4/Sylsq1q8N1c8OjnzJJI7O9vN13NYYAndN8rYAbA6naMPdI/NN+Qm8vQ3sGaOS8tHo131dIUJjR1R/1LsN0l/oniDG1FcUVOBZj+Px509+Qup/+fo91A5SZhnhYLeZK1QR6pm9gs1rYWWuf8M1iPrf4UAmhu7IYK0qAQzf84QiYPWSeOqunGh7MPARe9Sr2B1DSq9Fk84NMWv8Ky/znXDz4kUB7tAh0+Wrmr+8qQ4WkwcNwi00w5abrMI801Ie0DggI9oljH9bqp/yXInp+aiKnpglC83J7sBSIuokdTZhTrufYs8KCYjP+Ulnn+awTxocSxBeRYWgvo1e7F7PIAKejdxjdZXqtjAc2cKL3lfJ DYrPtfkr B4GbDKaoq0i+JsH1+gEWVpc1ShQhZRIXjIcbLHld6Xf+EfmuO2ixvffc6p8LoyGZp59LVj7dK6DS6bWVL/VWKq80oSv8q7Oeg9zrGSK1SKqJRHBAOrWn/dqhbANyeuIX3jZQ/0kqArhyDyyCrG2Uyn2VlcaF9cdglQuITsBKxJhSOfko= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: TDX introduces a new CPU mode: Secure Arbitration Mode (SEAM). This mode runs only the TDX module itself or other code to load the TDX module. The host kernel communicates with SEAM software via a new SEAMCALL instruction. This is conceptually similar to a guest->host hypercall, except it is made from the host to SEAM software instead. The TDX module establishes a new SEAMCALL ABI which allows the host to initialize the module and to manage VMs. Add infrastructure to make SEAMCALLs. The SEAMCALL ABI is very similar to the TDCALL ABI and leverages much TDCALL infrastructure. SEAMCALL instruction causes #GP when TDX isn't BIOS enabled, and #UD when CPU is not in VMX operation. The current TDX_MODULE_CALL macro doesn't handle any of them. There's no way to check whether the CPU is in VMX operation or not. Initializing the TDX module is done at runtime on demand, and it depends on the caller to ensure CPU is in VMX operation before making SEAMCALL. To avoid getting Oops when the caller mistakenly tries to initialize the TDX module when CPU is not in VMX operation, extend the TDX_MODULE_CALL macro to handle #UD (and opportunistically #GP since they share the same assembly). Introduce two new TDX error codes for #UD and #GP respectively so the caller can distinguish. Also, Opportunistically put the new TDX error codes and the existing TDX_SEAMCALL_VMFAILINVALID into INTEL_TDX_HOST Kconfig option as they are only used when it is on. Any failure during the module initialization is not recoverable for now. Print out error message when SEAMCALL failed depending on the error code to help the user to understand what went wrong. Signed-off-by: Kai Huang --- v8 -> v9: - Changed patch title (Dave). - Enhanced seamcall() to include the cpu id to the error message when SEAMCALL fails. v7 -> v8: - Improved changelog (Dave): - Trim down some sentences (Dave). - Removed __seamcall() and seamcall() function name and changed accordingly (Dave). - Improved the sentence explaining why to handle #GP (Dave). - Added code to print out error message in seamcall(), following the idea that tdx_enable() to return universal error and print out error message to make clear what's going wrong (Dave). Also mention this in changelog. v6 -> v7: - No change. v5 -> v6: - Added code to handle #UD and #GP (Dave). - Moved the seamcall() wrapper function to this patch, and used a temporary __always_unused to avoid compile warning (Dave). - v3 -> v5 (no feedback on v4): - Explicitly tell TDX_SEAMCALL_VMFAILINVALID is returned if the SEAMCALL itself fails. - Improve the changelog. --- arch/x86/include/asm/tdx.h | 9 +++++ arch/x86/virt/vmx/tdx/Makefile | 2 +- arch/x86/virt/vmx/tdx/seamcall.S | 52 +++++++++++++++++++++++++++ arch/x86/virt/vmx/tdx/tdx.c | 60 ++++++++++++++++++++++++++++++++ arch/x86/virt/vmx/tdx/tdx.h | 5 +++ arch/x86/virt/vmx/tdx/tdxcall.S | 19 ++++++++-- 6 files changed, 144 insertions(+), 3 deletions(-) create mode 100644 arch/x86/virt/vmx/tdx/seamcall.S diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index 4a3ee64c1ca7..5c5ecfddb15b 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -8,6 +8,10 @@ #include #include +#ifdef CONFIG_INTEL_TDX_HOST + +#include + /* * SW-defined error codes. * @@ -18,6 +22,11 @@ #define TDX_SW_ERROR (TDX_ERROR | GENMASK_ULL(47, 40)) #define TDX_SEAMCALL_VMFAILINVALID (TDX_SW_ERROR | _UL(0xFFFF0000)) +#define TDX_SEAMCALL_GP (TDX_SW_ERROR | X86_TRAP_GP) +#define TDX_SEAMCALL_UD (TDX_SW_ERROR | X86_TRAP_UD) + +#endif + #ifndef __ASSEMBLY__ /* TDX supported page sizes from the TDX module ABI. */ diff --git a/arch/x86/virt/vmx/tdx/Makefile b/arch/x86/virt/vmx/tdx/Makefile index 93ca8b73e1f1..38d534f2c113 100644 --- a/arch/x86/virt/vmx/tdx/Makefile +++ b/arch/x86/virt/vmx/tdx/Makefile @@ -1,2 +1,2 @@ # SPDX-License-Identifier: GPL-2.0-only -obj-y += tdx.o +obj-y += tdx.o seamcall.o diff --git a/arch/x86/virt/vmx/tdx/seamcall.S b/arch/x86/virt/vmx/tdx/seamcall.S new file mode 100644 index 000000000000..f81be6b9c133 --- /dev/null +++ b/arch/x86/virt/vmx/tdx/seamcall.S @@ -0,0 +1,52 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +#include +#include + +#include "tdxcall.S" + +/* + * __seamcall() - Host-side interface functions to SEAM software module + * (the P-SEAMLDR or the TDX module). + * + * Transform function call register arguments into the SEAMCALL register + * ABI. Return TDX_SEAMCALL_VMFAILINVALID if the SEAMCALL itself fails, + * or the completion status of the SEAMCALL leaf function. Additional + * output operands are saved in @out (if it is provided by the caller). + * + *------------------------------------------------------------------------- + * SEAMCALL ABI: + *------------------------------------------------------------------------- + * Input Registers: + * + * RAX - SEAMCALL Leaf number. + * RCX,RDX,R8-R9 - SEAMCALL Leaf specific input registers. + * + * Output Registers: + * + * RAX - SEAMCALL completion status code. + * RCX,RDX,R8-R11 - SEAMCALL Leaf specific output registers. + * + *------------------------------------------------------------------------- + * + * __seamcall() function ABI: + * + * @fn (RDI) - SEAMCALL Leaf number, moved to RAX + * @rcx (RSI) - Input parameter 1, moved to RCX + * @rdx (RDX) - Input parameter 2, moved to RDX + * @r8 (RCX) - Input parameter 3, moved to R8 + * @r9 (R8) - Input parameter 4, moved to R9 + * + * @out (R9) - struct tdx_module_output pointer + * stored temporarily in R12 (not + * used by the P-SEAMLDR or the TDX + * module). It can be NULL. + * + * Return (via RAX) the completion status of the SEAMCALL, or + * TDX_SEAMCALL_VMFAILINVALID. + */ +SYM_FUNC_START(__seamcall) + FRAME_BEGIN + TDX_MODULE_CALL host=1 + FRAME_END + RET +SYM_FUNC_END(__seamcall) diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index f5a20d56097c..5ae3d71b70b4 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -110,6 +110,66 @@ bool platform_tdx_enabled(void) return !!tdx_global_keyid; } +/* + * Wrapper of __seamcall() to convert SEAMCALL leaf function error code + * to kernel error code. @seamcall_ret and @out contain the SEAMCALL + * leaf function return code and the additional output respectively if + * not NULL. + */ +static int __always_unused seamcall(u64 fn, u64 rcx, u64 rdx, u64 r8, u64 r9, + u64 *seamcall_ret, + struct tdx_module_output *out) +{ + int cpu, ret = 0; + u64 sret; + + /* Need a stable CPU id for printing error message */ + cpu = get_cpu(); + + sret = __seamcall(fn, rcx, rdx, r8, r9, out); + + /* Save SEAMCALL return code if the caller wants it */ + if (seamcall_ret) + *seamcall_ret = sret; + + /* SEAMCALL was successful */ + if (!sret) + goto out; + + switch (sret) { + case TDX_SEAMCALL_GP: + /* + * tdx_enable() has already checked that BIOS has + * enabled TDX at the very beginning before going + * forward. It's likely a firmware bug if the + * SEAMCALL still caused #GP. + */ + pr_err_once("[firmware bug]: TDX is not enabled by BIOS.\n"); + ret = -ENODEV; + break; + case TDX_SEAMCALL_VMFAILINVALID: + pr_err_once("TDX module is not loaded.\n"); + ret = -ENODEV; + break; + case TDX_SEAMCALL_UD: + pr_err_once("SEAMCALL failed: CPU %d is not in VMX operation.\n", + cpu); + ret = -EINVAL; + break; + default: + pr_err_once("SEAMCALL failed: CPU %d: leaf %llu, error 0x%llx.\n", + cpu, fn, sret); + if (out) + pr_err_once("additional output: rcx 0x%llx, rdx 0x%llx, r8 0x%llx, r9 0x%llx, r10 0x%llx, r11 0x%llx.\n", + out->rcx, out->rdx, out->r8, + out->r9, out->r10, out->r11); + ret = -EIO; + } +out: + put_cpu(); + return ret; +} + static int init_tdx_module(void) { /* diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index 881cca276956..931a50f0f44c 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -2,6 +2,8 @@ #ifndef _X86_VIRT_TDX_H #define _X86_VIRT_TDX_H +#include + /* Kernel defined TDX module status during module initialization. */ enum tdx_module_status_t { TDX_MODULE_UNKNOWN, @@ -9,4 +11,7 @@ enum tdx_module_status_t { TDX_MODULE_ERROR }; +struct tdx_module_output; +u64 __seamcall(u64 fn, u64 rcx, u64 rdx, u64 r8, u64 r9, + struct tdx_module_output *out); #endif diff --git a/arch/x86/virt/vmx/tdx/tdxcall.S b/arch/x86/virt/vmx/tdx/tdxcall.S index 49a54356ae99..757b0c34be10 100644 --- a/arch/x86/virt/vmx/tdx/tdxcall.S +++ b/arch/x86/virt/vmx/tdx/tdxcall.S @@ -1,6 +1,7 @@ /* SPDX-License-Identifier: GPL-2.0 */ #include #include +#include /* * TDCALL and SEAMCALL are supported in Binutils >= 2.36. @@ -45,6 +46,7 @@ /* Leave input param 2 in RDX */ .if \host +1: seamcall /* * SEAMCALL instruction is essentially a VMExit from VMX root @@ -57,10 +59,23 @@ * This value will never be used as actual SEAMCALL error code as * it is from the Reserved status code class. */ - jnc .Lno_vmfailinvalid + jnc .Lseamcall_out mov $TDX_SEAMCALL_VMFAILINVALID, %rax -.Lno_vmfailinvalid: + jmp .Lseamcall_out +2: + /* + * SEAMCALL caused #GP or #UD. By reaching here %eax contains + * the trap number. Convert the trap number to the TDX error + * code by setting TDX_SW_ERROR to the high 32-bits of %rax. + * + * Note cannot OR TDX_SW_ERROR directly to %rax as OR instruction + * only accepts 32-bit immediate at most. + */ + mov $TDX_SW_ERROR, %r12 + orq %r12, %rax + _ASM_EXTABLE_FAULT(1b, 2b) +.Lseamcall_out: .else tdcall .endif From patchwork Mon Feb 13 11:59:13 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Huang, Kai" X-Patchwork-Id: 13138302 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 488DFC636D7 for ; Mon, 13 Feb 2023 12:00:48 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id DA6DE6B007D; Mon, 13 Feb 2023 07:00:47 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id D30326B007E; Mon, 13 Feb 2023 07:00:47 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id BA9EA6B0080; Mon, 13 Feb 2023 07:00:47 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0016.hostedemail.com [216.40.44.16]) by kanga.kvack.org (Postfix) with ESMTP id AA6DB6B007D for ; Mon, 13 Feb 2023 07:00:47 -0500 (EST) Received: from smtpin24.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay10.hostedemail.com (Postfix) with ESMTP id 78597C0B0E for ; Mon, 13 Feb 2023 12:00:47 +0000 (UTC) X-FDA: 80462126934.24.A32AADE Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by imf14.hostedemail.com (Postfix) with ESMTP id 41A08100004 for ; Mon, 13 Feb 2023 12:00:44 +0000 (UTC) Authentication-Results: imf14.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=JXgMi7ak; spf=pass (imf14.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1676289645; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=lmf70MF5krij5Y4lBqNrIJaapHYZyaFsGjseg0AJ/bQ=; b=phzYje6ScPtKKzDRFDbXYaiuVJSAuARaX8pFB0OOU/ZqU0X10+Tmww/uHAW5uMKuS6AucA Sa2B/c7QcSLzSvnIoUB7sBXoc92iai6NenMfmU6+DokfE7ZgEuWWL9JiTQNt9ItvHjqenm 4tfrob5ndUO4mA8NJaqZ2T4aoCYB74Y= ARC-Authentication-Results: i=1; imf14.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=JXgMi7ak; spf=pass (imf14.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1676289645; a=rsa-sha256; cv=none; b=Mr58w/2R9IU35YRwV6Km0CqVkDMWqHWQWWmjR00CjXfLfdm6onmuSzG+Bc/MVTfLwEEoe4 qQOuS/SFNDtlO2W3StgpKqZmxlplug07Z0gp9yd2QCEDSCRR0dM3ThXvwkeu8HFyIJTcAK BxdCoz5HtEqZ655T9bTpcMaMGp3Pi4E= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1676289645; x=1707825645; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=mUsApv8gVb1LZP98vlXGPOGZoTIkXgs3y140taNjlGw=; b=JXgMi7akNTLFGHVNxSvHG+5obpxB4m7gBaXMS6hGoTym6Ql60lGiR+Do wyhP5jd0afbdaiXofP1uAqdVCiZqRVkOfZ2iOraoIsmieE6fmN9CfSeXl 5C6r0ig4azFkjSfrgNzd0G5nXBkRk42TzMBAoOhjGkjc5hWPpAbp1exQe XlVVHEKMSKGcfK5jvaUGty2QAEqlRAdzV46FMeMi7iqKFoBSF+D/37MBm JnKUa7159Hbq5lx6iuC3nh/dT8dDlQ8MOu7JVIDcboL3+qoo30QkEmUOG uzYl+aTmsk1kpuPaJYOjtgIuG2opU74pEjDdDc7un57lY6N13gSQgAIRQ g==; X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="358283222" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="358283222" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:00:44 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="701243238" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="701243238" Received: from wonger-mobl.amr.corp.intel.com (HELO khuang2-desk.gar.corp.intel.com) ([10.209.188.34]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:00:39 -0800 From: Kai Huang To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: linux-mm@kvack.org, dave.hansen@intel.com, peterz@infradead.org, tglx@linutronix.de, seanjc@google.com, pbonzini@redhat.com, dan.j.williams@intel.com, rafael.j.wysocki@intel.com, kirill.shutemov@linux.intel.com, ying.huang@intel.com, reinette.chatre@intel.com, len.brown@intel.com, tony.luck@intel.com, ak@linux.intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com, david@redhat.com, bagasdotme@gmail.com, sagis@google.com, imammedo@redhat.com, kai.huang@intel.com Subject: [PATCH v9 06/18] x86/virt/tdx: Do TDX module global initialization Date: Tue, 14 Feb 2023 00:59:13 +1300 Message-Id: X-Mailer: git-send-email 2.39.1 In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Queue-Id: 41A08100004 X-Stat-Signature: nxcjar9fww41phpwe4nkrku5pzwrpxxb X-Rspam-User: X-Rspamd-Server: rspam08 X-HE-Tag: 1676289644-530389 X-HE-Meta: U2FsdGVkX18Si+k54zj1YdmqWNsmlccGCBwbOlV3mllCXn4pODauT+Da4s5FkPypgc9kM8YdXEjihrOyhlXgR4kf9eKX/4yh/eokO6TGVCvD0psRLw+L9VxHn+c1+Ehivim8dE6aUOUXZqkxdlqC3Yhp6+Sy06VbS7ehuse4Hac53XexShEk0G0fugixXgYDtfevhpkvxtJELtJ9R+ahQka3RgY7Okkq5fVcStpRVVlEMkKC4Glmhda3nq+X9fxv5cKhYJXKjv8Jrz6FTUCxwdfsqf20R69usW+7IwZvjFSfZCJN0+vYt0IuFPFQOjZijFVGReDE+bQCQEd4aMfKw9noxIVT3vY5vYiVQ0qFmPliIkOW6/JrfHAeuEKSttIhrF6rqqaGlpvDmy1pIWhhwGIQTw6PdGkBH82ZMFgmWWnha94EN100qkfWYTT6mkYsM839Vf9WNUI48zM73ONMSjkcI+SJx2vQa+DCcUdtV7C/e1gSIunS01aUZNQI7EPpgxqst4Rs0U7ed6vaUuc/dvAyZOJ6PynUTE48KsGfQwoiBkIRGqhbKVw1TEyjm2pqNAXXIIczqu6dkKvuRMS3pnkfFR1hIywz4ok4Sm+UIh7BA4utJSLw0yNg1Sr49TvioTUqEi31Y+rYvcecaxYgKKVmSTdjRZKOhqmAhuzf+J3w7l9GGMgNYK3pmukwEQTnRmcZU1Brwb+ZeL3EFoo6fDKvyylQ/qynhoJF3apDza3Yh/hA6i/jBXr2/i0Q0YUn6DttwInviEgQzQnBz+lKQPJyG048fsPtbg52ZHSVxjzNaK29dpvylTxHuFWMGVDF0mK+HU17WCeO3PkOX1uFyoHE8quBMyoFFkQ/069TjGP7w+ebb2wSLWhAgcY4vHj1d/073Z7sLjryTT08GMFRW9JnZXZuyofXTi6kL8DFJ508zLGsYUCgSiX5QRBBw4OCukiXncMLgyt0GJC95+x qapKC4tb 58+9srH/m8JOqFGtvf35fKaJCoRIuCiA1xrliLqCYuZorxlGjFmrcMQjDXCSCpD7+Iimmzy0m0gkupjI++avaAK3aEWycXHbV7x57cG07excKIjOXID9DAmuGoeOjJ1BBwIF5jnNu8Mnv6uVXmmyW0gzqBylspqx67A1gAMpq2Po2mBQ= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: Start to transit out the "multi-steps" of initializing the TDX module as listed in the skeleton infrastructure. Do the first step to do module global initialization, which is one SEAMCALL on any logical cpu. Signed-off-by: Kai Huang Reviewed-by: Isaku Yamahata --- v8 -> v9: - Added this patch back. --- arch/x86/virt/vmx/tdx/tdx.c | 11 ++++++++++- arch/x86/virt/vmx/tdx/tdx.h | 12 ++++++++++++ 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 5ae3d71b70b4..79cee28c51b5 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -172,10 +172,19 @@ static int __always_unused seamcall(u64 fn, u64 rcx, u64 rdx, u64 r8, u64 r9, static int init_tdx_module(void) { + int ret; + + /* + * TDX module global initialization. All '0's are just + * unused parameters. + */ + ret = seamcall(TDH_SYS_INIT, 0, 0, 0, 0, NULL, NULL); + if (ret) + return ret; + /* * TODO: * - * - TDX module global initialization. * - TDX module per-cpu initialization. * - Get TDX module information and TDX-capable memory regions. * - Build the list of TDX-usable memory regions. diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index 931a50f0f44c..55472e085bc8 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -4,6 +4,18 @@ #include +/* + * This file contains both macros and data structures defined by the TDX + * architecture and Linux defined software data structures and functions. + * The two should not be mixed together for better readability. The + * architectural definitions come first. + */ + + /* + * TDX module SEAMCALL leaf functions + */ +#define TDH_SYS_INIT 33 + /* Kernel defined TDX module status during module initialization. */ enum tdx_module_status_t { TDX_MODULE_UNKNOWN, From patchwork Mon Feb 13 11:59:14 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Huang, Kai" X-Patchwork-Id: 13138303 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 97E6DC636D7 for ; Mon, 13 Feb 2023 12:01:22 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 1E91A6B0073; Mon, 13 Feb 2023 07:01:22 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 170196B0075; Mon, 13 Feb 2023 07:01:22 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id F048B6B0078; Mon, 13 Feb 2023 07:01:21 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0017.hostedemail.com [216.40.44.17]) by kanga.kvack.org (Postfix) with ESMTP id DA1A66B0073 for ; Mon, 13 Feb 2023 07:01:21 -0500 (EST) Received: from smtpin13.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay10.hostedemail.com (Postfix) with ESMTP id 57F7FC154B for ; Mon, 13 Feb 2023 12:01:21 +0000 (UTC) X-FDA: 80462128362.13.E481731 Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by imf27.hostedemail.com (Postfix) with ESMTP id 9C9D940026 for ; Mon, 13 Feb 2023 12:01:18 +0000 (UTC) Authentication-Results: imf27.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=J4AqhOIp; spf=pass (imf27.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1676289679; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=i/JLo2mDH8DBL0gG7hrg2RJdPSSCcEHBTLYw2cJFx8g=; b=Qv1zbuRySzpbw+NfDHbtcN5NPNOhpZgkcOmgnB203tPF+BX9l658Fu2i36RSAi83q868XH Q+Q7IuEGxFWd/fD9vEVyMaQNG5BFAT+a7jQrRah65MXwBOWv1aY24LqxlaczcivASE9HOr 3+HUnjBpM2PFW/N7OdwtCqlmRzunl/Y= ARC-Authentication-Results: i=1; imf27.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=J4AqhOIp; spf=pass (imf27.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1676289679; a=rsa-sha256; cv=none; b=OOERY4cIHi8nOPLxB9FPPZ0i9Zf/YL0Gn4tWMdI053+S5/i+L17LHEI/cSu2r8BuLsVDal IV5STTr6JQH7taLBp+uPHo4iKk4zQza2i1a22gHXWLhap++EmA0fJv5EoFv/RG/qGe2txz reo3A9PMYUB3ZfY9dTc4RHC5DH3jmK4= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1676289678; x=1707825678; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=eUYI2f/G5Hw2W0lMnLcgpoR4LJWm2nSFqPt6Km379wQ=; b=J4AqhOIp6kfU5jdj4T2EKNV9Kzl2nSDeK89vZ4H0ocb5QILCsM5cWRfj nd5mTCk9cajsJqlFay4mnzkTb2j7ie85tJkB94dA4aUcN1RnnE6MbHMaH jyI31zTmtRsNGoR6OAKAWlxmNdRSZi70MPPenDgHEWJtsoiCaYTKcuSPS Hjy6CbewySQ/sMAQRG2hUMObcjPPLJ3RwU0qrJRCPiQcsQ6db2+gUXFEV qgenBgXTyGBIzg/UPlq/w3jKShtwfdhk5p28d93/YZJN7wQOZZAxWVsIJ ZvgiAQ+Up7u4YmvTEHFOScYUzaYghPivWaEqQnK7ZJuRN5+dvWAZZ9mZm Q==; X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="358283253" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="358283253" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:00:49 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="701243252" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="701243252" Received: from wonger-mobl.amr.corp.intel.com (HELO khuang2-desk.gar.corp.intel.com) ([10.209.188.34]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:00:44 -0800 From: Kai Huang To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: linux-mm@kvack.org, dave.hansen@intel.com, peterz@infradead.org, tglx@linutronix.de, seanjc@google.com, pbonzini@redhat.com, dan.j.williams@intel.com, rafael.j.wysocki@intel.com, kirill.shutemov@linux.intel.com, ying.huang@intel.com, reinette.chatre@intel.com, len.brown@intel.com, tony.luck@intel.com, ak@linux.intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com, david@redhat.com, bagasdotme@gmail.com, sagis@google.com, imammedo@redhat.com, kai.huang@intel.com Subject: [PATCH v9 07/18] x86/virt/tdx: Do TDX module per-cpu initialization Date: Tue, 14 Feb 2023 00:59:14 +1300 Message-Id: <557c526a1190903d11d67c4e2c76e01f67f6eb15.1676286526.git.kai.huang@intel.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Server: rspam05 X-Rspamd-Queue-Id: 9C9D940026 X-Stat-Signature: 9wd5uzprnd1kuzth3p4xzhesqhabyu6b X-Rspam-User: X-HE-Tag: 1676289678-820354 X-HE-Meta: U2FsdGVkX1+YB64SLp1ZyAa31EhTGchRRMdzb6JZy6jBXljGrupRb4RUDjuhJr4NDk3RF2W4dCbm1EMfNVqdtCDKjiH7QSvhM1mzGKf11o3dUqsHYaLGkGxS53LVsniDi9Jzl+pAmGhVz154RGKZzXOCMd/6wxsmqpX7IkibJ1rNuxMfvM4u9fEtI6EcWN+cjP0T7A7fuRyEZ4SvZZxXVjzhmChcKDzb2uvuTJoZihX7WFX5ybvArv5EqdwtPdZ1mYQaAh+EPD84bSPv2m9CxKEAdu+WS7aNIHuH3x6DvY91nfoK7l394BqszzkvIXZdDsE+1uYcve3AkCdZYappZS6WHMTZj2mxMEBanFWmjpha44ZES9HDJd3TIk6WgPNOPU2OT+V+oVnWVK9bZsaRfxs+zFlSOMjlv2mN4E1imCgj1/8r4AoFG0Upe2nD0SO5cj/MiFtMRyy3Eylh0V4k8GfCt7L76vX8T08j8iRMr8DS1PYmez6kk4edv72adma3sFnCqrNnnyS3KIvBw31FQd6vQizd2wZADkRxxF4IwPay85a0KmmecqVZCchoFo43gqQtTMij/SdgDtRORuCdzuISk4Me91SfFDUE44TQj287KlN0m6OHILgjmsR4bD1VAq/GMma714UkOvz3ZqC4r0lZzxvOk7H99+SuY7UrgzvPdlTUecOmmzs5Q8oTqeqIPSjmkDZR7YafsWCBpTykZ5HPDD/WkUe6WkHw0dP8fZ1Lb3XP18Rj+Id+v8vrTjgDFB4DWgwk9mLBRPjBEjdown3sNY3hWjVMIVWLzzTmpBozqRawt3odqsnBQDzk5W9B1UJBw/lZ0ii1cBOfHU+uYqfAJhjruXTjY4shBqm/Aor3CgqdjfIXpzDHMuuQ/e1gejUyZt88+O29ab/Orpi2B0PccGJnsfxdNQ6NSOfxc9YQ018EZlDhYKils4HxFwz+YVDedAXTkqcXl0+nrte B5fFzvBd eN284jiy5qwfRLtUrUeAoLKOgawfTdsNZYf/BcBtZyjUdNZGQ0kCY0QBtuufbNvRutSs4gDRGWk7VDoVd4jDQKZlszZUI5K5iCVHK6iwKA1RpVsYbTnpPO50Wn3FsIvTG+Inefkn8AIutKnzUdEavIC8s3jjp8HQiNMoYX2uVyRCuKUo= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: After the SEAMCALL to do TDX module global initialization, a SEAMCALL to do per-cpu initialization (TDH.SYS.LP.INIT) must be done on one logical cpu before any other SEAMCALLs can be made on that cpu, including those involved in the future steps of the module initialization. To keep things simple, this implementation just chooses to guarantee all online cpus are "TDX-runnable" (TDH.SYS.LP.INIT has been successfully done on them). If the kernel were to allow one cpu to be online while TDH.SYS.LP.INIT failed on it, the kernel would need to track a cpumask of "TDX-runnable" cpus, know which task is "TDX workload" and guarantee such task can only be scheduled to "TDX-runnable" cpus. For example, the kernel would need to reject in sched_setaffinity() if the userspace tries to bind TDX task to any "non-TDX-runnable" cpu. To guarantee all online cpus are "TDX-runnable", disable the CPU hotplug during module initialization and do TDH.SYS.LP.INIT for all online cpus before any further steps of module initialization. In CPU hotplug, do TDH.SYS.LP.INIT when TDX has been enabled in the CPU online callback and reject to online the cpu if the SEAMCALL fails. Currently only KVM handles VMXON. Similar to tdx_enable(), only provide a new helper tdx_cpu_online() but make KVM itself responsible for doing VMXON and calling tdx_cpu_online() in its own CPU online callback. Note tdx_enable() can be called multiple times by KVM because KVM module can be unloaded and reloaded. New cpus may become online while KVM is unloaded, and in this case TDH.SYS.LP.INIT won't be called for those new online cpus because KVM's CPU online callback is removed when KVM is unloaded. To make sure all online cpus are "TDX-runnable", always do the per-cpu initialization for all online cpus in tdx_enable() even the module has been initialized. Similar to the per-cpu module initialization, a later step to config the key for the global KeyID needs to call some SEAMCALL on one cpu for each CPU package. The difference is that SEAMCALL cannot run in parallel on different cpus but TDH.SYS.LP.INIT can. To avoid duplicated code, add a helper to call SEAMCALL on all online cpus one by one but with a skip function to check whether to skip certain cpus, and use that helper to do the per-cpu initialization. Signed-off-by: Kai Huang --- v8 -> v9: - Added this patch back. - Handled the relaxed new behaviour of TDH.SYS.LP.INIT --- arch/x86/include/asm/tdx.h | 2 + arch/x86/virt/vmx/tdx/tdx.c | 210 +++++++++++++++++++++++++++++++++++- arch/x86/virt/vmx/tdx/tdx.h | 1 + 3 files changed, 208 insertions(+), 5 deletions(-) diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h index 5c5ecfddb15b..2b2efaa4bc0e 100644 --- a/arch/x86/include/asm/tdx.h +++ b/arch/x86/include/asm/tdx.h @@ -107,9 +107,11 @@ static inline long tdx_kvm_hypercall(unsigned int nr, unsigned long p1, #ifdef CONFIG_INTEL_TDX_HOST bool platform_tdx_enabled(void); int tdx_enable(void); +int tdx_cpu_online(unsigned int cpu); #else /* !CONFIG_INTEL_TDX_HOST */ static inline bool platform_tdx_enabled(void) { return false; } static inline int tdx_enable(void) { return -EINVAL; } +static inline int tdx_cpu_online(unsigned int cpu) { return 0; } #endif /* CONFIG_INTEL_TDX_HOST */ #endif /* !__ASSEMBLY__ */ diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 79cee28c51b5..23b2db28726f 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include #include @@ -26,6 +28,10 @@ static enum tdx_module_status_t tdx_module_status; /* Prevent concurrent attempts on TDX module initialization */ static DEFINE_MUTEX(tdx_module_lock); +/* TDX-runnable cpus. Protected by cpu_hotplug_lock. */ +static cpumask_t __cpu_tdx_mask; +static cpumask_t *cpu_tdx_mask = &__cpu_tdx_mask; + /* * Use tdx_global_keyid to indicate that TDX is uninitialized. * This is used in TDX initialization error paths to take it from @@ -170,6 +176,63 @@ static int __always_unused seamcall(u64 fn, u64 rcx, u64 rdx, u64 r8, u64 r9, return ret; } +/* + * Call @func on all online cpus one by one but skip those cpus + * when @skip_func is valid and returns true for them. + */ +static int tdx_on_each_cpu_cond(int (*func)(void *), void *func_data, + bool (*skip_func)(int cpu, void *), + void *skip_data) +{ + int cpu; + + for_each_online_cpu(cpu) { + int ret; + + if (skip_func && skip_func(cpu, skip_data)) + continue; + + /* + * SEAMCALL can be time consuming. Call the @func on + * remote cpu via smp_call_on_cpu() instead of + * smp_call_function_single() to avoid busy waiting. + */ + ret = smp_call_on_cpu(cpu, func, func_data, true); + if (ret) + return ret; + } + + return 0; +} + +static int seamcall_lp_init(void) +{ + /* All '0's are just unused parameters */ + return seamcall(TDH_SYS_LP_INIT, 0, 0, 0, 0, NULL, NULL); +} + +static int smp_func_module_lp_init(void *data) +{ + int ret, cpu = smp_processor_id(); + + ret = seamcall_lp_init(); + if (!ret) + cpumask_set_cpu(cpu, cpu_tdx_mask); + + return ret; +} + +static bool skip_func_module_lp_init_done(int cpu, void *data) +{ + return cpumask_test_cpu(cpu, cpu_tdx_mask); +} + +static int module_lp_init_online_cpus(void) +{ + return tdx_on_each_cpu_cond(smp_func_module_lp_init, NULL, + skip_func_module_lp_init_done, NULL); +} + static int init_tdx_module(void) { int ret; @@ -182,10 +245,26 @@ static int init_tdx_module(void) if (ret) return ret; + /* + * TDX module per-cpu initialization SEAMCALL must be done on + * one cpu before any other SEAMCALLs can be made on that cpu, + * including those involved in further steps to initialize the + * TDX module. + * + * To make sure further SEAMCALLs can be done successfully w/o + * having to consider preemption, disable CPU hotplug during + * rest of module initialization and do per-cpu initialization + * for all online cpus. + */ + cpus_read_lock(); + + ret = module_lp_init_online_cpus(); + if (ret) + goto out; + /* * TODO: * - * - TDX module per-cpu initialization. * - Get TDX module information and TDX-capable memory regions. * - Build the list of TDX-usable memory regions. * - Construct a list of "TD Memory Regions" (TDMRs) to cover @@ -196,7 +275,17 @@ static int init_tdx_module(void) * * Return error before all steps are done. */ - return -EINVAL; + ret = -EINVAL; +out: + /* + * Clear @cpu_tdx_mask if module initialization fails before + * CPU hotplug is re-enabled. tdx_cpu_online() uses it to check + * whether the initialization has been successful or not. + */ + if (ret) + cpumask_clear(cpu_tdx_mask); + cpus_read_unlock(); + return ret; } static int __tdx_enable(void) @@ -220,13 +309,72 @@ static int __tdx_enable(void) return 0; } +/* + * Disable TDX module after it has been initialized successfully. + */ +static void disable_tdx_module(void) +{ + /* + * TODO: module clean up in reverse to steps in + * init_tdx_module(). Remove this comment after + * all steps are done. + */ + cpumask_clear(cpu_tdx_mask); +} + +static int tdx_module_init_online_cpus(void) +{ + int ret; + + /* + * Make sure no cpu can become online to prevent + * race against tdx_cpu_online(). + */ + cpus_read_lock(); + + /* + * Do per-cpu initialization for any new online cpus. + * If any fails, disable TDX. + */ + ret = module_lp_init_online_cpus(); + if (ret) + disable_tdx_module(); + + cpus_read_unlock(); + + return ret; + +} +static int __tdx_enable_online_cpus(void) +{ + if (tdx_module_init_online_cpus()) { + /* + * SEAMCALL failure has already printed + * meaningful error message. + */ + tdx_module_status = TDX_MODULE_ERROR; + + /* + * Just return one universal error code. + * For now the caller cannot recover anyway. + */ + return -EINVAL; + } + + return 0; +} + /** * tdx_enable - Enable TDX to be ready to run TDX guests * * Initialize the TDX module to enable TDX. After this function, the TDX - * module is ready to create and run TDX guests. + * module is ready to create and run TDX guests on all online cpus. + * + * This function internally calls cpus_read_lock()/unlock() to prevent + * any cpu from going online and offline. * * This function assumes all online cpus are already in VMX operation. + * * This function can be called in parallel by multiple callers. * * Return 0 if TDX is enabled successfully, otherwise error. @@ -247,8 +395,17 @@ int tdx_enable(void) ret = __tdx_enable(); break; case TDX_MODULE_INITIALIZED: - /* Already initialized, great, tell the caller. */ - ret = 0; + /* + * The previous call of __tdx_enable() may only have + * initialized part of present cpus during module + * initialization, and new cpus may have become online + * since then. + * + * To make sure all online cpus are TDX-runnable, always + * do per-cpu initialization for all online cpus here + * even the module has been initialized. + */ + ret = __tdx_enable_online_cpus(); break; default: /* Failed to initialize in the previous attempts */ @@ -261,3 +418,46 @@ int tdx_enable(void) return ret; } EXPORT_SYMBOL_GPL(tdx_enable); + +/** + * tdx_cpu_online - Enable TDX on a hotplugged local cpu + * + * @cpu: the cpu to be brought up. + * + * Do TDX module per-cpu initialization for a hotplugged cpu to make + * it TDX-runnable. All online cpus are initialized during module + * initialization. + * + * This function must be called from CPU hotplug callback which holds + * write lock of cpu_hotplug_lock. + * + * This function assumes local cpu is already in VMX operation. + */ +int tdx_cpu_online(unsigned int cpu) +{ + int ret; + + /* + * @cpu_tdx_mask is updated in tdx_enable() and is protected + * by cpus_read_lock()/unlock(). If it is empty, TDX module + * either hasn't been initialized, or TDX didn't get enabled + * successfully. + * + * In either case, do nothing but return success. + */ + if (cpumask_empty(cpu_tdx_mask)) + return 0; + + WARN_ON_ONCE(cpu != smp_processor_id()); + + /* Already done */ + if (cpumask_test_cpu(cpu, cpu_tdx_mask)) + return 0; + + ret = seamcall_lp_init(); + if (!ret) + cpumask_set_cpu(cpu, cpu_tdx_mask); + + return ret; +} +EXPORT_SYMBOL_GPL(tdx_cpu_online); diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index 55472e085bc8..30413d7fbee8 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -15,6 +15,7 @@ * TDX module SEAMCALL leaf functions */ #define TDH_SYS_INIT 33 +#define TDH_SYS_LP_INIT 35 /* Kernel defined TDX module status during module initialization. */ enum tdx_module_status_t { From patchwork Mon Feb 13 11:59:15 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Huang, Kai" X-Patchwork-Id: 13138304 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 5C95BC636CC for ; Mon, 13 Feb 2023 12:01:25 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id F2E9F6B0074; Mon, 13 Feb 2023 07:01:24 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id EB5C26B0075; Mon, 13 Feb 2023 07:01:24 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id CE2BE6B0078; Mon, 13 Feb 2023 07:01:24 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0010.hostedemail.com [216.40.44.10]) by kanga.kvack.org (Postfix) with ESMTP id B819E6B0074 for ; Mon, 13 Feb 2023 07:01:24 -0500 (EST) Received: from smtpin10.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay05.hostedemail.com (Postfix) with ESMTP id 871AC41769 for ; Mon, 13 Feb 2023 12:01:24 +0000 (UTC) X-FDA: 80462128488.10.4D26F5A Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by imf27.hostedemail.com (Postfix) with ESMTP id 4402D40027 for ; Mon, 13 Feb 2023 12:01:21 +0000 (UTC) Authentication-Results: imf27.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=Zc0hpm7Q; spf=pass (imf27.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1676289681; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=tqLXz0VUGb0EBzZzknxQrBJrNDKxzbBKT/WrvbH3EAg=; b=IBswhEqGfEF5tgoXWzQZcTcJn/trNYJusD6KDS3e/Chw6i6LGPtWRoZuLjlOosSRpW33Xa Qc8jd+Iz38h5VPHoCJMNKhqYqxMqo05NdhcGruLXzJt6f2FL2uAApZu8z9HhS9ILObKqpw 9qcxThCzcW54RRiOszBWFES/Rjtyew4= ARC-Authentication-Results: i=1; imf27.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=Zc0hpm7Q; spf=pass (imf27.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1676289681; a=rsa-sha256; cv=none; b=u4Biox+xlWKzBOt4YOYZR34bQ6etXln8GVhl/8ohY4oM/dGyLNR/VyqlOq0G2IytUHwuxI eP4Wv9Y6hNwQUSXfepx93qC14siKnBR3RMqrDVQSDje7BileKkrSS+BE1G2M2W2YXApzB3 0ruRKMhlzhmsyothKl8z3uyrYyQgu7Y= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1676289681; x=1707825681; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=OlCT5mi08fJ1Z5E2TiAQqi7R9htjkGCh91LfZCeJLjQ=; b=Zc0hpm7Q4vMfTrIDlro/m4fiYfCXO5Q4z/hLZyubu2cygra3sBnypXiX czzSbzR0u4OWuD1zFXQ0pn6FjSQat+d7TMJ3JZo9tajUFvrLwbLS/FmZg S66fqkAC9tTmg9saCRVk+d62kBmcOS8MwwIVCraiKdZBbreiGO53u0YnH il5fbb3Ij78XjYhMTfOTAJQmTo8Dpy+xF/+crdN+paYjrAZUSSewiW+pa 682EqGDmcHdcB8BvkYAwA9JHwtcC5gb5FFRJ+PNMb5QpkLvaG54tyR/lj GbrwdqheRz0wDhMs1eUMGX5pOMjLS3LlYk3l6SR0QDHDGFas/Bjm5QoMq g==; X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="358283290" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="358283290" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:00:54 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="701243266" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="701243266" Received: from wonger-mobl.amr.corp.intel.com (HELO khuang2-desk.gar.corp.intel.com) ([10.209.188.34]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:00:49 -0800 From: Kai Huang To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: linux-mm@kvack.org, dave.hansen@intel.com, peterz@infradead.org, tglx@linutronix.de, seanjc@google.com, pbonzini@redhat.com, dan.j.williams@intel.com, rafael.j.wysocki@intel.com, kirill.shutemov@linux.intel.com, ying.huang@intel.com, reinette.chatre@intel.com, len.brown@intel.com, tony.luck@intel.com, ak@linux.intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com, david@redhat.com, bagasdotme@gmail.com, sagis@google.com, imammedo@redhat.com, kai.huang@intel.com Subject: [PATCH v9 08/18] x86/virt/tdx: Get information about TDX module and TDX-capable memory Date: Tue, 14 Feb 2023 00:59:15 +1300 Message-Id: <7a2bc33fd7103d9b9d9c7fa828658ae1861ada49.1676286526.git.kai.huang@intel.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Server: rspam05 X-Rspamd-Queue-Id: 4402D40027 X-Stat-Signature: pm1zfkfhatjrmnrsqstgn5zemnepxkpz X-Rspam-User: X-HE-Tag: 1676289681-267572 X-HE-Meta: U2FsdGVkX18QGIb7JfR6sdWydyVnUYOpncWV8k6hQ847kTb7JIzdCcJwnnl2plL6D7CGsUQPJb6fG73gpptauova8ltNgT9KNq1CWoK+rBFf6ZcgJP0jXFfsKPn7/G3/AYDmaTTZhtUDMpL4+YWjcJ25rG1SQlTgM3S93B5kaXZcVvi9EUvOxEqFUGiZJH1PKppN7JGgTdImRMoiG9SGtaTCcr5krJViTD7GeAYWAr5B+cSTcItWMh7RfbvIBJIcdtbodF4n93kI8uBuzLwqlbtv6upufG7jipkJRe3R5D6z+s3mpDfThPbFOASfrwanWM1SWj1Y0yClAcgOobTztn/EaBhPRs1mNSADm1nNXBoruvgf4PO557BVJN9SiHzozyHsdRCBCOnVqIHLlEw09u0stdnL23S4LqpDPEJxub3AczfMuk6p7xgFeotUwNf+TPgm38APW1puElEvJEkmMtNu90SGAhDHGsDZ7DiFqO4n7ZNU7VQ1xJq15VTN5GHJNOAyLxr6OCvBV1j6DzYjvKYoK4PimjeJrOMa+3aYHaCCJ6BjasSM4+OXk9cuMGk5W4oHw8hHz7JS40Ba746fXVHGssNb8NIpmGsY2g7E+ktZeyslah9u+Ws4QaOvxRoa/XxWREkn+wOi6nqA3w/7i+hPlJQ0f9Fg2EHFSSh/qNhdIQ/fiv93g/LABHdJ8kCxOi2VA0KqXocblwMXlU/3CwMZAR2WLDJtNbZ+E0ZC08ELoKMzo7r4Yg8zMzSOhxDqFeflu/nnalO/ThsJncoWSPROKqkqgeUhPHukUrglBwFTw0Ia6lz4hG+DE3INxBmukx+X4cRjNS0nrUyAFP+jTNaoeKQeWaRVGqCKFvtqU+bk9VGPcFbOwPv5wQsDxmr+q2gRhcbdzPLKwM2VsquIMChNZfjKSrngc5vpGXClb5eGI4EsQzCGvcy6SIWf+LJwFfDhur9O9FYV+pSrY17 ir5nycaQ IgnX4NOAfAsnKu3c/jBA8yDvZrATsIde2NaHis/hpYCWUzY4Tfg8oNUONX523cWkgEypLI9qWyeewwsIm2D27z3H996m7kjTkw296EEAN34P0S1jpqKvaf1qBBdTtkkLaMAgGse9E2d2bJPhpo0ro/FCBttLPqRUuKu94zzWcOyp7cB2lp4xV9mIacINDu5TgBeDu77Ih3Rv7XDH0U9gD7lFkatXgeol0TDQY/bPcRQsVWEc= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: TDX provides increased levels of memory confidentiality and integrity. This requires special hardware support for features like memory encryption and storage of memory integrity checksums. Not all memory satisfies these requirements. As a result, TDX introduced the concept of a "Convertible Memory Region" (CMR). During boot, the firmware builds a list of all of the memory ranges which can provide the TDX security guarantees. CMRs tell the kernel which memory is TDX compatible. The kernel takes CMRs (plus a little more metadata) and constructs "TD Memory Regions" (TDMRs). TDMRs let the kernel grant TDX protections to some or all of the CMR areas. The TDX module also reports necessary information to let the kernel build TDMRs and run TDX guests in structure 'tdsysinfo_struct'. The list of CMRs, along with the TDX module information, is available to the kernel by querying the TDX module. As a preparation to construct TDMRs, get the TDX module information and the list of CMRs. Print out CMRs to help user to decode which memory regions are TDX convertible. The 'tdsysinfo_struct' is fairly large (1024 bytes) and contains a lot of info about the TDX module. Fully define the entire structure, but only use the fields necessary to build the TDMRs and pr_info() some basics about the module. The rest of the fields will get used by KVM. For now both 'tdsysinfo_struct' and CMRs are only used during the module initialization. But because they are both relatively big, declare them inside the module initialization function but as static variables. Signed-off-by: Kai Huang Reviewed-by: Isaku Yamahata --- v8 -> v9: - Removed "start to trransit out ..." part in changelog since this patch is no longer the first step anymore. - Changed to declare 'tdsysinfo' and 'cmr_array' as local static, and changed changelog accordingly (Dave). - Improved changelog to explain why to declare 'tdsysinfo_struct' in full but only use a few members of them (Dave). v7 -> v8: (Dave) - Improved changelog to tell this is the first patch to transit out the "multi-steps" init_tdx_module(). - Removed all CMR check/trim code but to depend on later SEAMCALL. - Variable 'vertical alignment' in print TDX module information. - Added DECLARE_PADDED_STRUCT() for padded structure. - Made tdx_sysinfo and tdx_cmr_array[] to be function local variable (and rename them accordingly), and added -Wframe-larger-than=4096 flag to silence the build warning. v6 -> v7: - Simplified the check of CMRs due to the fact that TDX actually verifies CMRs (that are passed by the BIOS) before enabling TDX. - Changed the function name from check_cmrs() -> trim_empty_cmrs(). - Added CMR page aligned check so that later patch can just get the PFN using ">> PAGE_SHIFT". v5 -> v6: - Added to also print TDX module's attribute (Isaku). - Removed all arguments in tdx_gete_sysinfo() to use static variables of 'tdx_sysinfo' and 'tdx_cmr_array' directly as they are all used directly in other functions in later patches. - Added Isaku's Reviewed-by. - v3 -> v5 (no feedback on v4): - Renamed sanitize_cmrs() to check_cmrs(). - Removed unnecessary sanity check against tdx_sysinfo and tdx_cmr_array actual size returned by TDH.SYS.INFO. - Changed -EFAULT to -EINVAL in couple places. - Added comments around tdx_sysinfo and tdx_cmr_array saying they are used by TDH.SYS.INFO ABI. - Changed to pass 'tdx_sysinfo' and 'tdx_cmr_array' as function arguments in tdx_get_sysinfo(). - Changed to only print BIOS-CMR when check_cmrs() fails. --- arch/x86/virt/vmx/tdx/tdx.c | 65 ++++++++++++++++++++++++++- arch/x86/virt/vmx/tdx/tdx.h | 88 +++++++++++++++++++++++++++++++++++++ 2 files changed, 152 insertions(+), 1 deletion(-) diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 23b2db28726f..ae8e59294b46 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "tdx.h" @@ -233,8 +234,67 @@ static int module_lp_init_online_cpus(void) skip_func_module_lp_init_done, NULL); } +static inline bool is_cmr_empty(struct cmr_info *cmr) +{ + return !cmr->size; +} + +static void print_cmrs(struct cmr_info *cmr_array, int nr_cmrs) +{ + int i; + + for (i = 0; i < nr_cmrs; i++) { + struct cmr_info *cmr = &cmr_array[i]; + + /* + * The array of CMRs reported via TDH.SYS.INFO can + * contain tail empty CMRs. Don't print them. + */ + if (is_cmr_empty(cmr)) + break; + + pr_info("CMR: [0x%llx, 0x%llx)\n", cmr->base, + cmr->base + cmr->size); + } +} + +/* + * Get the TDX module information (TDSYSINFO_STRUCT) and the array of + * CMRs, and save them to @sysinfo and @cmr_array. @sysinfo must have + * been padded to have enough room to save the TDSYSINFO_STRUCT. + */ +static int tdx_get_sysinfo(struct tdsysinfo_struct *sysinfo, + struct cmr_info *cmr_array) +{ + struct tdx_module_output out; + u64 sysinfo_pa, cmr_array_pa; + int ret; + + sysinfo_pa = __pa(sysinfo); + cmr_array_pa = __pa(cmr_array); + ret = seamcall(TDH_SYS_INFO, sysinfo_pa, TDSYSINFO_STRUCT_SIZE, + cmr_array_pa, MAX_CMRS, NULL, &out); + if (ret) + return ret; + + pr_info("TDX module: atributes 0x%x, vendor_id 0x%x, major_version %u, minor_version %u, build_date %u, build_num %u", + sysinfo->attributes, sysinfo->vendor_id, + sysinfo->major_version, sysinfo->minor_version, + sysinfo->build_date, sysinfo->build_num); + + /* R9 contains the actual entries written to the CMR array. */ + print_cmrs(cmr_array, out.r9); + + return 0; +} + static int init_tdx_module(void) { + static DECLARE_PADDED_STRUCT(tdsysinfo_struct, tdsysinfo, + TDSYSINFO_STRUCT_SIZE, TDSYSINFO_STRUCT_ALIGNMENT); + static struct cmr_info cmr_array[MAX_CMRS] + __aligned(CMR_INFO_ARRAY_ALIGNMENT); + struct tdsysinfo_struct *sysinfo = &PADDED_STRUCT(tdsysinfo); int ret; /* @@ -262,10 +322,13 @@ static int init_tdx_module(void) if (ret) goto out; + ret = tdx_get_sysinfo(sysinfo, cmr_array); + if (ret) + goto out; + /* * TODO: * - * - Get TDX module information and TDX-capable memory regions. * - Build the list of TDX-usable memory regions. * - Construct a list of "TD Memory Regions" (TDMRs) to cover * all TDX-usable memory regions. diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index 30413d7fbee8..e32d9920b3a7 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -3,6 +3,94 @@ #define _X86_VIRT_TDX_H #include +#include +#include + +/* + * This file contains both macros and data structures defined by the TDX + * architecture and Linux defined software data structures and functions. + * The two should not be mixed together for better readability. The + * architectural definitions come first. + */ + +/* + * TDX module SEAMCALL leaf functions + */ +#define TDH_SYS_INFO 32 + +struct cmr_info { + u64 base; + u64 size; +} __packed; + +#define MAX_CMRS 32 +#define CMR_INFO_ARRAY_ALIGNMENT 512 + +struct cpuid_config { + u32 leaf; + u32 sub_leaf; + u32 eax; + u32 ebx; + u32 ecx; + u32 edx; +} __packed; + +#define DECLARE_PADDED_STRUCT(type, name, size, alignment) \ + struct type##_padded { \ + union { \ + struct type name; \ + u8 padding[size]; \ + }; \ + } name##_padded __aligned(alignment) + +#define PADDED_STRUCT(name) (name##_padded.name) + +#define TDSYSINFO_STRUCT_SIZE 1024 +#define TDSYSINFO_STRUCT_ALIGNMENT 1024 + +/* + * The size of this structure itself is flexible. The actual structure + * passed to TDH.SYS.INFO must be padded to TDSYSINFO_STRUCT_SIZE and be + * aligned to TDSYSINFO_STRUCT_ALIGNMENT using DECLARE_PADDED_STRUCT(). + */ +struct tdsysinfo_struct { + /* TDX-SEAM Module Info */ + u32 attributes; + u32 vendor_id; + u32 build_date; + u16 build_num; + u16 minor_version; + u16 major_version; + u8 reserved0[14]; + /* Memory Info */ + u16 max_tdmrs; + u16 max_reserved_per_tdmr; + u16 pamt_entry_size; + u8 reserved1[10]; + /* Control Struct Info */ + u16 tdcs_base_size; + u8 reserved2[2]; + u16 tdvps_base_size; + u8 tdvps_xfam_dependent_size; + u8 reserved3[9]; + /* TD Capabilities */ + u64 attributes_fixed0; + u64 attributes_fixed1; + u64 xfam_fixed0; + u64 xfam_fixed1; + u8 reserved4[32]; + u32 num_cpuid_config; + /* + * The actual number of CPUID_CONFIG depends on above + * 'num_cpuid_config'. + */ + DECLARE_FLEX_ARRAY(struct cpuid_config, cpuid_configs); +} __packed; + +/* + * Do not put any hardware-defined TDX structure representations below + * this comment! + */ /* * This file contains both macros and data structures defined by the TDX From patchwork Mon Feb 13 11:59:16 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Huang, Kai" X-Patchwork-Id: 13138307 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0A2BEC636D4 for ; Mon, 13 Feb 2023 12:01:36 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id A24296B007B; Mon, 13 Feb 2023 07:01:35 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 9AD366B007E; Mon, 13 Feb 2023 07:01:35 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 7D91A6B0080; Mon, 13 Feb 2023 07:01:35 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0011.hostedemail.com [216.40.44.11]) by kanga.kvack.org (Postfix) with ESMTP id 6C7D96B007B for ; Mon, 13 Feb 2023 07:01:35 -0500 (EST) Received: from smtpin01.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay05.hostedemail.com (Postfix) with ESMTP id E275541765 for ; Mon, 13 Feb 2023 12:01:34 +0000 (UTC) X-FDA: 80462128908.01.C6B13D0 Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by imf07.hostedemail.com (Postfix) with ESMTP id 198434002D for ; Mon, 13 Feb 2023 12:01:23 +0000 (UTC) Authentication-Results: imf07.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=RrA1PdrG; dmarc=pass (policy=none) header.from=intel.com; spf=pass (imf07.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1676289692; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=MbyKg8euqH1Lxnknf+Yf6rHuxUGctzWjIwEvS3YCu90=; b=wydgfn0HRx9RGCTSjbo1UcQV6Vnmp+uQk8bzD1vWV353tEkIh63hCQde4Ahr+0r/i+SieH R0cw1qQ9rcuagXSbbFVeD0G1JcflyMWtt1/TMvVoldLqgapFRsJ9GYUPdd0jnHhX1tPFz1 ohkHDIw5ffX10nBVFdeMgqQdaajG8xE= ARC-Authentication-Results: i=1; imf07.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=RrA1PdrG; dmarc=pass (policy=none) header.from=intel.com; spf=pass (imf07.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1676289692; a=rsa-sha256; cv=none; b=wTJxtF/G/FhKBpMrYcQmpCCei96E3wlFyC+JsqtnxT4mYVALkbMEwN1qrHvoHNedDpTf7X zLMzDKczCYjlxv5w/ZYqHeU6He1E/wCwvbInzA+hm/W/KJqJsvh6McfOvWNbhZH2/31Duv svrh70Ilvh+hiizDZLV3Cy3gMrc3cCE= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1676289684; x=1707825684; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=HWyQYVqfDv21O43Gac9/BTJItIOh2vDGByh2XxGy4+k=; b=RrA1PdrGDaaqbGAjUMNXeQPgCX6tBu14C4zaWKtB7N3z59QOC9lfk+9Q ynHZCiWzkSXVQcao/7zJ1txwo1DU2JuWo2c3F190fl4pOwYCsdzI2rm3r Gyhn+sxt8/mEZMyrpDR1d18sfZho3e3DyEstlKWRqsGYuI0hnRKUWPvTg aFb0xUHvnS2enAxoFshGY8yLK/arKoWU+7Qavu/C7I5Qe6zljaVd1PVoi 8EcsPR1iBm+cIs5qp/q0JRdnyMy5B/y9PEhWyfFxoUx71vpzBmmt2ZWlJ upQoamXx6DV0+M689R+jez6I7DrB6+bH6pBYgGvgwC7T98aExTG70ARK2 Q==; X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="358283323" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="358283323" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:01:00 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="701243283" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="701243283" Received: from wonger-mobl.amr.corp.intel.com (HELO khuang2-desk.gar.corp.intel.com) ([10.209.188.34]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:00:54 -0800 From: Kai Huang To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: linux-mm@kvack.org, dave.hansen@intel.com, peterz@infradead.org, tglx@linutronix.de, seanjc@google.com, pbonzini@redhat.com, dan.j.williams@intel.com, rafael.j.wysocki@intel.com, kirill.shutemov@linux.intel.com, ying.huang@intel.com, reinette.chatre@intel.com, len.brown@intel.com, tony.luck@intel.com, ak@linux.intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com, david@redhat.com, bagasdotme@gmail.com, sagis@google.com, imammedo@redhat.com, kai.huang@intel.com Subject: [PATCH v9 09/18] x86/virt/tdx: Use all system memory when initializing TDX module as TDX memory Date: Tue, 14 Feb 2023 00:59:16 +1300 Message-Id: X-Mailer: git-send-email 2.39.1 In-Reply-To: References: MIME-Version: 1.0 X-Rspam-User: X-Rspamd-Server: rspam02 X-Rspamd-Queue-Id: 198434002D X-Stat-Signature: b5m71mrqmntdiwck91xogtn7hnmk7dnr X-HE-Tag: 1676289683-244800 X-HE-Meta: U2FsdGVkX18WhGEsyk2e6GS6Ph+vgP+/xyj6MSwXH5dPVupqP3omSMsRDyaR9RMTK2ywubDtuBXufo0PSjBMGh7rIAwQe38xOMp3YZnaWjT/P37hWpU+LYBkESHdezQC5uMDiMQ2Ce+fHYykEgGuB1ttj6KNBY+AkFo3ltixgt7d+MZHy8gn/4uejMJgl8ZMP4SZf5XzyKaYj6nr/Hf9LOyQ6cxWbIBrPPaUVK2TpVHxacQsaWy2HCpW55iS32UpG8Y+zv/jwwcSYD+Ov3Dr7DeWEPTHzf9H992bcGbrpJuV82Lvo4Nb95UV4IsvOMbgIRv09DCnmQWW45cTKO8dAMu4d1f2QX6GHQUH2AoLE8fZRmXtW6sj7PuqTEYXVu34YHtvPS1qYEty6Qqx3ScTn4yOVBBYjXrRlXJCb/ocdje5GWY8cwgorDmrhzBtQnzw2ITEFG9nBoxl2yOyFGQVbZpr8cXjyxx0YMUHIZ2FUinudMAJWzIN3hV3lEc6Ssy6i0JQxPiIt1vWzezNSqHdFmQFRpRp6AP8TsAxgdQ3aXiHT0yFAg5AwiCd6a4oXiEjdj10YV2/2wk7lcDsLcs5wPHZ4S0FRnMChwfXFPusGOf2KS3ldNWrRBqed3Xjp/Z9rAmoRdUp9MMuYD1EJ2jd5w49hEHlfq3jB4Ba+TAkVzA+J3ppi+KG7jiTrXTuzsEagoQw4HtftscxKWd0QOcQrtALwadfSubyuHXglYOaiRgPsorf9nU9VU7wTP7VNUr9bN8yIj+9gCecTGWB5b6956DPwUlY0LwNZdKQKk24biw0uA5KZQqayRnhEl3d20uW9K5GC1wI2Mw2m05Osm3e3w36RZEViIlG5/kwMMj4NH5ekQpTC58Gb8rAkOu9dn5Y6ooLG/LeEVtjMzuxU2vE56yIinfNO8XvMY008qW/Q+wNe6XQoLnvmUfOJ654RgZS9dFmTFHc18zvaHmx6yr l/uWyJZH lMjiZOvOhoRrHNVWvDtLWZC+vXp0aBzrD5IpL+Nll/qVJXC+Rqp3NfCEeTw5rlFVYpjXIueG8jjlXNVMbf/GAppCCc9WVqMxBdZMRSJri318u7jhS2RObTQ5awWdUa2xJzg46oFCU+cHwzeo7F1w4FMcLozKocXXQthCMJjHrkBkuEe0= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: As a step of initializing the TDX module, the kernel needs to tell the TDX module which memory regions can be used by the TDX module as TDX guest memory. TDX reports a list of "Convertible Memory Region" (CMR) to tell the kernel which memory is TDX compatible. The kernel needs to build a list of memory regions (out of CMRs) as "TDX-usable" memory and pass them to the TDX module. Once this is done, those "TDX-usable" memory regions are fixed during module's lifetime. To keep things simple, assume that all TDX-protected memory will come from the page allocator. Make sure all pages in the page allocator *are* TDX-usable memory. As TDX-usable memory is a fixed configuration, take a snapshot of the memory configuration from memblocks at the time of module initialization (memblocks are modified on memory hotplug). This snapshot is used to enable TDX support for *this* memory configuration only. Use a memory hotplug notifier to ensure that no other RAM can be added outside of this configuration. This approach requires all memblock memory regions at the time of module initialization to be TDX convertible memory to work, otherwise module initialization will fail in a later SEAMCALL when passing those regions to the module. This approach works when all boot-time "system RAM" are TDX convertible memory, and no non-TDX-convertible memory is hot-added to the core-mm before module initialization. For instance, on the first generation of TDX machines, both CXL memory and NVDIMM are not TDX convertible memory. Using kmem driver to hot-add any CXL memory or NVDIMM to the core-mm before module initialization will result in module fail to initialize. The SEAMCALL error code will be available in the dmesg to help user to understand the failure. Signed-off-by: Kai Huang Reviewed-by: "Huang, Ying" --- v8 -> v9: - Replace "The initial support ..." with timeless sentence in both changelog and comments(Dave). - Fix run-on sentence in changelog, and senstence to explain why to stash off memblock (Dave). - Tried to improve why to choose this approach and how it work in changelog based on Dave's suggestion. - Many other comments enhancement (Dave). v7 -> v8: - Trimed down changelog (Dave). - Changed to use PHYS_PFN() and PFN_PHYS() throughout this series (Ying). - Moved memory hotplug handling from add_arch_memory() to memory_notifier (Dan/David). - Removed 'nid' from 'struct tdx_memblock' to later patch (Dave). - {build|free}_tdx_memory() -> {build|}free_tdx_memlist() (Dave). - Removed pfn_covered_by_cmr() check as no code to trim CMRs now. - Improve the comment around first 1MB (Dave). - Added a comment around reserve_real_mode() to point out TDX code relies on first 1MB being reserved (Ying). - Added comment to explain why the new online memory range cannot cross multiple TDX memory blocks (Dave). - Improved other comments (Dave). --- arch/x86/Kconfig | 1 + arch/x86/kernel/setup.c | 2 + arch/x86/virt/vmx/tdx/tdx.c | 159 +++++++++++++++++++++++++++++++++++- arch/x86/virt/vmx/tdx/tdx.h | 6 ++ 4 files changed, 167 insertions(+), 1 deletion(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 6dd5d5586099..f23bc540778a 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1958,6 +1958,7 @@ config INTEL_TDX_HOST depends on X86_64 depends on KVM_INTEL depends on X86_X2APIC + select ARCH_KEEP_MEMBLOCK help Intel Trust Domain Extensions (TDX) protects guest VMs from malicious host and certain physical attacks. This option enables necessary TDX diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c index 88188549647c..a8a119a9b48c 100644 --- a/arch/x86/kernel/setup.c +++ b/arch/x86/kernel/setup.c @@ -1165,6 +1165,8 @@ void __init setup_arch(char **cmdline_p) * * Moreover, on machines with SandyBridge graphics or in setups that use * crashkernel the entire 1M is reserved anyway. + * + * Note the host kernel TDX also requires the first 1MB being reserved. */ x86_platform.realmode_reserve(); diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index ae8e59294b46..5101b636a9b0 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -15,6 +15,13 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include #include #include #include @@ -33,6 +40,9 @@ static DEFINE_MUTEX(tdx_module_lock); static cpumask_t __cpu_tdx_mask; static cpumask_t *cpu_tdx_mask = &__cpu_tdx_mask; +/* All TDX-usable memory regions. Protected by mem_hotplug_lock. */ +static LIST_HEAD(tdx_memlist); + /* * Use tdx_global_keyid to indicate that TDX is uninitialized. * This is used in TDX initialization error paths to take it from @@ -71,6 +81,51 @@ static int __init record_keyid_partitioning(u32 *tdx_keyid_start, return 0; } +static bool is_tdx_memory(unsigned long start_pfn, unsigned long end_pfn) +{ + struct tdx_memblock *tmb; + + /* Empty list means TDX isn't enabled. */ + if (list_empty(&tdx_memlist)) + return true; + + /* + * This check assumes that the start_pfn<->end_pfn range does not + * cross multiple @tdx_memlist entries. A single memory online + * event across multiple memblocks (from which @tdx_memlist + * entries are derived at the time of module initialization) is + * not possible. This is because memory offline/online is done + * on granularity of 'struct memory_block', and the hotpluggable + * memory region (one memblock) must be multiple of memory_block. + */ + list_for_each_entry(tmb, &tdx_memlist, list) { + if (start_pfn >= tmb->start_pfn && end_pfn <= tmb->end_pfn) + return true; + } + return false; +} + +static int tdx_memory_notifier(struct notifier_block *nb, unsigned long action, + void *v) +{ + struct memory_notify *mn = v; + + if (action != MEM_GOING_ONLINE) + return NOTIFY_OK; + + /* + * The TDX memory configuration is static and can not be + * changed. Reject onlining any memory which is outside of + * the static configuration whether it supports TDX or not. + */ + return is_tdx_memory(mn->start_pfn, mn->start_pfn + mn->nr_pages) ? + NOTIFY_OK : NOTIFY_BAD; +} + +static struct notifier_block tdx_memory_nb = { + .notifier_call = tdx_memory_notifier, +}; + static int __init tdx_init(void) { u32 tdx_keyid_start, nr_tdx_keyids; @@ -101,6 +156,13 @@ static int __init tdx_init(void) goto no_tdx; } + err = register_memory_notifier(&tdx_memory_nb); + if (err) { + pr_info("initialization failed: register_memory_notifier() failed (%d)\n", + err); + goto no_tdx; + } + tdx_guest_keyid_start = tdx_keyid_start; tdx_nr_guest_keyids = nr_tdx_keyids; @@ -288,6 +350,79 @@ static int tdx_get_sysinfo(struct tdsysinfo_struct *sysinfo, return 0; } +/* + * Add a memory region as a TDX memory block. The caller must make sure + * all memory regions are added in address ascending order and don't + * overlap. + */ +static int add_tdx_memblock(struct list_head *tmb_list, unsigned long start_pfn, + unsigned long end_pfn) +{ + struct tdx_memblock *tmb; + + tmb = kmalloc(sizeof(*tmb), GFP_KERNEL); + if (!tmb) + return -ENOMEM; + + INIT_LIST_HEAD(&tmb->list); + tmb->start_pfn = start_pfn; + tmb->end_pfn = end_pfn; + + /* @tmb_list is protected by mem_hotplug_lock */ + list_add_tail(&tmb->list, tmb_list); + return 0; +} + +static void free_tdx_memlist(struct list_head *tmb_list) +{ + /* @tmb_list is protected by mem_hotplug_lock */ + while (!list_empty(tmb_list)) { + struct tdx_memblock *tmb = list_first_entry(tmb_list, + struct tdx_memblock, list); + + list_del(&tmb->list); + kfree(tmb); + } +} + +/* + * Ensure that all memblock memory regions are convertible to TDX + * memory. Once this has been established, stash the memblock + * ranges off in a secondary structure because memblock is modified + * in memory hotplug while TDX memory regions are fixed. + */ +static int build_tdx_memlist(struct list_head *tmb_list) +{ + unsigned long start_pfn, end_pfn; + int i, ret; + + for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, NULL) { + /* + * The first 1MB is not reported as TDX convertible memory. + * Although the first 1MB is always reserved and won't end up + * to the page allocator, it is still in memblock's memory + * regions. Skip them manually to exclude them as TDX memory. + */ + start_pfn = max(start_pfn, PHYS_PFN(SZ_1M)); + if (start_pfn >= end_pfn) + continue; + + /* + * Add the memory regions as TDX memory. The regions in + * memblock has already guaranteed they are in address + * ascending order and don't overlap. + */ + ret = add_tdx_memblock(tmb_list, start_pfn, end_pfn); + if (ret) + goto err; + } + + return 0; +err: + free_tdx_memlist(tmb_list); + return ret; +} + static int init_tdx_module(void) { static DECLARE_PADDED_STRUCT(tdsysinfo_struct, tdsysinfo, @@ -326,10 +461,25 @@ static int init_tdx_module(void) if (ret) goto out; + /* + * To keep things simple, assume that all TDX-protected memory + * will come from the page allocator. Make sure all pages in the + * page allocator are TDX-usable memory. + * + * Build the list of "TDX-usable" memory regions which cover all + * pages in the page allocator to guarantee that. Do it while + * holding mem_hotplug_lock read-lock as the memory hotplug code + * path reads the @tdx_memlist to reject any new memory. + */ + get_online_mems(); + + ret = build_tdx_memlist(&tdx_memlist); + if (ret) + goto out; + /* * TODO: * - * - Build the list of TDX-usable memory regions. * - Construct a list of "TD Memory Regions" (TDMRs) to cover * all TDX-usable memory regions. * - Configure the TDMRs and the global KeyID to the TDX module. @@ -340,6 +490,12 @@ static int init_tdx_module(void) */ ret = -EINVAL; out: + /* + * @tdx_memlist is written here and read at memory hotplug time. + * Lock out memory hotplug code while building it. + */ + put_online_mems(); + /* * Clear @cpu_tdx_mask if module initialization fails before * CPU hotplug is re-enabled. tdx_cpu_online() uses it to check @@ -382,6 +538,7 @@ static void disable_tdx_module(void) * init_tdx_module(). Remove this comment after * all steps are done. */ + free_tdx_memlist(&tdx_memlist); cpumask_clear(cpu_tdx_mask); } diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index e32d9920b3a7..edb1d697347f 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -112,6 +112,12 @@ enum tdx_module_status_t { TDX_MODULE_ERROR }; +struct tdx_memblock { + struct list_head list; + unsigned long start_pfn; + unsigned long end_pfn; +}; + struct tdx_module_output; u64 __seamcall(u64 fn, u64 rcx, u64 rdx, u64 r8, u64 r9, struct tdx_module_output *out); From patchwork Mon Feb 13 11:59:17 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Huang, Kai" X-Patchwork-Id: 13138305 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id D6714C636CC for ; Mon, 13 Feb 2023 12:01:30 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 73EAD6B0075; Mon, 13 Feb 2023 07:01:30 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 6C7876B0078; Mon, 13 Feb 2023 07:01:30 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 540816B007B; Mon, 13 Feb 2023 07:01:30 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0010.hostedemail.com [216.40.44.10]) by kanga.kvack.org (Postfix) with ESMTP id 425286B0075 for ; Mon, 13 Feb 2023 07:01:30 -0500 (EST) Received: from smtpin05.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay01.hostedemail.com (Postfix) with ESMTP id 1B2951C7022 for ; Mon, 13 Feb 2023 12:01:30 +0000 (UTC) X-FDA: 80462128740.05.F58C6C0 Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by imf27.hostedemail.com (Postfix) with ESMTP id 3743C4001A for ; Mon, 13 Feb 2023 12:01:26 +0000 (UTC) Authentication-Results: imf27.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=fTzLUBq6; spf=pass (imf27.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1676289687; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=VgFCqZR6GidMRT1RYwaIcONkPtUxuGYjqoqxQhvaOYY=; b=iJBjxQWnd+cwPlsQwEyyfqrW6sENXLdybR0xSfDPTrLT5+wo6pmKXIxIZhXRQRpOeVEKOT tjFzBpd9K6R8fL53yLlFxW0iL1xocl1mVxHv4D4DVk9c6072p3NabIQ75bUJcfVaq2o+VH anr8s5u6ItPQsu0xKb3LlTOUj9bsz78= ARC-Authentication-Results: i=1; imf27.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=fTzLUBq6; spf=pass (imf27.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1676289687; a=rsa-sha256; cv=none; b=RWnSiQ6ae3mFKdVxUt4LZ0h4GpaSeeJit0odWcLTglAS5jvpzisfi5jdXnhWk7xQy3bZbh 3dopOIIpz6wj0HZd+/fZE9U8Tiywjpr0Dvb7xXtxk1CGI53ldMkHSvXXNH6XNK5cLpfcNq 5Qv4unI2sw9HTFoM9Pf5OIciqAS5dRE= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1676289687; x=1707825687; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Qg+L2xamk2c4dM8UMQqLpZigSzwKoQvWiqi4pXBJ/Dw=; b=fTzLUBq6Sn9KIOam8DiabYkvnqxW3YLCXraqQ9CnkDxbjNcqfj9OxvM8 4TABBSWjnHE6lm39jsBR3bDzDxgFE2lMKeICDv6NkUiP5/sv/ViDiHa9+ 1N6sbrkkJ6v3j4g/4pwzbJX3H1sgIwpt4mdKJ4V4jMQ5wPy5+k0Pe4GNW SGjJ7BqqIdywD8hqNs57opJzic0gHFus+Y2BJSzyDKCL/+/eZq5rxJL5/ STN7S/hobV78+rKCVIsRB6/uC6WpQoYgUceqKe1JGFZCZ31hOLaukNGoc GSQvhpxXT5yEKKw7mGgyrliaGshcQ88GDwUTI4fmJArtvhm8ItH5DIkg0 Q==; X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="358283349" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="358283349" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:01:05 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="701243352" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="701243352" Received: from wonger-mobl.amr.corp.intel.com (HELO khuang2-desk.gar.corp.intel.com) ([10.209.188.34]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:01:00 -0800 From: Kai Huang To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: linux-mm@kvack.org, dave.hansen@intel.com, peterz@infradead.org, tglx@linutronix.de, seanjc@google.com, pbonzini@redhat.com, dan.j.williams@intel.com, rafael.j.wysocki@intel.com, kirill.shutemov@linux.intel.com, ying.huang@intel.com, reinette.chatre@intel.com, len.brown@intel.com, tony.luck@intel.com, ak@linux.intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com, david@redhat.com, bagasdotme@gmail.com, sagis@google.com, imammedo@redhat.com, kai.huang@intel.com Subject: [PATCH v9 10/18] x86/virt/tdx: Add placeholder to construct TDMRs to cover all TDX memory regions Date: Tue, 14 Feb 2023 00:59:17 +1300 Message-Id: <017a73980fbf276fbd18811ed567462febd2c085.1676286526.git.kai.huang@intel.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Server: rspam05 X-Rspamd-Queue-Id: 3743C4001A X-Stat-Signature: qgmd3s8kegm9hzu58h1kwrsgozdstode X-Rspam-User: X-HE-Tag: 1676289686-431253 X-HE-Meta: U2FsdGVkX19i/7ehSjd+pnT1YYhe2lZA9CkdB4/LT4lBRULeLM4M0rv/0vEaSpWih8I7FF/adkWUns6tJurWShQgeDYt4FYx4O7zJw6F0Ybxa63CNy+a1T91m4TGT0g0ncWK/81thbEQwlrW+htumceztpFA9Wes4IJYNNwA5Rav+bDFOHQphDi+aL8l36Pu5G6Mc4kgZA+eTCq/PFYPGiqq8kKAG8vstYXWwNHBC4OeU3/Cnzdmbj1IxJ3XyKRBTW/MN6GvzLG11FLLWzGezvoPAyxzuXzPsL42Kaa/Ki3d91D4v+adIJkae2ysLyV7BgU/FNhaSnNGPYyl0MOnPhVvZ1yAxYftvNAxoq+auj8CqHnsvBVAJoh91aOCIMcMg/zQQEAJ3oa+KKr80qSLEaOkDaGwwCZGkA0ci2OkkRzhkkDcUC6O+zOr1HkJD+7HZNsQcKHeKSD35fwcexLtENHw9Ilx8xIsOZeYNCzRO+83Cqj5qZEPGrRq/oc5JTRXWI1j3JsecI7F2+4dyEah8pk3dfAVzlKgOY/IIUaMD7O67YAkschlp/rlI0w5ezM0EYfnCXL0x5SSRhVPsXzzXg1F0nJT6e528p8tgctoSszw76ziMFZrHpLo/M6n1O6yLLuLDAnLdov1uVT3xVkaDi4mL7zPpZCWmtlrZTsCPWA1MqKumJSA3W4LJkdjPvoWliqhMnL3Jl1CtnF+y7Vy0PPxGDQ5/cSL9fLm9I9bQbj2lrGKY5h2cUd4Z3DWCHc2vNST6VS81XUcuZupIAIaMxp1+YF7AvSWh3TIgpnxeBnUbSNPn0ChQGsHynyeBfM/Fdq1QwGqwCgOHVIwNurIzOkvHWzKGpD2Lo+kbpmEwhvZetxHgwOy0WeuPEa0VDJyNrjFBuLL+eE2am8VqyZQyUFKqb9tCK/z7ko7PYRynzatp7CEI3MJ7v2gX+OGZqyEXBkoa0Hn6SkSYb/eZ9r d/AQPnDS kjwUHscAKL2TvPXHZTDGRaqirmdgcoDFP+J8bsRW8TUWK2WONcdCsWaZ66AiAXjjwsoPKm246pqBWmXrAjLhwT1s6D46IAIzK3vwK/LDRECBTx77A1Z1VMu49QXReZcMJ549N7p+zQhMZ4tyBhYCXtraTkdvx+WkcKDpF1nr/SqC+jfQ= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: After the kernel selects all TDX-usable memory regions, the kernel needs to pass those regions to the TDX module via data structure "TD Memory Region" (TDMR). Add a placeholder to construct a list of TDMRs (in multiple steps) to cover all TDX-usable memory regions. === Long Version === TDX provides increased levels of memory confidentiality and integrity. This requires special hardware support for features like memory encryption and storage of memory integrity checksums. Not all memory satisfies these requirements. As a result, TDX introduced the concept of a "Convertible Memory Region" (CMR). During boot, the firmware builds a list of all of the memory ranges which can provide the TDX security guarantees. The list of these ranges is available to the kernel by querying the TDX module. The TDX architecture needs additional metadata to record things like which TD guest "owns" a given page of memory. This metadata essentially serves as the 'struct page' for the TDX module. The space for this metadata is not reserved by the hardware up front and must be allocated by the kernel and given to the TDX module. Since this metadata consumes space, the VMM can choose whether or not to allocate it for a given area of convertible memory. If it chooses not to, the memory cannot receive TDX protections and can not be used by TDX guests as private memory. For every memory region that the VMM wants to use as TDX memory, it sets up a "TD Memory Region" (TDMR). Each TDMR represents a physically contiguous convertible range and must also have its own physically contiguous metadata table, referred to as a Physical Address Metadata Table (PAMT), to track status for each page in the TDMR range. Unlike a CMR, each TDMR requires 1G granularity and alignment. To support physical RAM areas that don't meet those strict requirements, each TDMR permits a number of internal "reserved areas" which can be placed over memory holes. If PAMT metadata is placed within a TDMR it must be covered by one of these reserved areas. Let's summarize the concepts: CMR - Firmware-enumerated physical ranges that support TDX. CMRs are 4K aligned. TDMR - Physical address range which is chosen by the kernel to support TDX. 1G granularity and alignment required. Each TDMR has reserved areas where TDX memory holes and overlapping PAMTs can be represented. PAMT - Physically contiguous TDX metadata. One table for each page size per TDMR. Roughly 1/256th of TDMR in size. 256G TDMR = ~1G PAMT. As one step of initializing the TDX module, the kernel configures TDX-usable memory regions by passing a list of TDMRs to the TDX module. Constructing the list of TDMRs consists below steps: 1) Fill out TDMRs to cover all memory regions that the TDX module will use for TD memory. 2) Allocate and set up PAMT for each TDMR. 3) Designate reserved areas for each TDMR. Add a placeholder to construct TDMRs to do the above steps. To keep things simple, just allocate enough space to hold maximum number of TDMRs up front. Although the TDMRs are not used by the TDX module anymore after module initialization, still keep the TDMRs as static as they are needed to find PAMTs when TDX gets disabled after module initialization. Signed-off-by: Kai Huang Reviewed-by: Isaku Yamahata --- v8 -> v9: - Changes around 'struct tdmr_info_list' (Dave): - Moved the declaration from tdx.c to tdx.h. - Renamed 'first_tdmr' to 'tdmrs'. - 'nr_tdmrs' -> 'nr_consumed_tdmrs'. - Changed 'tdmrs' to 'void *'. - Improved comments for all structure members. - Added a missing empty line in alloc_tdmr_list() (Dave). v7 -> v8: - Improved changelog to tell this is one step of "TODO list" in init_tdx_module(). - Other changelog improvement suggested by Dave (with "Create TDMRs" to "Fill out TDMRs" to align with the code). - Added a "TODO list" comment to lay out the steps to construct TDMRs, following the same idea of "TODO list" in tdx_module_init(). - Introduced 'struct tdmr_info_list' (Dave) - Further added additional members (tdmr_sz/max_tdmrs/nr_tdmrs) to simplify getting TDMR by given index, and reduce passing arguments around functions. - Added alloc_tdmr_list()/free_tdmr_list() accordingly, which internally uses tdmr_size_single() (Dave). - tdmr_num -> nr_tdmrs (Dave). v6 -> v7: - Improved commit message to explain 'int' overflow cannot happen in cal_tdmr_size() and alloc_tdmr_array(). -- Andy/Dave. v5 -> v6: - construct_tdmrs_memblock() -> construct_tdmrs() as 'tdx_memblock' is used instead of memblock. - Added Isaku's Reviewed-by. - v3 -> v5 (no feedback on v4): - Moved calculating TDMR size to this patch. - Changed to use alloc_pages_exact() to allocate buffer for all TDMRs once, instead of allocating each TDMR individually. - Removed "crypto protection" in the changelog. - -EFAULT -> -EINVAL in couple of places. --- arch/x86/virt/vmx/tdx/tdx.c | 97 ++++++++++++++++++++++++++++++++++++- arch/x86/virt/vmx/tdx/tdx.h | 32 ++++++++++++ 2 files changed, 127 insertions(+), 2 deletions(-) diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 5101b636a9b0..f604e3399d03 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -43,6 +44,9 @@ static cpumask_t *cpu_tdx_mask = &__cpu_tdx_mask; /* All TDX-usable memory regions. Protected by mem_hotplug_lock. */ static LIST_HEAD(tdx_memlist); +/* The list of TDMRs passed to TDX module */ +struct tdmr_info_list tdx_tdmr_list; + /* * Use tdx_global_keyid to indicate that TDX is uninitialized. * This is used in TDX initialization error paths to take it from @@ -423,6 +427,80 @@ static int build_tdx_memlist(struct list_head *tmb_list) return ret; } +/* Calculate the actual TDMR size */ +static int tdmr_size_single(u16 max_reserved_per_tdmr) +{ + int tdmr_sz; + + /* + * The actual size of TDMR depends on the maximum + * number of reserved areas. + */ + tdmr_sz = sizeof(struct tdmr_info); + tdmr_sz += sizeof(struct tdmr_reserved_area) * max_reserved_per_tdmr; + + return ALIGN(tdmr_sz, TDMR_INFO_ALIGNMENT); +} + +static int alloc_tdmr_list(struct tdmr_info_list *tdmr_list, + struct tdsysinfo_struct *sysinfo) +{ + size_t tdmr_sz, tdmr_array_sz; + void *tdmr_array; + + tdmr_sz = tdmr_size_single(sysinfo->max_reserved_per_tdmr); + tdmr_array_sz = tdmr_sz * sysinfo->max_tdmrs; + + /* + * To keep things simple, allocate all TDMRs together. + * The buffer needs to be physically contiguous to make + * sure each TDMR is physically contiguous. + */ + tdmr_array = alloc_pages_exact(tdmr_array_sz, + GFP_KERNEL | __GFP_ZERO); + if (!tdmr_array) + return -ENOMEM; + + tdmr_list->tdmrs = tdmr_array; + + /* + * Keep the size of TDMR to find the target TDMR + * at a given index in the TDMR list. + */ + tdmr_list->tdmr_sz = tdmr_sz; + tdmr_list->max_tdmrs = sysinfo->max_tdmrs; + tdmr_list->nr_consumed_tdmrs = 0; + + return 0; +} + +static void free_tdmr_list(struct tdmr_info_list *tdmr_list) +{ + free_pages_exact(tdmr_list->tdmrs, + tdmr_list->max_tdmrs * tdmr_list->tdmr_sz); +} + +/* + * Construct a list of TDMRs on the preallocated space in @tdmr_list + * to cover all TDX memory regions in @tmb_list based on the TDX module + * information in @sysinfo. + */ +static int construct_tdmrs(struct list_head *tmb_list, + struct tdmr_info_list *tdmr_list, + struct tdsysinfo_struct *sysinfo) +{ + /* + * TODO: + * + * - Fill out TDMRs to cover all TDX memory regions. + * - Allocate and set up PAMTs for each TDMR. + * - Designate reserved areas for each TDMR. + * + * Return -EINVAL until constructing TDMRs is done + */ + return -EINVAL; +} + static int init_tdx_module(void) { static DECLARE_PADDED_STRUCT(tdsysinfo_struct, tdsysinfo, @@ -477,11 +555,19 @@ static int init_tdx_module(void) if (ret) goto out; + /* Allocate enough space for constructing TDMRs */ + ret = alloc_tdmr_list(&tdx_tdmr_list, sysinfo); + if (ret) + goto out_free_tdx_mem; + + /* Cover all TDX-usable memory regions in TDMRs */ + ret = construct_tdmrs(&tdx_memlist, &tdx_tdmr_list, sysinfo); + if (ret) + goto out_free_tdmrs; + /* * TODO: * - * - Construct a list of "TD Memory Regions" (TDMRs) to cover - * all TDX-usable memory regions. * - Configure the TDMRs and the global KeyID to the TDX module. * - Configure the global KeyID on all packages. * - Initialize all TDMRs. @@ -489,6 +575,12 @@ static int init_tdx_module(void) * Return error before all steps are done. */ ret = -EINVAL; +out_free_tdmrs: + if (ret) + free_tdmr_list(&tdx_tdmr_list); +out_free_tdx_mem: + if (ret) + free_tdx_memlist(&tdx_memlist); out: /* * @tdx_memlist is written here and read at memory hotplug time. @@ -538,6 +630,7 @@ static void disable_tdx_module(void) * init_tdx_module(). Remove this comment after * all steps are done. */ + free_tdmr_list(&tdx_tdmr_list); free_tdx_memlist(&tdx_memlist); cpumask_clear(cpu_tdx_mask); } diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index edb1d697347f..66c7617b357c 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -87,6 +87,29 @@ struct tdsysinfo_struct { DECLARE_FLEX_ARRAY(struct cpuid_config, cpuid_configs); } __packed; +struct tdmr_reserved_area { + u64 offset; + u64 size; +} __packed; + +#define TDMR_INFO_ALIGNMENT 512 + +struct tdmr_info { + u64 base; + u64 size; + u64 pamt_1g_base; + u64 pamt_1g_size; + u64 pamt_2m_base; + u64 pamt_2m_size; + u64 pamt_4k_base; + u64 pamt_4k_size; + /* + * Actual number of reserved areas depends on + * 'struct tdsysinfo_struct'::max_reserved_per_tdmr. + */ + DECLARE_FLEX_ARRAY(struct tdmr_reserved_area, reserved_areas); +} __packed __aligned(TDMR_INFO_ALIGNMENT); + /* * Do not put any hardware-defined TDX structure representations below * this comment! @@ -118,6 +141,15 @@ struct tdx_memblock { unsigned long end_pfn; }; +struct tdmr_info_list { + void *tdmrs; /* Flexible array to hold 'tdmr_info's */ + int nr_consumed_tdmrs; /* How many 'tdmr_info's are in use */ + + /* Metadata for finding target 'tdmr_info' and freeing @tdmrs */ + int tdmr_sz; /* Size of one 'tdmr_info' */ + int max_tdmrs; /* How many 'tdmr_info's are allocated */ +}; + struct tdx_module_output; u64 __seamcall(u64 fn, u64 rcx, u64 rdx, u64 r8, u64 r9, struct tdx_module_output *out); From patchwork Mon Feb 13 11:59:18 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Huang, Kai" X-Patchwork-Id: 13138306 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 35737C636D4 for ; Mon, 13 Feb 2023 12:01:33 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id CBD226B0078; Mon, 13 Feb 2023 07:01:32 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id BF98D6B007B; Mon, 13 Feb 2023 07:01:32 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id A228A6B007E; Mon, 13 Feb 2023 07:01:32 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0012.hostedemail.com [216.40.44.12]) by kanga.kvack.org (Postfix) with ESMTP id 8E8CF6B0078 for ; Mon, 13 Feb 2023 07:01:32 -0500 (EST) Received: from smtpin22.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay09.hostedemail.com (Postfix) with ESMTP id 52748815FE for ; Mon, 13 Feb 2023 12:01:32 +0000 (UTC) X-FDA: 80462128824.22.A1CF3CD Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by imf27.hostedemail.com (Postfix) with ESMTP id EF07840024 for ; Mon, 13 Feb 2023 12:01:29 +0000 (UTC) Authentication-Results: imf27.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=cgliCOfl; spf=pass (imf27.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1676289690; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=Tr7vtxE7jDcbxprf4UmD76gcQ+Qef0jvU/HjSIe2whY=; b=7w52GmC3R34ecbOdle1xmO3T9k6dwS8iICBUa5vKpla/RbU0xVnzGvFoz4Zb9xEXWet4uS DnlQE8UkNUfD8Xs2jiA3GMIBV65QbABhYoD52gsv8QYe2j4kak+IiQnCVex9Hf3FG5f1WV MhnMtbTFBWLhnn/93SY0oBz67SyZlSs= ARC-Authentication-Results: i=1; imf27.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=cgliCOfl; spf=pass (imf27.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1676289690; a=rsa-sha256; cv=none; b=2GE+2uJkJCWIWOPvACOtfAnfXMZ62djE+fjpS5v1vz0hZfBphaxvE7fH7eUQZZ31FT6b7O gzww34chhAN2lfQHv2rJRFldqTTuuyjWdOrWW2AqEZLjWuiaUVtgmwSS0hDMTvLx/3OQaM xI1buPaJQ54H4IrcFKugdvHxa3GJJMU= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1676289690; x=1707825690; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=fHOs3sHTQVlPGDUyZEr3B2p6A0ySFsXFodjDNyu3joU=; b=cgliCOflXFLsPjB4ibGAWpBU1Rm1TOS/sPJgszJ1gTqZig3uS1gosdJU h9Gbh4p01mIV/mKGt1tyRpBAONibiEqbF/7HR8Ur883X0uq1zOUlR4J4y ARkakYZ17i0uxOVcScjWzv8OYMi1Nmpw41nuthZBVLhTFMJO8J1l5OCSk W0WkjY0iyNgXg5ryzPhMomdbLRUZvvAT12h9DigLv9qDW3oy0j7qZNWaP U9YFIob8MGTzA5AFQ9IGfJ2x06bLLtkb+MNiUCx0kjfiS4BgMMdglAJ9T COEAh5B0h8IXQCQTDtW2tnGczZstO3TtN7kq+IZsGQ2d5KPi/kqYc9yWM Q==; X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="358283371" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="358283371" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:01:10 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="701243403" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="701243403" Received: from wonger-mobl.amr.corp.intel.com (HELO khuang2-desk.gar.corp.intel.com) ([10.209.188.34]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:01:05 -0800 From: Kai Huang To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: linux-mm@kvack.org, dave.hansen@intel.com, peterz@infradead.org, tglx@linutronix.de, seanjc@google.com, pbonzini@redhat.com, dan.j.williams@intel.com, rafael.j.wysocki@intel.com, kirill.shutemov@linux.intel.com, ying.huang@intel.com, reinette.chatre@intel.com, len.brown@intel.com, tony.luck@intel.com, ak@linux.intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com, david@redhat.com, bagasdotme@gmail.com, sagis@google.com, imammedo@redhat.com, kai.huang@intel.com Subject: [PATCH v9 11/18] x86/virt/tdx: Fill out TDMRs to cover all TDX memory regions Date: Tue, 14 Feb 2023 00:59:18 +1300 Message-Id: <2de22607f9e00d6b9beb3ca9922c30911650c2c1.1676286526.git.kai.huang@intel.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Server: rspam05 X-Rspamd-Queue-Id: EF07840024 X-Stat-Signature: 98dw4nroe4s1pe39z7kkb8k5c1ixdfmk X-Rspam-User: X-HE-Tag: 1676289689-638328 X-HE-Meta: U2FsdGVkX18WxFPzEkz3GGuQz/2I241VHdfOyDOa/MBMHAhT+L7zhPa/Alvu5I1uxTyjIInOUFuIZ0Q9OJCHqDgKkOo9sNHal1w60+1FLVFzEByc0guaQkHAHMZSFJpxBQ4b6xJ5mlP1LRoDFSftVGk/gG21LWnGDWrVxvTQsaui1qoU/DBlYlxT8A/Uc3EYSxDDxeOVKqqjrZZPYmoXzA8S44BlH4StPoqabtxhgNMbsalQolkS2ViEvWWIGkffdf33txqu5l2xZOsY+TfaRn3gwVi7G7ASjQh8fvC8giahxJJnEbouvNOAxuTzECVcplvDdreu5HqvXbzzCM7cI7t9KcaYXJXkasDX0oFn790HGGkQfIU5BJtHo7u5KFkpl7gUnNFBXQyPwjoiNa/FysAiFC/PJLPFXqY7ASBkj32eYgkP39FqBmtvJXYA9rq6xE4lybFM+P2+HjtmLsZ5+yeU7e2zAVE9tLmGpVGQb8/Bt8oVxv8Ve4IauUAybvr1emHVRxJwJtb+i9hezn+G7AR0seUyTNrS5DpvKVmXltz6IbSPK1aZZvcKNy4l7LnkjLN29aruTmTbtM4MXhbkSoENACvuIpz47r2iiGxf0XqMyOky4rur/KIMlX033ckUSAcWWdnhA9b82BrMGiGw15s96GYZtydU1ehTzK9DPsRTAsqYaDGobeiiq6Qr8yU90cuJ7RlnIgGi3I9t0GTc46oW6hxviPtQ5LGuk9sJWp6emIb7/M5Y50rGooir72sVYN29xBikHlPvWKWjr+E+ODWVNeqS/OHx3rl0owxLGW+Siyqbb8F756+98YTTbyrca/lXgLG/9wDT0YnKq+daHGSb0iEPUCBKCxM3UgfuAT6A2ehRlTvpVZtkf4bEoEFUooh7gVMX2P7G+jbNpheEoCKnW0Eh7n4WmQX6ub0U7dtRGDKr9KTulvPP8tFYtr71cU8+um3Gf0RO3Sb20G3 TecLjFlS EN9+RVj3px7Ls21Q+UPCQnwrlvy85RPuEzCZHHQZcasv1Yv/SgRURNs31h9RhgYsbiB0U0ngEsFjv1dXw1ZnvMTbockHDuKXMiYCvwu1KzEZc1QohAtSjZHlrwA6gnvTwXczvY3HF09oYSpvcqesViTscOCrFu5XGB921nWLPkyb+4kU= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: Start to transit out the "multi-steps" to construct a list of "TD Memory Regions" (TDMRs) to cover all TDX-usable memory regions. The kernel configures TDX-usable memory regions by passing a list of TDMRs "TD Memory Regions" (TDMRs) to the TDX module. Each TDMR contains the information of the base/size of a memory region, the base/size of the associated Physical Address Metadata Table (PAMT) and a list of reserved areas in the region. Do the first step to fill out a number of TDMRs to cover all TDX memory regions. To keep it simple, always try to use one TDMR for each memory region. As the first step only set up the base/size for each TDMR. Each TDMR must be 1G aligned and the size must be in 1G granularity. This implies that one TDMR could cover multiple memory regions. If a memory region spans the 1GB boundary and the former part is already covered by the previous TDMR, just use a new TDMR for the remaining part. TDX only supports a limited number of TDMRs. Disable TDX if all TDMRs are consumed but there is more memory region to cover. There are fancier things that could be done like trying to merge adjacent TDMRs. This would allow more pathological memory layouts to be supported. But, current systems are not even close to exhausting the existing TDMR resources in practice. For now, keep it simple. Signed-off-by: Kai Huang --- v8 -> v9: - Added the last paragraph in the changelog (Dave). - Removed unnecessary type cast in tdmr_entry() (Dave). --- arch/x86/virt/vmx/tdx/tdx.c | 94 ++++++++++++++++++++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index f604e3399d03..5ff346871b4b 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -480,6 +480,93 @@ static void free_tdmr_list(struct tdmr_info_list *tdmr_list) tdmr_list->max_tdmrs * tdmr_list->tdmr_sz); } +/* Get the TDMR from the list at the given index. */ +static struct tdmr_info *tdmr_entry(struct tdmr_info_list *tdmr_list, + int idx) +{ + int tdmr_info_offset = tdmr_list->tdmr_sz * idx; + + return (void *)tdmr_list->tdmrs + tdmr_info_offset; +} + +#define TDMR_ALIGNMENT BIT_ULL(30) +#define TDMR_PFN_ALIGNMENT (TDMR_ALIGNMENT >> PAGE_SHIFT) +#define TDMR_ALIGN_DOWN(_addr) ALIGN_DOWN((_addr), TDMR_ALIGNMENT) +#define TDMR_ALIGN_UP(_addr) ALIGN((_addr), TDMR_ALIGNMENT) + +static inline u64 tdmr_end(struct tdmr_info *tdmr) +{ + return tdmr->base + tdmr->size; +} + +/* + * Take the memory referenced in @tmb_list and populate the + * preallocated @tdmr_list, following all the special alignment + * and size rules for TDMR. + */ +static int fill_out_tdmrs(struct list_head *tmb_list, + struct tdmr_info_list *tdmr_list) +{ + struct tdx_memblock *tmb; + int tdmr_idx = 0; + + /* + * Loop over TDX memory regions and fill out TDMRs to cover them. + * To keep it simple, always try to use one TDMR to cover one + * memory region. + * + * In practice TDX1.0 supports 64 TDMRs, which is big enough to + * cover all memory regions in reality if the admin doesn't use + * 'memmap' to create a bunch of discrete memory regions. When + * there's a real problem, enhancement can be done to merge TDMRs + * to reduce the final number of TDMRs. + */ + list_for_each_entry(tmb, tmb_list, list) { + struct tdmr_info *tdmr = tdmr_entry(tdmr_list, tdmr_idx); + u64 start, end; + + start = TDMR_ALIGN_DOWN(PFN_PHYS(tmb->start_pfn)); + end = TDMR_ALIGN_UP(PFN_PHYS(tmb->end_pfn)); + + /* + * A valid size indicates the current TDMR has already + * been filled out to cover the previous memory region(s). + */ + if (tdmr->size) { + /* + * Loop to the next if the current memory region + * has already been fully covered. + */ + if (end <= tdmr_end(tdmr)) + continue; + + /* Otherwise, skip the already covered part. */ + if (start < tdmr_end(tdmr)) + start = tdmr_end(tdmr); + + /* + * Create a new TDMR to cover the current memory + * region, or the remaining part of it. + */ + tdmr_idx++; + if (tdmr_idx >= tdmr_list->max_tdmrs) { + pr_warn("initialization failed: TDMRs exhausted.\n"); + return -ENOSPC; + } + + tdmr = tdmr_entry(tdmr_list, tdmr_idx); + } + + tdmr->base = start; + tdmr->size = end - start; + } + + /* @tdmr_idx is always the index of last valid TDMR. */ + tdmr_list->nr_consumed_tdmrs = tdmr_idx + 1; + + return 0; +} + /* * Construct a list of TDMRs on the preallocated space in @tdmr_list * to cover all TDX memory regions in @tmb_list based on the TDX module @@ -489,10 +576,15 @@ static int construct_tdmrs(struct list_head *tmb_list, struct tdmr_info_list *tdmr_list, struct tdsysinfo_struct *sysinfo) { + int ret; + + ret = fill_out_tdmrs(tmb_list, tdmr_list); + if (ret) + return ret; + /* * TODO: * - * - Fill out TDMRs to cover all TDX memory regions. * - Allocate and set up PAMTs for each TDMR. * - Designate reserved areas for each TDMR. * From patchwork Mon Feb 13 11:59:19 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Huang, Kai" X-Patchwork-Id: 13138308 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 407B8C636CC for ; Mon, 13 Feb 2023 12:01:37 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 89E2B6B007E; Mon, 13 Feb 2023 07:01:36 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 7D8D46B0080; Mon, 13 Feb 2023 07:01:36 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 5DE536B0081; Mon, 13 Feb 2023 07:01:36 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0015.hostedemail.com [216.40.44.15]) by kanga.kvack.org (Postfix) with ESMTP id 499856B007E for ; Mon, 13 Feb 2023 07:01:36 -0500 (EST) Received: from smtpin16.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay08.hostedemail.com (Postfix) with ESMTP id D42F11416CB for ; Mon, 13 Feb 2023 12:01:35 +0000 (UTC) X-FDA: 80462128950.16.5B4ADD1 Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by imf11.hostedemail.com (Postfix) with ESMTP id 758624002E for ; Mon, 13 Feb 2023 12:01:33 +0000 (UTC) Authentication-Results: imf11.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=VOMG7BM8; dmarc=pass (policy=none) header.from=intel.com; spf=pass (imf11.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1676289693; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=9mJgchGaF6Ynu7QUYd0jvHBwMvPkq4TjLllH0wWD2qg=; b=Z/Li3MsMJrf6QaWSukdGlrZ6kXRbJnu+c22Ja4nQetBtQ6tW1bq3l/EvllyIAKhfXBVQvj SVmYZ5mxFm0mJtMKH0iBfB/G731vJAFHw3yxYCAucUFLKbQZPGrxqe7BN0cA1KDM+QmH7p 31a+04rYu+GHErH+Vym+vSZpatBHo/s= ARC-Authentication-Results: i=1; imf11.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=VOMG7BM8; dmarc=pass (policy=none) header.from=intel.com; spf=pass (imf11.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1676289693; a=rsa-sha256; cv=none; b=hNWR/ovcLBcyU4dtg/aJG5tKRYDkbZagZHSgvxnBf6RFwLqQsuMymfgQf0aUUR/uYVC5il Rx1hlN3ILa5isRAIBjFtc0nNiiKL+S+/Z2GzzWz5NW7Ngi+grSjFyXG1AbOXy+K4Q1V+A+ PBWp4LFbcKS3F0dtFxFL3upUsXsVdTY= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1676289693; x=1707825693; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=Emd7ZKNJK0qIvzZuy5qijXUOyMUcqlj1gjNqVrMTEGA=; b=VOMG7BM85CcPWONRNu0NRJZ1eA3Mt383hPtRPCBhar5NC0wbvF92wccn prNnlU0PG4sYfldCsmpfx2zIpQUfGIG/9uyzTB0rqXn+h+2Zb2h1ipOMU cLgr3ztHJZ734JRC7E0YLgcADT+dBAE03KhionwWiKrtwtMOONh/Pl3OA kf7W+zc/ajsLH7ypf99uUiMsPKQCltiR1MFUCjViIp4blQi0GfkH17CFw OhbHK9/Y7QSLNAWGyAEOoLaCczrUoUCABBCuhWm7X4bU5phIeqXQPsDck KlPINelTPsmMKyrFNkRS9qwJiEqHXpgfl9bVIymj/QQYiURJwbYbex7ac Q==; X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="358283406" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="358283406" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:01:16 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="701243432" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="701243432" Received: from wonger-mobl.amr.corp.intel.com (HELO khuang2-desk.gar.corp.intel.com) ([10.209.188.34]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:01:10 -0800 From: Kai Huang To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: linux-mm@kvack.org, dave.hansen@intel.com, peterz@infradead.org, tglx@linutronix.de, seanjc@google.com, pbonzini@redhat.com, dan.j.williams@intel.com, rafael.j.wysocki@intel.com, kirill.shutemov@linux.intel.com, ying.huang@intel.com, reinette.chatre@intel.com, len.brown@intel.com, tony.luck@intel.com, ak@linux.intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com, david@redhat.com, bagasdotme@gmail.com, sagis@google.com, imammedo@redhat.com, kai.huang@intel.com Subject: [PATCH v9 12/18] x86/virt/tdx: Allocate and set up PAMTs for TDMRs Date: Tue, 14 Feb 2023 00:59:19 +1300 Message-Id: <25f6a0f58d803ac084cb6787e1a89217b9867cf8.1676286526.git.kai.huang@intel.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Queue-Id: 758624002E X-Rspamd-Server: rspam09 X-Rspam-User: X-Stat-Signature: amg1skj3zbmcpnp36a3rd4amgoma54m7 X-HE-Tag: 1676289693-406757 X-HE-Meta: U2FsdGVkX1/lBDjtGqsEk/A8C80yWoCWacrNYlKQ5dgy4RzhwFGB6Ww1MyxQN0G/z2eCb78SXugSN5cW/xs5qu52/CuKSlRBHGM/y/d0L/353EGZlPDy5hJQdxlOZgYQG6A8KoQTkjVoAgKQcZi13wEVb0YVp9N8zTY6RMWSm/4ztskZO4VwzAB11e1tpWZaUh50UM1uPavcnmBOn8SyxTUkdcg+U+JYBOsZ7+7RxuRJXQO3bgHdrySl/N9u5sSodgyg5xYI4C6PF2TFlEuRNASXC2nqwplymjpfI2jAqozAPbSunWT3bsADsdGIg1NoHtSe4IhVrVh4nxsxJQATJ/b5cs1fjDMGnfsXdjdNJUV9ZIr6eCZQlwYNY3Y8dxY1g6V4IUN49JvxqfadiQqWj3M07wxoIQDLXLxCajYwyhCAaxOwld/6yCzgMjf0UaOnlFkS2QOQiHTDHl7ecWo31ZuSEErK2vaZQ0bNf1wR5d4NFx8QgOI1nncQ9CmODyjiUzkI2Le8gvjJh4WX/Gl/mJZ0m1pWNuG6LKXOrBdYF1RxprS3O8lz2uFwnxAJ6iw32AtN0DFRn+nTovtkOBnVtC977IN1KZ0gphBFgieWSOUjuflCrpUh63Mc8HT/aX4NOpUknyxwRewKBuvVQvbkHOdxTbx7rjhDdLzltHOem5+dKePsaBmYMRSZalAE6lYVsxrz9oU02eSHHol97OtDdcYq0mr2r5esCbmwCRsb8sCAyRyuKMQ2LYIXxVqgAUedbRd34fAiDNAmMgOi29fwFmwOYNywr0MALxC5Bq+s6rQeAeVdAeuvX6EXK0uYXrNZZk461nhlvAQnMAUaq1UOjjR1Z7HKELtHudfx3WKMghc2+RT0kS69CI2rNr05iZdhY54sJl296FZflKSHH1jZKXeeTHR0dNug0V9L0pHxH3fh+j6GWb24hNDbLcmrX9WzvrLuAVuq8fdQlC2/Nhd kZgQeW6m qtHNRF9zOD6mtsixtCmKBW633m8hpC6SFfop5XmO9Bjf2JhCW2s5fhq0rtomPMas5R2MGhTs/Qq/XSegtHLyjSOVsE2RSY4TNiM8WF72DfuMtCfMHL0wLmTKmR9PVqGmtEmTmqm//LfQOtFkmpuG1PISHRmRs76W4fSloB5ay15ffFY4= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: The TDX module uses additional metadata to record things like which guest "owns" a given page of memory. This metadata, referred as Physical Address Metadata Table (PAMT), essentially serves as the 'struct page' for the TDX module. PAMTs are not reserved by hardware up front. They must be allocated by the kernel and then given to the TDX module during module initialization. TDX supports 3 page sizes: 4K, 2M, and 1G. Each "TD Memory Region" (TDMR) has 3 PAMTs to track the 3 supported page sizes. Each PAMT must be a physically contiguous area from a Convertible Memory Region (CMR). However, the PAMTs which track pages in one TDMR do not need to reside within that TDMR but can be anywhere in CMRs. If one PAMT overlaps with any TDMR, the overlapping part must be reported as a reserved area in that particular TDMR. Use alloc_contig_pages() since PAMT must be a physically contiguous area and it may be potentially large (~1/256th of the size of the given TDMR). The downside is alloc_contig_pages() may fail at runtime. One (bad) mitigation is to launch a TDX guest early during system boot to get those PAMTs allocated at early time, but the only way to fix is to add a boot option to allocate or reserve PAMTs during kernel boot. It is imperfect but will be improved on later. TDX only supports a limited number of reserved areas per TDMR to cover both PAMTs and memory holes within the given TDMR. If many PAMTs are allocated within a single TDMR, the reserved areas may not be sufficient to cover all of them. Adopt the following policies when allocating PAMTs for a given TDMR: - Allocate three PAMTs of the TDMR in one contiguous chunk to minimize the total number of reserved areas consumed for PAMTs. - Try to first allocate PAMT from the local node of the TDMR for better NUMA locality. Also dump out how many pages are allocated for PAMTs when the TDX module is initialized successfully. This helps answer the eternal "where did all my memory go?" questions. Signed-off-by: Kai Huang Reviewed-by: Isaku Yamahata Reviewed-by: Dave Hansen --- Hi Dave, I added your Reviewed-by, but let me know if you want me to remove since this patch contains one more chunk introduced by the new "per-cpu initialization" handling. v8 -> v9: - Added TDX_PS_NR macro instead of open-coding (Dave). - Better alignment of 'pamt_entry_size' in tdmr_set_up_pamt() (Dave). - Changed to print out PAMTs in "KBs" instead of "pages" (Dave). - Added Dave's Reviewed-by. v7 -> v8: (Dave) - Changelog: - Added a sentence to state PAMT allocation will be improved. - Others suggested by Dave. - Moved 'nid' of 'struct tdx_memblock' to this patch. - Improved comments around tdmr_get_nid(). - WARN_ON_ONCE() -> pr_warn() in tdmr_get_nid(). - Other changes due to 'struct tdmr_info_list'. v6 -> v7: - Changes due to using macros instead of 'enum' for TDX supported page sizes. v5 -> v6: - Rebase due to using 'tdx_memblock' instead of memblock. - 'int pamt_entry_nr' -> 'unsigned long nr_pamt_entries' (Dave/Sagis). - Improved comment around tdmr_get_nid() (Dave). - Improved comment in tdmr_set_up_pamt() around breaking the PAMT into PAMTs for 4K/2M/1G (Dave). - tdmrs_get_pamt_pages() -> tdmrs_count_pamt_pages() (Dave). - v3 -> v5 (no feedback on v4): - Used memblock to get the NUMA node for given TDMR. - Removed tdmr_get_pamt_sz() helper but use open-code instead. - Changed to use 'switch .. case..' for each TDX supported page size in tdmr_get_pamt_sz() (the original __tdmr_get_pamt_sz()). - Added printing out memory used for PAMT allocation when TDX module is initialized successfully. - Explained downside of alloc_contig_pages() in changelog. - Addressed other minor comments. --- arch/x86/Kconfig | 1 + arch/x86/virt/vmx/tdx/tdx.c | 217 +++++++++++++++++++++++++++++++++++- arch/x86/virt/vmx/tdx/tdx.h | 1 + 3 files changed, 214 insertions(+), 5 deletions(-) diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index f23bc540778a..2a4d4097c5e6 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -1959,6 +1959,7 @@ config INTEL_TDX_HOST depends on KVM_INTEL depends on X86_X2APIC select ARCH_KEEP_MEMBLOCK + depends on CONTIG_ALLOC help Intel Trust Domain Extensions (TDX) protects guest VMs from malicious host and certain physical attacks. This option enables necessary TDX diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 5ff346871b4b..ce71a3ef86d3 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -360,7 +360,7 @@ static int tdx_get_sysinfo(struct tdsysinfo_struct *sysinfo, * overlap. */ static int add_tdx_memblock(struct list_head *tmb_list, unsigned long start_pfn, - unsigned long end_pfn) + unsigned long end_pfn, int nid) { struct tdx_memblock *tmb; @@ -371,6 +371,7 @@ static int add_tdx_memblock(struct list_head *tmb_list, unsigned long start_pfn, INIT_LIST_HEAD(&tmb->list); tmb->start_pfn = start_pfn; tmb->end_pfn = end_pfn; + tmb->nid = nid; /* @tmb_list is protected by mem_hotplug_lock */ list_add_tail(&tmb->list, tmb_list); @@ -398,9 +399,9 @@ static void free_tdx_memlist(struct list_head *tmb_list) static int build_tdx_memlist(struct list_head *tmb_list) { unsigned long start_pfn, end_pfn; - int i, ret; + int i, nid, ret; - for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, NULL) { + for_each_mem_pfn_range(i, MAX_NUMNODES, &start_pfn, &end_pfn, &nid) { /* * The first 1MB is not reported as TDX convertible memory. * Although the first 1MB is always reserved and won't end up @@ -416,7 +417,7 @@ static int build_tdx_memlist(struct list_head *tmb_list) * memblock has already guaranteed they are in address * ascending order and don't overlap. */ - ret = add_tdx_memblock(tmb_list, start_pfn, end_pfn); + ret = add_tdx_memblock(tmb_list, start_pfn, end_pfn, nid); if (ret) goto err; } @@ -567,6 +568,202 @@ static int fill_out_tdmrs(struct list_head *tmb_list, return 0; } +/* + * Calculate PAMT size given a TDMR and a page size. The returned + * PAMT size is always aligned up to 4K page boundary. + */ +static unsigned long tdmr_get_pamt_sz(struct tdmr_info *tdmr, int pgsz, + u16 pamt_entry_size) +{ + unsigned long pamt_sz, nr_pamt_entries; + + switch (pgsz) { + case TDX_PS_4K: + nr_pamt_entries = tdmr->size >> PAGE_SHIFT; + break; + case TDX_PS_2M: + nr_pamt_entries = tdmr->size >> PMD_SHIFT; + break; + case TDX_PS_1G: + nr_pamt_entries = tdmr->size >> PUD_SHIFT; + break; + default: + WARN_ON_ONCE(1); + return 0; + } + + pamt_sz = nr_pamt_entries * pamt_entry_size; + /* TDX requires PAMT size must be 4K aligned */ + pamt_sz = ALIGN(pamt_sz, PAGE_SIZE); + + return pamt_sz; +} + +/* + * Locate a NUMA node which should hold the allocation of the @tdmr + * PAMT. This node will have some memory covered by the TDMR. The + * relative amount of memory covered is not considered. + */ +static int tdmr_get_nid(struct tdmr_info *tdmr, struct list_head *tmb_list) +{ + struct tdx_memblock *tmb; + + /* + * A TDMR must cover at least part of one TMB. That TMB will end + * after the TDMR begins. But, that TMB may have started before + * the TDMR. Find the next 'tmb' that _ends_ after this TDMR + * begins. Ignore 'tmb' start addresses. They are irrelevant. + */ + list_for_each_entry(tmb, tmb_list, list) { + if (tmb->end_pfn > PHYS_PFN(tdmr->base)) + return tmb->nid; + } + + /* + * Fall back to allocating the TDMR's metadata from node 0 when + * no TDX memory block can be found. This should never happen + * since TDMRs originate from TDX memory blocks. + */ + pr_warn("TDMR [0x%llx, 0x%llx): unable to find local NUMA node for PAMT allocation, fallback to use node 0.\n", + tdmr->base, tdmr_end(tdmr)); + return 0; +} + +#define TDX_PS_NR (TDX_PS_1G + 1) + +/* + * Allocate PAMTs from the local NUMA node of some memory in @tmb_list + * within @tdmr, and set up PAMTs for @tdmr. + */ +static int tdmr_set_up_pamt(struct tdmr_info *tdmr, + struct list_head *tmb_list, + u16 pamt_entry_size) +{ + unsigned long pamt_base[TDX_PS_NR]; + unsigned long pamt_size[TDX_PS_NR]; + unsigned long tdmr_pamt_base; + unsigned long tdmr_pamt_size; + struct page *pamt; + int pgsz, nid; + + nid = tdmr_get_nid(tdmr, tmb_list); + + /* + * Calculate the PAMT size for each TDX supported page size + * and the total PAMT size. + */ + tdmr_pamt_size = 0; + for (pgsz = TDX_PS_4K; pgsz <= TDX_PS_1G ; pgsz++) { + pamt_size[pgsz] = tdmr_get_pamt_sz(tdmr, pgsz, + pamt_entry_size); + tdmr_pamt_size += pamt_size[pgsz]; + } + + /* + * Allocate one chunk of physically contiguous memory for all + * PAMTs. This helps minimize the PAMT's use of reserved areas + * in overlapped TDMRs. + */ + pamt = alloc_contig_pages(tdmr_pamt_size >> PAGE_SHIFT, GFP_KERNEL, + nid, &node_online_map); + if (!pamt) + return -ENOMEM; + + /* + * Break the contiguous allocation back up into the + * individual PAMTs for each page size. + */ + tdmr_pamt_base = page_to_pfn(pamt) << PAGE_SHIFT; + for (pgsz = TDX_PS_4K; pgsz <= TDX_PS_1G; pgsz++) { + pamt_base[pgsz] = tdmr_pamt_base; + tdmr_pamt_base += pamt_size[pgsz]; + } + + tdmr->pamt_4k_base = pamt_base[TDX_PS_4K]; + tdmr->pamt_4k_size = pamt_size[TDX_PS_4K]; + tdmr->pamt_2m_base = pamt_base[TDX_PS_2M]; + tdmr->pamt_2m_size = pamt_size[TDX_PS_2M]; + tdmr->pamt_1g_base = pamt_base[TDX_PS_1G]; + tdmr->pamt_1g_size = pamt_size[TDX_PS_1G]; + + return 0; +} + +static void tdmr_get_pamt(struct tdmr_info *tdmr, unsigned long *pamt_pfn, + unsigned long *pamt_npages) +{ + unsigned long pamt_base, pamt_sz; + + /* + * The PAMT was allocated in one contiguous unit. The 4K PAMT + * should always point to the beginning of that allocation. + */ + pamt_base = tdmr->pamt_4k_base; + pamt_sz = tdmr->pamt_4k_size + tdmr->pamt_2m_size + tdmr->pamt_1g_size; + + *pamt_pfn = PHYS_PFN(pamt_base); + *pamt_npages = pamt_sz >> PAGE_SHIFT; +} + +static void tdmr_free_pamt(struct tdmr_info *tdmr) +{ + unsigned long pamt_pfn, pamt_npages; + + tdmr_get_pamt(tdmr, &pamt_pfn, &pamt_npages); + + /* Do nothing if PAMT hasn't been allocated for this TDMR */ + if (!pamt_npages) + return; + + if (WARN_ON_ONCE(!pamt_pfn)) + return; + + free_contig_range(pamt_pfn, pamt_npages); +} + +static void tdmrs_free_pamt_all(struct tdmr_info_list *tdmr_list) +{ + int i; + + for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) + tdmr_free_pamt(tdmr_entry(tdmr_list, i)); +} + +/* Allocate and set up PAMTs for all TDMRs */ +static int tdmrs_set_up_pamt_all(struct tdmr_info_list *tdmr_list, + struct list_head *tmb_list, + u16 pamt_entry_size) +{ + int i, ret = 0; + + for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) { + ret = tdmr_set_up_pamt(tdmr_entry(tdmr_list, i), tmb_list, + pamt_entry_size); + if (ret) + goto err; + } + + return 0; +err: + tdmrs_free_pamt_all(tdmr_list); + return ret; +} + +static unsigned long tdmrs_count_pamt_pages(struct tdmr_info_list *tdmr_list) +{ + unsigned long pamt_npages = 0; + int i; + + for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) { + unsigned long pfn, npages; + + tdmr_get_pamt(tdmr_entry(tdmr_list, i), &pfn, &npages); + pamt_npages += npages; + } + + return pamt_npages; +} + /* * Construct a list of TDMRs on the preallocated space in @tdmr_list * to cover all TDX memory regions in @tmb_list based on the TDX module @@ -582,10 +779,13 @@ static int construct_tdmrs(struct list_head *tmb_list, if (ret) return ret; + ret = tdmrs_set_up_pamt_all(tdmr_list, tmb_list, + sysinfo->pamt_entry_size); + if (ret) + return ret; /* * TODO: * - * - Allocate and set up PAMTs for each TDMR. * - Designate reserved areas for each TDMR. * * Return -EINVAL until constructing TDMRs is done @@ -666,7 +866,13 @@ static int init_tdx_module(void) * * Return error before all steps are done. */ + ret = -EINVAL; + if (ret) + tdmrs_free_pamt_all(&tdx_tdmr_list); + else + pr_info("%lu KBs allocated for PAMT.\n", + tdmrs_count_pamt_pages(&tdx_tdmr_list) * 4); out_free_tdmrs: if (ret) free_tdmr_list(&tdx_tdmr_list); @@ -722,6 +928,7 @@ static void disable_tdx_module(void) * init_tdx_module(). Remove this comment after * all steps are done. */ + tdmrs_free_pamt_all(&tdx_tdmr_list); free_tdmr_list(&tdx_tdmr_list); free_tdx_memlist(&tdx_memlist); cpumask_clear(cpu_tdx_mask); diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index 66c7617b357c..7348ffdfc287 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -139,6 +139,7 @@ struct tdx_memblock { struct list_head list; unsigned long start_pfn; unsigned long end_pfn; + int nid; }; struct tdmr_info_list { From patchwork Mon Feb 13 11:59:20 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Huang, Kai" X-Patchwork-Id: 13138311 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 0F1B1C636CC for ; Mon, 13 Feb 2023 12:01:43 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id B35026B0082; Mon, 13 Feb 2023 07:01:41 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id A98ED6B0083; Mon, 13 Feb 2023 07:01:41 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 89E5B6B0085; Mon, 13 Feb 2023 07:01:41 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0010.hostedemail.com [216.40.44.10]) by kanga.kvack.org (Postfix) with ESMTP id 6C9126B0082 for ; Mon, 13 Feb 2023 07:01:41 -0500 (EST) Received: from smtpin26.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay04.hostedemail.com (Postfix) with ESMTP id 1D82F1A1628 for ; Mon, 13 Feb 2023 12:01:41 +0000 (UTC) X-FDA: 80462129202.26.197B0D9 Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by imf07.hostedemail.com (Postfix) with ESMTP id 196ED40004 for ; Mon, 13 Feb 2023 12:01:34 +0000 (UTC) Authentication-Results: imf07.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=ZvWlGujr; dmarc=pass (policy=none) header.from=intel.com; spf=pass (imf07.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1676289696; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=PxGGycX3P3e48EhxhTs0zNtso4v/dCy0P6jYUV5j4Yk=; b=0HUYo5SlJHZMIpBNZvZioGVfL2Rmb2iqj2DdkWEsSAhqRq/csJDmfpJu8GCscM548SLQrv fiVq1KfC1JPy8gDafH362TD3bzsecLWWXgZLKSfAmSPAvy4AERPQI0J0Mi1mz8WjGhQ6nO Xgwjitg+TPyzIrsOxEYDIqtjL97FT9Y= ARC-Authentication-Results: i=1; imf07.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=ZvWlGujr; dmarc=pass (policy=none) header.from=intel.com; spf=pass (imf07.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1676289696; a=rsa-sha256; cv=none; b=WaGHfK0KfKf4+YhROSpkgcc+qlkNd6N5mQ1IlrPX7RldxvGAOUN5OzHKhmlMInxSA3h2iB GNOVEZs2E69mA5QrS5Jiz8PyiKTcYr8Pz8+8logjoIoyd+ZR5js2rKYoU4kg1QcgrjkaKl fSdkkSMj3C24oX4yXalh9vfB+YYEk6I= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1676289695; x=1707825695; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=cPTXs6TistRhJL+86sIA6aP4IWCDYwochHr95MYjXrw=; b=ZvWlGujroCG1WVl5fKYiEF779Df6vTdBHevrG+Qte98mXSn8LNJvADTN SXvwHMrnT8Lb/ObHC58QIQGLPUFH7g3TQTvwJKHNJ90qM+5MvNrjtogb1 fkcOmUad8WUGOL0Kn7sRTOBAuOedQ9E2OFDHJcZQzukT53Hfxa60IUFeT 2Lpjz/+JAMVK/EQIjdY99st28xBr/kn+twuE+8syse4BFHwFP63ejLIlM JBHuUQrHZNhdY3iRq5Pxg/e81XXcf47oVuhTG73Uoo37Gi4l1B3+4Q3tR 35OVdI0SLSdpCFCYy6q92gKT4QKtHlmsHD1XR0ThldbjFdVT23A2xWB2r g==; X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="358283425" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="358283425" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:01:21 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="701243473" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="701243473" Received: from wonger-mobl.amr.corp.intel.com (HELO khuang2-desk.gar.corp.intel.com) ([10.209.188.34]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:01:16 -0800 From: Kai Huang To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: linux-mm@kvack.org, dave.hansen@intel.com, peterz@infradead.org, tglx@linutronix.de, seanjc@google.com, pbonzini@redhat.com, dan.j.williams@intel.com, rafael.j.wysocki@intel.com, kirill.shutemov@linux.intel.com, ying.huang@intel.com, reinette.chatre@intel.com, len.brown@intel.com, tony.luck@intel.com, ak@linux.intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com, david@redhat.com, bagasdotme@gmail.com, sagis@google.com, imammedo@redhat.com, kai.huang@intel.com Subject: [PATCH v9 13/18] x86/virt/tdx: Designate reserved areas for all TDMRs Date: Tue, 14 Feb 2023 00:59:20 +1300 Message-Id: <5c2c0fbc422223470c5b38ff86e1b9e3dd81e22e.1676286526.git.kai.huang@intel.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: References: MIME-Version: 1.0 X-Rspam-User: X-Rspamd-Server: rspam02 X-Rspamd-Queue-Id: 196ED40004 X-Stat-Signature: d83kezcehypwf7qdy9nao9memw7fu8tr X-HE-Tag: 1676289694-830142 X-HE-Meta: U2FsdGVkX19qnRP8uEZ24MlKJjEtj0EDvpcWbVTvP9cUUnKyLbs2kqsK/8R10yy9lR8XB1cDKMEvJon8N1bIaUlUaGRARbNjrc8i8WMKggCffdIyFU1IOzPbc6pSwlSX47qbdfg9dpc+WNZImv00/k5sUOBO5VKhLIfd9tZoTIZg3cogj4RpvhabpJ5nGprFjXvZj+w2LpUFbeRaIbZ7SX2SueSiukSHAZ/VWrqL88ltgAPs1QA0t6MvpM/lVbTPqKEwu+TwotDzpb+NTBnZKHN0DmSUPlRkLN8TzFptA4YgANEwOcTrwnYLNCyXgkpowOicW3LA4QpnJ/N77WxqQknb+nCt/1IfA5c0fs3ZuQ4bJwOMcRvtcvkkI8Es4yk0zOgOJzA5rJcouV1GLzvBeiRox3TFGFv/3jhiDkIcckDyS2tatW93XyS1SK4vaYVM2EWFxtYUvImMqINvbH3WYEyNCtrY00GTXkJ/8P7Eo7tWmWswWvbQtygbuvhCd/pekiSsVaXsJkbP7PK3rlbGxBJUX3YF7uP7F6u7ThrfCUaVpQxsWv5kol/b+D5bPnGbOrFRDJOzimRDGeggn0iQ4o5YRN0YCAuzU5JtEwigkve2s/T7KxGDc0r+Nnz0BUMHBQ0iAEVbSd6QkY47UWxSh4ZTmVv4zKndXp9Rf2S/4EH5CsBEbSWxLRunIEGltURH/T9m4Limpf69ootPTgU+lvbWGlB2DXkHzvNglrZnqRLbnq5sHPuxvSvardwP67xKIGpWl/b5yQFNAmHnKW7KPjVSDVg30PVgAfUJlhv3IyOXy17yHPgmMGizw+N+3SfvPneD31ATM2W8nzK7asoALgDrBpjxgMTRHsxa8lEsSzswgHI1MovuNW2vbBX558ODLWfQwsuT+RbKQpxIZEn0VqwC0ZvXdTarRexO78kizcopiC5leU+peT3TpNpvSdkoq7zqRm9fmVLQcnK0h4N XH/91l0t tAPokDnN+HHnz7rad7/2TGOI7DkMCqSoDFR6sf8rJFrdnvDIFV4pRtyXgCNtPaByt6iD2aH/A+BaQwDsfM/eKEUHq8fChV10UXqW9UUJ12ZW4+DdqTHq+1bs48ti2jLa+TiVeBzS0mBoEwiD7hAOMNdc21Axt89+6wexUeD3wQgB6StY= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: As the last step of constructing TDMRs, populate reserved areas for all TDMRs. For each TDMR, put all memory holes within this TDMR to the reserved areas. And for all PAMTs which overlap with this TDMR, put all the overlapping parts to reserved areas too. Signed-off-by: Kai Huang Reviewed-by: Isaku Yamahata --- v8 -> v9: - Added comment around 'tdmr_add_rsvd_area()' to point out it doesn't do optimization to save reserved areas. (Dave). v7 -> v8: (Dave) - "set_up" -> "populate" in function name change (Dave). - Improved comment suggested by Dave. - Other changes due to 'struct tdmr_info_list'. v6 -> v7: - No change. v5 -> v6: - Rebase due to using 'tdx_memblock' instead of memblock. - Split tdmr_set_up_rsvd_areas() into two functions to handle memory hole and PAMT respectively. - Added Isaku's Reviewed-by. --- arch/x86/virt/vmx/tdx/tdx.c | 220 ++++++++++++++++++++++++++++++++++-- 1 file changed, 212 insertions(+), 8 deletions(-) diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index ce71a3ef86d3..34aed2aa9f4b 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -23,6 +23,7 @@ #include #include #include +#include #include #include #include @@ -764,6 +765,210 @@ static unsigned long tdmrs_count_pamt_pages(struct tdmr_info_list *tdmr_list) return pamt_npages; } +static int tdmr_add_rsvd_area(struct tdmr_info *tdmr, int *p_idx, u64 addr, + u64 size, u16 max_reserved_per_tdmr) +{ + struct tdmr_reserved_area *rsvd_areas = tdmr->reserved_areas; + int idx = *p_idx; + + /* Reserved area must be 4K aligned in offset and size */ + if (WARN_ON(addr & ~PAGE_MASK || size & ~PAGE_MASK)) + return -EINVAL; + + if (idx >= max_reserved_per_tdmr) { + pr_warn("initialization failed: TDMR [0x%llx, 0x%llx): reserved areas exhausted.\n", + tdmr->base, tdmr_end(tdmr)); + return -ENOSPC; + } + + /* + * Consume one reserved area per call. Make no effort to + * optimize or reduce the number of reserved areas which are + * consumed by contiguous reserved areas, for instance. + */ + rsvd_areas[idx].offset = addr - tdmr->base; + rsvd_areas[idx].size = size; + + *p_idx = idx + 1; + + return 0; +} + +/* + * Go through @tmb_list to find holes between memory areas. If any of + * those holes fall within @tdmr, set up a TDMR reserved area to cover + * the hole. + */ +static int tdmr_populate_rsvd_holes(struct list_head *tmb_list, + struct tdmr_info *tdmr, + int *rsvd_idx, + u16 max_reserved_per_tdmr) +{ + struct tdx_memblock *tmb; + u64 prev_end; + int ret; + + /* + * Start looking for reserved blocks at the + * beginning of the TDMR. + */ + prev_end = tdmr->base; + list_for_each_entry(tmb, tmb_list, list) { + u64 start, end; + + start = PFN_PHYS(tmb->start_pfn); + end = PFN_PHYS(tmb->end_pfn); + + /* Break if this region is after the TDMR */ + if (start >= tdmr_end(tdmr)) + break; + + /* Exclude regions before this TDMR */ + if (end < tdmr->base) + continue; + + /* + * Skip over memory areas that + * have already been dealt with. + */ + if (start <= prev_end) { + prev_end = end; + continue; + } + + /* Add the hole before this region */ + ret = tdmr_add_rsvd_area(tdmr, rsvd_idx, prev_end, + start - prev_end, + max_reserved_per_tdmr); + if (ret) + return ret; + + prev_end = end; + } + + /* Add the hole after the last region if it exists. */ + if (prev_end < tdmr_end(tdmr)) { + ret = tdmr_add_rsvd_area(tdmr, rsvd_idx, prev_end, + tdmr_end(tdmr) - prev_end, + max_reserved_per_tdmr); + if (ret) + return ret; + } + + return 0; +} + +/* + * Go through @tdmr_list to find all PAMTs. If any of those PAMTs + * overlaps with @tdmr, set up a TDMR reserved area to cover the + * overlapping part. + */ +static int tdmr_populate_rsvd_pamts(struct tdmr_info_list *tdmr_list, + struct tdmr_info *tdmr, + int *rsvd_idx, + u16 max_reserved_per_tdmr) +{ + int i, ret; + + for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) { + struct tdmr_info *tmp = tdmr_entry(tdmr_list, i); + unsigned long pamt_start_pfn, pamt_npages; + u64 pamt_start, pamt_end; + + tdmr_get_pamt(tmp, &pamt_start_pfn, &pamt_npages); + /* Each TDMR must already have PAMT allocated */ + WARN_ON_ONCE(!pamt_npages || !pamt_start_pfn); + + pamt_start = PFN_PHYS(pamt_start_pfn); + pamt_end = PFN_PHYS(pamt_start_pfn + pamt_npages); + + /* Skip PAMTs outside of the given TDMR */ + if ((pamt_end <= tdmr->base) || + (pamt_start >= tdmr_end(tdmr))) + continue; + + /* Only mark the part within the TDMR as reserved */ + if (pamt_start < tdmr->base) + pamt_start = tdmr->base; + if (pamt_end > tdmr_end(tdmr)) + pamt_end = tdmr_end(tdmr); + + ret = tdmr_add_rsvd_area(tdmr, rsvd_idx, pamt_start, + pamt_end - pamt_start, + max_reserved_per_tdmr); + if (ret) + return ret; + } + + return 0; +} + +/* Compare function called by sort() for TDMR reserved areas */ +static int rsvd_area_cmp_func(const void *a, const void *b) +{ + struct tdmr_reserved_area *r1 = (struct tdmr_reserved_area *)a; + struct tdmr_reserved_area *r2 = (struct tdmr_reserved_area *)b; + + if (r1->offset + r1->size <= r2->offset) + return -1; + if (r1->offset >= r2->offset + r2->size) + return 1; + + /* Reserved areas cannot overlap. The caller must guarantee. */ + WARN_ON_ONCE(1); + return -1; +} + +/* + * Populate reserved areas for the given @tdmr, including memory holes + * (via @tmb_list) and PAMTs (via @tdmr_list). + */ +static int tdmr_populate_rsvd_areas(struct tdmr_info *tdmr, + struct list_head *tmb_list, + struct tdmr_info_list *tdmr_list, + u16 max_reserved_per_tdmr) +{ + int ret, rsvd_idx = 0; + + ret = tdmr_populate_rsvd_holes(tmb_list, tdmr, &rsvd_idx, + max_reserved_per_tdmr); + if (ret) + return ret; + + ret = tdmr_populate_rsvd_pamts(tdmr_list, tdmr, &rsvd_idx, + max_reserved_per_tdmr); + if (ret) + return ret; + + /* TDX requires reserved areas listed in address ascending order */ + sort(tdmr->reserved_areas, rsvd_idx, sizeof(struct tdmr_reserved_area), + rsvd_area_cmp_func, NULL); + + return 0; +} + +/* + * Populate reserved areas for all TDMRs in @tdmr_list, including memory + * holes (via @tmb_list) and PAMTs. + */ +static int tdmrs_populate_rsvd_areas_all(struct tdmr_info_list *tdmr_list, + struct list_head *tmb_list, + u16 max_reserved_per_tdmr) +{ + int i; + + for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) { + int ret; + + ret = tdmr_populate_rsvd_areas(tdmr_entry(tdmr_list, i), + tmb_list, tdmr_list, max_reserved_per_tdmr); + if (ret) + return ret; + } + + return 0; +} + /* * Construct a list of TDMRs on the preallocated space in @tdmr_list * to cover all TDX memory regions in @tmb_list based on the TDX module @@ -783,14 +988,13 @@ static int construct_tdmrs(struct list_head *tmb_list, sysinfo->pamt_entry_size); if (ret) return ret; - /* - * TODO: - * - * - Designate reserved areas for each TDMR. - * - * Return -EINVAL until constructing TDMRs is done - */ - return -EINVAL; + + ret = tdmrs_populate_rsvd_areas_all(tdmr_list, tmb_list, + sysinfo->max_reserved_per_tdmr); + if (ret) + tdmrs_free_pamt_all(tdmr_list); + + return ret; } static int init_tdx_module(void) From patchwork Mon Feb 13 11:59:21 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Huang, Kai" X-Patchwork-Id: 13138309 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4EBC4C636D4 for ; Mon, 13 Feb 2023 12:01:39 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id D31D86B0080; Mon, 13 Feb 2023 07:01:38 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id C930A6B0081; Mon, 13 Feb 2023 07:01:38 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id A70C26B0082; Mon, 13 Feb 2023 07:01:38 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0016.hostedemail.com [216.40.44.16]) by kanga.kvack.org (Postfix) with ESMTP id 92FCD6B0080 for ; Mon, 13 Feb 2023 07:01:38 -0500 (EST) Received: from smtpin26.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay10.hostedemail.com (Postfix) with ESMTP id 4A295C154E for ; Mon, 13 Feb 2023 12:01:38 +0000 (UTC) X-FDA: 80462129076.26.3261C32 Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by imf11.hostedemail.com (Postfix) with ESMTP id 14E1440026 for ; Mon, 13 Feb 2023 12:01:35 +0000 (UTC) Authentication-Results: imf11.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=mB7i3TK0; dmarc=pass (policy=none) header.from=intel.com; spf=pass (imf11.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1676289696; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=Zwhg4Ecrj+mlyKk7x+AI9w0b4sjnLbK8JX2XBMf8FY0=; b=3tvCdZmDXFOGtNrlUilNdS8EHz9borFyJfcsYC7gV7g7sM8FvPe+BG7oG1J7xUKTuJzeum 6L+kvQopXMieI9kfKyfsLonCLIjPQw6evujOop6TuDA43jw1C2UmeFhubmGe/6OnRWipfm KRO4ODM+wP+GhinuosRcONddWJeflBs= ARC-Authentication-Results: i=1; imf11.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=mB7i3TK0; dmarc=pass (policy=none) header.from=intel.com; spf=pass (imf11.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1676289696; a=rsa-sha256; cv=none; b=HXIs+xnrOPVDblCc2BJZhwIo1N1QgfsrZYZM7qkysMX1V/D6twB2DpUlX3agABjbi1vmGb 5pUIF9tOD6eWGH7YRx14goyuGDz4DGYyIzHfmacd1qJTexXPD90YqlcIheHUJ4aqX+Qfqg WON4TX0+nNJfokIUR32NWbaYs9dsd/M= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1676289696; x=1707825696; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=bJvVJsnRcKkHlH10MX+mqczhV6X41iy5nbj4zqxw7oo=; b=mB7i3TK0Zsdl2xKJU0V73wsfRg7HpLYik14R/jbHOqjFSTkFEIm+rVZz Q+29WyoZuY8rLHH+qdXeyMR6qbt/tIK3IvrVTVI4ZD1cWMTphSufYqcoO 3ebmN7lnCQaWp+le1G/odemOQskOWc7QZ7p3CtvLpOmvBJZcIkVSx0H8r 2FKBZrTS4wvoIWsk4sw/ObWWJ0V2Qr+2RMBxJ+/Y28jMqBrr/p4OAZgvq 1nswj0AFEpcrjeM7GFDaXpocajYDQufJfFV3o17sDbyq0n15ntpfEQAMX 6eJyUGoLy4U9HpbC5RrJTHsqOBlWKYUHWT1kFXcOHzwq7Uc2HEN0cEzCR w==; X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="358283456" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="358283456" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:01:27 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="701243513" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="701243513" Received: from wonger-mobl.amr.corp.intel.com (HELO khuang2-desk.gar.corp.intel.com) ([10.209.188.34]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:01:21 -0800 From: Kai Huang To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: linux-mm@kvack.org, dave.hansen@intel.com, peterz@infradead.org, tglx@linutronix.de, seanjc@google.com, pbonzini@redhat.com, dan.j.williams@intel.com, rafael.j.wysocki@intel.com, kirill.shutemov@linux.intel.com, ying.huang@intel.com, reinette.chatre@intel.com, len.brown@intel.com, tony.luck@intel.com, ak@linux.intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com, david@redhat.com, bagasdotme@gmail.com, sagis@google.com, imammedo@redhat.com, kai.huang@intel.com Subject: [PATCH v9 14/18] x86/virt/tdx: Configure TDX module with the TDMRs and global KeyID Date: Tue, 14 Feb 2023 00:59:21 +1300 Message-Id: <4cc5ec58d639a4c10e87abd35bc2002a88a7eb43.1676286526.git.kai.huang@intel.com> X-Mailer: git-send-email 2.39.1 In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Queue-Id: 14E1440026 X-Rspamd-Server: rspam09 X-Rspam-User: X-Stat-Signature: mz3ttpt6hbqpjak88afk4iomn1r9axy1 X-HE-Tag: 1676289695-347693 X-HE-Meta: U2FsdGVkX1+FffVbCNY9erC2/IrdzB0hAL6oz0p+enKNA+8/vDpKgFYnkLSGBTYND52U7bqrJIpGxofeKjkT8mX5f6sOvliPsOAda8gKCpnFMsa1+0goZZNdAP5eRxK2v/9r6OYmmj6Cyg1cYTH8LmHYAfP6xSDBvupZmNvZQurFj3asEnbJixXmA4/uUa79rqlmm6QPBWPl8RaNVT08oUphMIoR/F07JzVZNF99oCq+awUhf/exT6KkWL1vUrbk2BnfhETkZrF2Tn5+SHwMUQLH8KglOP8k4qRqQyXqoRCzh4sz0u+qPcsIwoPK8ROL+uvMBHhjmpCRNv1kypTLPwhCuLg9RTe3Z76xSaX4ja9whL7umbL8dEbDRV9pckPEKuTxMQenh7N84TXfZPxe3bbKKzN/6GPJ//QsHTVTjBj2GacSvCI/1oOYKapkxgnycWsXAdNiBADM+CuevLRrLXMaJes4gXRSEIIxYAZWqW4IWyyMMJ18Qkm+YG36AZ7nEmN2rerH1CMMgzTSI6XUds8E2eLh3keXpf7bP40HFN90SXYn58pJL3+wak7QjR21rLMT3KzVUwzbx/45q0gYZQb5XqiIoNPIwamCsztT0Jy6vZswwSIsgv4lMxQ1KU7rFQTOC7oJFi45fnjbc9ndoRXRKBsKn8yXw2tf1MQ33mKc4XHgcnKU9z6l2BPY+0UCx/UJlpKvp2XWYSy2FmqAlANuTKv8XYe7149n0TwVdKJI2HUW1E+CSFeJs4xF1X3Snc7XltXsXn6sH8WnJhCmsc+5uETQY0J3l2OY2sR88uTDaUqIpTzC5dOlnqzxAI2XaxTBmnhbZzX4b/V3UO8k180sgi+xGIxGKVSAPg37dNQMt58v8aEZxUsDDmyx/M0NdEPx3AL6AacjfGx9eg+/EEcxPoeh3sZt4vWt21InYuhz+TkXZO2GBSbrHKz8ZJgYO31ZlqJTIwb21GIho7R 0Iy6a4Gt BZf0jg4CkJp1yyUiBdIw8XF/DNw8wNFz52FKaVIEp2GsBGcadwGhBG36WyflNGDM/UE9XVcB+NtOLarcMK3fSd6IzTcmQdSaIEFzKHDLuikqvNNn/4lVlT8Om0y8YvrbcOZG/voQPgR0pycJnWMBcWG/vyNN17YZztTGydiisU2bAufY= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: The TDX module uses a private KeyID as the "global KeyID" for mapping things like the PAMT and other TDX metadata. This KeyID has already been reserved when detecting TDX during the kernel early boot. After the list of "TD Memory Regions" (TDMRs) has been constructed to cover all TDX-usable memory regions, the next step is to pass them to the TDX module together with the global KeyID. Signed-off-by: Kai Huang Reviewed-by: Isaku Yamahata --- v8 -> v9: - Removed 'i.e.' in changelog and removed the passive voice (Dave). - Improved changelog (Dave). - Changed the way to allocate aligned PA array (Dave). - Moved reserving the TDX global KeyID to the second patch, and also changed 'tdx_keyid_start' and 'nr_tdx_keyid' to guest's KeyIDs in that patch (Dave). v7 -> v8: - Merged "Reserve TDX module global KeyID" patch to this patch, and removed 'tdx_global_keyid' but use 'tdx_keyid_start' directly. - Changed changelog accordingly. - Changed how to allocate aligned array (Dave). --- arch/x86/virt/vmx/tdx/tdx.c | 41 ++++++++++++++++++++++++++++++++++++- arch/x86/virt/vmx/tdx/tdx.h | 2 ++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 34aed2aa9f4b..5a4163d40f58 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include #include @@ -997,6 +998,39 @@ static int construct_tdmrs(struct list_head *tmb_list, return ret; } +static int config_tdx_module(struct tdmr_info_list *tdmr_list, u64 global_keyid) +{ + u64 *tdmr_pa_array; + size_t array_sz; + int i, ret; + + /* + * TDMRs are passed to the TDX module via an array of physical + * addresses of each TDMR. The array itself also has certain + * alignment requirement. + */ + array_sz = tdmr_list->nr_consumed_tdmrs * sizeof(u64); + array_sz = roundup_pow_of_two(array_sz); + if (array_sz < TDMR_INFO_PA_ARRAY_ALIGNMENT) + array_sz = TDMR_INFO_PA_ARRAY_ALIGNMENT; + + tdmr_pa_array = kzalloc(array_sz, GFP_KERNEL); + if (!tdmr_pa_array) + return -ENOMEM; + + for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) + tdmr_pa_array[i] = __pa(tdmr_entry(tdmr_list, i)); + + ret = seamcall(TDH_SYS_CONFIG, __pa(tdmr_pa_array), + tdmr_list->nr_consumed_tdmrs, + global_keyid, 0, NULL, NULL); + + /* Free the array as it is not required anymore. */ + kfree(tdmr_pa_array); + + return ret; +} + static int init_tdx_module(void) { static DECLARE_PADDED_STRUCT(tdsysinfo_struct, tdsysinfo, @@ -1061,10 +1095,14 @@ static int init_tdx_module(void) if (ret) goto out_free_tdmrs; + /* Pass the TDMRs and the global KeyID to the TDX module */ + ret = config_tdx_module(&tdx_tdmr_list, tdx_global_keyid); + if (ret) + goto out_free_pamts; + /* * TODO: * - * - Configure the TDMRs and the global KeyID to the TDX module. * - Configure the global KeyID on all packages. * - Initialize all TDMRs. * @@ -1072,6 +1110,7 @@ static int init_tdx_module(void) */ ret = -EINVAL; +out_free_pamts: if (ret) tdmrs_free_pamt_all(&tdx_tdmr_list); else diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index 7348ffdfc287..7b34ac257b9a 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -17,6 +17,7 @@ * TDX module SEAMCALL leaf functions */ #define TDH_SYS_INFO 32 +#define TDH_SYS_CONFIG 45 struct cmr_info { u64 base; @@ -93,6 +94,7 @@ struct tdmr_reserved_area { } __packed; #define TDMR_INFO_ALIGNMENT 512 +#define TDMR_INFO_PA_ARRAY_ALIGNMENT 512 struct tdmr_info { u64 base; From patchwork Mon Feb 13 11:59:22 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Huang, Kai" X-Patchwork-Id: 13138310 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 4BD67C636D7 for ; Mon, 13 Feb 2023 12:01:41 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id DA6B46B0081; Mon, 13 Feb 2023 07:01:40 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id D31076B0082; Mon, 13 Feb 2023 07:01:40 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id A49F26B0083; Mon, 13 Feb 2023 07:01:40 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0015.hostedemail.com [216.40.44.15]) by kanga.kvack.org (Postfix) with ESMTP id 927D76B0081 for ; Mon, 13 Feb 2023 07:01:40 -0500 (EST) Received: from smtpin10.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay10.hostedemail.com (Postfix) with ESMTP id 6888FC1556 for ; Mon, 13 Feb 2023 12:01:40 +0000 (UTC) X-FDA: 80462129160.10.32FCFFC Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by imf11.hostedemail.com (Postfix) with ESMTP id 52B444001A for ; Mon, 13 Feb 2023 12:01:38 +0000 (UTC) Authentication-Results: imf11.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b="TCiv8V/S"; dmarc=pass (policy=none) header.from=intel.com; spf=pass (imf11.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1676289698; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=HLE1+USv0XakWKwN8DkEY8FJMz/7FDyxsLIh3uDhmX0=; b=6dGcQiUX2q9XP8n5gRR/OT41MOZvlv1t1t9tdkIhIXD4d/fJff+HjSR604x4PkjudRxOmC 5Mhic/VGw9zIeTm+DzEwtDW9UniKBQx1qF6DXbDRo8x+qjtjidbCq+CMegF6+HKG9chKJA qcVpypH4EkKawTPCiAgxHYP6IXErDR4= ARC-Authentication-Results: i=1; imf11.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b="TCiv8V/S"; dmarc=pass (policy=none) header.from=intel.com; spf=pass (imf11.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1676289698; a=rsa-sha256; cv=none; b=f5osHXNtZikmlmdFZcWQv74qzJBCNFOjMhn5dkp9Q3ExHNU0YaokpR7aC6exaGnSZHgNA/ 2nNGqQ12zlAdG08pbtCu2ng13mW2sBcALn9GuXGiMXLABd0o3P/qmXIPBc2M9nFTeRGfXQ yL03Xa14m9gb75As3CuW/Hu1rSgbDSQ= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1676289698; x=1707825698; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=gV7imOVz4HnigCq8Nw4/g/zyr45AbaY82hHOJD6E8Zc=; b=TCiv8V/Sc0Yn3PuBHNbFYpohNt6b1fP5ihQWhY439mr2LpZ8Nattk0up XEDnZjqoz91YcHYzYB+qcu3PdSZY9DfIgAzCt8qaWvdZVihSp9BPg2WaU Gg6glDEPB9n73j6Zpmcm+UTA7W3rtIK5x+A1KS8Y5UiBTFBWnOYZ/RnIV v643RiC1gmlazGAg62YJOYOjhEpvXlCnkIhZa/PjMtcgXQbfMKwVf6Lch ue977jxTSjrJSlCFQ3dZstHruMWlVJisMS8jArBVcsolPz+RMbdC5XW1T SicwbrBgf/sF5eYgXwNolGkYSIXBJbpqvlk+x8Ns3NyII84+QOmojWl0l g==; X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="358283483" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="358283483" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:01:32 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="701243521" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="701243521" Received: from wonger-mobl.amr.corp.intel.com (HELO khuang2-desk.gar.corp.intel.com) ([10.209.188.34]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:01:27 -0800 From: Kai Huang To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: linux-mm@kvack.org, dave.hansen@intel.com, peterz@infradead.org, tglx@linutronix.de, seanjc@google.com, pbonzini@redhat.com, dan.j.williams@intel.com, rafael.j.wysocki@intel.com, kirill.shutemov@linux.intel.com, ying.huang@intel.com, reinette.chatre@intel.com, len.brown@intel.com, tony.luck@intel.com, ak@linux.intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com, david@redhat.com, bagasdotme@gmail.com, sagis@google.com, imammedo@redhat.com, kai.huang@intel.com Subject: [PATCH v9 15/18] x86/virt/tdx: Configure global KeyID on all packages Date: Tue, 14 Feb 2023 00:59:22 +1300 Message-Id: X-Mailer: git-send-email 2.39.1 In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Queue-Id: 52B444001A X-Rspamd-Server: rspam09 X-Rspam-User: X-Stat-Signature: hhugz5jgnfw94y4cuk5f6jgn69jykprd X-HE-Tag: 1676289698-276305 X-HE-Meta: U2FsdGVkX1+lQvu3iO2PBTUBayGzxZ1YK1a5jcR/4OR4JOC/e2kTXaAz4ltE7fddW+izHrexR14NeVxeRZ/s2rbJj78NZtLRr3Xe87ldOEi75FvQvmypL+ADUCadMvdNfN2eGDYff1vTT3dAlKS+Qr388Y09683ABIys07sREE9eSr7ehLieXnZwG5xodxvOsyL9dvMss7nONOgkdEbRBcDNE+OuQjAW0c+q8ebXhRAqG1yJdHMfSrvyH7WNfSOyRAxenoGX3rKU7vSdxEGVeKpn2acduQRCIb2KZteegQYqjOM3Tl4MR3itKmTgyb6Q2r5w6c7XIDmw8eJ2MQu7AIp3hjDzLOC+SKmcVbuxF3Scqz/ym09gMs13VLAKOgf5/evjCmnZArrBC96Nce+hivxgZiJYfcvXpdmhtoYV6a5jiX2zPqzgvpwQ/ilZT5PfVT514hhE731W3zamcQuFLYtUgyaMlUbdBzagk+pJByQhk9AuV5jqN6qx7x7QQJd/rNvHWarX0vEaso5A8NEOdx9MlrNDLzdTO22JNLG9LvTM9UImnvGpQEvKG+GqWPoKB4eSz0SU7OM7dw2q4i7f9U1obOmB9JWsya+MZXnLEBn8VXV8cEB3kGz8idwG7DfhIrZPDUpGhYRRMVcbvbe7iIDCvQeb4oxk/+lYtZy5QPvoMYR5wBMmfT9VjWD7PwOHfqSTMLRc/VRaO06+Xwy3/BK2i8cZPY0Hak4C+CkJ7qaL/GHgdP3OnTp8KYfaXnv2u1ipg/YFLzWSbjrKZ/h56a8WCtEFfnBcdJxK1UiZvlwjAPTL+Xu/yXcWXDNXNuwq3XxkvzgRRphG//iM7mGgqtA65FEFti3XI0RW4YghDJAUZLqoIt8gPKWh8rpcK+qzpq3Ngd9zBB+I9WCrKzj8JZnyDNyTSnjhiUjOOr1KrTLf+veC0OE5byvbKSB+bhqfSOcQQRnpscip47SfAma 8o5Ao5bj tKqVfHi6fo2U+lcNo9wBqdb8+6LgumowjbjzzwmGKEAGvGE8xx1+6/Uy39LPVpWvBIPdotzr+n5G8rlV5a/jsnORVxTfVmc/BsocnOOpCLwwuAlxeTlPQ7mdlDkWPi/gPGRNEFLNzgk6OIw4rhzKE+U9oIPo0MBQOnnZhVxw20cYD4Bk= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: After the list of TDMRs and the global KeyID are configured to the TDX module, the kernel needs to configure the key of the global KeyID on all packages using TDH.SYS.KEY.CONFIG. Just use the helper, which conditionally calls function on all online cpus, to configure the global KeyID on all packages. Loop all online cpus, keep track which packages have been called and skip all cpus for those already called packages. To keep things simple, this implementation takes no affirmative steps to online cpus to make sure there's at least one cpu for each package. The callers (aka. KVM) can ensure success by ensuring that. Intel hardware doesn't guarantee cache coherency across different KeyIDs. The PAMTs are transitioning from being used by the kernel mapping (KeyId 0) to the TDX module's "global KeyID" mapping. This means that the kernel must flush any dirty KeyID-0 PAMT cachelines before the TDX module uses the global KeyID to access the PAMT. Otherwise, if those dirty cachelines were written back, they would corrupt the TDX module's metadata. Aside: This corruption would be detected by the memory integrity hardware on the next read of the memory with the global KeyID. The result would likely be fatal to the system but would not impact TDX security. Following the TDX module specification, flush cache before configuring the global KeyID on all packages. Given the PAMT size can be large (~1/256th of system RAM), just use WBINVD on all CPUs to flush. Note if any TDH.SYS.KEY.CONFIG fails, the TDX module may already have used the global KeyID to write any PAMT. Therefore, use WBINVD to flush cache before freeing the PAMTs back to the kernel. Signed-off-by: Kai Huang Reviewed-by: Isaku Yamahata --- v8 -> v9: - Improved changelog (Dave). - Improved comments to explain the function to configure global KeyID "takes no affirmative action to online any cpu". (Dave). - Improved other comments suggested by Dave. v7 -> v8: (Dave) - Changelog changes: - Point out this is the step of "multi-steps" of init_tdx_module(). - Removed MOVDIR64B part. - Other changes due to removing TDH.SYS.SHUTDOWN and TDH.SYS.LP.INIT. - Changed to loop over online cpus and use smp_call_function_single() directly as the patch to shut down TDX module has been removed. - Removed MOVDIR64B part in comment. v6 -> v7: - Improved changelong and comment to explain why MOVDIR64B isn't used when returning PAMTs back to the kernel. --- arch/x86/virt/vmx/tdx/tdx.c | 92 ++++++++++++++++++++++++++++++++++--- arch/x86/virt/vmx/tdx/tdx.h | 1 + 2 files changed, 86 insertions(+), 7 deletions(-) diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index 5a4163d40f58..ff6f2c9d9838 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -1031,6 +1031,61 @@ static int config_tdx_module(struct tdmr_info_list *tdmr_list, u64 global_keyid) return ret; } +static int smp_func_config_global_keyid(void *data) +{ + cpumask_var_t packages = data; + int pkg, ret; + + pkg = topology_physical_package_id(smp_processor_id()); + + /* + * TDH.SYS.KEY.CONFIG may fail with entropy error (which is a + * recoverable error). Assume this is exceedingly rare and + * just return error if encountered instead of retrying. + * + * All '0's are just unused parameters. + */ + ret = seamcall(TDH_SYS_KEY_CONFIG, 0, 0, 0, 0, NULL, NULL); + if (!ret) + cpumask_set_cpu(pkg, packages); + + return ret; +} + +static bool skip_func_config_global_keyid(int cpu, void *data) +{ + cpumask_var_t packages = data; + + return cpumask_test_cpu(topology_physical_package_id(cpu), + packages); +} + +/* + * Attempt to configure the global KeyID on all physical packages. + * + * This requires running code on at least one CPU in each package. If a + * package has no online CPUs, that code will not run and TDX module + * initialization (TDMR initialization) will fail. + * + * This code takes no affirmative steps to online CPUs. Callers (aka. + * KVM) can ensure success by ensuring sufficient CPUs are online for + * this to succeed. + */ +static int config_global_keyid(void) +{ + cpumask_var_t packages; + int ret; + + if (!zalloc_cpumask_var(&packages, GFP_KERNEL)) + return -ENOMEM; + + ret = tdx_on_each_cpu_cond(smp_func_config_global_keyid, packages, + skip_func_config_global_keyid, packages); + + free_cpumask_var(packages); + return ret; +} + static int init_tdx_module(void) { static DECLARE_PADDED_STRUCT(tdsysinfo_struct, tdsysinfo, @@ -1100,10 +1155,24 @@ static int init_tdx_module(void) if (ret) goto out_free_pamts; + /* + * Hardware doesn't guarantee cache coherency across different + * KeyIDs. The kernel needs to flush PAMT's dirty cachelines + * (associated with KeyID 0) before the TDX module can use the + * global KeyID to access the PAMT. Given PAMTs are potentially + * large (~1/256th of system RAM), just use WBINVD on all cpus + * to flush the cache. + */ + wbinvd_on_all_cpus(); + + /* Config the key of global KeyID on all packages */ + ret = config_global_keyid(); + if (ret) + goto out_free_pamts; + /* * TODO: * - * - Configure the global KeyID on all packages. * - Initialize all TDMRs. * * Return error before all steps are done. @@ -1111,8 +1180,18 @@ static int init_tdx_module(void) ret = -EINVAL; out_free_pamts: - if (ret) + if (ret) { + /* + * Part of PAMT may already have been initialized by the + * TDX module. Flush cache before returning PAMT back + * to the kernel. + * + * No need to worry about integrity checks here. KeyID + * 0 has integrity checking disabled. + */ + wbinvd_on_all_cpus(); tdmrs_free_pamt_all(&tdx_tdmr_list); + } else pr_info("%lu KBs allocated for PAMT.\n", tdmrs_count_pamt_pages(&tdx_tdmr_list) * 4); @@ -1166,11 +1245,7 @@ static int __tdx_enable(void) */ static void disable_tdx_module(void) { - /* - * TODO: module clean up in reverse to steps in - * init_tdx_module(). Remove this comment after - * all steps are done. - */ + wbinvd_on_all_cpus(); tdmrs_free_pamt_all(&tdx_tdmr_list); free_tdmr_list(&tdx_tdmr_list); free_tdx_memlist(&tdx_memlist); @@ -1228,6 +1303,9 @@ static int __tdx_enable_online_cpus(void) * This function internally calls cpus_read_lock()/unlock() to prevent * any cpu from going online and offline. * + * This function requires there's at least one online cpu for each CPU + * package to succeed. + * * This function assumes all online cpus are already in VMX operation. * * This function can be called in parallel by multiple callers. diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index 7b34ac257b9a..ca4e2edbf4bc 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -16,6 +16,7 @@ /* * TDX module SEAMCALL leaf functions */ +#define TDH_SYS_KEY_CONFIG 31 #define TDH_SYS_INFO 32 #define TDH_SYS_CONFIG 45 From patchwork Mon Feb 13 11:59:23 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Huang, Kai" X-Patchwork-Id: 13138312 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id EBD6AC64EC4 for ; Mon, 13 Feb 2023 12:01:44 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 7B2FD6B0083; Mon, 13 Feb 2023 07:01:42 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 73C186B0085; Mon, 13 Feb 2023 07:01:42 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 56B886B0087; Mon, 13 Feb 2023 07:01:42 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0010.hostedemail.com [216.40.44.10]) by kanga.kvack.org (Postfix) with ESMTP id 3F2266B0083 for ; Mon, 13 Feb 2023 07:01:42 -0500 (EST) Received: from smtpin11.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay07.hostedemail.com (Postfix) with ESMTP id 196D01615BA for ; Mon, 13 Feb 2023 12:01:42 +0000 (UTC) X-FDA: 80462129244.11.3E8D33E Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by imf18.hostedemail.com (Postfix) with ESMTP id DCCF41C0029 for ; Mon, 13 Feb 2023 12:01:39 +0000 (UTC) Authentication-Results: imf18.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=QHD6uN6n; spf=pass (imf18.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1676289700; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=RdfcsHWDVDtG1P+CRifyEeWTxdd0FDIz6IgiWxp1zAw=; b=l8NcO3yYRvlqr0betwkO1sq+vWtRW8OW4rI8lwOYcUWtWMTC5aDregfOPKvGmQdnkaIGnt kQf17nucBPze+TJInvtWJbtUDDz7V2J5hf92+QUvi8YVP1t1kGJyz+ZmorQsi9G72BIdfG pyreP24LFbJGMhMRGx6MPTPCv+Wc3HE= ARC-Authentication-Results: i=1; imf18.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=QHD6uN6n; spf=pass (imf18.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1676289700; a=rsa-sha256; cv=none; b=5ZiDUXNS5CgjDF1T44bSLwbSvt7nZzNbq89bKGV0SWFsZycBkIFcykvPE2oJl7s1QIg3nJ PqeUPihdyfL3cFP6KN9KLVEB4dH8oJYM6tpBffrylBqkZDnflkH6pFWxTiju12uxX/5bo4 uGLZtp372DvrXNERpUyTUcHKsbQWzHI= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1676289699; x=1707825699; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=TGDot2bjHCtuoG3UVHU78PX2clfks7hjsOzbIQgZuuE=; b=QHD6uN6n7rKXB6zJuhLbymE83NeqkuC3PKW6iVuefQh9aVPlcp0INgR+ SXjzScrTBrcle+/x1uy9oTWXWXHoBSwm4J+AiU4pOKdHG2v3Sbt6yWCrq NUErm81CPuozv5b5/sLE5dLnQj5OZVOQvrfkOOoAnwoivcIAZqZzIuhay fVDPbVy8TO0RFm5yCz/5mz5o6e2lDzM391NUNS3VWQRjOeAYSOkGBYazk FQ0zGv67+Gcgaz5seMzDHzoT3t537uD73mUmgIZeFwWKUwcsX+rS1E4xr Yaf2YzUCxVJhA/DQlFwIDzs/ZJEhKPK5z33oof3pcpG8oaQRC34CrbC3J g==; X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="358283510" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="358283510" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:01:37 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="701243539" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="701243539" Received: from wonger-mobl.amr.corp.intel.com (HELO khuang2-desk.gar.corp.intel.com) ([10.209.188.34]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:01:32 -0800 From: Kai Huang To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: linux-mm@kvack.org, dave.hansen@intel.com, peterz@infradead.org, tglx@linutronix.de, seanjc@google.com, pbonzini@redhat.com, dan.j.williams@intel.com, rafael.j.wysocki@intel.com, kirill.shutemov@linux.intel.com, ying.huang@intel.com, reinette.chatre@intel.com, len.brown@intel.com, tony.luck@intel.com, ak@linux.intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com, david@redhat.com, bagasdotme@gmail.com, sagis@google.com, imammedo@redhat.com, kai.huang@intel.com Subject: [PATCH v9 16/18] x86/virt/tdx: Initialize all TDMRs Date: Tue, 14 Feb 2023 00:59:23 +1300 Message-Id: X-Mailer: git-send-email 2.39.1 In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Server: rspam05 X-Rspamd-Queue-Id: DCCF41C0029 X-Stat-Signature: xz6ik5ttg9c6awfamxm3a9eo1tmosmfa X-Rspam-User: X-HE-Tag: 1676289699-532315 X-HE-Meta: U2FsdGVkX198G/QSRS+W0J3N6ide/ZKrU5zySL8pN54kNHf4P184p/e709byPhfJjHQTViwo3E2FlVVWPoXpGY2WQqNa0EwTNtJtCkB3jgX2JZEWz9QQpB1bcWZ/Yrj7KrkJGZylElKP+ggu0ahSLfmJn7wecKVcnC+vT70IhMtaIZs+b/hndqtxcWyTPjcbxuYBSRuCxowo8q3eGj5daCxzgXm9w/A4QtW9Yic7dRwM3QXGWRWOpsEvZnMRYv1MydU0obuQnZuugZ2fTv020cb+tGqUDHkHzMYbB+7ybtYVqYzusZfips1vujB6Ld/BJ2oQhW8EN8YFGkNlcUNjqUJzzY9+KHlSDVl8pN79oq0fREh+f0tvxPd12e1iRhuzgWybNx5eizeYj2XUwWfMhi0dD3VSq+dL3Xzo/1Vc9WVOqIM35jfUQ8eUsA9IdhopqnQ2NT3osQTftc2aAhM1JjtuErvW8E58r9uH/GxH4PLiDE+zaJ2NPOBeKpFbg5OtMF/m4oHAUq9pYWojk2OTJ0IW2YQ9t1P/HpAnyM+2ZAQffp3rg9/j7F4Nc5C26Z0Y2k1DycnoGPutYLsiDh0Iwk2Gl0v5dqnpjCA24F4kuSmNQ4LPtYvmuBqdf8+n3V3seEaDii5FD055NtTJXVqR3UVb9v/2yHqUj+WpJrQJzCOmANt+UFt/yRUGeejFIgMcQ268AOOKaZacfRRh2VH8iu20eMWEYzyakqyTZkWSP2PW3f63cVgK6JD57Nrsh3ZMy3jytBFXu+2kFWXfPl5oc2jBlW8hNA66EdX9z4lpVl0hmPIydTLx7+5s0U6hLQrMtkhdzme5bEOt6kkNSjCkRqCUiySx+u3ZzsOVlr7AlvH/Xk768/vubkvJMpIHteHmuw5UevzpI9M2kJOMO2lDqVc7psX+4VUO8J/szr5IhMEu9N8dfLV0moYs6LCglf+kylfk1i27350p6g0jZHd CJwHFa8V whaYkSM0sTXL+AFXiBvbh7gLsy6XFQPTwrkrPsyNiIhIRrq/H0yJz67HbbPA7N1T0HD98SXw99+V6mO5sfH/mMSZosArwoV0s3QJDPtYbr/85qOUs0nLGRLY1wPnOS2k66WXCt2PZy6NeXre5OvOLee1bxQw5DH2Owud/W3Jovxc0ub0= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: After the global KeyID has been configured on all packages, initialize all TDMRs to make all TDX-usable memory regions that are passed to the TDX module become usable. This is the last step of initializing the TDX module. Initializing TDMRs can be time consuming on large memory systems as it involves initializing all metadata entries for all pages that can be used by TDX guests. Initializing different TDMRs can be parallelized. For now to keep it simple, just initialize all TDMRs one by one. It can be enhanced in the future. Signed-off-by: Kai Huang Reviewed-by: Isaku Yamahata --- v8 -> v9: - Improved changlog to explain why initializing TDMRs can take long time (Dave). - Improved comments around 'next-to-initialize' address (Dave). v7 -> v8: (Dave) - Changelog: - explicitly call out this is the last step of TDX module initialization. - Trimed down changelog by removing SEAMCALL name and details. - Removed/trimmed down unnecessary comments. - Other changes due to 'struct tdmr_info_list'. v6 -> v7: - Removed need_resched() check. -- Andi. --- arch/x86/virt/vmx/tdx/tdx.c | 60 ++++++++++++++++++++++++++++++++----- arch/x86/virt/vmx/tdx/tdx.h | 1 + 2 files changed, 53 insertions(+), 8 deletions(-) diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c index ff6f2c9d9838..c291fbd29bb0 100644 --- a/arch/x86/virt/vmx/tdx/tdx.c +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -1086,6 +1086,56 @@ static int config_global_keyid(void) return ret; } +static int init_tdmr(struct tdmr_info *tdmr) +{ + u64 next; + + /* + * Initializing a TDMR can be time consuming. To avoid long + * SEAMCALLs, the TDX module may only initialize a part of the + * TDMR in each call. + */ + do { + struct tdx_module_output out; + int ret; + + /* All 0's are unused parameters, they mean nothing. */ + ret = seamcall(TDH_SYS_TDMR_INIT, tdmr->base, 0, 0, 0, NULL, + &out); + if (ret) + return ret; + /* + * RDX contains 'next-to-initialize' address if + * TDH.SYS.TDMR.INIT did not fully complete and + * should be retried. + */ + next = out.rdx; + cond_resched(); + /* Keep making SEAMCALLs until the TDMR is done */ + } while (next < tdmr->base + tdmr->size); + + return 0; +} + +static int init_tdmrs(struct tdmr_info_list *tdmr_list) +{ + int i; + + /* + * This operation is costly. It can be parallelized, + * but keep it simple for now. + */ + for (i = 0; i < tdmr_list->nr_consumed_tdmrs; i++) { + int ret; + + ret = init_tdmr(tdmr_entry(tdmr_list, i)); + if (ret) + return ret; + } + + return 0; +} + static int init_tdx_module(void) { static DECLARE_PADDED_STRUCT(tdsysinfo_struct, tdsysinfo, @@ -1170,15 +1220,9 @@ static int init_tdx_module(void) if (ret) goto out_free_pamts; - /* - * TODO: - * - * - Initialize all TDMRs. - * - * Return error before all steps are done. - */ + /* Initialize TDMRs to complete the TDX module initialization */ + ret = init_tdmrs(&tdx_tdmr_list); - ret = -EINVAL; out_free_pamts: if (ret) { /* diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h index ca4e2edbf4bc..4e312c7f9553 100644 --- a/arch/x86/virt/vmx/tdx/tdx.h +++ b/arch/x86/virt/vmx/tdx/tdx.h @@ -18,6 +18,7 @@ */ #define TDH_SYS_KEY_CONFIG 31 #define TDH_SYS_INFO 32 +#define TDH_SYS_TDMR_INIT 36 #define TDH_SYS_CONFIG 45 struct cmr_info { From patchwork Mon Feb 13 11:59:24 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Huang, Kai" X-Patchwork-Id: 13138313 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 9B261C636CC for ; Mon, 13 Feb 2023 12:01:46 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 287976B0085; Mon, 13 Feb 2023 07:01:46 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 173096B0087; Mon, 13 Feb 2023 07:01:46 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id E8F616B0088; Mon, 13 Feb 2023 07:01:45 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0015.hostedemail.com [216.40.44.15]) by kanga.kvack.org (Postfix) with ESMTP id D428E6B0085 for ; Mon, 13 Feb 2023 07:01:45 -0500 (EST) Received: from smtpin02.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay08.hostedemail.com (Postfix) with ESMTP id B34DB1416D6 for ; Mon, 13 Feb 2023 12:01:45 +0000 (UTC) X-FDA: 80462129370.02.1FAEEFF Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by imf18.hostedemail.com (Postfix) with ESMTP id 870DD1C001F for ; Mon, 13 Feb 2023 12:01:42 +0000 (UTC) Authentication-Results: imf18.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=NhB5lGB+; spf=pass (imf18.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1676289703; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=rKc9/iJhCIadU6Tu39L8nkDDWYBGjK38hhBdShNscZ0=; b=ThvHunjRCtf6DAWfIGSvQfSW7mDTQx5LimgQQsShQkb7CWODRVFoPhBySTxFJeaw91BKPm 6Y/TVzyjCFNCHeLl8D6rpompRbwcxcFY2c23UD/lF+mt02j87VIucSSlvZQLpGB8K14Aht A9Uv1S25+lhXTYCbqh6Qe1vGKRablv8= ARC-Authentication-Results: i=1; imf18.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=NhB5lGB+; spf=pass (imf18.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1676289704; a=rsa-sha256; cv=none; b=ODdnuFur3WiuYfy5b1CiWMOdE8PO8Yu2XwnkwbZYUlEvNceeDX3dGA45HZOXP1ha2SP+bK /bozvhSWsqHQXbhLjixoAYmzgUbccgActfp5C7PSzSEaIbBFq3yELvX14FMqWbAql2srBa Owm0wYlMyyuMsDeg2MfBFASm4BhK2wI= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1676289703; x=1707825703; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=aXDcPR17uuWmglTwVX1NU6yhdcGMUuz+E4pRKPyDy0k=; b=NhB5lGB+xbpPcFxTkNysEvNgDhj4tTqDvf4vxgpqGwbhreFcnCeYWzMd ecErYFWetHIqbwbA9tXqL2jFhtmxb9zvN0KjWlTv56vBCT2TjCSkalkuv k/qGB+10mqRSB6YO1sIPOvtdyfdeMoA0moGJ/mLxzOX0X2DyAmbKov220 NbHfWqV8sJSHmqgcXwKjyVg8zLKYHe1Uz57npnGX9RA9A3DPvys0RrndX haBCZyyrMaXZ/wbyae2NyH79PX27tOgAGJAYqPJzpbDoLVFs/H5MvqO4v D71UdMsNgvHL9A821riygjkuC0IPE/D8HZHyKh/tWGdmOU5ro+V2BfG+G g==; X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="358283527" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="358283527" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:01:42 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="701243552" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="701243552" Received: from wonger-mobl.amr.corp.intel.com (HELO khuang2-desk.gar.corp.intel.com) ([10.209.188.34]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:01:37 -0800 From: Kai Huang To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: linux-mm@kvack.org, dave.hansen@intel.com, peterz@infradead.org, tglx@linutronix.de, seanjc@google.com, pbonzini@redhat.com, dan.j.williams@intel.com, rafael.j.wysocki@intel.com, kirill.shutemov@linux.intel.com, ying.huang@intel.com, reinette.chatre@intel.com, len.brown@intel.com, tony.luck@intel.com, ak@linux.intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com, david@redhat.com, bagasdotme@gmail.com, sagis@google.com, imammedo@redhat.com, kai.huang@intel.com Subject: [PATCH v9 17/18] x86/virt/tdx: Flush cache in kexec() when TDX is enabled Date: Tue, 14 Feb 2023 00:59:24 +1300 Message-Id: X-Mailer: git-send-email 2.39.1 In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Server: rspam05 X-Rspamd-Queue-Id: 870DD1C001F X-Stat-Signature: 45pqy8capyoo8fxc6d6gh3usxwfhhcsb X-Rspam-User: X-HE-Tag: 1676289702-660120 X-HE-Meta: U2FsdGVkX194y97+QPTWYdCX1573w4mnsEAbcaFh/Vk/U4CZv9ilS3zOq9NNz0Hs1s/hM+Aai5MTVGplvkLC19rUtRZI42qqecVoKLb5i281tId9Q/wUilQO8KKPuuPB4hG87m4xBsPLCuFBeOZ4VGI/x+QKBMCAHjQGJusZY0kV3XM2T0CcZvxwNAdOzKyvkbsoDe3LZzlxHvDZHeiRvQrXsENfWj0zVOgxLZo0FJahQ2l/3qaFXAzzBWAdEGmHZMDaZHz5s8gCojN+ULUvSV5FC/3h+bqHCx2CPL8nS+O4J3hRnV6fBs4ZOflRtJ3ngo87LzSNHKDhD6lfYV41p+fO+9k2CL854LJu2R2W7tyacCga6OWUiNWHcSlmvTiqYBSoAQgLg7HoCUu76pkRKvz6xG2fkdauYICjqlFXCSql8BBOofRJK4bRraLFSys9JUkL59g2/u3Mtgmu7zWkuv7aIMW2lW7twRC9PfkK0Ib4J015Qbx1CzCkzxVNXnZ9b/RYSQnqHx1GPTABxSeS7NMm70b0v3rByYL2lWFo/FKaJ7tmx+j2Mz63PN1HmpYmLx+a2utcyIw9kUrrqM6p4anQYytfyQAL3IX3CapyKYh3Wrwxs+B7ZlFfb6XMnVlq/Qn4fuQIsnx580TPcbhXvuiiN1eVjatBhP3Ij8tGMyKtY+IWgCenmGvYZyCU9K47inDd+Xph6QENIZDz4S0+qImQdB1GsClyqZWOKHIcZK2hUiA5xcpVnTNSmS8s+6fITUcY1Tbavb4P3Hz1QXTBqq/119ImyeXba/zalz8/aVkFgpF2CM4/mzk3qxiXGvOJRyruG0RE2eLvjAoZt8mNyQV2eg50RsmcKz5pc+46vWa3l9byKzc4TElReNjrUXMoRvPLh8iyvj+FLpaopscBjJNRw7iQHWj995KfH+MVNGddD/1yKS9MXNei5SV0Qj27V4qQ3rekmTFU5rU/O84 QWqjrxpQ e5rieOWKQ3Imonoat39WP7LM31i7/Uj+LZ9IL0oki6sy8Tey/DWK5T2SM9jXAmZ4jVyMSQXyOOQaKVIP17AZL4uOnwAhk1wNxX+JnrbrUB5TK9tlNpyJYWCQ4kYdocLvLRE5bzeJH71owR3D+EaVnKTLZa/l9SnwAH7e6NkGltNZJK2c= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: There are two problems in terms of using kexec() to boot to a new kernel when the old kernel has enabled TDX: 1) Part of the memory pages are still TDX private pages; 2) There might be dirty cachelines associated with TDX private pages. The first problem doesn't matter. KeyID 0 doesn't have integrity check. Even the new kernel wants to use any non-zero KeyID, it needs to convert the memory to that KeyID and such conversion would work from any KeyID. However the old kernel needs to guarantee there's no dirty cacheline left behind before booting to the new kernel to avoid silent corruption from later cacheline writeback (Intel hardware doesn't guarantee cache coherency across different KeyIDs). There are two things that the old kernel needs to do to achieve that: 1) Stop accessing TDX private memory mappings: a. Stop making TDX module SEAMCALLs (TDX global KeyID); b. Stop TDX guests from running (per-guest TDX KeyID). 2) Flush any cachelines from previous TDX private KeyID writes. For 2), use wbinvd() to flush cache in stop_this_cpu(), following SME support. And in this way 1) happens for free as there's no TDX activity between wbinvd() and the native_halt(). Theoretically, cache flush is only needed when the TDX module has been initialized. However initializing the TDX module is done on demand at runtime, and it takes a mutex to read the module status. Just check whether TDX is enabled by the BIOS instead to flush cache. Signed-off-by: Kai Huang Reviewed-by: Isaku Yamahata --- v8 -> v9: - Various changelog enhancement and fix (Dave). - Improved comment (Dave). v7 -> v8: - Changelog: - Removed "leave TDX module open" part due to shut down patch has been removed. v6 -> v7: - Improved changelog to explain why don't convert TDX private pages back to normal. --- arch/x86/kernel/process.c | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/arch/x86/kernel/process.c b/arch/x86/kernel/process.c index 40d156a31676..5876dda412c7 100644 --- a/arch/x86/kernel/process.c +++ b/arch/x86/kernel/process.c @@ -765,8 +765,13 @@ void __noreturn stop_this_cpu(void *dummy) * * Test the CPUID bit directly because the machine might've cleared * X86_FEATURE_SME due to cmdline options. + * + * The TDX module or guests might have left dirty cachelines + * behind. Flush them to avoid corruption from later writeback. + * Note that this flushes on all systems where TDX is possible, + * but does not actually check that TDX was in use. */ - if (cpuid_eax(0x8000001f) & BIT(0)) + if (cpuid_eax(0x8000001f) & BIT(0) || platform_tdx_enabled()) native_wbinvd(); for (;;) { /* From patchwork Mon Feb 13 11:59:25 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Huang, Kai" X-Patchwork-Id: 13138314 Return-Path: X-Spam-Checker-Version: SpamAssassin 3.4.0 (2014-02-07) on aws-us-west-2-korg-lkml-1.web.codeaurora.org Received: from kanga.kvack.org (kanga.kvack.org [205.233.56.17]) by smtp.lore.kernel.org (Postfix) with ESMTP id 12B4FC636CC for ; Mon, 13 Feb 2023 12:01:52 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id A4ABB6B007D; Mon, 13 Feb 2023 07:01:51 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 9D4BB6B0087; Mon, 13 Feb 2023 07:01:51 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 826F16B0089; Mon, 13 Feb 2023 07:01:51 -0500 (EST) X-Delivered-To: linux-mm@kvack.org Received: from relay.hostedemail.com (smtprelay0017.hostedemail.com [216.40.44.17]) by kanga.kvack.org (Postfix) with ESMTP id 70DBF6B0087 for ; Mon, 13 Feb 2023 07:01:51 -0500 (EST) Received: from smtpin22.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay07.hostedemail.com (Postfix) with ESMTP id 37D0516164B for ; Mon, 13 Feb 2023 12:01:51 +0000 (UTC) X-FDA: 80462129622.22.CA75369 Received: from mga01.intel.com (mga01.intel.com [192.55.52.88]) by imf18.hostedemail.com (Postfix) with ESMTP id 9076C1C0028 for ; Mon, 13 Feb 2023 12:01:48 +0000 (UTC) Authentication-Results: imf18.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=M3C1wsx5; spf=pass (imf18.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=hostedemail.com; s=arc-20220608; t=1676289709; h=from:from:sender:reply-to:subject:subject:date:date: message-id:message-id:to:to:cc:cc:mime-version:mime-version: content-type:content-transfer-encoding:content-transfer-encoding: in-reply-to:in-reply-to:references:references:dkim-signature; bh=8u9bePdMvnRhsuSfdz4Y/Sjlvhbyrm8i3jUTymnEv/E=; b=v1EbVtuFQNX5bUOGqoESMHUInYIIcBPjvMZl51KS0yd6WJDoOULoRcjxh2R60Dt+7FSbmi A9/T77dNP0e3Hkw36niqzQwaaco9+ZuRw9coYU+eXhvEUedA69hsUjwXfd0hM3rXL/Iapa BBojzYb19mulVvfT4G85vsNOn8TcW8c= ARC-Authentication-Results: i=1; imf18.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=M3C1wsx5; spf=pass (imf18.hostedemail.com: domain of kai.huang@intel.com designates 192.55.52.88 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1676289709; a=rsa-sha256; cv=none; b=1kw6tAsiEvDac3gOE2eLtNabljTVGfDlu1tIkI4Z0LNPd4Jn63byBH9bmMHxlZmR2Y7N3J VeD40dywXIPZEBUtrqQez7vgPls/FF6tf4HpgD/4XJdxmmtTNWqJkjWYdNLzA3+8q/hhhF 2NLN7gVOT5B9/S8wHHXGjZQ4QCnZvY0= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1676289708; x=1707825708; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=qRkFxe75ERnC5jK/b+M7BGDdGYgReE01fFl0GkUIxpw=; b=M3C1wsx5jJvtc9c6kvXXH4qZttt0HQ+KVJelPz4DWLTurwYIb2eRyuVK r2T1Atsnm+I296nsNuxvRbfQcmeODgFGL1pMwX3oxr/83zA97i7/j9pwZ 8tQcgY0CytDgF+B/QycxfW8M1d7FplN/ecjkilVQkuvIfx7ala0dil+1T BEdubLlp/zi5lmLxwNNQmfGffSKEx8hzngCssoGPnK04WrXqOS2AIpVfS 39BtgZiB2rFoCGhqpGdexSKohzLv/7MyRqdNXe3kOeH8pgb28ecryOgDU S0rv/Mrb4hqqoEqb1UKsFgR/qPbPGTtVg5iDEsV+IeKt+SM42END6KrEi w==; X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="358283555" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="358283555" Received: from orsmga001.jf.intel.com ([10.7.209.18]) by fmsmga101.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:01:48 -0800 X-IronPort-AV: E=McAfee;i="6500,9779,10619"; a="701243571" X-IronPort-AV: E=Sophos;i="5.97,293,1669104000"; d="scan'208";a="701243571" Received: from wonger-mobl.amr.corp.intel.com (HELO khuang2-desk.gar.corp.intel.com) ([10.209.188.34]) by orsmga001-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 13 Feb 2023 04:01:42 -0800 From: Kai Huang To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: linux-mm@kvack.org, dave.hansen@intel.com, peterz@infradead.org, tglx@linutronix.de, seanjc@google.com, pbonzini@redhat.com, dan.j.williams@intel.com, rafael.j.wysocki@intel.com, kirill.shutemov@linux.intel.com, ying.huang@intel.com, reinette.chatre@intel.com, len.brown@intel.com, tony.luck@intel.com, ak@linux.intel.com, isaku.yamahata@intel.com, chao.gao@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com, david@redhat.com, bagasdotme@gmail.com, sagis@google.com, imammedo@redhat.com, kai.huang@intel.com Subject: [PATCH v9 18/18] Documentation/x86: Add documentation for TDX host support Date: Tue, 14 Feb 2023 00:59:25 +1300 Message-Id: X-Mailer: git-send-email 2.39.1 In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Server: rspam05 X-Rspamd-Queue-Id: 9076C1C0028 X-Stat-Signature: f4w8kris9a7oxisz3omjm4bw5f1tbsk9 X-Rspam-User: X-HE-Tag: 1676289708-795578 X-HE-Meta: U2FsdGVkX19jcAtfTWgSe/P5XiZQvqbZZLzVxVlbOMMHUBeTuCNDHLUsdJ5htQd26vs+T9LXGFxBj067m5cJ56cUMFFLhaDSpkEJNPW4fbZoe1xMYzzK1c0SpcRxQUVCACfGxIJJ8boD3jro7MC8g9KH0xJwuDRnJvI9IGwyJN0HXdBlKLrUX9gFXv0vedrHVA+L6VRwb1l3BWKYbwcbFxVGjJdulHrpLnqYjGVmHELauyUTzJf7TCkfEEeJxAXp0NxL4QwiiBIAth2FfDG+sO/KyRstWEYIx4wvZYCyFYQ0Vc+bbLj0uga8PmaEtWJPqXdL5nQBO68aAJ9GqufaVVMOV/G33LndG75DaGWLrUwMDXFZkPpfAghsodl1d6rBT6ZG6HmiGIRRrPDWttke0kMzjj/1456TBbvnrsuIoYSqYLDnVeletoBEGSEFxzJ+OBR8vnbEAPMWpQ+NP12OUV69u6ztVt/HSzlHsQKLmGq9b+IP8BVR95SxrKSTHcpeHVOckVhKeOYLhlwZ5YAK8gOkhnJS9IFL+fe7qMz/yPJsz8x241BjKDvIf3M0DbCQw40hHWTQe7lNd8wIicRc/qKTMQf+ZK8PAOdq130V20512H7+9d1+aJJiKZivjWQeq++KgzQ448+zHCirMk9AKTHj9awjuJThmT12yD+8x7THtSl+yKdgWrhMm/3bzz5RLeRzDYJJeqZ5g7xOy85f1qiHXgmo4xxT85EX6aQ0QKT34vmmWEk3LMNGsfMj+jlt4F5fBKHlMc8dpS9Ka1gEQ2RVWLcxE5d9gMAva1w0+6QGGbC7ZfER1dpHqWUVfCp3lqni+ToFsaUXxIU1xy3HCe3DMPB18MLIxOqwJFgYmmbaEr0eMFBtate8qLsRdlxOGmhxqvYAJoHDTRSB/EnlvPpxjZwlLt+fwe7xbekZGg9Z3TleMsRcYT8sqsEXPYBKaGmcGfX7ZZGr13ncmr7 e5KexAMB EKIwYWvAR7Ce1nif625abK1IlGqjhyj5X4B0e5lQ/J1H1NpQR4oVJt2tnM6NylvrY1EuF3gO+YvR27s88YaiWeuR9mb0TDfIXcVcYotIwRyvusbl1OPGbDDs7IpTzp/0uc6T+MhhVghi4ocXoKinbi4AR5k3XX+RVoc4j+jllunXh+bU= X-Bogosity: Ham, tests=bogofilter, spamicity=0.000000, version=1.2.4 Sender: owner-linux-mm@kvack.org Precedence: bulk X-Loop: owner-majordomo@kvack.org List-ID: Add documentation for TDX host kernel support. There is already one file Documentation/x86/tdx.rst containing documentation for TDX guest internals. Also reuse it for TDX host kernel support. Introduce a new level menu "TDX Guest Support" and move existing materials under it, and add a new menu for TDX host kernel support. Signed-off-by: Kai Huang --- Documentation/x86/tdx.rst | 176 +++++++++++++++++++++++++++++++++++--- 1 file changed, 165 insertions(+), 11 deletions(-) diff --git a/Documentation/x86/tdx.rst b/Documentation/x86/tdx.rst index dc8d9fd2c3f7..8a84d7646bc3 100644 --- a/Documentation/x86/tdx.rst +++ b/Documentation/x86/tdx.rst @@ -10,6 +10,160 @@ encrypting the guest memory. In TDX, a special module running in a special mode sits between the host and the guest and manages the guest/host separation. +TDX Host Kernel Support +======================= + +TDX introduces a new CPU mode called Secure Arbitration Mode (SEAM) and +a new isolated range pointed by the SEAM Ranger Register (SEAMRR). A +CPU-attested software module called 'the TDX module' runs inside the new +isolated range to provide the functionalities to manage and run protected +VMs. + +TDX also leverages Intel Multi-Key Total Memory Encryption (MKTME) to +provide crypto-protection to the VMs. TDX reserves part of MKTME KeyIDs +as TDX private KeyIDs, which are only accessible within the SEAM mode. +BIOS is responsible for partitioning legacy MKTME KeyIDs and TDX KeyIDs. + +Before the TDX module can be used to create and run protected VMs, it +must be loaded into the isolated range and properly initialized. The TDX +architecture doesn't require the BIOS to load the TDX module, but the +kernel assumes it is loaded by the BIOS. + +TDX boot-time detection +----------------------- + +The kernel detects TDX by detecting TDX private KeyIDs during kernel +boot. Below dmesg shows when TDX is enabled by BIOS:: + + [..] tdx: BIOS enabled: private KeyID range: [16, 64). + +TDX module detection and initialization +--------------------------------------- + +There is no CPUID or MSR to detect the TDX module. The kernel detects it +by initializing it. + +The kernel talks to the TDX module via the new SEAMCALL instruction. The +TDX module implements SEAMCALL leaf functions to allow the kernel to +initialize it. + +Initializing the TDX module consumes roughly ~1/256th system RAM size to +use it as 'metadata' for the TDX memory. It also takes additional CPU +time to initialize those metadata along with the TDX module itself. Both +are not trivial. The kernel initializes the TDX module at runtime on +demand. The caller to call tdx_enable() to initialize the TDX module:: + + ret = tdx_enable(); + if (ret) + goto no_tdx; + // TDX is ready to use + +One step of initializing the TDX module requires at least one online cpu +for each package. The caller needs to guarantee this otherwise the +initialization will fail. + +Making SEAMCALL requires the CPU already being in VMX operation (VMXON +has been done). For now tdx_enable() doesn't handle VMXON internally, +but depends on the caller to guarantee that. So far only KVM calls +tdx_enable() and KVM already handles VMXON. + +User can consult dmesg to see the presence of the TDX module, and whether +it has been initialized. + +If the TDX module is not loaded, dmesg shows below:: + + [..] tdx: TDX module is not loaded. + +If the TDX module is initialized successfully, dmesg shows something +like below:: + + [..] tdx: TDX module: attributes 0x0, vendor_id 0x8086, major_version 1, minor_version 0, build_date 20211209, build_num 160 + [..] tdx: 262668 KBs allocated for PAMT. + [..] tdx: TDX module initialized. + +If the TDX module failed to initialize, dmesg also shows it failed to +initialize:: + + [..] tdx: initialization failed ... + +TDX Interaction to Other Kernel Components +------------------------------------------ + +TDX Memory Policy +~~~~~~~~~~~~~~~~~ + +TDX reports a list of "Convertible Memory Region" (CMR) to tell the +kernel which memory is TDX compatible. The kernel needs to build a list +of memory regions (out of CMRs) as "TDX-usable" memory and pass those +regions to the TDX module. Once this is done, those "TDX-usable" memory +regions are fixed during module's lifetime. + +To keep things simple, currently the kernel simply guarantees all pages +in the page allocator are TDX memory. Specifically, the kernel uses all +system memory in the core-mm at the time of initializing the TDX module +as TDX memory, and in the meantime, refuses to online any non-TDX-memory +in the memory hotplug. + +This can be enhanced in the future, i.e. by allowing adding non-TDX +memory to a separate NUMA node. In this case, the "TDX-capable" nodes +and the "non-TDX-capable" nodes can co-exist, but the kernel/userspace +needs to guarantee memory pages for TDX guests are always allocated from +the "TDX-capable" nodes. + +Physical Memory Hotplug +~~~~~~~~~~~~~~~~~~~~~~~ + +Note TDX assumes convertible memory is always physically present during +machine's runtime. A non-buggy BIOS should never support hot-removal of +any convertible memory. This implementation doesn't handle ACPI memory +removal but depends on the BIOS to behave correctly. + +CPU Hotplug +~~~~~~~~~~~ + +TDX module requires one SEAMCALL (TDH.SYS.LP.INIT) to do per-cpu module +initialization on one cpu before any other SEAMCALLs can be made on that +cpu, including those involved during the module initialization. + +Currently kernel simply guarantees all online cpus are "TDX-runnable" +(TDH.SYS.LP.INIT has been done successfully on them). During module +initialization, the SEAMCALL is done for all online cpus and CPU hotplug +is disabled during the entire module initialization. If any fails, TDX +is disabled. In CPU hotplug, the kernel provides another function +tdx_cpu_online() for the user of TDX (KVM for now) to call in it's own +CPU online callback, and reject to online the cpu if SEAMCALL fails. + +TDX doesn't support physical (ACPI) CPU hotplug. During machine boot, +TDX verifies all boot-time present logical CPUs are TDX compatible before +enabling TDX. A non-buggy BIOS should never support hot-add/removal of +physical CPU. Currently the kernel doesn't handle physical CPU hotplug, +but depends on the BIOS to behave correctly. + +Note TDX works with CPU logical online/offline, thus the kernel still +allows to offline logical CPU and online it again. + +Kexec() +~~~~~~~ + +There are two problems in terms of using kexec() to boot to a new kernel +when the old kernel has enabled TDX: 1) Part of the memory pages are +still TDX private pages; 2) There might be dirty cachelines associated +with TDX private pages. + +The first problem doesn't matter. KeyID 0 doesn't have integrity check. +Even the new kernel wants use any non-zero KeyID, it needs to convert +the memory to that KeyID and such conversion would work from any KeyID. + +However the old kernel needs to guarantee there's no dirty cacheline +left behind before booting to the new kernel to avoid silent corruption +from later cacheline writeback (Intel hardware doesn't guarantee cache +coherency across different KeyIDs). + +Similar to AMD SME, the kernel just uses wbinvd() to flush cache before +booting to the new kernel. + +TDX Guest Support +================= Since the host cannot directly access guest registers or memory, much normal functionality of a hypervisor must be moved into the guest. This is implemented using a Virtualization Exception (#VE) that is handled by the @@ -20,7 +174,7 @@ TDX includes new hypercall-like mechanisms for communicating from the guest to the hypervisor or the TDX module. New TDX Exceptions -================== +------------------ TDX guests behave differently from bare-metal and traditional VMX guests. In TDX guests, otherwise normal instructions or memory accesses can cause @@ -30,7 +184,7 @@ Instructions marked with an '*' conditionally cause exceptions. The details for these instructions are discussed below. Instruction-based #VE ---------------------- +~~~~~~~~~~~~~~~~~~~~~ - Port I/O (INS, OUTS, IN, OUT) - HLT @@ -41,7 +195,7 @@ Instruction-based #VE - CPUID* Instruction-based #GP ---------------------- +~~~~~~~~~~~~~~~~~~~~~ - All VMX instructions: INVEPT, INVVPID, VMCLEAR, VMFUNC, VMLAUNCH, VMPTRLD, VMPTRST, VMREAD, VMRESUME, VMWRITE, VMXOFF, VMXON @@ -52,7 +206,7 @@ Instruction-based #GP - RDMSR*,WRMSR* RDMSR/WRMSR Behavior --------------------- +~~~~~~~~~~~~~~~~~~~~ MSR access behavior falls into three categories: @@ -73,7 +227,7 @@ trapping and handling in the TDX module. Other than possibly being slow, these MSRs appear to function just as they would on bare metal. CPUID Behavior --------------- +~~~~~~~~~~~~~~ For some CPUID leaves and sub-leaves, the virtualized bit fields of CPUID return values (in guest EAX/EBX/ECX/EDX) are configurable by the @@ -93,7 +247,7 @@ not know how to handle. The guest kernel may ask the hypervisor for the value with a hypercall. #VE on Memory Accesses -====================== +---------------------- There are essentially two classes of TDX memory: private and shared. Private memory receives full TDX protections. Its content is protected @@ -107,7 +261,7 @@ entries. This helps ensure that a guest does not place sensitive information in shared memory, exposing it to the untrusted hypervisor. #VE on Shared Memory --------------------- +~~~~~~~~~~~~~~~~~~~~ Access to shared mappings can cause a #VE. The hypervisor ultimately controls whether a shared memory access causes a #VE, so the guest must be @@ -127,7 +281,7 @@ be careful not to access device MMIO regions unless it is also prepared to handle a #VE. #VE on Private Pages --------------------- +~~~~~~~~~~~~~~~~~~~~ An access to private mappings can also cause a #VE. Since all kernel memory is also private memory, the kernel might theoretically need to @@ -145,7 +299,7 @@ The hypervisor is permitted to unilaterally move accepted pages to a to handle the exception. Linux #VE handler -================= +----------------- Just like page faults or #GP's, #VE exceptions can be either handled or be fatal. Typically, an unhandled userspace #VE results in a SIGSEGV. @@ -167,7 +321,7 @@ While the block is in place, any #VE is elevated to a double fault (#DF) which is not recoverable. MMIO handling -============= +------------- In non-TDX VMs, MMIO is usually implemented by giving a guest access to a mapping which will cause a VMEXIT on access, and then the hypervisor @@ -189,7 +343,7 @@ MMIO access via other means (like structure overlays) may result in an oops. Shared Memory Conversions -========================= +------------------------- All TDX guest memory starts out as private at boot. This memory can not be accessed by the hypervisor. However, some kernel users like device