From patchwork Mon Mar 6 14:13:47 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Huang, Kai" X-Patchwork-Id: 13161217 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 D0C5EC61DA4 for ; Mon, 6 Mar 2023 14:14:42 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 671E26B0073; Mon, 6 Mar 2023 09:14:42 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 622A9280002; Mon, 6 Mar 2023 09:14:42 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 4C398280001; Mon, 6 Mar 2023 09:14:42 -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 3C35C6B0073 for ; Mon, 6 Mar 2023 09:14:42 -0500 (EST) Received: from smtpin11.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay08.hostedemail.com (Postfix) with ESMTP id 0E39B14043E for ; Mon, 6 Mar 2023 14:14:42 +0000 (UTC) X-FDA: 80538669204.11.6015F61 Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by imf03.hostedemail.com (Postfix) with ESMTP id DC34A2000B for ; Mon, 6 Mar 2023 14:14:39 +0000 (UTC) Authentication-Results: imf03.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=XCmVtalQ; dmarc=pass (policy=none) header.from=intel.com; spf=pass (imf03.hostedemail.com: domain of kai.huang@intel.com designates 134.134.136.24 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=1678112080; 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=vFnKjnW2TAIoTuGWc5ZCUtdQVts2h4dgavA5fZAr0lE=; b=W3tXRqODR/OLkfKDXsfIOOU1+S6ytcrcMctUh9hHKz66NUTJ76mpD2fA64ZUkC1YQLBrEx KOWAvjqVnFba+/4i47uX+ROUsKHdY08q7qQ24pdDZSfKGisFhtjjuWNpqnSy+stgv39zno qkvwa5ls3HJ41WK2GskkkNPeOaWmbaU= ARC-Authentication-Results: i=1; imf03.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=XCmVtalQ; dmarc=pass (policy=none) header.from=intel.com; spf=pass (imf03.hostedemail.com: domain of kai.huang@intel.com designates 134.134.136.24 as permitted sender) smtp.mailfrom=kai.huang@intel.com ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1678112080; a=rsa-sha256; cv=none; b=WhTBts7AlJyaG4NQRoFXuEYptEkpSWitXTUqz8M8PQU45GzOiMHgwSvNKqXTflC3ErU6M1 nY7NBmp+cPTLDhkyMr49/nc9EN574XBU2UuaMT/C/6N4n0UCAUexAApok+BtAMfalz5g99 B6GLJpLAHke5ENOIamtPJQcRAr1UnP4= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1678112080; x=1709648080; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=E/xESLm6AuJmJjZ1XaxBdqGbrkk49BYxt+tFKArhrw4=; b=XCmVtalQPWrvo64Q/4DGnU6MMHJRPwZm+zJAL3k2E0a7+tmbVWwcNx96 ke0zHRA3UYMcut4f6aNEPNUzosNpWNLaBVcZJbyB82vbMyigTRITNiZKh 49gewf1BVrrAOdYmdYctECXFGHJwZyIr0g578EQgjj35lBe35d3KrDP40 aNghPyInEqb/wa1owJA8+QZ3QvMRG+fQu7n10jQZvsI+oVRFff6BG8+cq /EvjpRYBqvpfWi1BYyDuc9oay4d9osTbURjsps90woEnMPPEmd+TGuBM3 gNBu/pXqb04wRMrLLOL4e46DEuNjL33zgtkh/dfXcrKTnxZRiNEtu4b6q Q==; X-IronPort-AV: E=McAfee;i="6500,9779,10641"; a="337080009" X-IronPort-AV: E=Sophos;i="5.98,238,1673942400"; d="scan'208";a="337080009" Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Mar 2023 06:14:39 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10641"; a="765232021" X-IronPort-AV: E=Sophos;i="5.98,238,1673942400"; d="scan'208";a="765232021" Received: from jwhisle1-mobl2.amr.corp.intel.com (HELO khuang2-desk.gar.corp.intel.com) ([10.212.92.57]) by fmsmga003-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 06 Mar 2023 06:14:34 -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 v10 02/16] x86/virt/tdx: Detect TDX during kernel boot Date: Tue, 7 Mar 2023 03:13:47 +1300 Message-Id: <35a2421ca97d9e8dd938dcd744674602f4faa617.1678111292.git.kai.huang@intel.com> X-Mailer: git-send-email 2.39.2 In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Queue-Id: DC34A2000B X-Rspamd-Server: rspam09 X-Rspam-User: X-Stat-Signature: hgiw6qmh1p3g5ftiqnq4um4yfun14qhn X-HE-Tag: 1678112079-236556 X-HE-Meta: U2FsdGVkX19oPe+umVQiy8YaUHqKVKgtqvmyyABL/Vyxw04dhFhJwnVbtbOobaJkGS7lDr82NUNO85cs8HzzwTnyXj14uUMnYBCi2fGTrTqvWVPpd1kerImo1wlzHPxw83Ye1mSbspHCHIIJOhheni796VEF3o4oYquT51phtDBGanSbLtA1arps/fl6sllyqnKZQKejLfnk4T1IB/xp9x3MwLNF1oZ8KLjyptXS3xGQweVo4yKgWtjdVkMS/k0fuM0uFtUvibCpeEnIvIhmW+E4h8BzGOFIXuxaX+FsU6SzhODiht19bOcppxFWHe69OmRmMzv1ZrkNFp/s/CcNAjHz1FhTRHiLAafbVmIbXPIwAmGLTDwqOvbshqBuNZ4XJxfND2YE7AcFBT+kh6E6XXHWqS2na/9vmnblvSuNOtuxiMbyGIWHANYAZfx+IcGcx44vgXNfNI+l0fNWVHkyFSy8+wc160kR6TmiZAje0V7ogMew5hmx82u40U22yYfvcLFKjYajfu/5FFQjR5wCqY99tadQR4UWZ2atXF6rGyLjW9AUDzB2A5q59zjZDTQiFMPPl3CsNJ3J1zKhDFxrK4StxhjUvOK7QqJqKnPKYWAP3a7TJ0ncPP7ZIqySlBt59rslYs0RQuexL1mQyMZhBnem8FXl9sfYBL0P5z1giz9SvTDdoxSkxiOMctmtokPV5tShyV7+UHQo2t9iWzmgd/6l6fXiBf2tZHIVeDEzABnvOIKLbthlSD37a4D7ys/ZT1Emi/BLcGDICVSOUQHZGEPKVPiTORg+5VjAuqd5C6SQEvC6aWTIgMdxHFLlslHa965bK4nQ3C/xrQFflAPX1Ga6i676ymuyFJXXhGjnsxrnGoG2FBjRP4/93xr6MNq/EjSyaAMt3hCMDqn0n56BMOoLLk0MI1d1Gpwo01ETD0/9N25NLxWpye8+yMDdhNC+11fV7al5qiDrugOAt1K 3OrQf/1E qWqcDgx+LoQ0DWMCn+UZIqmxzNhdJf+9bJXedI13ziAmW5NLamD+1oKpzmA2sF4n/aN0pGMyEQED0/hDnGl7eAjkDMCDpbuOnTusx1nr0Sr0JQLzq2Gm1tzbyqSlZEqn1guhKlYzsGDMIdE7dJ2kmYbH2D/lWDvTFmYuKhjMQ45olCIg= 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 --- v9 -> v10: - No change. 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; +}