From patchwork Mon Mar 6 14:14:01 2023 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Huang, Kai" X-Patchwork-Id: 13161231 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 006C6C61DA4 for ; Mon, 6 Mar 2023 14:15:50 +0000 (UTC) Received: by kanga.kvack.org (Postfix) id 97E15280008; Mon, 6 Mar 2023 09:15:50 -0500 (EST) Received: by kanga.kvack.org (Postfix, from userid 40) id 92E86280005; Mon, 6 Mar 2023 09:15:50 -0500 (EST) X-Delivered-To: int-list-linux-mm@kvack.org Received: by kanga.kvack.org (Postfix, from userid 63042) id 7A999280008; Mon, 6 Mar 2023 09:15:50 -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 665E5280005 for ; Mon, 6 Mar 2023 09:15:50 -0500 (EST) Received: from smtpin01.hostedemail.com (a10.router.float.18 [10.200.18.1]) by unirelay01.hostedemail.com (Postfix) with ESMTP id 412181C5D80 for ; Mon, 6 Mar 2023 14:15:50 +0000 (UTC) X-FDA: 80538672060.01.999791D Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by imf05.hostedemail.com (Postfix) with ESMTP id 00EFC100012 for ; Mon, 6 Mar 2023 14:15:47 +0000 (UTC) Authentication-Results: imf05.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=SFLMFDJ+; dmarc=pass (policy=none) header.from=intel.com; spf=pass (imf05.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=1678112148; 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=sJDUpZRkFdE1JvBPgkD3+gsgIMKIkVKhyBqOuwgOhF8=; b=g/7FfWtMTYhfDXuOB1GJGMkf3QTW8NWY/ymB5k6YoBqVM0KJxA7iNJPsWS9k3wqWhvGf8b e2D1hss3iYXBowfLgbWDLOjJ0ucOuwswIoVurf+IMQJK67Nk4xPZKWYwUbTT1oX4Eu3BAn dxUMKQ1yVJ4PbQaHXqwKU4RwgqA9VRA= ARC-Authentication-Results: i=1; imf05.hostedemail.com; dkim=pass header.d=intel.com header.s=Intel header.b=SFLMFDJ+; dmarc=pass (policy=none) header.from=intel.com; spf=pass (imf05.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=1678112148; a=rsa-sha256; cv=none; b=mphRF/Kk4CZINNora979jwKkattViITNbjkECzQfZzemgPJKH8DN3A1GBLC6FOFBGSoWGI 8C3u8dnvUVDYebvMZOOzav1ZCDJ10Q28aby61LNYjFww8JS3SvSDqYheohS0lZ04jOOvVI xVAqVfBU6UBArDVArzvMcSNrR7qzxwM= DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1678112148; x=1709648148; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=coSckihc/FGLGVwvcV+LqtmdmdjmpY1DZ81B3xj/jnI=; b=SFLMFDJ+AfmvFgFQyZ5owpVUmghfZPL0+vmfFp0lzaIEtAHiokKLIrOV em9NoFCr68icEbbR/lKoIw01X0pdkAtaFnfXnHZg/CkCYUN2BKLttCpRc 5Df1FOZ4ZIRRKClHu+T4Wp1U2dSeDV4eBIhGgIsosNg8etb+YeqFRC3/5 Lpk7xoNZTXKkbJy3LpFJaaj4TWG6e0dNJuyKMPokg9WV64ZbpJ1p4k1RN TkCrEEqKD+DskNvozVwHdTQjoyHI8tsM6bPmr/5jLnq5GJA4GE7nvFZOV UMwGplYwutSsjqjfBGVYYfNmAbTn+Bq/uUbCZrj/baTx3twcXqx+jkdYH A==; X-IronPort-AV: E=McAfee;i="6500,9779,10641"; a="337080354" X-IronPort-AV: E=Sophos;i="5.98,238,1673942400"; d="scan'208";a="337080354" 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:15:47 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=McAfee;i="6500,9779,10641"; a="765232577" X-IronPort-AV: E=Sophos;i="5.98,238,1673942400"; d="scan'208";a="765232577" 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:15:43 -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 16/16] Documentation/x86: Add documentation for TDX host support Date: Tue, 7 Mar 2023 03:14:01 +1300 Message-Id: X-Mailer: git-send-email 2.39.2 In-Reply-To: References: MIME-Version: 1.0 X-Rspamd-Queue-Id: 00EFC100012 X-Rspamd-Server: rspam09 X-Rspam-User: X-Stat-Signature: 7c98b5fk7nnpftdm4xzwf3t4xcdjih1n X-HE-Tag: 1678112147-842700 X-HE-Meta: U2FsdGVkX1844DUeiWBfkTYKWrgEqNfmvhnM+Q/X5OZwFWnd61UmOiK5zwzj49UQTdNgfXqHHuLfR6dwusfAmyQknEoD7SAEsSD4nQom7xl99sl4H4kPXPSgaSY4AuKM6m7az+Dkrhu9L1pCvWigfNPhwo/OppsS6ExvXCGE+hpZHsF8XpC3GU6g4Kp4uRBOKGtgQV20WZtPK+BWlvoTxbtZjXyZXaHSl17eHkhvc9UknU+HYuSufh4PpVKzKHjv0RW6m2/uy9L+kiYE+OusmpqqwKfY0Z1qRc+zDGXIfWzsc92lMb/0MHgo67rOqIuDvvYO2R3z0xx+VWL0Rv2+R9oOHUwF5aDjeD4Aro10gwyHCIR2gwbYh0zJ937bKIjT7ZtqZ/Svse/GtnVnGTZDgPNW52Gk37clKo1qyPJzfuQ+p/kXY6QoSbi6MnQxll85oZz+dSAvPm3HyxIqoAYMoHNaryvhDy0bH7wB36S/8LfCvxYakMX3RQkEIZbPDodu2cIvgKzC/Qp2BMa++7Yez/ilCwZ9zjWYfE2kvfwWWTWwx8vNr50mnnguWtbzaCFRlG79X+vsIubVE20zw3cX1UEO+8FzFw4ogM9XpHKPlfr4eyRqaILiqgRJ1bD/+diC9+RsVvrvqFBb78sT9JlAV2sA3kTSJupeglYgniiPnvc6Zq1jN/dgSC2xIhK8ooCNMiGA4VLGCus74Sj0rOeh2prppTXX/y9VxNbO5yV0dKN2mOtxvWXxeg4dBQ2G7YA1deCr5yijZLjYq0C8+4APdnbIgk1yH+T5Zz4zgTq8bsmTCR0rcaVFIRFaIDndSEOjI4Lh81ps1dLLKm/2y4f1HPrPQvk/EfOyGmTInMRdYuflqxevvvwmnwV2DZraUQT8nlVfHM5pcE6CryDBw86uWaLiQqxiGnVD86YKcU+1NN4CW/KfzvaN/xpyvA6lgQjxofiP1N4yTLADg2jrdj4 4zsZbvLG cGPXpA6j/2rYAcsV9MDADY2d+ZH5QFwis15K8L6w2TGQO2zDtT5AbPXZ2UKwKCAX86FmVcdEBtmVL0yO96aJ22pHuJKyXqqTR5Dj040yYy5dtP6xABBA0fFIqOBCi+OwI/paR1TOIJICTdZd2pxYmzE7XgGJKt376CxIZvKeHuryGHj4= 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 | 186 +++++++++++++++++++++++++++++++++++--- 1 file changed, 175 insertions(+), 11 deletions(-) diff --git a/Documentation/x86/tdx.rst b/Documentation/x86/tdx.rst index dc8d9fd2c3f7..a6f66a28bef4 100644 --- a/Documentation/x86/tdx.rst +++ b/Documentation/x86/tdx.rst @@ -10,6 +10,170 @@ 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. + +Besides initializing the TDX module, a per-cpu initialization SEAMCALL +must be done on one cpu before any other SEAMCALLs can be made on that +cpu. + +The kernel provides two functions, tdx_enable() and tdx_cpu_enable() to +allow the user of TDX to enable the TDX module and enable TDX on local +cpu. + +Making SEAMCALL requires the CPU already being in VMX operation (VMXON +has been done). For now both tdx_enable() and tdx_cpu_enable() don't +handle VMXON internally, but depends on the caller to guarantee that. + +To enable TDX, the user of TDX should: 1) hold read lock of CPU hotplug +lock; 2) do VMXON and tdx_enable_cpu() on all online cpus successfully; +3) call tdx_enable(). For example:: + + cpus_read_lock(); + on_each_cpu(vmxon_and_tdx_cpu_enable()); + ret = tdx_enable(); + cpus_read_unlock(); + if (ret) + goto no_tdx; + // TDX is ready to use + +And the user of TDX must be guarantee tdx_cpu_enable() has beene +successfully done on any cpu before it wants to run any other SEAMCALL. +A typical usage is do both VMXON and tdx_cpu_enable() in CPU hotplug +online callback, and refuse to online if tdx_cpu_enable() fails. + +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: TDX module 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 the per-cpu initialization SEAMCALL (TDH.SYS.LP.INIT) +must be done on one cpu before any other SEAMCALLs can be made on that +cpu, including those involved during the module initialization. + +The kernel provides tdx_cpu_enable() to let the user of TDX to do it when +the user wants to use a new cpu for TDX task. + +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 +184,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 +194,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 +205,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 +216,7 @@ Instruction-based #GP - RDMSR*,WRMSR* RDMSR/WRMSR Behavior --------------------- +~~~~~~~~~~~~~~~~~~~~ MSR access behavior falls into three categories: @@ -73,7 +237,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 +257,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 +271,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 +291,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 +309,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 +331,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 +353,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