From patchwork Mon Jun 26 14:12:32 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Huang, Kai" X-Patchwork-Id: 13292970 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 8BC02EB64D7 for ; Mon, 26 Jun 2023 14:13:50 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 2F4058D0003; Mon, 26 Jun 2023 10:13:50 -0400 (EDT) Received: by kanga.kvack.org (Postfix, from userid 40) id 2A3418D0001; Mon, 26 Jun 2023 10:13:50 -0400 (EDT) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 192A18D0003; Mon, 26 Jun 2023 10:13:50 -0400 (EDT) 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 0C4008D0001 for ; Mon, 26 Jun 2023 10:13:50 -0400 (EDT) Received: from smtpin09.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay02.hostedemail.com (Postfix) with ESMTP id D37F012069D for ; Mon, 26 Jun 2023 14:13:49 +0000 (UTC) X-FDA: 80945092578.09.3104752 Received: from mga18.intel.com (mga18.intel.com [134.134.136.126]) by imf09.hostedemail.com (Postfix) with ESMTP id 8ABCD14001A for ; Mon, 26 Jun 2023 14:13:47 +0000 (UTC) Authentication-Results: imf09.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b="X5T/3x81"; spf=pass (imf09.hostedemail.com: domain of kai.huang@intel.com designates 134.134.136.126 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=1687788827; 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=CKLcb4n1OvSW1pq6wsIu8HJ/8KW6Qigm5L2LtTDpXx0=; b=lQwlZZiNFTEan9fO9J6r1bIsMarKVw9Ab9abeDAKi61fzcjYw6p2ZG3f/ur0R2OXJdE47+ Du1+GUwNEAvs8x2ID0wbzymVmoKU8qVdDWbjaQ90Wt+wNjdeRWk+RvkNzwkQVgo68rZ11w TdzGsTsAwGmA299EMoV2THN5Ivm57J8= ARC-Seal: i=1; s=arc-20220608; d=hostedemail.com; t=1687788827; a=rsa-sha256; cv=none; b=G6pKI6i0xXBxMl2Yd5dcUyiPXah+3Yf9IR0C4lKDybbVx+tPLqCfWlFD8clN9z4yDNOCkm hxWjReDINiRQqoKUcLN2bieau9sBrq6tB26391ksrk2xaFGoeEKE8x6IySkPEmOZDvb7Fv Td+YnC4ElpdvM0F3UhD+Yhm9QKwG24I= ARC-Authentication-Results: i=1; imf09.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b="X5T/3x81"; spf=pass (imf09.hostedemail.com: domain of kai.huang@intel.com designates 134.134.136.126 as permitted sender) smtp.mailfrom=kai.huang@intel.com; dmarc=pass (policy=none) header.from=intel.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1687788827; x=1719324827; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=AleeWME7o6+0K/8YXlexP0eyV6hKggwVTUBDGmDHQc8=; b=X5T/3x81laJUWQylFXGDEG6+MBk3ZaW8Pmf3h5tx9rAIQX08/61T21zx 1yvTMWHDWBYyk7YOTkhbWzslMuQxREvUCUIPJ1gdsRpxmGxSANgWEMaVW gjakBocuSEQyq4Ap2PDg2w3T5+yZ/X3An+CIh6CoTo+y/wTnk27BC/wpK WQRvXGjNKvcAryeflRnAtv5u81xpW1szGmoGqGajGD3VoVWnGOfu0S9/r 0YDSDbUJO5+0C8StllmkGUI9mgI0Jj/UmDnXxfMfIa7LCaQpU9TOcp9Yz l0kvmOkmXSXZNwx+RXJcuu/vc4v0RDHmwCnlu8YXutbeoxmzLIHrtLK2n Q==; X-IronPort-AV: E=McAfee;i="6600,9927,10753"; a="346033531" X-IronPort-AV: E=Sophos;i="6.01,159,1684825200"; d="scan'208";a="346033531" Received: from orsmga005.jf.intel.com ([10.7.209.41]) by orsmga106.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 26 Jun 2023 07:13:45 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6600,9927,10753"; a="890292238" X-IronPort-AV: E=Sophos;i="6.01,159,1684825200"; d="scan'208";a="890292238" Received: from smithau-mobl1.amr.corp.intel.com (HELO khuang2-desk.gar.corp.intel.com) ([10.213.179.223]) by orsmga005-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 26 Jun 2023 07:13:38 -0700 From: Kai Huang To: linux-kernel@vger.kernel.org, kvm@vger.kernel.org Cc: linux-mm@kvack.org, x86@kernel.org, dave.hansen@intel.com, kirill.shutemov@linux.intel.com, tony.luck@intel.com, peterz@infradead.org, tglx@linutronix.de, bp@alien8.de, mingo@redhat.com, hpa@zytor.com, seanjc@google.com, pbonzini@redhat.com, david@redhat.com, dan.j.williams@intel.com, rafael.j.wysocki@intel.com, ashok.raj@intel.com, reinette.chatre@intel.com, len.brown@intel.com, ak@linux.intel.com, isaku.yamahata@intel.com, ying.huang@intel.com, chao.gao@intel.com, sathyanarayanan.kuppuswamy@linux.intel.com, nik.borisov@suse.com, bagasdotme@gmail.com, sagis@google.com, imammedo@redhat.com, kai.huang@intel.com Subject: [PATCH v12 02/22] x86/virt/tdx: Detect TDX during kernel boot Date: Tue, 27 Jun 2023 02:12:32 +1200 Message-Id: <648189408c827bde1003344294c9222861d3315f.1687784645.git.kai.huang@intel.com> X-Mailer: git-send-email 2.40.1 In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Queue-Id: 8ABCD14001A X-Rspam-User: X-Stat-Signature: gzsnwa4ay9smtgrhonuyax9c59gcj5ds X-Rspamd-Server: rspam03 X-HE-Tag: 1687788827-26356 X-HE-Meta: U2FsdGVkX19Mvt/fNygwVCpvMtOvrfqVxLJzsJjtOdr2EvqGK7sNN3Vo9NtwO5T1ISXF3PeEPv2KkoUxm7xlzzzdhJiESbKlXdC9LTlX097VAYo7+AEg8tr2ofHN46Txec+J77Dvab5A6ma+igYwd1pkaUhunj7h34TNJEyzHFf6lS7m82hM+F/CKRKuircn1RO9iuflt06mMZVz9IeoRZJIkzwdIdbmNeA+xh0hfdRXHbNC9Y+XmY7p3CVbnSqN/ayE3dNWCHy0GW07fVOce50DpIbjWY/6S6hkXnfP1AGfK7UEylkFLKTCfucT7KpX4xEantfepahqtXo+rAUGsaEe239+QoiOR7wmcvBJrYxGw32fmHh2mlU9Sy4ea/bFWmK/psSXQ5kgxLxGZHOC/3qShq/Qb/MhdSzFW7f6dj2Y3CzI+oH+Y3ryQSvhO9L1iB+KZOuJxK1uMtOexvvuk3ptDX7011BC96/A3W+vmrvhxE8NTJV0AWyCp7GVpr+uoe/xoCsmU1QXGuYe8bs2heViSLIpg5bDb0ocFx1TeYowaR80crVTcfG/JwNVyRecaLVY0brqac37fxoRjtJQM1aXlIn9sfvubiI0fCquJ7aPA/xtrXR5TfEiMfAM6frR7EVCujC2anxI+YK7059rUkSaSFRPDUMnAFiUgb4TIH/+7fB1atqcth8bX+XBoqNGhgIc9PyUXEAAF3Q5YnLy4RW2pkCfyTXxxMPnym030C5w/TapySi4LJui1JleOxH5wzx1UYqkLjFzAr5QVQSRFZg3LQ70bea1XZy8EJckIBJzE+iQeKHZe0KtSChmjtOiRk/WQ/gV9sheUUqWYKM0wIFMhVDfyDMHTbNh1SPQFEnJ9cPoiOP+td/yUAT6VfMM1yrTYvkwrMcebSINo8l5mCAL0p5hsqxf6D2wsBHADMJsBI9T7rZTG8rbKmIzyx+BYCHsgZ3lIooTFhsKX0j 8RT6sbrc /xJivwb8vm6Ud0FNm1y+rYDBuRiM7g9xOM4s8/zhmpS0TSPr0AFK8/F+vh5xW/QLGb99imzEF8v8HGsxVNzyp1VeRlbNag1SbS5ZzGBn8rhZ7j1FuYC4IOaviUrp0anfaXCZiXKH2jvwXeCrMrFK+mUIETH4LyBKGoMZSmGfBVgWRla8CyclmLbmk/A== 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. During machine boot, TDX microcode verifies that the BIOS programmed TDX private KeyIDs consistently and correctly programmed across all CPU packages. The MSRs are locked in this state after verification. This is why MSR_IA32_MKTME_KEYID_PARTITIONING gets used for TDX enumeration: it indicates not just that the hardware supports TDX, but that all the boot-time security checks passed. 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 Reviewed-by: Isaku Yamahata Reviewed-by: David Hildenbrand --- v11 -> v12: - Improve setting up guest's TDX keyID range (David) - ++tdx_keyid_start -> tdx_keyid_start + 1 - --nr_tdx_keyids -> nr_tdx_keyids - 1 - 'return -ENODEV' instead of 'goto no_tdx' (Sathy) - pr_info() -> pr_err() (Isaku) - Added tags from Isaku/David v10 -> v11 (David): - "host kernel" -> "the host kernel" - "protected VM" -> "confidential VM". - Moved setting tdx_global_keyid to the end of tdx_init(). 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 | 90 ++++++++++++++++++++++++++++++++ 8 files changed, 120 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 53bab123a8ee..191587f75810 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 the host kernel to run confidential 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 b39975977c03..ec0e71d8fa30 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 3aedae61af4f..6d8f15b1552c 100644 --- a/arch/x86/include/asm/msr-index.h +++ b/arch/x86/include/asm/msr-index.h @@ -523,6 +523,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..908590e85749 --- /dev/null +++ b/arch/x86/virt/vmx/tdx/tdx.c @@ -0,0 +1,90 @@ +// 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; + +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 'global KeyID' to protect + * its metadata. If there's only one TDX KeyID, there won't be + * any left for TDX guests thus there's no point to enable TDX + * at all. + */ + if (nr_tdx_keyids < 2) { + pr_err("initialization failed: too few private KeyIDs available.\n"); + return -ENODEV; + } + + /* + * Just use the first TDX KeyID as the 'global KeyID' and + * leave the rest for TDX guests. + */ + tdx_global_keyid = tdx_keyid_start; + tdx_guest_keyid_start = tdx_keyid_start + 1; + tdx_nr_guest_keyids = nr_tdx_keyids - 1; + + return 0; +} +early_initcall(tdx_init); + +/* Return whether the BIOS has enabled TDX */ +bool platform_tdx_enabled(void) +{ + return !!tdx_global_keyid; +}