public inbox for linux-kernel@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v5 00/22] Runtime TDX module update support
@ 2026-03-15 13:58 Chao Gao
  2026-03-15 13:58 ` [PATCH v5 01/22] x86/virt/tdx: Move low level SEAMCALL helpers out of <asm/tdx.h> Chao Gao
                   ` (21 more replies)
  0 siblings, 22 replies; 80+ messages in thread
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
  To: kvm, linux-coco, linux-doc, linux-kernel, x86
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Chao Gao, Borislav Petkov, H. Peter Anvin, Ingo Molnar,
	Jonathan Corbet, Shuah Khan, Thomas Gleixner

Hi Reviewers,

With this posting, I'm hoping to collect more Reviewed-by or Acked-by tags.

Please note these changes:

  Patch 18 handles a CPU erratum that clears the active VMCS after
  P-SEAMLDR calls. Because of this erratum, patch 6 now exposes seamldr
  attributes during device probe rather than creation as unconditional
  exposure would be unsafe.

  Patch 22 adds error logging for update failures. It's kind of
  nice-to-have, so it is placed last for easy removal if necessary.

For transparency, I should note that I used an Intel-operated AI tool to
help proofread this cover-letter and commit messages.

Changelog:
v4->v5:
 - s/TDX Module/TDX module/g [Binbin/Dave]
 - drop is_vmalloc_addr() checking [Dave/Rick]
 - protect lockstep control data with a lock [Dave]
 - clarify why raw_spinlock is used [Dave/Kai]
 - drop patches that check all CPUs are online and updates are not exhausted [Dave]
 - register seamldr attributes in device probe
 - use devm_add_action_or_reset for seamldr deinit [Yilun]
 - remove global tdx_fw [Yilun]
 - clarify request_firmware() doesn't take filename from userspace [Rick]
 - drop unnecessary checks when populating an update request [Rick]
 - rewrite the commit message for the skeleton patch
 - rewrite the commit message for the "update-sensitive operations" handling patch
 - other minor code changes, changelog improvements and typo fixes [Binbin/Yan etc]
 - collect review tags from Yilun/Rick/Kai/Binbin
 - v4: https://lore.kernel.org/kvm/20260212143606.534586-1-chao.gao@intel.com/

This series adds support for runtime TDX module updates that preserve
running TDX guests. It is also available at:

  https://github.com/gaochaointel/linux-dev/commits/tdx-module-updates-v5/

== Background ==

Intel TDX isolates Trusted Domains (TDs), or confidential guests, from the
host. A key component of Intel TDX is the TDX module, which enforces
security policies to protect the memory and CPU states of TDs from the
host. However, the TDX module is software that requires updates.

== Problems ==

Currently, the TDX module is loaded by the BIOS at boot time, and the only
way to update it is through a reboot, which results in significant system
downtime. Users expect the TDX module to be updatable at runtime without
disrupting TDX guests.

== Solution ==

On TDX platforms, P-SEAMLDR[1] is a component within the protected SEAM
range. It is loaded by the BIOS and provides the host with functions to
install a TDX module at runtime.

Implement a TDX module update facility via the fw_upload mechanism. Given
that there is variability in which module update to load based on features,
fix levels, and potentially reloading the same version for error recovery
scenarios, the explicit userspace chosen payload flexibility of fw_upload
is attractive.

This design allows the kernel to accept a bitstream instead of loading a
named file from the filesystem, as the module selection and policy
enforcement for TDX modules are quite complex (see patch "coco/tdx-host:
Implement firmware upload sysfs ABI for TDX module updates"). By doing
so, much of this complexity is shifted out of the kernel. The kernel
needs to expose information, such as the TDX module version, to
userspace.  Userspace must understand the TDX module versioning scheme
and update policy to select the appropriate TDX module (see "TDX module
Versioning" below).

In the unlikely event the update fails, for example userspace picks an
incompatible update image, or the image is otherwise corrupted, all TDs
will experience SEAMCALL failures and be killed. The recovery of TD
operation from that event requires a reboot.

Given there is no mechanism to quiesce SEAMCALLs, the TDs themselves must
pause execution over an update. The most straightforward way to meet the
'pause TDs while update executes' constraint is to run the update in
stop_machine() context. All other evaluated solutions export more
complexity to KVM, or exports more fragility to userspace.

== How to test this series ==

First, load kvm-intel.ko and tdx-host.ko if they haven't been loaded:

 # modprobe -r kvm_intel
 # modprobe kvm_intel tdx=1
 # modprobe tdx-host

Then, use the userspace tool below to select the appropriate TDX module and
install it via the interfaces exposed by this series:

 # git clone https://github.com/intel/tdx-module-binaries
 # cd tdx-module-binaries
 # python version_select_and_load.py --update

this version changes the firmware directory name from seamldr_upload to
tdx_module, so, below change should be applied to version_select_and_load.py:

diff --git a/version_select_and_load.py b/version_select_and_load.py
index 2193bd8..6a3b604 100644
--- a/version_select_and_load.py
+++ b/version_select_and_load.py
@@ -38,7 +38,7 @@ except ImportError:
     print("Error: cpuid module is not installed. Please install it using 'pip install cpuid'")
     sys.exit(1)

-FIRMWARE_PATH = "/sys/class/firmware/seamldr_upload"
+FIRMWARE_PATH = "/sys/class/firmware/tdx_module"
 MODULE_PATH = "/sys/devices/faux/tdx_host"
 SEAMLDR_PATH = "/sys/devices/faux/tdx_host/seamldr"
 allow_debug = False


== Other information relevant to Runtime TDX module updates ==

=== TDX module versioning ===

Each TDX module is assigned a version number x.y.z, where x represents the
"major" version, y the "minor" version, and z the "update" version.

Runtime TDX module updates are restricted to Z-stream releases.

Note that Z-stream releases do not necessarily guarantee compatibility. A
new release may not be compatible with all previous versions. To address this,
Intel provides a separate file containing compatibility information, which
specifies the minimum module version required for a particular update. This
information is referenced by the tool to determine if two modules are
compatible.

=== TCB Stability ===

Updates change the TCB as viewed by attestation reports. In TDX there is
a distinction between launch-time version and current version where
runtime TDX module updates cause that latter version number to change,
subject to Z-stream constraints.

The concern that a malicious host may attack confidential VMs by loading
insecure updates was addressed by Alex in [3]. Similarly, the scenario
where some "theoretical paranoid tenant" in the cloud wants to audit
updates and stop trusting the host after updates until audit completion
was also addressed in [4]. Users not in the cloud control the host machine
and can manage updates themselves, so they don't have these concerns.

See more about the implications of current TCB version changes in
attestation as summarized by Dave in [5].

=== TDX module Distribution Model ===

At a high level, Intel publishes all TDX modules on the github [2], along
with a mapping_file.json which documents the compatibility information
about each TDX module and a userspace tool to install the TDX module. OS
vendors can package these modules and distribute them. Administrators
install the package and use the tool to select the appropriate TDX module
and install it via the interfaces exposed by this series.

[1]: https://cdrdv2.intel.com/v1/dl/getContent/733584
[2]: https://github.com/intel/tdx-module-binaries
[3]: https://lore.kernel.org/all/665c5ae0-4b7c-4852-8995-255adf7b3a2f@amazon.com/
[4]: https://lore.kernel.org/all/5d1da767-491b-4077-b472-2cc3d73246d6@amazon.com/
[5]: https://lore.kernel.org/all/94d6047e-3b7c-4bc1-819c-85c16ff85abf@intel.com/


Chao Gao (21):
  coco/tdx-host: Introduce a "tdx_host" device
  coco/tdx-host: Expose TDX module version
  x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs
  x86/virt/seamldr: Retrieve P-SEAMLDR information
  coco/tdx-host: Expose P-SEAMLDR information via sysfs
  coco/tdx-host: Implement firmware upload sysfs ABI for TDX module
    updates
  x86/virt/seamldr: Allocate and populate a module update request
  x86/virt/seamldr: Introduce skeleton for TDX module updates
  x86/virt/seamldr: Abort updates if errors occurred midway
  x86/virt/seamldr: Shut down the current TDX module
  x86/virt/tdx: Reset software states during TDX module shutdown
  x86/virt/seamldr: Install a new TDX module
  x86/virt/seamldr: Do TDX per-CPU initialization after updates
  x86/virt/tdx: Restore TDX module state
  x86/virt/tdx: Update tdx_sysinfo and check features post-update
  x86/virt/tdx: Avoid updates during update-sensitive operations
  coco/tdx-host: Don't expose P-SEAMLDR features on CPUs with erratum
  x86/virt/tdx: Enable TDX module runtime updates
  coco/tdx-host: Document TDX module update compatibility criteria
  x86/virt/tdx: Document TDX module update
  x86/virt/seamldr: Log TDX module update failures

Kai Huang (1):
  x86/virt/tdx: Move low level SEAMCALL helpers out of <asm/tdx.h>

 .../ABI/testing/sysfs-devices-faux-tdx-host   |  75 ++++
 Documentation/arch/x86/tdx.rst                |  36 ++
 arch/x86/include/asm/cpufeatures.h            |   1 +
 arch/x86/include/asm/seamldr.h                |  37 ++
 arch/x86/include/asm/tdx.h                    |  65 +---
 arch/x86/include/asm/tdx_global_metadata.h    |   5 +
 arch/x86/include/asm/vmx.h                    |   1 +
 arch/x86/kvm/vmx/tdx_errno.h                  |   2 -
 arch/x86/virt/vmx/tdx/Makefile                |   2 +-
 arch/x86/virt/vmx/tdx/seamcall_internal.h     | 109 ++++++
 arch/x86/virt/vmx/tdx/seamldr.c               | 325 ++++++++++++++++++
 arch/x86/virt/vmx/tdx/tdx.c                   | 165 ++++++---
 arch/x86/virt/vmx/tdx/tdx.h                   |  11 +-
 arch/x86/virt/vmx/tdx/tdx_global_metadata.c   |  18 +
 drivers/virt/coco/Kconfig                     |   2 +
 drivers/virt/coco/Makefile                    |   1 +
 drivers/virt/coco/tdx-host/Kconfig            |  12 +
 drivers/virt/coco/tdx-host/Makefile           |   1 +
 drivers/virt/coco/tdx-host/tdx-host.c         | 228 ++++++++++++
 19 files changed, 995 insertions(+), 101 deletions(-)
 create mode 100644 Documentation/ABI/testing/sysfs-devices-faux-tdx-host
 create mode 100644 arch/x86/include/asm/seamldr.h
 create mode 100644 arch/x86/virt/vmx/tdx/seamcall_internal.h
 create mode 100644 arch/x86/virt/vmx/tdx/seamldr.c
 create mode 100644 drivers/virt/coco/tdx-host/Kconfig
 create mode 100644 drivers/virt/coco/tdx-host/Makefile
 create mode 100644 drivers/virt/coco/tdx-host/tdx-host.c

-- 
2.47.3


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v5 01/22] x86/virt/tdx: Move low level SEAMCALL helpers out of <asm/tdx.h>
  2026-03-15 13:58 [PATCH v5 00/22] Runtime TDX module update support Chao Gao
@ 2026-03-15 13:58 ` Chao Gao
  2026-03-16 12:41   ` Kiryl Shutsemau
  2026-03-15 13:58 ` [PATCH v5 02/22] coco/tdx-host: Introduce a "tdx_host" device Chao Gao
                   ` (20 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
  To: linux-kernel, linux-coco, kvm
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Chao Gao, Zhenzhong Duan, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, x86, H. Peter Anvin

From: Kai Huang <kai.huang@intel.com>

TDX host core code implements three seamcall*() helpers to make SEAMCALL
to the TDX module.  Currently, they are implemented in <asm/tdx.h> and
are exposed to other kernel code which includes <asm/tdx.h>.

However, other than the TDX host core, seamcall*() are not expected to
be used by other kernel code directly.  For instance, for all SEAMCALLs
that are used by KVM, the TDX host core exports a wrapper function for
each of them.

Move seamcall*() and related code out of <asm/tdx.h> and make them only
visible to TDX host core.

Since TDX host core tdx.c is already very heavy, don't put low level
seamcall*() code there but to a new dedicated "seamcall_internal.h".  Also,
currently tdx.c has seamcall_prerr*() helpers which additionally print
error message when calling seamcall*() fails.  Move them to
"seamcall_internal.h" as well. In such way all low level SEAMCALL helpers
are in a dedicated place, which is much more readable.

Copy the copyright notice from the original files and consolidate the
date ranges to:

	Copyright (C) 2021-2023 Intel Corporation

Signed-off-by: Kai Huang <kai.huang@intel.com>
Signed-off-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
Acked-by: Dave Hansen <dave.hansen@linux.intel.com>
---
v5:
 - s/seamcall.h/seamcall_internal.h [Binbin]
 - Fix an unintentional change to sc_retry() during code movement.
v4:
 - Collect reviews
 - add "internal" to the new header file [Dave]
 - document the scope of the new header file [Dave]
 - correct the copyright notice [Dave]
v2:
 - new
---
 arch/x86/include/asm/tdx.h                |  47 ----------
 arch/x86/virt/vmx/tdx/seamcall_internal.h | 109 ++++++++++++++++++++++
 arch/x86/virt/vmx/tdx/tdx.c               |  47 +---------
 3 files changed, 111 insertions(+), 92 deletions(-)
 create mode 100644 arch/x86/virt/vmx/tdx/seamcall_internal.h

diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index 6b338d7f01b7..cb2219302dfc 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -97,54 +97,7 @@ static inline long tdx_kvm_hypercall(unsigned int nr, unsigned long p1,
 #endif /* CONFIG_INTEL_TDX_GUEST && CONFIG_KVM_GUEST */
 
 #ifdef CONFIG_INTEL_TDX_HOST
-u64 __seamcall(u64 fn, struct tdx_module_args *args);
-u64 __seamcall_ret(u64 fn, struct tdx_module_args *args);
-u64 __seamcall_saved_ret(u64 fn, struct tdx_module_args *args);
 void tdx_init(void);
-
-#include <linux/preempt.h>
-#include <asm/archrandom.h>
-#include <asm/processor.h>
-
-typedef u64 (*sc_func_t)(u64 fn, struct tdx_module_args *args);
-
-static __always_inline u64 __seamcall_dirty_cache(sc_func_t func, u64 fn,
-						  struct tdx_module_args *args)
-{
-	lockdep_assert_preemption_disabled();
-
-	/*
-	 * SEAMCALLs are made to the TDX module and can generate dirty
-	 * cachelines of TDX private memory.  Mark cache state incoherent
-	 * so that the cache can be flushed during kexec.
-	 *
-	 * This needs to be done before actually making the SEAMCALL,
-	 * because kexec-ing CPU could send NMI to stop remote CPUs,
-	 * in which case even disabling IRQ won't help here.
-	 */
-	this_cpu_write(cache_state_incoherent, true);
-
-	return func(fn, args);
-}
-
-static __always_inline u64 sc_retry(sc_func_t func, u64 fn,
-			   struct tdx_module_args *args)
-{
-	int retry = RDRAND_RETRY_LOOPS;
-	u64 ret;
-
-	do {
-		preempt_disable();
-		ret = __seamcall_dirty_cache(func, fn, args);
-		preempt_enable();
-	} while (ret == TDX_RND_NO_ENTROPY && --retry);
-
-	return ret;
-}
-
-#define seamcall(_fn, _args)		sc_retry(__seamcall, (_fn), (_args))
-#define seamcall_ret(_fn, _args)	sc_retry(__seamcall_ret, (_fn), (_args))
-#define seamcall_saved_ret(_fn, _args)	sc_retry(__seamcall_saved_ret, (_fn), (_args))
 int tdx_cpu_enable(void);
 int tdx_enable(void);
 const char *tdx_dump_mce_info(struct mce *m);
diff --git a/arch/x86/virt/vmx/tdx/seamcall_internal.h b/arch/x86/virt/vmx/tdx/seamcall_internal.h
new file mode 100644
index 000000000000..be5f446467df
--- /dev/null
+++ b/arch/x86/virt/vmx/tdx/seamcall_internal.h
@@ -0,0 +1,109 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * SEAMCALL utilities for TDX host-side operations.
+ *
+ * Provides convenient wrappers around SEAMCALL assembly with retry logic,
+ * error reporting and cache coherency tracking.
+ *
+ * Copyright (C) 2021-2023 Intel Corporation
+ */
+
+#ifndef _X86_VIRT_SEAMCALL_INTERNAL_H
+#define _X86_VIRT_SEAMCALL_INTERNAL_H
+
+#include <linux/printk.h>
+#include <linux/types.h>
+#include <asm/archrandom.h>
+#include <asm/processor.h>
+#include <asm/tdx.h>
+
+u64 __seamcall(u64 fn, struct tdx_module_args *args);
+u64 __seamcall_ret(u64 fn, struct tdx_module_args *args);
+u64 __seamcall_saved_ret(u64 fn, struct tdx_module_args *args);
+
+typedef u64 (*sc_func_t)(u64 fn, struct tdx_module_args *args);
+
+static __always_inline u64 __seamcall_dirty_cache(sc_func_t func, u64 fn,
+						  struct tdx_module_args *args)
+{
+	lockdep_assert_preemption_disabled();
+
+	/*
+	 * SEAMCALLs are made to the TDX module and can generate dirty
+	 * cachelines of TDX private memory.  Mark cache state incoherent
+	 * so that the cache can be flushed during kexec.
+	 *
+	 * This needs to be done before actually making the SEAMCALL,
+	 * because kexec-ing CPU could send NMI to stop remote CPUs,
+	 * in which case even disabling IRQ won't help here.
+	 */
+	this_cpu_write(cache_state_incoherent, true);
+
+	return func(fn, args);
+}
+
+static __always_inline u64 sc_retry(sc_func_t func, u64 fn,
+			   struct tdx_module_args *args)
+{
+	int retry = RDRAND_RETRY_LOOPS;
+	u64 ret;
+
+	do {
+		preempt_disable();
+		ret = __seamcall_dirty_cache(func, fn, args);
+		preempt_enable();
+	} while (ret == TDX_RND_NO_ENTROPY && --retry);
+
+	return ret;
+}
+
+#define seamcall(_fn, _args)		sc_retry(__seamcall, (_fn), (_args))
+#define seamcall_ret(_fn, _args)	sc_retry(__seamcall_ret, (_fn), (_args))
+#define seamcall_saved_ret(_fn, _args)	sc_retry(__seamcall_saved_ret, (_fn), (_args))
+
+typedef void (*sc_err_func_t)(u64 fn, u64 err, struct tdx_module_args *args);
+
+static inline void seamcall_err(u64 fn, u64 err, struct tdx_module_args *args)
+{
+	pr_err("SEAMCALL (0x%016llx) failed: 0x%016llx\n", fn, err);
+}
+
+static inline void seamcall_err_ret(u64 fn, u64 err,
+				    struct tdx_module_args *args)
+{
+	seamcall_err(fn, err, args);
+	pr_err("RCX 0x%016llx RDX 0x%016llx R08 0x%016llx\n",
+			args->rcx, args->rdx, args->r8);
+	pr_err("R09 0x%016llx R10 0x%016llx R11 0x%016llx\n",
+			args->r9, args->r10, args->r11);
+}
+
+static __always_inline int sc_retry_prerr(sc_func_t func,
+					  sc_err_func_t err_func,
+					  u64 fn, struct tdx_module_args *args)
+{
+	u64 sret = sc_retry(func, fn, args);
+
+	if (sret == TDX_SUCCESS)
+		return 0;
+
+	if (sret == TDX_SEAMCALL_VMFAILINVALID)
+		return -ENODEV;
+
+	if (sret == TDX_SEAMCALL_GP)
+		return -EOPNOTSUPP;
+
+	if (sret == TDX_SEAMCALL_UD)
+		return -EACCES;
+
+	err_func(fn, sret, args);
+	return -EIO;
+}
+
+#define seamcall_prerr(__fn, __args)						\
+	sc_retry_prerr(__seamcall, seamcall_err, (__fn), (__args))
+
+#define seamcall_prerr_ret(__fn, __args)					\
+	sc_retry_prerr(__seamcall_ret, seamcall_err_ret, (__fn), (__args))
+
+#endif /* _X86_VIRT_SEAMCALL_INTERNAL_H */
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index 8b8e165a2001..06d9709ade85 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -39,6 +39,8 @@
 #include <asm/cpu_device_id.h>
 #include <asm/processor.h>
 #include <asm/mce.h>
+
+#include "seamcall_internal.h"
 #include "tdx.h"
 
 static u32 tdx_global_keyid __ro_after_init;
@@ -59,51 +61,6 @@ static LIST_HEAD(tdx_memlist);
 
 static struct tdx_sys_info tdx_sysinfo;
 
-typedef void (*sc_err_func_t)(u64 fn, u64 err, struct tdx_module_args *args);
-
-static inline void seamcall_err(u64 fn, u64 err, struct tdx_module_args *args)
-{
-	pr_err("SEAMCALL (0x%016llx) failed: 0x%016llx\n", fn, err);
-}
-
-static inline void seamcall_err_ret(u64 fn, u64 err,
-				    struct tdx_module_args *args)
-{
-	seamcall_err(fn, err, args);
-	pr_err("RCX 0x%016llx RDX 0x%016llx R08 0x%016llx\n",
-			args->rcx, args->rdx, args->r8);
-	pr_err("R09 0x%016llx R10 0x%016llx R11 0x%016llx\n",
-			args->r9, args->r10, args->r11);
-}
-
-static __always_inline int sc_retry_prerr(sc_func_t func,
-					  sc_err_func_t err_func,
-					  u64 fn, struct tdx_module_args *args)
-{
-	u64 sret = sc_retry(func, fn, args);
-
-	if (sret == TDX_SUCCESS)
-		return 0;
-
-	if (sret == TDX_SEAMCALL_VMFAILINVALID)
-		return -ENODEV;
-
-	if (sret == TDX_SEAMCALL_GP)
-		return -EOPNOTSUPP;
-
-	if (sret == TDX_SEAMCALL_UD)
-		return -EACCES;
-
-	err_func(fn, sret, args);
-	return -EIO;
-}
-
-#define seamcall_prerr(__fn, __args)						\
-	sc_retry_prerr(__seamcall, seamcall_err, (__fn), (__args))
-
-#define seamcall_prerr_ret(__fn, __args)					\
-	sc_retry_prerr(__seamcall_ret, seamcall_err_ret, (__fn), (__args))
-
 /*
  * Do the module global initialization once and return its result.
  * It can be done on any cpu.  It's always called with interrupts
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v5 02/22] coco/tdx-host: Introduce a "tdx_host" device
  2026-03-15 13:58 [PATCH v5 00/22] Runtime TDX module update support Chao Gao
  2026-03-15 13:58 ` [PATCH v5 01/22] x86/virt/tdx: Move low level SEAMCALL helpers out of <asm/tdx.h> Chao Gao
@ 2026-03-15 13:58 ` Chao Gao
  2026-03-16 12:48   ` Kiryl Shutsemau
  2026-03-15 13:58 ` [PATCH v5 03/22] coco/tdx-host: Expose TDX module version Chao Gao
                   ` (19 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
  To: linux-kernel, linux-coco, kvm
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Chao Gao, Jonathan Cameron, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

TDX depends on a platform firmware module that is invoked via instructions
similar to vmenter (i.e. enter into a new privileged "root-mode" context to
manage private memory and private device mechanisms). It is a software
construct that depends on the CPU vmxon state to enable invocation of
TDX module ABIs. Unlike other Trusted Execution Environment (TEE) platform
implementations that employ a firmware module running on a PCI device with
an MMIO mailbox for communication, TDX has no hardware device to point to
as the TEE Secure Manager (TSM).

Create a virtual device not only to align with other implementations but
also to make it easier to

 - expose metadata (e.g., TDX module version, seamldr version etc) to
   the userspace as device attributes

 - implement firmware uploader APIs which are tied to a device. This is
   needed to support TDX module runtime updates

 - enable TDX Connect which will share a common infrastructure with other
   platform implementations. In the TDX Connect context, every
   architecture has a TSM, represented by a PCIe or virtual device. The
   new "tdx_host" device will serve the TSM role.

A faux device is used for TDX because the TDX module is singular within
the system and lacks associated platform resources. Using a faux device
eliminates the need to create a stub bus.

The call to tdx_get_sysinfo() ensures that the TDX module is ready to
provide services.

Note that AMD has a PCI device for the PSP for SEV and ARM CCA will
likely have a faux device [1].

Co-developed-by: Xu Yilun <yilun.xu@linux.intel.com>
Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
Reviewed-by: Kai Huang <kai.huang@intel.com>
Link: https://lore.kernel.org/all/2025073035-bulginess-rematch-b92e@gregkh/ # [1]
---
v3:
 - add Jonathan's reviewed-by
 - add tdx_get_sysinfo() in module_init() to ensure the TDX module is up
   and running.
 - note in the changelog that both AMD and ARM have devices for coco
---
 arch/x86/virt/vmx/tdx/tdx.c           |  2 +-
 drivers/virt/coco/Kconfig             |  2 ++
 drivers/virt/coco/Makefile            |  1 +
 drivers/virt/coco/tdx-host/Kconfig    | 10 +++++++
 drivers/virt/coco/tdx-host/Makefile   |  1 +
 drivers/virt/coco/tdx-host/tdx-host.c | 43 +++++++++++++++++++++++++++
 6 files changed, 58 insertions(+), 1 deletion(-)
 create mode 100644 drivers/virt/coco/tdx-host/Kconfig
 create mode 100644 drivers/virt/coco/tdx-host/Makefile
 create mode 100644 drivers/virt/coco/tdx-host/tdx-host.c

diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index 06d9709ade85..172f6d4133b5 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -1435,7 +1435,7 @@ const struct tdx_sys_info *tdx_get_sysinfo(void)
 
 	return p;
 }
-EXPORT_SYMBOL_FOR_KVM(tdx_get_sysinfo);
+EXPORT_SYMBOL_FOR_MODULES(tdx_get_sysinfo, "kvm-intel,tdx-host");
 
 u32 tdx_get_nr_guest_keyids(void)
 {
diff --git a/drivers/virt/coco/Kconfig b/drivers/virt/coco/Kconfig
index df1cfaf26c65..f7691f64fbe3 100644
--- a/drivers/virt/coco/Kconfig
+++ b/drivers/virt/coco/Kconfig
@@ -17,5 +17,7 @@ source "drivers/virt/coco/arm-cca-guest/Kconfig"
 source "drivers/virt/coco/guest/Kconfig"
 endif
 
+source "drivers/virt/coco/tdx-host/Kconfig"
+
 config TSM
 	bool
diff --git a/drivers/virt/coco/Makefile b/drivers/virt/coco/Makefile
index cb52021912b3..b323b0ae4f82 100644
--- a/drivers/virt/coco/Makefile
+++ b/drivers/virt/coco/Makefile
@@ -6,6 +6,7 @@ obj-$(CONFIG_EFI_SECRET)	+= efi_secret/
 obj-$(CONFIG_ARM_PKVM_GUEST)	+= pkvm-guest/
 obj-$(CONFIG_SEV_GUEST)		+= sev-guest/
 obj-$(CONFIG_INTEL_TDX_GUEST)	+= tdx-guest/
+obj-$(CONFIG_INTEL_TDX_HOST)	+= tdx-host/
 obj-$(CONFIG_ARM_CCA_GUEST)	+= arm-cca-guest/
 obj-$(CONFIG_TSM) 		+= tsm-core.o
 obj-$(CONFIG_TSM_GUEST)		+= guest/
diff --git a/drivers/virt/coco/tdx-host/Kconfig b/drivers/virt/coco/tdx-host/Kconfig
new file mode 100644
index 000000000000..d35d85ef91c0
--- /dev/null
+++ b/drivers/virt/coco/tdx-host/Kconfig
@@ -0,0 +1,10 @@
+config TDX_HOST_SERVICES
+	tristate "TDX Host Services Driver"
+	depends on INTEL_TDX_HOST
+	default m
+	help
+	  Enable access to TDX host services like module update and
+	  extensions (e.g. TDX Connect).
+
+	  Say y or m if enabling support for confidential virtual machine
+	  support (CONFIG_INTEL_TDX_HOST). The module is called tdx_host.ko.
diff --git a/drivers/virt/coco/tdx-host/Makefile b/drivers/virt/coco/tdx-host/Makefile
new file mode 100644
index 000000000000..e61e749a8dff
--- /dev/null
+++ b/drivers/virt/coco/tdx-host/Makefile
@@ -0,0 +1 @@
+obj-$(CONFIG_TDX_HOST_SERVICES) += tdx-host.o
diff --git a/drivers/virt/coco/tdx-host/tdx-host.c b/drivers/virt/coco/tdx-host/tdx-host.c
new file mode 100644
index 000000000000..c77885392b09
--- /dev/null
+++ b/drivers/virt/coco/tdx-host/tdx-host.c
@@ -0,0 +1,43 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * TDX host user interface driver
+ *
+ * Copyright (C) 2025 Intel Corporation
+ */
+
+#include <linux/device/faux.h>
+#include <linux/module.h>
+#include <linux/mod_devicetable.h>
+
+#include <asm/cpu_device_id.h>
+#include <asm/tdx.h>
+
+static const struct x86_cpu_id tdx_host_ids[] = {
+	X86_MATCH_FEATURE(X86_FEATURE_TDX_HOST_PLATFORM, NULL),
+	{}
+};
+MODULE_DEVICE_TABLE(x86cpu, tdx_host_ids);
+
+static struct faux_device *fdev;
+
+static int __init tdx_host_init(void)
+{
+	if (!x86_match_cpu(tdx_host_ids) || !tdx_get_sysinfo())
+		return -ENODEV;
+
+	fdev = faux_device_create(KBUILD_MODNAME, NULL, NULL);
+	if (!fdev)
+		return -ENODEV;
+
+	return 0;
+}
+module_init(tdx_host_init);
+
+static void __exit tdx_host_exit(void)
+{
+	faux_device_destroy(fdev);
+}
+module_exit(tdx_host_exit);
+
+MODULE_DESCRIPTION("TDX Host Services");
+MODULE_LICENSE("GPL");
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v5 03/22] coco/tdx-host: Expose TDX module version
  2026-03-15 13:58 [PATCH v5 00/22] Runtime TDX module update support Chao Gao
  2026-03-15 13:58 ` [PATCH v5 01/22] x86/virt/tdx: Move low level SEAMCALL helpers out of <asm/tdx.h> Chao Gao
  2026-03-15 13:58 ` [PATCH v5 02/22] coco/tdx-host: Introduce a "tdx_host" device Chao Gao
@ 2026-03-15 13:58 ` Chao Gao
  2026-03-16 12:54   ` Kiryl Shutsemau
  2026-03-18 21:37   ` Huang, Kai
  2026-03-15 13:58 ` [PATCH v5 04/22] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs Chao Gao
                   ` (18 subsequent siblings)
  21 siblings, 2 replies; 80+ messages in thread
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
  To: x86, linux-coco, kvm, linux-kernel
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Chao Gao

For TDX module updates, userspace needs to select compatible update
versions based on the current module version. This design delegates
module selection complexity to userspace because TDX module update
policies are complex and version series are platform-specific.

For example, the 1.5.x series is for certain platform generations, while
the 2.0.x series is intended for others. And TDX module 1.5.x may be
updated to 1.5.y but not to 1.5.y+1.

Expose the TDX module version to userspace via sysfs to aid module
selection. Since the TDX faux device will drive module updates, expose
the version as its attribute.

One bonus of exposing TDX module version via sysfs is: TDX module
version information remains available even after dmesg logs are cleared.

== Background ==

The "faux device + device attribute" approach compares to other update
mechanisms as follows:

1. AMD SEV leverages an existing PCI device for the PSP to expose
   metadata. TDX uses a faux device as it doesn't have PCI device
   in its architecture.

2. Microcode uses per-CPU virtual devices to report microcode revisions
   because CPUs can have different revisions. But, there is only a
   single TDX module, so exposing the TDX module version through a global
   TDX faux device is appropriate

3. ARM's CCA implementation isn't in-tree yet, but will likely follow a
   similar faux device approach, though it's unclear whether they need
   to expose firmware version information

Signed-off-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
Link: https://lore.kernel.org/all/2025073035-bulginess-rematch-b92e@gregkh/ # [1]
---
v4:
 - collect reviews
 - Explain other version exposure implementations and why tdx's approach differs
   from them
v3:
 - Justify the sysfs ABI choice and expand background on other CoCo
   implementations.
---
 .../ABI/testing/sysfs-devices-faux-tdx-host   |  6 +++++
 drivers/virt/coco/tdx-host/tdx-host.c         | 26 ++++++++++++++++++-
 2 files changed, 31 insertions(+), 1 deletion(-)
 create mode 100644 Documentation/ABI/testing/sysfs-devices-faux-tdx-host

diff --git a/Documentation/ABI/testing/sysfs-devices-faux-tdx-host b/Documentation/ABI/testing/sysfs-devices-faux-tdx-host
new file mode 100644
index 000000000000..2cf682b65acf
--- /dev/null
+++ b/Documentation/ABI/testing/sysfs-devices-faux-tdx-host
@@ -0,0 +1,6 @@
+What:		/sys/devices/faux/tdx_host/version
+Contact:	linux-coco@lists.linux.dev
+Description:	(RO) Report the version of the loaded TDX module. The TDX module
+		version is formatted as x.y.z, where "x" is the major version,
+		"y" is the minor version and "z" is the update version. Versions
+		are used for bug reporting, TDX module updates etc.
diff --git a/drivers/virt/coco/tdx-host/tdx-host.c b/drivers/virt/coco/tdx-host/tdx-host.c
index c77885392b09..0424933b2560 100644
--- a/drivers/virt/coco/tdx-host/tdx-host.c
+++ b/drivers/virt/coco/tdx-host/tdx-host.c
@@ -8,6 +8,7 @@
 #include <linux/device/faux.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
+#include <linux/sysfs.h>
 
 #include <asm/cpu_device_id.h>
 #include <asm/tdx.h>
@@ -18,6 +19,29 @@ static const struct x86_cpu_id tdx_host_ids[] = {
 };
 MODULE_DEVICE_TABLE(x86cpu, tdx_host_ids);
 
+static ssize_t version_show(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	const struct tdx_sys_info *tdx_sysinfo = tdx_get_sysinfo();
+	const struct tdx_sys_info_version *ver;
+
+	if (!tdx_sysinfo)
+		return -ENXIO;
+
+	ver = &tdx_sysinfo->version;
+
+	return sysfs_emit(buf, "%u.%u.%02u\n", ver->major_version,
+					       ver->minor_version,
+					       ver->update_version);
+}
+static DEVICE_ATTR_RO(version);
+
+static struct attribute *tdx_host_attrs[] = {
+	&dev_attr_version.attr,
+	NULL,
+};
+ATTRIBUTE_GROUPS(tdx_host);
+
 static struct faux_device *fdev;
 
 static int __init tdx_host_init(void)
@@ -25,7 +49,7 @@ static int __init tdx_host_init(void)
 	if (!x86_match_cpu(tdx_host_ids) || !tdx_get_sysinfo())
 		return -ENODEV;
 
-	fdev = faux_device_create(KBUILD_MODNAME, NULL, NULL);
+	fdev = faux_device_create_with_groups(KBUILD_MODNAME, NULL, NULL, tdx_host_groups);
 	if (!fdev)
 		return -ENODEV;
 
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v5 04/22] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs
  2026-03-15 13:58 [PATCH v5 00/22] Runtime TDX module update support Chao Gao
                   ` (2 preceding siblings ...)
  2026-03-15 13:58 ` [PATCH v5 03/22] coco/tdx-host: Expose TDX module version Chao Gao
@ 2026-03-15 13:58 ` Chao Gao
  2026-03-16 13:05   ` Kiryl Shutsemau
                     ` (2 more replies)
  2026-03-15 13:58 ` [PATCH v5 05/22] x86/virt/seamldr: Retrieve P-SEAMLDR information Chao Gao
                   ` (17 subsequent siblings)
  21 siblings, 3 replies; 80+ messages in thread
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
  To: linux-kernel, linux-coco, kvm
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Chao Gao, Farrah Chen, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, x86, H. Peter Anvin

The TDX architecture uses the "SEAMCALL" instruction to communicate with
SEAM mode software. Right now, the only SEAM mode software that the kernel
communicates with is the TDX module. But, there is actually another
component that runs in SEAM mode but it is separate from the TDX module:
the persistent SEAM loader or "P-SEAMLDR". Right now, the only component
that communicates with it is the BIOS which loads the TDX module itself at
boot. But, to support updating the TDX module, the kernel now needs to be
able to talk to it.

P-SEAMLDR SEAMCALLs differ from TDX module SEAMCALLs in areas such as
concurrency requirements. Add a P-SEAMLDR wrapper to handle these
differences and prepare for implementing concrete functions.

Note that unlike P-SEAMLDR, there is also a non-persistent SEAM loader
("NP-SEAMLDR"). This is an authenticated code module (ACM) that is not
callable at runtime. Only BIOS launches it to load P-SEAMLDR at boot;
the kernel does not need to interact with it for runtime update.

For details of P-SEAMLDR SEAMCALLs, see Intel® Trust Domain CPU
Architectural Extensions, Revision 343754-002, Chapter 2.3 "INSTRUCTION
SET REFERENCE".

Signed-off-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
Tested-by: Farrah Chen <farrah.chen@intel.com>
Link: https://cdrdv2.intel.com/v1/dl/getContent/733582 # [1]
---
v5:
 - Don't save/restore irq flags as P-SEAMLDR calls are made only in process
   context
 - clarify why raw_spinlock is used [Dave]
v4:
 - Give more background about P-SEAMLDR in changelog [Dave]
 - Don't handle P-SEAMLDR's "no_entropy" error [Dave]
 - Assume current VMCS is preserved across P-SEAMLDR calls [Dave]
 - I'm not adding Reviewed-by tags as the code has changed significantly.
v2:
 - don't create a new, inferior framework to save/restore VMCS
 - use human-friendly language, just "current VMCS" rather than
   SDM term "current-VMCS pointer"
 - don't mix guard() with goto
---
 arch/x86/virt/vmx/tdx/Makefile  |  2 +-
 arch/x86/virt/vmx/tdx/seamldr.c | 24 ++++++++++++++++++++++++
 2 files changed, 25 insertions(+), 1 deletion(-)
 create mode 100644 arch/x86/virt/vmx/tdx/seamldr.c

diff --git a/arch/x86/virt/vmx/tdx/Makefile b/arch/x86/virt/vmx/tdx/Makefile
index 90da47eb85ee..d1dbc5cc5697 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 += seamcall.o tdx.o
+obj-y += seamcall.o seamldr.o tdx.o
diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
new file mode 100644
index 000000000000..7ed9be89017c
--- /dev/null
+++ b/arch/x86/virt/vmx/tdx/seamldr.c
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * P-SEAMLDR support for TDX module management features like runtime updates
+ *
+ * Copyright (C) 2025 Intel Corporation
+ */
+#define pr_fmt(fmt)	"seamldr: " fmt
+
+#include <linux/spinlock.h>
+
+#include "seamcall_internal.h"
+
+/*
+ * Serialize P-SEAMLDR calls since the hardware only allows a single CPU to
+ * interact with P-SEAMLDR simultaneously. Use raw version as the calls can
+ * be made with interrupts disabled.
+ */
+static DEFINE_RAW_SPINLOCK(seamldr_lock);
+
+static __maybe_unused int seamldr_call(u64 fn, struct tdx_module_args *args)
+{
+	guard(raw_spinlock)(&seamldr_lock);
+	return seamcall_prerr(fn, args);
+}
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v5 05/22] x86/virt/seamldr: Retrieve P-SEAMLDR information
  2026-03-15 13:58 [PATCH v5 00/22] Runtime TDX module update support Chao Gao
                   ` (3 preceding siblings ...)
  2026-03-15 13:58 ` [PATCH v5 04/22] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs Chao Gao
@ 2026-03-15 13:58 ` Chao Gao
  2026-03-16 13:12   ` Kiryl Shutsemau
                     ` (2 more replies)
  2026-03-15 13:58 ` [PATCH v5 06/22] coco/tdx-host: Expose P-SEAMLDR information via sysfs Chao Gao
                   ` (16 subsequent siblings)
  21 siblings, 3 replies; 80+ messages in thread
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
  To: linux-kernel, linux-coco, kvm
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Chao Gao, Farrah Chen, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, x86, H. Peter Anvin

P-SEAMLDR returns its information such as version number, in response to
the SEAMLDR.INFO SEAMCALL.

This information is useful for userspace. For example, the admin can decide
which TDX module versions are compatible with the P-SEAMLDR according to
the P-SEAMLDR version.

Retrieve P-SEAMLDR information in preparation for exposing P-SEAMLDR
version and other necessary information to userspace. Export the new kAPI
for use by tdx-host.ko.

Note that there are two distinct P-SEAMLDR APIs with similar names:

  SEAMLDR.INFO: Returns a SEAMLDR_INFO structure containing SEAMLDR
                information such as version and remaining updates.

  SEAMLDR.SEAMINFO: Returns a SEAMLDR_SEAMINFO structure containing SEAM
                    and system information such as Convertible Memory
		    Regions (CMRs) and number of CPUs and sockets.

The former is used here.

For details, see "Intel® Trust Domain Extensions - SEAM Loader (SEAMLDR)
Interface Specification" revision 343755-003.

Signed-off-by: Chao Gao <chao.gao@intel.com>
Tested-by: Farrah Chen <farrah.chen@intel.com>
---
Kai also suggested merging this patch with the first use of the new
kAPI, so we don't need to add a comment for slow_virt_to_phys() (as the
reason can be seen from the call site). I am fine with it, but the
changelog may be a bit lengthy.

v5:
 - add a comment for slow_virt_to_phys() [Kai]
v4:
 - put seamldr_info on stack [Dave]
 - improve changelogs to explain SEAMLDR.INFO and SEAMLDR.SEAMINFO [Dave]
 - add P-SEAMLDR spec information in the changelog [Dave]
 - add proper comments above ABI structure definition [Dave]
 - add unused ABI structure fields rather than marking them as reserved
   to better align with the specc [Dave] (I omitted "not used by kernel"
   tags since there are 5-6 such fields and maintaining these tags would
   be tedious.)
---
 arch/x86/include/asm/seamldr.h  | 36 +++++++++++++++++++++++++++++++++
 arch/x86/virt/vmx/tdx/seamldr.c | 19 ++++++++++++++++-
 2 files changed, 54 insertions(+), 1 deletion(-)
 create mode 100644 arch/x86/include/asm/seamldr.h

diff --git a/arch/x86/include/asm/seamldr.h b/arch/x86/include/asm/seamldr.h
new file mode 100644
index 000000000000..c67e5bc910a9
--- /dev/null
+++ b/arch/x86/include/asm/seamldr.h
@@ -0,0 +1,36 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_SEAMLDR_H
+#define _ASM_X86_SEAMLDR_H
+
+#include <linux/types.h>
+
+/*
+ * This is called the "SEAMLDR_INFO" data structure and is defined
+ * in "SEAM Loader (SEAMLDR) Interface Specification".
+ *
+ * The SEAMLDR.INFO documentation requires this to be aligned to a
+ * 256-byte boundary.
+ */
+struct seamldr_info {
+	u32	version;
+	u32	attributes;
+	u32	vendor_id;
+	u32	build_date;
+	u16	build_num;
+	u16	minor_version;
+	u16	major_version;
+	u16	update_version;
+	u32	acm_x2apicid;
+	u32	num_remaining_updates;
+	u8	seam_info[128];
+	u8	seam_ready;
+	u8	seam_debug;
+	u8	p_seam_ready;
+	u8	reserved[93];
+} __packed __aligned(256);
+
+static_assert(sizeof(struct seamldr_info) == 256);
+
+int seamldr_get_info(struct seamldr_info *seamldr_info);
+
+#endif /* _ASM_X86_SEAMLDR_H */
diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
index 7ed9be89017c..7c0cbab2c4c0 100644
--- a/arch/x86/virt/vmx/tdx/seamldr.c
+++ b/arch/x86/virt/vmx/tdx/seamldr.c
@@ -8,8 +8,13 @@
 
 #include <linux/spinlock.h>
 
+#include <asm/seamldr.h>
+
 #include "seamcall_internal.h"
 
+/* P-SEAMLDR SEAMCALL leaf function */
+#define P_SEAMLDR_INFO			0x8000000000000000
+
 /*
  * Serialize P-SEAMLDR calls since the hardware only allows a single CPU to
  * interact with P-SEAMLDR simultaneously. Use raw version as the calls can
@@ -17,8 +22,20 @@
  */
 static DEFINE_RAW_SPINLOCK(seamldr_lock);
 
-static __maybe_unused int seamldr_call(u64 fn, struct tdx_module_args *args)
+static int seamldr_call(u64 fn, struct tdx_module_args *args)
 {
 	guard(raw_spinlock)(&seamldr_lock);
 	return seamcall_prerr(fn, args);
 }
+
+int seamldr_get_info(struct seamldr_info *seamldr_info)
+{
+	/*
+	 * Use slow_virt_to_phys() since @seamldr_info may be allocated on
+	 * the stack.
+	 */
+	struct tdx_module_args args = { .rcx = slow_virt_to_phys(seamldr_info) };
+
+	return seamldr_call(P_SEAMLDR_INFO, &args);
+}
+EXPORT_SYMBOL_FOR_MODULES(seamldr_get_info, "tdx-host");
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v5 06/22] coco/tdx-host: Expose P-SEAMLDR information via sysfs
  2026-03-15 13:58 [PATCH v5 00/22] Runtime TDX module update support Chao Gao
                   ` (4 preceding siblings ...)
  2026-03-15 13:58 ` [PATCH v5 05/22] x86/virt/seamldr: Retrieve P-SEAMLDR information Chao Gao
@ 2026-03-15 13:58 ` Chao Gao
  2026-03-17 10:06   ` Kiryl Shutsemau
  2026-03-15 13:58 ` [PATCH v5 07/22] coco/tdx-host: Implement firmware upload sysfs ABI for TDX module updates Chao Gao
                   ` (15 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
  To: x86, linux-coco, kvm, linux-kernel
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Chao Gao

TDX module updates require userspace to select the appropriate module
to load. Expose necessary information to facilitate this decision. Two
values are needed:

- P-SEAMLDR version: for compatibility checks between TDX module and
		     P-SEAMLDR
- num_remaining_updates: indicates how many updates can be performed

Expose them as tdx-host device attributes. Register these attributes
during device probe rather than creation, making it easier to hide them
when P-SEAMLDR calls are unsafe (due to CPU erratum).

Signed-off-by: Chao Gao <chao.gao@intel.com>
---
v5:
 - fix typos [Binbin]
 - register seamldr_group during device probe
v4:
 - Make seamldr attribute permission "0400" [Dave]
 - Don't include implementation details in OS ABI docs [Dave]
 - Tag tdx_host_group as static [Kai]

v3:
 - use #ifdef rather than .is_visible() to control P-SEAMLDR sysfs
   visibility [Yilun]
---
 .../ABI/testing/sysfs-devices-faux-tdx-host   | 23 +++++++
 drivers/virt/coco/tdx-host/tdx-host.c         | 68 ++++++++++++++++++-
 2 files changed, 90 insertions(+), 1 deletion(-)

diff --git a/Documentation/ABI/testing/sysfs-devices-faux-tdx-host b/Documentation/ABI/testing/sysfs-devices-faux-tdx-host
index 2cf682b65acf..44b8356aed6b 100644
--- a/Documentation/ABI/testing/sysfs-devices-faux-tdx-host
+++ b/Documentation/ABI/testing/sysfs-devices-faux-tdx-host
@@ -4,3 +4,26 @@ Description:	(RO) Report the version of the loaded TDX module. The TDX module
 		version is formatted as x.y.z, where "x" is the major version,
 		"y" is the minor version and "z" is the update version. Versions
 		are used for bug reporting, TDX module updates etc.
+
+What:		/sys/devices/faux/tdx_host/seamldr/version
+Contact:	linux-coco@lists.linux.dev
+Description:	(RO) Report the version of the loaded SEAM loader. The SEAM
+		loader version is formatted as x.y.z, where "x" is the major
+		version, "y" is the minor version and "z" is the update version.
+		Versions are used for bug reporting and compatibility checks.
+
+What:		/sys/devices/faux/tdx_host/seamldr/num_remaining_updates
+Contact:	linux-coco@lists.linux.dev
+Description:	(RO) Report the number of remaining updates. TDX maintains a
+		log about each TDX module that has been loaded. This log has
+		a finite size, which limits the number of TDX module updates
+		that can be performed.
+
+		After each successful update, the number reduces by one. Once it
+		reaches zero, further updates will fail until next reboot. The
+		number is always zero if the P-SEAMLDR doesn't support updates.
+
+		See Intel® Trust Domain Extensions - SEAM Loader (SEAMLDR)
+		Interface Specification, Revision 343755-003, Chapter 3.3
+		"SEAMLDR_INFO" and Chapter 4.2 "SEAMLDR.INSTALL" for more
+		information.
diff --git a/drivers/virt/coco/tdx-host/tdx-host.c b/drivers/virt/coco/tdx-host/tdx-host.c
index 0424933b2560..8d46e3c039ba 100644
--- a/drivers/virt/coco/tdx-host/tdx-host.c
+++ b/drivers/virt/coco/tdx-host/tdx-host.c
@@ -11,6 +11,7 @@
 #include <linux/sysfs.h>
 
 #include <asm/cpu_device_id.h>
+#include <asm/seamldr.h>
 #include <asm/tdx.h>
 
 static const struct x86_cpu_id tdx_host_ids[] = {
@@ -42,6 +43,71 @@ static struct attribute *tdx_host_attrs[] = {
 };
 ATTRIBUTE_GROUPS(tdx_host);
 
+static ssize_t seamldr_version_show(struct device *dev, struct device_attribute *attr,
+				    char *buf)
+{
+	struct seamldr_info info;
+	int ret;
+
+	ret = seamldr_get_info(&info);
+	if (ret)
+		return ret;
+
+	return sysfs_emit(buf, "%u.%u.%02u\n", info.major_version,
+					       info.minor_version,
+					       info.update_version);
+}
+
+static ssize_t num_remaining_updates_show(struct device *dev,
+					  struct device_attribute *attr,
+					  char *buf)
+{
+	struct seamldr_info info;
+	int ret;
+
+	ret = seamldr_get_info(&info);
+	if (ret)
+		return ret;
+
+	return sysfs_emit(buf, "%u\n", info.num_remaining_updates);
+}
+
+/*
+ * Open-code DEVICE_ATTR_ADMIN_RO to specify a different 'show' function
+ * for P-SEAMLDR version as version_show() is used for TDX module version.
+ *
+ * Admin-only readable as reading these attributes calls into P-SEAMLDR,
+ * which may have potential performance and system impact.
+ */
+static struct device_attribute dev_attr_seamldr_version =
+	__ATTR(version, 0400, seamldr_version_show, NULL);
+static DEVICE_ATTR_ADMIN_RO(num_remaining_updates);
+
+static struct attribute *seamldr_attrs[] = {
+	&dev_attr_seamldr_version.attr,
+	&dev_attr_num_remaining_updates.attr,
+	NULL,
+};
+
+static const struct attribute_group seamldr_group = {
+	.name = "seamldr",
+	.attrs = seamldr_attrs,
+};
+
+static int seamldr_init(struct device *dev)
+{
+	return devm_device_add_group(dev, &seamldr_group);
+}
+
+static int tdx_host_probe(struct faux_device *fdev)
+{
+	return seamldr_init(&fdev->dev);
+}
+
+static const struct faux_device_ops tdx_host_ops = {
+	.probe		= tdx_host_probe,
+};
+
 static struct faux_device *fdev;
 
 static int __init tdx_host_init(void)
@@ -49,7 +115,7 @@ static int __init tdx_host_init(void)
 	if (!x86_match_cpu(tdx_host_ids) || !tdx_get_sysinfo())
 		return -ENODEV;
 
-	fdev = faux_device_create_with_groups(KBUILD_MODNAME, NULL, NULL, tdx_host_groups);
+	fdev = faux_device_create_with_groups(KBUILD_MODNAME, NULL, &tdx_host_ops, tdx_host_groups);
 	if (!fdev)
 		return -ENODEV;
 
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v5 07/22] coco/tdx-host: Implement firmware upload sysfs ABI for TDX module updates
  2026-03-15 13:58 [PATCH v5 00/22] Runtime TDX module update support Chao Gao
                   ` (5 preceding siblings ...)
  2026-03-15 13:58 ` [PATCH v5 06/22] coco/tdx-host: Expose P-SEAMLDR information via sysfs Chao Gao
@ 2026-03-15 13:58 ` Chao Gao
  2026-03-17 10:20   ` Kiryl Shutsemau
  2026-03-18 21:45   ` Huang, Kai
  2026-03-15 13:58 ` [PATCH v5 08/22] x86/virt/seamldr: Allocate and populate a module update request Chao Gao
                   ` (14 subsequent siblings)
  21 siblings, 2 replies; 80+ messages in thread
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
  To: linux-kernel, linux-coco, kvm
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Chao Gao, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	x86, H. Peter Anvin

Linux kernel supports two primary firmware update mechanisms:
  - request_firmware()
  - firmware upload (or fw_upload)

The former is used by microcode updates, SEV firmware updates, etc. The
latter is used by CXL and FPGA firmware updates.

One key difference between them is: request_firmware() loads a named
file from the filesystem where the filename is kernel-controlled, while
fw_upload accepts firmware data directly from userspace.

Use fw_upload for TDX module updates as loading a named file isn't
suitable for TDX (see below for more reasons). Specifically, register
TDX faux device with fw_upload framework to expose sysfs interfaces
and implement operations to process data blobs supplied by userspace.

Implementation notes:
1. P-SEAMLDR processes the entire update at once rather than
   chunk-by-chunk, so .write() is called only once per update; so the
   offset should be always 0.
2. An update completes synchronously within .write(), meaning
   .poll_complete() is only called after the update succeeds and so always
   returns success

Why fw_upload instead of request_firmware()?
============================================
The explicit file selection capabilities of fw_upload is preferred over
the implicit file selection of request_firmware() for the following
reasons:

a. Intel distributes all versions of the TDX module, allowing admins to
load any version rather than always defaulting to the latest. This
flexibility is necessary because future extensions may require reverting to
a previous version to clear fatal errors.

b. Some module version series are platform-specific. For example, the 1.5.x
series is for certain platform generations, while the 2.0.x series is
intended for others.

c. The update policy for TDX module updates is non-linear at times. The
latest TDX module may not be compatible. For example, TDX module 1.5.x
may be updated to 1.5.y but not to 1.5.y+1. This policy is documented
separately in a file released along with each TDX module release.

So, the default policy of "request_firmware()" of "always load latest", is
not suitable for TDX. Userspace needs to deploy a more sophisticated policy
check (e.g., latest may not be compatible), and there is potential
operator choice to consider.

Just have userspace pick rather than add kernel mechanism to change the
default policy of request_firmware().

Signed-off-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
---
v5:
 - remove a tail comment [Yan]
 - remove is_vmalloc_addr() check [Dave]
 - use devm_add_action_or_reset() for deinit [Yilun]
 - remove global tdx_fwl [Yilun]
 - clarify request_firmware() doesn't take filename from userspace
   [Rick]

v4:
 - make tdx_fwl static [Kai]
 - don't support update canceling [Yilun]
 - explain why seamldr_init() doesn't return an error [Kai]
 - bail out if TDX module updates are not supported [Kai]
 - name the firmware "tdx_module" instead of "seamldr_upload" [Cedric]

v3:
 - clear "cancel_request" in the "prepare" phase [Binbin]
 - Don't fail the whole tdx-host device if seamldr_init() met an error
 [Yilun]
 - Add kdoc for seamldr_install_module() and verify that the input
   buffer is vmalloc'd. [Yilun]
---
 arch/x86/include/asm/seamldr.h        |  1 +
 arch/x86/include/asm/tdx.h            |  6 ++
 arch/x86/virt/vmx/tdx/seamldr.c       | 15 +++++
 drivers/virt/coco/tdx-host/Kconfig    |  2 +
 drivers/virt/coco/tdx-host/tdx-host.c | 87 +++++++++++++++++++++++++++
 5 files changed, 111 insertions(+)

diff --git a/arch/x86/include/asm/seamldr.h b/arch/x86/include/asm/seamldr.h
index c67e5bc910a9..ac6f80f7208b 100644
--- a/arch/x86/include/asm/seamldr.h
+++ b/arch/x86/include/asm/seamldr.h
@@ -32,5 +32,6 @@ struct seamldr_info {
 static_assert(sizeof(struct seamldr_info) == 256);
 
 int seamldr_get_info(struct seamldr_info *seamldr_info);
+int seamldr_install_module(const u8 *data, u32 size);
 
 #endif /* _ASM_X86_SEAMLDR_H */
diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index cb2219302dfc..b3a7301e77c6 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -103,6 +103,12 @@ int tdx_enable(void);
 const char *tdx_dump_mce_info(struct mce *m);
 const struct tdx_sys_info *tdx_get_sysinfo(void);
 
+static inline bool tdx_supports_runtime_update(const struct tdx_sys_info *sysinfo)
+{
+	 /* To be enabled when kernel is ready. */
+	return false;
+}
+
 int tdx_guest_keyid_alloc(void);
 u32 tdx_get_nr_guest_keyids(void);
 void tdx_guest_keyid_free(unsigned int keyid);
diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
index 7c0cbab2c4c0..7114326d7569 100644
--- a/arch/x86/virt/vmx/tdx/seamldr.c
+++ b/arch/x86/virt/vmx/tdx/seamldr.c
@@ -6,6 +6,7 @@
  */
 #define pr_fmt(fmt)	"seamldr: " fmt
 
+#include <linux/mm.h>
 #include <linux/spinlock.h>
 
 #include <asm/seamldr.h>
@@ -39,3 +40,17 @@ int seamldr_get_info(struct seamldr_info *seamldr_info)
 	return seamldr_call(P_SEAMLDR_INFO, &args);
 }
 EXPORT_SYMBOL_FOR_MODULES(seamldr_get_info, "tdx-host");
+
+/**
+ * seamldr_install_module - Install a new TDX module.
+ * @data: Pointer to the TDX module update blob.
+ * @size: Size of the TDX module update blob.
+ *
+ * Returns 0 on success, negative error code on failure.
+ */
+int seamldr_install_module(const u8 *data, u32 size)
+{
+	/* TODO: Update TDX module here */
+	return 0;
+}
+EXPORT_SYMBOL_FOR_MODULES(seamldr_install_module, "tdx-host");
diff --git a/drivers/virt/coco/tdx-host/Kconfig b/drivers/virt/coco/tdx-host/Kconfig
index d35d85ef91c0..ca600a39d97b 100644
--- a/drivers/virt/coco/tdx-host/Kconfig
+++ b/drivers/virt/coco/tdx-host/Kconfig
@@ -1,6 +1,8 @@
 config TDX_HOST_SERVICES
 	tristate "TDX Host Services Driver"
 	depends on INTEL_TDX_HOST
+	select FW_LOADER
+	select FW_UPLOAD
 	default m
 	help
 	  Enable access to TDX host services like module update and
diff --git a/drivers/virt/coco/tdx-host/tdx-host.c b/drivers/virt/coco/tdx-host/tdx-host.c
index 8d46e3c039ba..1b93d20406c1 100644
--- a/drivers/virt/coco/tdx-host/tdx-host.c
+++ b/drivers/virt/coco/tdx-host/tdx-host.c
@@ -6,6 +6,7 @@
  */
 
 #include <linux/device/faux.h>
+#include <linux/firmware.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/sysfs.h>
@@ -94,8 +95,94 @@ static const struct attribute_group seamldr_group = {
 	.attrs = seamldr_attrs,
 };
 
+static enum fw_upload_err tdx_fw_prepare(struct fw_upload *fwl,
+					 const u8 *data, u32 size)
+{
+	return FW_UPLOAD_ERR_NONE;
+}
+
+static enum fw_upload_err tdx_fw_write(struct fw_upload *fwl, const u8 *data,
+				       u32 offset, u32 size, u32 *written)
+{
+	int ret;
+
+	/*
+	 * tdx_fw_write() always processes all data on the first call with
+	 * offset == 0. Since it never returns partial success (it either
+	 * succeeds completely or fails), there is no subsequent call with
+	 * non-zero offsets.
+	 */
+	WARN_ON_ONCE(offset);
+	ret = seamldr_install_module(data, size);
+	switch (ret) {
+	case 0:
+		*written = size;
+		return FW_UPLOAD_ERR_NONE;
+	case -EBUSY:
+		return FW_UPLOAD_ERR_BUSY;
+	case -EIO:
+		return FW_UPLOAD_ERR_HW_ERROR;
+	case -ENOSPC:
+		return FW_UPLOAD_ERR_WEAROUT;
+	case -ENOMEM:
+		return FW_UPLOAD_ERR_RW_ERROR;
+	default:
+		return FW_UPLOAD_ERR_FW_INVALID;
+	}
+}
+
+static enum fw_upload_err tdx_fw_poll_complete(struct fw_upload *fwl)
+{
+	/*
+	 * TDX module updates are completed in the previous phase
+	 * (tdx_fw_write()). If any error occurred, the previous phase
+	 * would return an error code to abort the update process. In
+	 * other words, reaching this point means the update succeeded.
+	 */
+	return FW_UPLOAD_ERR_NONE;
+}
+
+/*
+ * TDX module updates cannot be cancelled. Provide a stub function since
+ * the firmware upload framework requires a .cancel operation.
+ */
+static void tdx_fw_cancel(struct fw_upload *fwl)
+{
+}
+
+static const struct fw_upload_ops tdx_fw_ops = {
+	.prepare	= tdx_fw_prepare,
+	.write		= tdx_fw_write,
+	.poll_complete	= tdx_fw_poll_complete,
+	.cancel		= tdx_fw_cancel,
+};
+
+static void seamldr_deinit(void *tdx_fwl)
+{
+	firmware_upload_unregister(tdx_fwl);
+}
+
 static int seamldr_init(struct device *dev)
 {
+	const struct tdx_sys_info *tdx_sysinfo = tdx_get_sysinfo();
+	struct fw_upload *tdx_fwl;
+	int ret;
+
+	if (WARN_ON_ONCE(!tdx_sysinfo))
+		return -EIO;
+
+	if (!tdx_supports_runtime_update(tdx_sysinfo))
+		return 0;
+
+	tdx_fwl = firmware_upload_register(THIS_MODULE, dev, "tdx_module",
+					   &tdx_fw_ops, NULL);
+	if (IS_ERR(tdx_fwl))
+		return PTR_ERR(tdx_fwl);
+
+	ret = devm_add_action_or_reset(dev, seamldr_deinit, tdx_fwl);
+	if (ret)
+		return ret;
+
 	return devm_device_add_group(dev, &seamldr_group);
 }
 
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v5 08/22] x86/virt/seamldr: Allocate and populate a module update request
  2026-03-15 13:58 [PATCH v5 00/22] Runtime TDX module update support Chao Gao
                   ` (6 preceding siblings ...)
  2026-03-15 13:58 ` [PATCH v5 07/22] coco/tdx-host: Implement firmware upload sysfs ABI for TDX module updates Chao Gao
@ 2026-03-15 13:58 ` Chao Gao
  2026-03-17 10:59   ` Kiryl Shutsemau
  2026-03-18 21:36   ` Huang, Kai
  2026-03-15 13:58 ` [PATCH v5 09/22] x86/virt/seamldr: Introduce skeleton for TDX module updates Chao Gao
                   ` (13 subsequent siblings)
  21 siblings, 2 replies; 80+ messages in thread
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
  To: linux-kernel, linux-coco, kvm
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Chao Gao, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	x86, H. Peter Anvin

P-SEAMLDR uses the SEAMLDR_PARAMS structure to describe TDX module
update requests. This structure contains physical addresses pointing to
the module binary and its signature file (or sigstruct), along with an
update scenario field.

TDX modules are distributed in the tdx_blob format defined in
blob_structure.txt from the "Intel TDX module Binaries Repository". A
tdx_blob contains a header, sigstruct, and module binary. This is also the
format supplied by the userspace to the kernel.

Parse the tdx_blob format and populate a SEAMLDR_PARAMS structure
accordingly. This structure will be passed to P-SEAMLDR to initiate the
update.

Note that the sigstruct_pa field in SEAMLDR_PARAMS has been extended to
a 4-element array. The updated "SEAM Loader (SEAMLDR) Interface
Specification" will be published separately. P-SEAMLDR compatibility
validation (such as 4KB vs 16KB sigstruct support) is left to userspace,
which must verify the P-SEAMLDR version meets the TDX module's minimum
requirements.

Signed-off-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
---
v5:
 - use a macro for tdx_blob version (0x100) [Yan]
 - don't do alignment checking for the binary/sigstruct [Rick]
 - drop blob's sigstruct and validation checking
 - set seamldr_params.version to 1 when necessary
 - drop the link to blob_structure.txt which might be unstable [Kai]

v4:
 - Remove checksum verification as it is optional
 - Convert comments to is_vmalloc_addr() checks [Kai]
 - Explain size/alignment checks in alloc_seamldr_params() [Kai]

v3:
 - Print tdx_blob version in hex [Binbin]
 - Drop redundant sigstruct alignment check [Yilun]
 - Note buffers passed from firmware upload infrastructure are
   vmalloc()'d above alloc_seamldr_params()
---
 arch/x86/virt/vmx/tdx/seamldr.c | 141 ++++++++++++++++++++++++++++++++
 1 file changed, 141 insertions(+)

diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
index 7114326d7569..20cb6c797ce5 100644
--- a/arch/x86/virt/vmx/tdx/seamldr.c
+++ b/arch/x86/virt/vmx/tdx/seamldr.c
@@ -7,6 +7,7 @@
 #define pr_fmt(fmt)	"seamldr: " fmt
 
 #include <linux/mm.h>
+#include <linux/slab.h>
 #include <linux/spinlock.h>
 
 #include <asm/seamldr.h>
@@ -16,6 +17,33 @@
 /* P-SEAMLDR SEAMCALL leaf function */
 #define P_SEAMLDR_INFO			0x8000000000000000
 
+#define SEAMLDR_MAX_NR_MODULE_4KB_PAGES	496
+#define SEAMLDR_MAX_NR_SIG_4KB_PAGES	4
+
+/*
+ * The seamldr_params "scenario" field specifies the operation mode:
+ * 0: Install TDX module from scratch (not used by kernel)
+ * 1: Update existing TDX module to a compatible version
+ */
+#define SEAMLDR_SCENARIO_UPDATE		1
+
+/*
+ * This is called the "SEAMLDR_PARAMS" data structure and is defined
+ * in "SEAM Loader (SEAMLDR) Interface Specification".
+ *
+ * It describes the TDX module that will be installed.
+ */
+struct seamldr_params {
+	u32	version;
+	u32	scenario;
+	u64	sigstruct_pa[SEAMLDR_MAX_NR_SIG_4KB_PAGES];
+	u8	reserved[80];
+	u64	num_module_pages;
+	u64	mod_pages_pa_list[SEAMLDR_MAX_NR_MODULE_4KB_PAGES];
+} __packed;
+
+static_assert(sizeof(struct seamldr_params) == 4096);
+
 /*
  * Serialize P-SEAMLDR calls since the hardware only allows a single CPU to
  * interact with P-SEAMLDR simultaneously. Use raw version as the calls can
@@ -41,6 +69,114 @@ int seamldr_get_info(struct seamldr_info *seamldr_info)
 }
 EXPORT_SYMBOL_FOR_MODULES(seamldr_get_info, "tdx-host");
 
+static void free_seamldr_params(struct seamldr_params *params)
+{
+	free_page((unsigned long)params);
+}
+
+static struct seamldr_params *alloc_seamldr_params(const void *module, unsigned int module_size,
+						   const void *sig, unsigned int sig_size)
+{
+	struct seamldr_params *params;
+	const u8 *ptr;
+	int i;
+
+	if (module_size > SEAMLDR_MAX_NR_MODULE_4KB_PAGES * SZ_4K)
+		return ERR_PTR(-EINVAL);
+
+	if (sig_size > SEAMLDR_MAX_NR_SIG_4KB_PAGES * SZ_4K)
+		return ERR_PTR(-EINVAL);
+
+	params = (struct seamldr_params *)get_zeroed_page(GFP_KERNEL);
+	if (!params)
+		return ERR_PTR(-ENOMEM);
+
+	/*
+	 * Only use version 1 when required (sigstruct > 4KB) for backward
+	 * compatibility with P-SEAMLDR that lacks version 1 support.
+	 */
+	if (sig_size > SZ_4K)
+		params->version = 1;
+	else
+		params->version = 0;
+
+	params->scenario = SEAMLDR_SCENARIO_UPDATE;
+
+	ptr = sig;
+	for (i = 0; i < sig_size / SZ_4K; i++) {
+		/*
+		 * Don't assume @sig is page-aligned although it is 4KB-aligned.
+		 * Always add the in-page offset to get the physical address.
+		 */
+		params->sigstruct_pa[i] = (vmalloc_to_pfn(ptr) << PAGE_SHIFT) +
+					  ((unsigned long)ptr & ~PAGE_MASK);
+		ptr += SZ_4K;
+	}
+
+	params->num_module_pages = module_size / SZ_4K;
+
+	ptr = module;
+	for (i = 0; i < params->num_module_pages; i++) {
+		params->mod_pages_pa_list[i] = (vmalloc_to_pfn(ptr) << PAGE_SHIFT) +
+					       ((unsigned long)ptr & ~PAGE_MASK);
+		ptr += SZ_4K;
+	}
+
+	return params;
+}
+
+/*
+ * Intel TDX module blob. Its format is defined at:
+ * https://github.com/intel/tdx-module-binaries/blob/main/blob_structure.txt
+ *
+ * Note this structure differs from the reference above: the two variable-length
+ * fields "@sigstruct" and "@module" are represented as a single "@data" field
+ * here and split programmatically using the offset_of_module value.
+ */
+struct tdx_blob {
+	u16	version;
+	u16	checksum;
+	u32	offset_of_module;
+	u8	signature[8];
+	u32	length;
+	u32	reserved0;
+	u64	reserved1[509];
+	u8	data[];
+} __packed;
+
+/* Supported versions of the tdx_blob */
+#define TDX_BLOB_VERSION_1	0x100
+
+static struct seamldr_params *init_seamldr_params(const u8 *data, u32 size)
+{
+	const struct tdx_blob *blob = (const void *)data;
+	int module_size, sig_size;
+	const void *sig, *module;
+
+	/* Ensure the size is valid otherwise reading any field from the blob may overflow. */
+	if (size <= sizeof(struct tdx_blob) || size <= blob->offset_of_module)
+		return ERR_PTR(-EINVAL);
+
+	if (blob->version != TDX_BLOB_VERSION_1) {
+		pr_err("unsupported blob version: %x\n", blob->version);
+		return ERR_PTR(-EINVAL);
+	}
+
+	/* Split the blob into a sigstruct and a module. */
+	sig		= blob->data;
+	sig_size	= blob->offset_of_module - sizeof(struct tdx_blob);
+	module		= data + blob->offset_of_module;
+	module_size	= size - blob->offset_of_module;
+
+	if (sig_size <= 0 || module_size <= 0 || blob->length != size)
+		return ERR_PTR(-EINVAL);
+
+	return alloc_seamldr_params(module, module_size, sig, sig_size);
+}
+
+DEFINE_FREE(free_seamldr_params, struct seamldr_params *,
+	    if (!IS_ERR_OR_NULL(_T)) free_seamldr_params(_T))
+
 /**
  * seamldr_install_module - Install a new TDX module.
  * @data: Pointer to the TDX module update blob.
@@ -50,6 +186,11 @@ EXPORT_SYMBOL_FOR_MODULES(seamldr_get_info, "tdx-host");
  */
 int seamldr_install_module(const u8 *data, u32 size)
 {
+	struct seamldr_params *params __free(free_seamldr_params) =
+						init_seamldr_params(data, size);
+	if (IS_ERR(params))
+		return PTR_ERR(params);
+
 	/* TODO: Update TDX module here */
 	return 0;
 }
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v5 09/22] x86/virt/seamldr: Introduce skeleton for TDX module updates
  2026-03-15 13:58 [PATCH v5 00/22] Runtime TDX module update support Chao Gao
                   ` (7 preceding siblings ...)
  2026-03-15 13:58 ` [PATCH v5 08/22] x86/virt/seamldr: Allocate and populate a module update request Chao Gao
@ 2026-03-15 13:58 ` Chao Gao
  2026-03-18 22:11   ` Huang, Kai
  2026-03-19 13:15   ` Kiryl Shutsemau
  2026-03-15 13:58 ` [PATCH v5 10/22] x86/virt/seamldr: Abort updates if errors occurred midway Chao Gao
                   ` (12 subsequent siblings)
  21 siblings, 2 replies; 80+ messages in thread
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
  To: linux-kernel, linux-coco, kvm
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Chao Gao, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	x86, H. Peter Anvin

TDX module updates require careful synchronization with other TDX
operations. The requirements are (#1/#2 reflect current behavior that
must be preserved):

1. SEAMCALLs need to be callable from both process and IRQ contexts.
2. SEAMCALLs need to be able to run concurrently across CPUs
3. During updates, only update-related SEAMCALLs are permitted; all
   other SEAMCALLs shouldn't be called.
4. During updates, all online CPUs must participate in the update work.

No single lock primitive satisfies all requirements. For instance,
rwlock_t handles #1/#2 but fails #4: CPUs spinning with IRQs disabled
cannot be directed to perform update work.

Use stop_machine() as it is the only well-understood mechanism that can
meet all requirements.

And TDX module updates consist of several steps (See Intel® Trust Domain
Extensions (Intel® TDX) Module Base Architecture Specification, Revision
348549-007, Chapter 4.5 "TD-Preserving TDX module Update"). Ordering
requirements between steps mandate lockstep synchronization across all
CPUs.

multi_cpu_stop() is a good example of performing a multi-step task in
lockstep. But it doesn't synchronize steps within the callback function
it takes. So, implement one based on its pattern to establish the
skeleton for TDX module updates. Specifically, add a global state
machine where each state represents a step in the update flow. The state
advances only after all CPUs acknowledge completing their work in the
current state. This acknowledgment mechanism is what ensures lockstep
execution.

Potential alternative to stop_machine()
=======================================
An alternative approach is to lock all KVM entry points and kick all
vCPUs. Here, KVM entry points refer to KVM VM/vCPU ioctl entry points,
implemented in KVM common code (virt/kvm). Adding a locking mechanism
there would affect all architectures KVM supports. And to lock only TDX
vCPUs, new logic would be needed to identify TDX vCPUs, which the KVM
common code currently lacks. This would add significant complexity and
maintenance overhead to KVM for this TDX-specific use case.

Signed-off-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
---
v5:
 - rewrite the commit message [Rick]
 - use a lock to synchronize accesses to update_data [Dave]
 - rename tdp_state and tdp_data to module_update_state and update_data
   for clarity [Kai]

v2:
 - refine the changlog to follow context-problem-solution structure
 - move alternative discussions at the end of the changelog
 - add a comment about state machine transition
 - Move rcu_momentary_eqs() call to the else branch.
---
 arch/x86/virt/vmx/tdx/seamldr.c | 77 ++++++++++++++++++++++++++++++++-
 1 file changed, 75 insertions(+), 2 deletions(-)

diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
index 20cb6c797ce5..978fcca92128 100644
--- a/arch/x86/virt/vmx/tdx/seamldr.c
+++ b/arch/x86/virt/vmx/tdx/seamldr.c
@@ -7,8 +7,10 @@
 #define pr_fmt(fmt)	"seamldr: " fmt
 
 #include <linux/mm.h>
+#include <linux/nmi.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
+#include <linux/stop_machine.h>
 
 #include <asm/seamldr.h>
 
@@ -174,6 +176,77 @@ static struct seamldr_params *init_seamldr_params(const u8 *data, u32 size)
 	return alloc_seamldr_params(module, module_size, sig, sig_size);
 }
 
+/*
+ * During a TDX module update, all CPUs start from MODULE_UPDATE_START and
+ * progress to MODULE_UPDATE_DONE. Each state is associated with certain
+ * work. For some states, just one CPU needs to perform the work, while
+ * other CPUs just wait during those states.
+ */
+enum module_update_state {
+	MODULE_UPDATE_START,
+	MODULE_UPDATE_DONE,
+};
+
+static struct {
+	enum module_update_state state;
+	int thread_ack;
+	/*
+	 * Protect update_data. Raw spinlock as it will be acquired from
+	 * interrupt-disabled contexts.
+	 */
+	raw_spinlock_t lock;
+} update_data = {
+	.lock = __RAW_SPIN_LOCK_UNLOCKED(update_data.lock)
+};
+
+static void set_target_state(enum module_update_state state)
+{
+	/* Reset ack counter. */
+	update_data.thread_ack = num_online_cpus();
+	update_data.state = state;
+}
+
+/* Last one to ack a state moves to the next state. */
+static void ack_state(void)
+{
+	guard(raw_spinlock)(&update_data.lock);
+	update_data.thread_ack--;
+	if (!update_data.thread_ack)
+		set_target_state(update_data.state + 1);
+}
+
+/*
+ * See multi_cpu_stop() from where this multi-cpu state-machine was
+ * adopted, and the rationale for touch_nmi_watchdog().
+ */
+static int do_seamldr_install_module(void *seamldr_params)
+{
+	enum module_update_state newstate, curstate = MODULE_UPDATE_START;
+	int ret = 0;
+
+	do {
+		/* Chill out and re-read update_data. */
+		cpu_relax();
+		newstate = READ_ONCE(update_data.state);
+
+		if (newstate != curstate) {
+			curstate = newstate;
+			switch (curstate) {
+			/* TODO: add the update steps. */
+			default:
+				break;
+			}
+
+			ack_state();
+		} else {
+			touch_nmi_watchdog();
+			rcu_momentary_eqs();
+		}
+	} while (curstate != MODULE_UPDATE_DONE);
+
+	return ret;
+}
+
 DEFINE_FREE(free_seamldr_params, struct seamldr_params *,
 	    if (!IS_ERR_OR_NULL(_T)) free_seamldr_params(_T))
 
@@ -191,7 +264,7 @@ int seamldr_install_module(const u8 *data, u32 size)
 	if (IS_ERR(params))
 		return PTR_ERR(params);
 
-	/* TODO: Update TDX module here */
-	return 0;
+	set_target_state(MODULE_UPDATE_START + 1);
+	return stop_machine(do_seamldr_install_module, params, cpu_online_mask);
 }
 EXPORT_SYMBOL_FOR_MODULES(seamldr_install_module, "tdx-host");
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v5 10/22] x86/virt/seamldr: Abort updates if errors occurred midway
  2026-03-15 13:58 [PATCH v5 00/22] Runtime TDX module update support Chao Gao
                   ` (8 preceding siblings ...)
  2026-03-15 13:58 ` [PATCH v5 09/22] x86/virt/seamldr: Introduce skeleton for TDX module updates Chao Gao
@ 2026-03-15 13:58 ` Chao Gao
  2026-03-19 13:19   ` Kiryl Shutsemau
  2026-03-15 13:58 ` [PATCH v5 11/22] x86/virt/seamldr: Shut down the current TDX module Chao Gao
                   ` (11 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
  To: linux-kernel, linux-coco, kvm
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Chao Gao, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	x86, H. Peter Anvin

The TDX module update process has multiple steps, each of which may
encounter failures.

The current state machine of updates proceeds to the next step regardless
of errors. But continuing updates when errors occur midway is pointless.

Abort the update by setting a flag to indicate that a CPU has encountered
an error, forcing all CPUs to exit the execution loop. Note that failing
CPUs do not acknowledge the current step. This keeps all other CPUs waiting
in the current step (since advancing to the next step requires all CPUs to
acknowledge the current step) until they detect the fault flag and exit the
loop.

Signed-off-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
Reviewed-by: Kai Huang <kai.huang@intel.com>
---
v5:
 - Replace failed count from atomic_t to int since it's now protected by
   a lock.

v3:
 - Instead of fast-forward to the final stage, exit the execution loop
   directly.
---
 arch/x86/virt/vmx/tdx/seamldr.c | 11 +++++++++--
 1 file changed, 9 insertions(+), 2 deletions(-)

diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
index 978fcca92128..e195703398e7 100644
--- a/arch/x86/virt/vmx/tdx/seamldr.c
+++ b/arch/x86/virt/vmx/tdx/seamldr.c
@@ -190,6 +190,7 @@ enum module_update_state {
 static struct {
 	enum module_update_state state;
 	int thread_ack;
+	int failed;
 	/*
 	 * Protect update_data. Raw spinlock as it will be acquired from
 	 * interrupt-disabled contexts.
@@ -237,12 +238,17 @@ static int do_seamldr_install_module(void *seamldr_params)
 				break;
 			}
 
-			ack_state();
+			if (ret) {
+				scoped_guard(raw_spinlock, &update_data.lock)
+					update_data.failed++;
+			} else {
+				ack_state();
+			}
 		} else {
 			touch_nmi_watchdog();
 			rcu_momentary_eqs();
 		}
-	} while (curstate != MODULE_UPDATE_DONE);
+	} while (curstate != MODULE_UPDATE_DONE && !READ_ONCE(update_data.failed));
 
 	return ret;
 }
@@ -264,6 +270,7 @@ int seamldr_install_module(const u8 *data, u32 size)
 	if (IS_ERR(params))
 		return PTR_ERR(params);
 
+	update_data.failed = 0;
 	set_target_state(MODULE_UPDATE_START + 1);
 	return stop_machine(do_seamldr_install_module, params, cpu_online_mask);
 }
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v5 11/22] x86/virt/seamldr: Shut down the current TDX module
  2026-03-15 13:58 [PATCH v5 00/22] Runtime TDX module update support Chao Gao
                   ` (9 preceding siblings ...)
  2026-03-15 13:58 ` [PATCH v5 10/22] x86/virt/seamldr: Abort updates if errors occurred midway Chao Gao
@ 2026-03-15 13:58 ` Chao Gao
  2026-03-19 13:24   ` Kiryl Shutsemau
  2026-03-15 13:58 ` [PATCH v5 12/22] x86/virt/tdx: Reset software states during TDX module shutdown Chao Gao
                   ` (10 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
  To: linux-kernel, linux-coco, kvm
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Chao Gao, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	x86, H. Peter Anvin

The first step of TDX module updates is shutting down the current TDX
Module. This step also packs state information that needs to be
preserved across updates as handoff data, which will be consumed by the
updated module. The handoff data is stored internally in the SEAM range
and is hidden from the kernel.

To ensure a successful update, the new module must be able to consume
the handoff data generated by the old module. Since handoff data layout
may change between modules, the handoff data is versioned. Each module
has a native handoff version and provides backward support for several
older versions.

The complete handoff versioning protocol is complex as it supports both
module upgrades and downgrades. See details in Intel® Trust Domain
Extensions (Intel® TDX) Module Base Architecture Specification, Revision
348549-007, Chapter 4.5.3 "Handoff Versioning".

Ideally, the kernel needs to retrieve the handoff versions supported by
the current module and the new module and select a version supported by
both. But, since this implementation chooses to only support module
upgrades, simply request the current module to generate handoff data
using its highest supported version, expecting that the new module will
likely support it.

Note that only one CPU needs to call the TDX module's shutdown API.

Signed-off-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
Reviewed-by: Kai Huang <kai.huang@intel.com>
---
v5:
 - Massage changelog [Kai]
 - Avoid "refers to the global copy while populating the tdx_sys_info
   passed as a pointer" [Rick/Yilun]

v4:
 - skip the whole handoff metadata if runtime updates are not supported
   [Yilun]
v3:
 - remove autogeneration stuff in the changelog
v2:
 - add a comment about how handoff version is chosen.
 - remove the first !ret in get_tdx_sys_info_handoff() as we edited the
   auto-generated code anyway
 - remove !! when determining whether a CPU is the primary one
 - remove unnecessary if-break nesting in TDP_SHUTDOWN
---
 arch/x86/include/asm/tdx_global_metadata.h  |  5 +++++
 arch/x86/virt/vmx/tdx/seamldr.c             | 11 ++++++++++-
 arch/x86/virt/vmx/tdx/tdx.c                 | 15 +++++++++++++++
 arch/x86/virt/vmx/tdx/tdx.h                 |  3 +++
 arch/x86/virt/vmx/tdx/tdx_global_metadata.c | 18 ++++++++++++++++++
 5 files changed, 51 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/tdx_global_metadata.h b/arch/x86/include/asm/tdx_global_metadata.h
index 40689c8dc67e..8a9ebd895e70 100644
--- a/arch/x86/include/asm/tdx_global_metadata.h
+++ b/arch/x86/include/asm/tdx_global_metadata.h
@@ -40,12 +40,17 @@ struct tdx_sys_info_td_conf {
 	u64 cpuid_config_values[128][2];
 };
 
+struct tdx_sys_info_handoff {
+	u16 module_hv;
+};
+
 struct tdx_sys_info {
 	struct tdx_sys_info_version version;
 	struct tdx_sys_info_features features;
 	struct tdx_sys_info_tdmr tdmr;
 	struct tdx_sys_info_td_ctrl td_ctrl;
 	struct tdx_sys_info_td_conf td_conf;
+	struct tdx_sys_info_handoff handoff;
 };
 
 #endif
diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
index e195703398e7..bb4aa6327eee 100644
--- a/arch/x86/virt/vmx/tdx/seamldr.c
+++ b/arch/x86/virt/vmx/tdx/seamldr.c
@@ -15,6 +15,7 @@
 #include <asm/seamldr.h>
 
 #include "seamcall_internal.h"
+#include "tdx.h"
 
 /* P-SEAMLDR SEAMCALL leaf function */
 #define P_SEAMLDR_INFO			0x8000000000000000
@@ -184,6 +185,7 @@ static struct seamldr_params *init_seamldr_params(const u8 *data, u32 size)
  */
 enum module_update_state {
 	MODULE_UPDATE_START,
+	MODULE_UPDATE_SHUTDOWN,
 	MODULE_UPDATE_DONE,
 };
 
@@ -223,8 +225,12 @@ static void ack_state(void)
 static int do_seamldr_install_module(void *seamldr_params)
 {
 	enum module_update_state newstate, curstate = MODULE_UPDATE_START;
+	int cpu = smp_processor_id();
+	bool primary;
 	int ret = 0;
 
+	primary = cpumask_first(cpu_online_mask) == cpu;
+
 	do {
 		/* Chill out and re-read update_data. */
 		cpu_relax();
@@ -233,7 +239,10 @@ static int do_seamldr_install_module(void *seamldr_params)
 		if (newstate != curstate) {
 			curstate = newstate;
 			switch (curstate) {
-			/* TODO: add the update steps. */
+			case MODULE_UPDATE_SHUTDOWN:
+				if (primary)
+					ret = tdx_module_shutdown();
+				break;
 			default:
 				break;
 			}
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index 172f6d4133b5..f87fad429f4e 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -1176,6 +1176,21 @@ int tdx_enable(void)
 }
 EXPORT_SYMBOL_FOR_KVM(tdx_enable);
 
+int tdx_module_shutdown(void)
+{
+	struct tdx_module_args args = {};
+
+	/*
+	 * Shut down the TDX module and prepare handoff data for the next
+	 * TDX module. This SEAMCALL requires a handoff version. Use the
+	 * module's handoff version, as it is the highest version the
+	 * module can produce and is more likely to be supported by new
+	 * modules as new modules likely have higher handoff version.
+	 */
+	args.rcx = tdx_sysinfo.handoff.module_hv;
+	return seamcall_prerr(TDH_SYS_SHUTDOWN, &args);
+}
+
 static bool is_pamt_page(unsigned long phys)
 {
 	struct tdmr_info_list *tdmr_list = &tdx_tdmr_list;
diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h
index 82bb82be8567..1c4da9540ae0 100644
--- a/arch/x86/virt/vmx/tdx/tdx.h
+++ b/arch/x86/virt/vmx/tdx/tdx.h
@@ -46,6 +46,7 @@
 #define TDH_PHYMEM_PAGE_WBINVD		41
 #define TDH_VP_WR			43
 #define TDH_SYS_CONFIG			45
+#define TDH_SYS_SHUTDOWN		52
 
 /*
  * SEAMCALL leaf:
@@ -118,4 +119,6 @@ struct tdmr_info_list {
 	int max_tdmrs;	/* How many 'tdmr_info's are allocated */
 };
 
+int tdx_module_shutdown(void);
+
 #endif
diff --git a/arch/x86/virt/vmx/tdx/tdx_global_metadata.c b/arch/x86/virt/vmx/tdx/tdx_global_metadata.c
index 4c9917a9c2c3..d6a4fa8deb5e 100644
--- a/arch/x86/virt/vmx/tdx/tdx_global_metadata.c
+++ b/arch/x86/virt/vmx/tdx/tdx_global_metadata.c
@@ -100,6 +100,17 @@ static int get_tdx_sys_info_td_conf(struct tdx_sys_info_td_conf *sysinfo_td_conf
 	return ret;
 }
 
+static int get_tdx_sys_info_handoff(struct tdx_sys_info_handoff *sysinfo_handoff)
+{
+	int ret = 0;
+	u64 val;
+
+	if (!ret && !(ret = read_sys_metadata_field(0x8900000100000000, &val)))
+		sysinfo_handoff->module_hv = val;
+
+	return ret;
+}
+
 static int get_tdx_sys_info(struct tdx_sys_info *sysinfo)
 {
 	int ret = 0;
@@ -116,5 +127,12 @@ static int get_tdx_sys_info(struct tdx_sys_info *sysinfo)
 	ret = ret ?: get_tdx_sys_info_td_ctrl(&sysinfo->td_ctrl);
 	ret = ret ?: get_tdx_sys_info_td_conf(&sysinfo->td_conf);
 
+	/*
+	 * Don't treat a module that doesn't support update as a failure.
+	 * Only read the metadata optionally.
+	 */
+	if (tdx_supports_runtime_update(sysinfo))
+		ret = ret ?: get_tdx_sys_info_handoff(&sysinfo->handoff);
+
 	return ret;
 }
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v5 12/22] x86/virt/tdx: Reset software states during TDX module shutdown
  2026-03-15 13:58 [PATCH v5 00/22] Runtime TDX module update support Chao Gao
                   ` (10 preceding siblings ...)
  2026-03-15 13:58 ` [PATCH v5 11/22] x86/virt/seamldr: Shut down the current TDX module Chao Gao
@ 2026-03-15 13:58 ` Chao Gao
  2026-03-16  9:06   ` Huang, Kai
  2026-03-15 13:58 ` [PATCH v5 13/22] x86/virt/seamldr: Install a new TDX module Chao Gao
                   ` (9 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
  To: linux-kernel, linux-coco, kvm
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Chao Gao, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	x86, H. Peter Anvin

The TDX module requires a one-time global initialization (TDH.SYS.INIT) and
per-CPU initialization (TDH.SYS.LP.INIT) before use. These initializations
are guarded by software flags to prevent repetition.

After TDX module updates, the new TDX module requires the same global and
per-CPU initializations, but the existing software flags prevent
re-initialization.

Reset all software flags guarding the initialization flows to allow the
global and per-CPU initializations to be triggered again after updates.

Signed-off-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
Reviewed-by: Kai Huang <kai.huang@intel.com>
---
v5:
 - add a comment to clarify why state access doesn't require holding a
   lock. [Kai]
---
 arch/x86/virt/vmx/tdx/tdx.c | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index f87fad429f4e..cfe76d4ca570 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -55,6 +55,8 @@ static struct tdmr_info_list tdx_tdmr_list;
 
 static enum tdx_module_status_t tdx_module_status;
 static DEFINE_MUTEX(tdx_module_lock);
+static bool sysinit_done;
+static int sysinit_ret;
 
 /* All TDX-usable memory regions.  Protected by mem_hotplug_lock. */
 static LIST_HEAD(tdx_memlist);
@@ -70,8 +72,6 @@ static int try_init_module_global(void)
 {
 	struct tdx_module_args args = {};
 	static DEFINE_RAW_SPINLOCK(sysinit_lock);
-	static bool sysinit_done;
-	static int sysinit_ret;
 
 	lockdep_assert_irqs_disabled();
 
@@ -1179,6 +1179,7 @@ EXPORT_SYMBOL_FOR_KVM(tdx_enable);
 int tdx_module_shutdown(void)
 {
 	struct tdx_module_args args = {};
+	int ret, cpu;
 
 	/*
 	 * Shut down the TDX module and prepare handoff data for the next
@@ -1188,7 +1189,22 @@ int tdx_module_shutdown(void)
 	 * modules as new modules likely have higher handoff version.
 	 */
 	args.rcx = tdx_sysinfo.handoff.module_hv;
-	return seamcall_prerr(TDH_SYS_SHUTDOWN, &args);
+	ret = seamcall_prerr(TDH_SYS_SHUTDOWN, &args);
+	if (ret)
+		return ret;
+
+	tdx_module_status = TDX_MODULE_UNINITIALIZED;
+	sysinit_done = false;
+	sysinit_ret = 0;
+
+	/*
+	 * By reaching here CPUHP is disabled and all present CPUs
+	 * are online. It's safe to just loop all online CPUs and
+	 * reset the per-cpu flag.
+	 */
+	for_each_online_cpu(cpu)
+		per_cpu(tdx_lp_initialized, cpu) = false;
+	return 0;
 }
 
 static bool is_pamt_page(unsigned long phys)
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v5 13/22] x86/virt/seamldr: Install a new TDX module
  2026-03-15 13:58 [PATCH v5 00/22] Runtime TDX module update support Chao Gao
                   ` (11 preceding siblings ...)
  2026-03-15 13:58 ` [PATCH v5 12/22] x86/virt/tdx: Reset software states during TDX module shutdown Chao Gao
@ 2026-03-15 13:58 ` Chao Gao
  2026-03-19 13:32   ` Kiryl Shutsemau
  2026-03-15 13:58 ` [PATCH v5 14/22] x86/virt/seamldr: Do TDX per-CPU initialization after updates Chao Gao
                   ` (8 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
  To: linux-kernel, linux-coco, kvm
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Chao Gao, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	x86, H. Peter Anvin

Following the shutdown of the existing TDX module, the update process
continues with installing the new module. P-SEAMLDR provides the
SEAMLDR.INSTALL SEAMCALL to perform this installation, which must be
executed on all CPUs.

Implement SEAMLDR.INSTALL and execute it on every CPU.

Signed-off-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
Reviewed-by: Kai Huang <kai.huang@intel.com>
Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
---
v5:
 - drop "serially" from the changelog as it doesn't matter to
   this patch
---
 arch/x86/virt/vmx/tdx/seamldr.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
index bb4aa6327eee..a64271f94aed 100644
--- a/arch/x86/virt/vmx/tdx/seamldr.c
+++ b/arch/x86/virt/vmx/tdx/seamldr.c
@@ -19,6 +19,7 @@
 
 /* P-SEAMLDR SEAMCALL leaf function */
 #define P_SEAMLDR_INFO			0x8000000000000000
+#define P_SEAMLDR_INSTALL		0x8000000000000001
 
 #define SEAMLDR_MAX_NR_MODULE_4KB_PAGES	496
 #define SEAMLDR_MAX_NR_SIG_4KB_PAGES	4
@@ -186,6 +187,7 @@ static struct seamldr_params *init_seamldr_params(const u8 *data, u32 size)
 enum module_update_state {
 	MODULE_UPDATE_START,
 	MODULE_UPDATE_SHUTDOWN,
+	MODULE_UPDATE_CPU_INSTALL,
 	MODULE_UPDATE_DONE,
 };
 
@@ -225,6 +227,7 @@ static void ack_state(void)
 static int do_seamldr_install_module(void *seamldr_params)
 {
 	enum module_update_state newstate, curstate = MODULE_UPDATE_START;
+	struct tdx_module_args args = {};
 	int cpu = smp_processor_id();
 	bool primary;
 	int ret = 0;
@@ -243,6 +246,10 @@ static int do_seamldr_install_module(void *seamldr_params)
 				if (primary)
 					ret = tdx_module_shutdown();
 				break;
+			case MODULE_UPDATE_CPU_INSTALL:
+				args.rcx = __pa(seamldr_params);
+				ret = seamldr_call(P_SEAMLDR_INSTALL, &args);
+				break;
 			default:
 				break;
 			}
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v5 14/22] x86/virt/seamldr: Do TDX per-CPU initialization after updates
  2026-03-15 13:58 [PATCH v5 00/22] Runtime TDX module update support Chao Gao
                   ` (12 preceding siblings ...)
  2026-03-15 13:58 ` [PATCH v5 13/22] x86/virt/seamldr: Install a new TDX module Chao Gao
@ 2026-03-15 13:58 ` Chao Gao
  2026-03-19 13:33   ` Kiryl Shutsemau
  2026-03-15 13:58 ` [PATCH v5 15/22] x86/virt/tdx: Restore TDX module state Chao Gao
                   ` (7 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
  To: linux-kernel, linux-coco, kvm
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Chao Gao, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	x86, H. Peter Anvin

After installing the new TDX module, each CPU needs to be initialized
again to make the CPU ready to run any other SEAMCALLs. So, call
tdx_cpu_enable() on all CPUs.

Signed-off-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
Reviewed-by: Kai Huang <kai.huang@intel.com>
---
 arch/x86/virt/vmx/tdx/seamldr.c | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
index a64271f94aed..4d8c96d82c05 100644
--- a/arch/x86/virt/vmx/tdx/seamldr.c
+++ b/arch/x86/virt/vmx/tdx/seamldr.c
@@ -188,6 +188,7 @@ enum module_update_state {
 	MODULE_UPDATE_START,
 	MODULE_UPDATE_SHUTDOWN,
 	MODULE_UPDATE_CPU_INSTALL,
+	MODULE_UPDATE_CPU_INIT,
 	MODULE_UPDATE_DONE,
 };
 
@@ -250,6 +251,9 @@ static int do_seamldr_install_module(void *seamldr_params)
 				args.rcx = __pa(seamldr_params);
 				ret = seamldr_call(P_SEAMLDR_INSTALL, &args);
 				break;
+			case MODULE_UPDATE_CPU_INIT:
+				ret = tdx_cpu_enable();
+				break;
 			default:
 				break;
 			}
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v5 15/22] x86/virt/tdx: Restore TDX module state
  2026-03-15 13:58 [PATCH v5 00/22] Runtime TDX module update support Chao Gao
                   ` (13 preceding siblings ...)
  2026-03-15 13:58 ` [PATCH v5 14/22] x86/virt/seamldr: Do TDX per-CPU initialization after updates Chao Gao
@ 2026-03-15 13:58 ` Chao Gao
  2026-03-19 13:37   ` Kiryl Shutsemau
  2026-03-15 13:58 ` [PATCH v5 16/22] x86/virt/tdx: Update tdx_sysinfo and check features post-update Chao Gao
                   ` (6 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
  To: linux-kernel, linux-coco, kvm
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Chao Gao, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	x86, H. Peter Anvin

TDX module state was packed as handoff data during module shutdown. After
per-CPU initialization, the new module can restore TDX module state from
handoff data to preserve running TDs.

Once the restoration is done, the TDX module update is complete, which
means the new module is ready to handle requests from the host and guests.

Implement the new TDH.SYS.UPDATE SEAMCALL to restore TDX module state
and invoke it on one CPU since it only needs to be called once.

Note that Intel® Trust Domain Extensions (Intel® TDX) Module Base
Architecture Specification, Revision 348549-007, Chapter 4.5.5 states:

  If TDH.SYS.UPDATE returns an error, then the host VMM can continue
  with the non-update sequence (TDH.SYS.CONFIG, 15 TDH.SYS.KEY.CONFIG
  etc.). In this case all existing TDs are lost. Alternatively, the host
  VMM can request the P-SEAMLDR to update to another TDX module. If that
  update is successful, existing TDs are preserved

Don't implement the two alternatives due to their complexity and unclear
benefits.

Also note that the location and the format of handoff data is defined by
the TDX module. The new module knows where to get handoff data and how
to parse it. The kernel doesn't need to provide its location, format etc.

Signed-off-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
Reviewed-by: Kai Huang <kai.huang@intel.com>
---
v5:
 - Massage changelog [Kai]
v3:
 - use seamcall_prerr() rather than raw seamcall() [Binbin]
 - use pr_err() to print error message [Binbin]
---
 arch/x86/virt/vmx/tdx/seamldr.c |  5 +++++
 arch/x86/virt/vmx/tdx/tdx.c     | 16 ++++++++++++++++
 arch/x86/virt/vmx/tdx/tdx.h     |  2 ++
 3 files changed, 23 insertions(+)

diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
index 4d8c96d82c05..806edf50a952 100644
--- a/arch/x86/virt/vmx/tdx/seamldr.c
+++ b/arch/x86/virt/vmx/tdx/seamldr.c
@@ -189,6 +189,7 @@ enum module_update_state {
 	MODULE_UPDATE_SHUTDOWN,
 	MODULE_UPDATE_CPU_INSTALL,
 	MODULE_UPDATE_CPU_INIT,
+	MODULE_UPDATE_RUN_UPDATE,
 	MODULE_UPDATE_DONE,
 };
 
@@ -254,6 +255,10 @@ static int do_seamldr_install_module(void *seamldr_params)
 			case MODULE_UPDATE_CPU_INIT:
 				ret = tdx_cpu_enable();
 				break;
+			case MODULE_UPDATE_RUN_UPDATE:
+				if (primary)
+					ret = tdx_module_run_update();
+				break;
 			default:
 				break;
 			}
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index cfe76d4ca570..9f137d15553f 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -1207,6 +1207,22 @@ int tdx_module_shutdown(void)
 	return 0;
 }
 
+int tdx_module_run_update(void)
+{
+	struct tdx_module_args args = {};
+	int ret;
+
+	ret = seamcall_prerr(TDH_SYS_UPDATE, &args);
+	if (ret) {
+		pr_err("update failed (%d)\n", ret);
+		tdx_module_status = TDX_MODULE_ERROR;
+		return ret;
+	}
+
+	tdx_module_status = TDX_MODULE_INITIALIZED;
+	return 0;
+}
+
 static bool is_pamt_page(unsigned long phys)
 {
 	struct tdmr_info_list *tdmr_list = &tdx_tdmr_list;
diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h
index 1c4da9540ae0..c62874b87d7a 100644
--- a/arch/x86/virt/vmx/tdx/tdx.h
+++ b/arch/x86/virt/vmx/tdx/tdx.h
@@ -47,6 +47,7 @@
 #define TDH_VP_WR			43
 #define TDH_SYS_CONFIG			45
 #define TDH_SYS_SHUTDOWN		52
+#define TDH_SYS_UPDATE			53
 
 /*
  * SEAMCALL leaf:
@@ -120,5 +121,6 @@ struct tdmr_info_list {
 };
 
 int tdx_module_shutdown(void);
+int tdx_module_run_update(void);
 
 #endif
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v5 16/22] x86/virt/tdx: Update tdx_sysinfo and check features post-update
  2026-03-15 13:58 [PATCH v5 00/22] Runtime TDX module update support Chao Gao
                   ` (14 preceding siblings ...)
  2026-03-15 13:58 ` [PATCH v5 15/22] x86/virt/tdx: Restore TDX module state Chao Gao
@ 2026-03-15 13:58 ` Chao Gao
  2026-03-19 13:43   ` Kiryl Shutsemau
  2026-03-15 13:58 ` [PATCH v5 17/22] x86/virt/tdx: Avoid updates during update-sensitive operations Chao Gao
                   ` (5 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
  To: linux-kernel, linux-coco, kvm
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Chao Gao, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	x86, H. Peter Anvin

tdx_sysinfo contains all metadata of the active TDX module, including
versions, supported features, and TDMR/TDCS/TDVPS information etc. These
values may change over updates. Blindly refreshing the entire tdx_sysinfo
could disrupt running software, as it may subtly rely on the previous state
unless proven otherwise.

Adopt a conservative approach, like microcode updates, by only refreshing
version information that does not affect functionality, while ignoring
all other changes. This is acceptable as new modules are required to
maintain backward compatibility.

Any updates to metadata beyond versions should be justified and reviewed on
a case-by-case basis.

Note that preallocating a tdx_sys_info buffer before updates is to avoid
having to handle -ENOMEM when updating tdx_sysinfo after a successful
update.

Signed-off-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
Reviewed-by: Kai Huang <kai.huang@intel.com>
Reviewed-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
---
v5:
 - Drop the comment above tdx_module_post_update() [Kai]

v3:
 - use 'old' instead of 'cur' as the local variable to represent the
   sysinfo of the previous module [Binbin]
 - combine if(ret) and WARN_ONCE(1, ...) to WARN_ONCE(ret, ...) [Binbin]
 - Improve the print log messages after detecting new features from updates.
   [Binbin]

v2:
 - don't add a separate function for version and feature checks. Do them
   directly in tdx_module_post_update()
 - add a comment about preallocating a tdx_sys_info buffer in
   seamldr_install_module().
---
 arch/x86/virt/vmx/tdx/seamldr.c | 18 ++++++++++++++-
 arch/x86/virt/vmx/tdx/tdx.c     | 39 +++++++++++++++++++++++++++++++++
 arch/x86/virt/vmx/tdx/tdx.h     |  3 +++
 3 files changed, 59 insertions(+), 1 deletion(-)

diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
index 806edf50a952..e6b7af410c54 100644
--- a/arch/x86/virt/vmx/tdx/seamldr.c
+++ b/arch/x86/virt/vmx/tdx/seamldr.c
@@ -290,6 +290,18 @@ DEFINE_FREE(free_seamldr_params, struct seamldr_params *,
  */
 int seamldr_install_module(const u8 *data, u32 size)
 {
+	int ret;
+
+	/*
+	 * Preallocating a tdx_sys_info buffer before an update is to avoid
+	 * having to handle -ENOMEM when updating tdx_sysinfo after a
+	 * successful update.
+	 */
+	struct tdx_sys_info *sysinfo __free(kfree) = kzalloc(sizeof(*sysinfo),
+							     GFP_KERNEL);
+	if (!sysinfo)
+		return -ENOMEM;
+
 	struct seamldr_params *params __free(free_seamldr_params) =
 						init_seamldr_params(data, size);
 	if (IS_ERR(params))
@@ -297,6 +309,10 @@ int seamldr_install_module(const u8 *data, u32 size)
 
 	update_data.failed = 0;
 	set_target_state(MODULE_UPDATE_START + 1);
-	return stop_machine(do_seamldr_install_module, params, cpu_online_mask);
+	ret = stop_machine(do_seamldr_install_module, params, cpu_online_mask);
+	if (ret)
+		return ret;
+
+	return tdx_module_post_update(sysinfo);
 }
 EXPORT_SYMBOL_FOR_MODULES(seamldr_install_module, "tdx-host");
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index 9f137d15553f..98682c4a383a 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -1223,6 +1223,45 @@ int tdx_module_run_update(void)
 	return 0;
 }
 
+int tdx_module_post_update(struct tdx_sys_info *info)
+{
+	struct tdx_sys_info_version *old, *new;
+	int ret;
+
+	/* Shouldn't fail as the update has succeeded. */
+	ret = get_tdx_sys_info(info);
+	if (WARN_ONCE(ret, "version retrieval failed after update, replace the TDX module\n"))
+		return ret;
+
+	old = &tdx_sysinfo.version;
+	new = &info->version;
+	pr_info("version %u.%u.%02u -> %u.%u.%02u\n", old->major_version,
+						      old->minor_version,
+						      old->update_version,
+						      new->major_version,
+						      new->minor_version,
+						      new->update_version);
+
+	/*
+	 * Blindly refreshing the entire tdx_sysinfo could disrupt running
+	 * software, as it may subtly rely on the previous state unless
+	 * proven otherwise.
+	 *
+	 * Only refresh version information (including handoff version)
+	 * that does not affect functionality, and ignore all other
+	 * changes.
+	 */
+	tdx_sysinfo.version	= info->version;
+	tdx_sysinfo.handoff	= info->handoff;
+
+	if (!memcmp(&tdx_sysinfo, info, sizeof(*info)))
+		return 0;
+
+	pr_info("TDX module features have changed after updates, but might not take effect.\n");
+	pr_info("Please consider updating your BIOS to install the TDX module.\n");
+	return 0;
+}
+
 static bool is_pamt_page(unsigned long phys)
 {
 	struct tdmr_info_list *tdmr_list = &tdx_tdmr_list;
diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h
index c62874b87d7a..f8686247c660 100644
--- a/arch/x86/virt/vmx/tdx/tdx.h
+++ b/arch/x86/virt/vmx/tdx/tdx.h
@@ -4,6 +4,8 @@
 
 #include <linux/bits.h>
 
+#include <asm/tdx_global_metadata.h>
+
 /*
  * This file contains both macros and data structures defined by the TDX
  * architecture and Linux defined software data structures and functions.
@@ -122,5 +124,6 @@ struct tdmr_info_list {
 
 int tdx_module_shutdown(void);
 int tdx_module_run_update(void);
+int tdx_module_post_update(struct tdx_sys_info *info);
 
 #endif
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v5 17/22] x86/virt/tdx: Avoid updates during update-sensitive operations
  2026-03-15 13:58 [PATCH v5 00/22] Runtime TDX module update support Chao Gao
                   ` (15 preceding siblings ...)
  2026-03-15 13:58 ` [PATCH v5 16/22] x86/virt/tdx: Update tdx_sysinfo and check features post-update Chao Gao
@ 2026-03-15 13:58 ` Chao Gao
  2026-03-19 14:00   ` Kiryl Shutsemau
  2026-03-15 13:58 ` [PATCH v5 18/22] coco/tdx-host: Don't expose P-SEAMLDR features on CPUs with erratum Chao Gao
                   ` (4 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
  To: linux-kernel, linux-coco, kvm
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Chao Gao, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	x86, H. Peter Anvin

A runtime TDX module update can conflict with TD lifecycle operations that
are update-sensitive.

Today, update-sensitive operations include:

- TD build: TD measurement is accumulated across multiple
  TDH.MEM.PAGE.ADD, TDH.MR.EXTEND, and TDH.MR.FINALIZE calls.

- TD migration: intermediate crypto state is saved/restored across
  interrupted/resumed TDH.EXPORT.STATE.* and TDH.IMPORT.STATE.* flows.

If an update races TD build, for example, TD measurement can become
incorrect and attestation can fail.

The TDX architecture exposes two approaches:

1) Avoid updates during update-sensitive operations.
2) Detect incompatibility after update and recover.

Post-update detection (option #2) is not a good fit: as discussed in [1],
future module behavior may expand update-sensitive operations in ways that
make post-update detection fragile for existing KVM userspace APIs.

"Do nothing" is also not preferred: while it keeps kernel code simple, it
lets the issue leak into the broader stack, where both detection and
recovery require significantly more effort.

So, use option #1. Specifically, request "avoid update-sensitive" behavior
during TDX module shutdown and map the resulting failure to -EBUSY so
userspace can distinguish an update race from other failures.

Do not disable updates when option #1 is unavailable. In that case,
effectively fall back to "do nothing", and set the expectation for
userspace to "update your module at your own risk".

Note: this implementation is based on a reference patch by Vishal [2].
Note2: moving "NO_RBP_MOD" is just to centralize bit definitions.

Signed-off-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
Link: https://lore.kernel.org/linux-coco/aQIbM5m09G0FYTzE@google.com/ # [1]
Link: https://lore.kernel.org/linux-coco/CAGtprH_oR44Vx9Z0cfxvq5-QbyLmy_+Gn3tWm3wzHPmC1nC0eg@mail.gmail.com/ # [2]
---
 arch/x86/include/asm/tdx.h   | 16 ++++++++++++++--
 arch/x86/kvm/vmx/tdx_errno.h |  2 --
 arch/x86/virt/vmx/tdx/tdx.c  | 23 +++++++++++++++++++----
 arch/x86/virt/vmx/tdx/tdx.h  |  3 ---
 4 files changed, 33 insertions(+), 11 deletions(-)

diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index b3a7301e77c6..4c4f7acd4044 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -26,11 +26,18 @@
 #define TDX_SEAMCALL_GP			(TDX_SW_ERROR | X86_TRAP_GP)
 #define TDX_SEAMCALL_UD			(TDX_SW_ERROR | X86_TRAP_UD)
 
+#define TDX_SEAMCALL_STATUS_MASK		0xFFFFFFFF00000000ULL
+
 /*
  * TDX module SEAMCALL leaf function error codes
  */
-#define TDX_SUCCESS		0ULL
-#define TDX_RND_NO_ENTROPY	0x8000020300000000ULL
+#define TDX_SUCCESS			0ULL
+#define TDX_RND_NO_ENTROPY		0x8000020300000000ULL
+#define TDX_UPDATE_COMPAT_SENSITIVE	0x8000051200000000ULL
+
+/* Bit definitions of TDX_FEATURES0 metadata field */
+#define TDX_FEATURES0_NO_RBP_MOD	BIT_ULL(18)
+#define TDX_FEATURES0_UPDATE_COMPAT	BIT_ULL(47)
 
 #ifndef __ASSEMBLER__
 
@@ -109,6 +116,11 @@ static inline bool tdx_supports_runtime_update(const struct tdx_sys_info *sysinf
 	return false;
 }
 
+static inline bool tdx_supports_update_compatibility(const struct tdx_sys_info *sysinfo)
+{
+	return sysinfo->features.tdx_features0 & TDX_FEATURES0_UPDATE_COMPAT;
+}
+
 int tdx_guest_keyid_alloc(void);
 u32 tdx_get_nr_guest_keyids(void);
 void tdx_guest_keyid_free(unsigned int keyid);
diff --git a/arch/x86/kvm/vmx/tdx_errno.h b/arch/x86/kvm/vmx/tdx_errno.h
index 6ff4672c4181..215c00d76a94 100644
--- a/arch/x86/kvm/vmx/tdx_errno.h
+++ b/arch/x86/kvm/vmx/tdx_errno.h
@@ -4,8 +4,6 @@
 #ifndef __KVM_X86_TDX_ERRNO_H
 #define __KVM_X86_TDX_ERRNO_H
 
-#define TDX_SEAMCALL_STATUS_MASK		0xFFFFFFFF00000000ULL
-
 /*
  * TDX SEAMCALL Status Codes (returned in RAX)
  */
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index 98682c4a383a..2025d00b0567 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -1176,10 +1176,13 @@ int tdx_enable(void)
 }
 EXPORT_SYMBOL_FOR_KVM(tdx_enable);
 
+#define TDX_SYS_SHUTDOWN_AVOID_COMPAT_SENSITIVE BIT(16)
+
 int tdx_module_shutdown(void)
 {
 	struct tdx_module_args args = {};
-	int ret, cpu;
+	u64 ret;
+	int cpu;
 
 	/*
 	 * Shut down the TDX module and prepare handoff data for the next
@@ -1189,9 +1192,21 @@ int tdx_module_shutdown(void)
 	 * modules as new modules likely have higher handoff version.
 	 */
 	args.rcx = tdx_sysinfo.handoff.module_hv;
-	ret = seamcall_prerr(TDH_SYS_SHUTDOWN, &args);
-	if (ret)
-		return ret;
+
+	if (tdx_supports_update_compatibility(&tdx_sysinfo))
+		args.rcx |= TDX_SYS_SHUTDOWN_AVOID_COMPAT_SENSITIVE;
+
+	ret = seamcall(TDH_SYS_SHUTDOWN, &args);
+
+	/*
+	 * Return -EBUSY to signal that there is one or more ongoing flows
+	 * which may not be compatible with an updated TDX module, so that
+	 * userspace can retry on this error.
+	 */
+	if ((ret & TDX_SEAMCALL_STATUS_MASK) == TDX_UPDATE_COMPAT_SENSITIVE)
+		return -EBUSY;
+	else if (ret)
+		return -EIO;
 
 	tdx_module_status = TDX_MODULE_UNINITIALIZED;
 	sysinit_done = false;
diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h
index f8686247c660..2435f88c6994 100644
--- a/arch/x86/virt/vmx/tdx/tdx.h
+++ b/arch/x86/virt/vmx/tdx/tdx.h
@@ -88,9 +88,6 @@ struct tdmr_info {
 	DECLARE_FLEX_ARRAY(struct tdmr_reserved_area, reserved_areas);
 } __packed __aligned(TDMR_INFO_ALIGNMENT);
 
-/* Bit definitions of TDX_FEATURES0 metadata field */
-#define TDX_FEATURES0_NO_RBP_MOD	BIT(18)
-
 /*
  * Do not put any hardware-defined TDX structure representations below
  * this comment!
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v5 18/22] coco/tdx-host: Don't expose P-SEAMLDR features on CPUs with erratum
  2026-03-15 13:58 [PATCH v5 00/22] Runtime TDX module update support Chao Gao
                   ` (16 preceding siblings ...)
  2026-03-15 13:58 ` [PATCH v5 17/22] x86/virt/tdx: Avoid updates during update-sensitive operations Chao Gao
@ 2026-03-15 13:58 ` Chao Gao
  2026-03-19 14:02   ` Kiryl Shutsemau
  2026-03-15 13:58 ` [PATCH v5 19/22] x86/virt/tdx: Enable TDX module runtime updates Chao Gao
                   ` (3 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
  To: linux-kernel, kvm, linux-coco
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Chao Gao, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	x86, H. Peter Anvin

Some TDX-capable CPUs have an erratum, as documented in Intel® Trust
Domain CPU Architectural Extensions (May 2021 edition) Chapter 2.3:

  SEAMRET from the P-SEAMLDR clears the current VMCS structure pointed
  to by the current-VMCS pointer. A VMM that invokes the P-SEAMLDR using
  SEAMCALL must reload the current-VMCS, if required, using the VMPTRLD
  instruction.

Clearing the current VMCS behind KVM's back will break KVM.

This erratum is not present when IA32_VMX_BASIC[60] is set. Add a CPU
bug bit for this erratum and refuse to expose P-SEAMLDR features (e.g.,
TDX module updates) on affected CPUs.

== Alternatives ==
Two workarounds were considered but both were rejected:

1. Save/restore the current VMCS around P-SEAMLDR calls. This produces ugly
   assembly code [1] and doesn't play well with #MCE or #NMI if they
   need to use the current VMCS.

2. Move KVM's VMCS tracking logic to the TDX core code, which would break
   the boundary between KVM and the TDX core code [2].

Signed-off-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Kai Huang <kai.huang@intel.com>
Link: https://lore.kernel.org/kvm/fedb3192-e68c-423c-93b2-a4dc2f964148@intel.com/ # [1]
Link: https://lore.kernel.org/kvm/aYIXFmT-676oN6j0@google.com/ # [2]
---
 arch/x86/include/asm/cpufeatures.h    |  1 +
 arch/x86/include/asm/vmx.h            |  1 +
 arch/x86/virt/vmx/tdx/tdx.c           | 11 +++++++++++
 drivers/virt/coco/tdx-host/tdx-host.c |  8 ++++++++
 4 files changed, 21 insertions(+)

diff --git a/arch/x86/include/asm/cpufeatures.h b/arch/x86/include/asm/cpufeatures.h
index dbe104df339b..377d009b7e2e 100644
--- a/arch/x86/include/asm/cpufeatures.h
+++ b/arch/x86/include/asm/cpufeatures.h
@@ -572,4 +572,5 @@
 #define X86_BUG_ITS_NATIVE_ONLY		X86_BUG( 1*32+ 8) /* "its_native_only" CPU is affected by ITS, VMX is not affected */
 #define X86_BUG_TSA			X86_BUG( 1*32+ 9) /* "tsa" CPU is affected by Transient Scheduler Attacks */
 #define X86_BUG_VMSCAPE			X86_BUG( 1*32+10) /* "vmscape" CPU is affected by VMSCAPE attacks from guests */
+#define X86_BUG_SEAMRET_INVD_VMCS	X86_BUG( 1*32+11) /* "seamret_invd_vmcs" SEAMRET from P-SEAMLDR clears the current VMCS */
 #endif /* _ASM_X86_CPUFEATURES_H */
diff --git a/arch/x86/include/asm/vmx.h b/arch/x86/include/asm/vmx.h
index b92ff87e3560..a5a5b373ec42 100644
--- a/arch/x86/include/asm/vmx.h
+++ b/arch/x86/include/asm/vmx.h
@@ -136,6 +136,7 @@
 #define VMX_BASIC_INOUT				BIT_ULL(54)
 #define VMX_BASIC_TRUE_CTLS			BIT_ULL(55)
 #define VMX_BASIC_NO_HW_ERROR_CODE_CC		BIT_ULL(56)
+#define VMX_BASIC_NO_SEAMRET_INVD_VMCS		BIT_ULL(60)
 
 static inline u32 vmx_basic_vmcs_revision_id(u64 vmx_basic)
 {
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index 2025d00b0567..b76b8c393425 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -39,6 +39,7 @@
 #include <asm/cpu_device_id.h>
 #include <asm/processor.h>
 #include <asm/mce.h>
+#include <asm/vmx.h>
 
 #include "seamcall_internal.h"
 #include "tdx.h"
@@ -1454,6 +1455,8 @@ static struct notifier_block tdx_memory_nb = {
 
 static void __init check_tdx_erratum(void)
 {
+	u64 basic_msr;
+
 	/*
 	 * These CPUs have an erratum.  A partial write from non-TD
 	 * software (e.g. via MOVNTI variants or UC/WC mapping) to TDX
@@ -1465,6 +1468,14 @@ static void __init check_tdx_erratum(void)
 	case INTEL_EMERALDRAPIDS_X:
 		setup_force_cpu_bug(X86_BUG_TDX_PW_MCE);
 	}
+
+	/*
+	 * Some TDX-capable CPUs have an erratum where the current VMCS is
+	 * cleared after calling into P-SEAMLDR.
+	 */
+	rdmsrq(MSR_IA32_VMX_BASIC, basic_msr);
+	if (!(basic_msr & VMX_BASIC_NO_SEAMRET_INVD_VMCS))
+		setup_force_cpu_bug(X86_BUG_SEAMRET_INVD_VMCS);
 }
 
 void __init tdx_init(void)
diff --git a/drivers/virt/coco/tdx-host/tdx-host.c b/drivers/virt/coco/tdx-host/tdx-host.c
index 1b93d20406c1..8cf3cc99024a 100644
--- a/drivers/virt/coco/tdx-host/tdx-host.c
+++ b/drivers/virt/coco/tdx-host/tdx-host.c
@@ -174,6 +174,14 @@ static int seamldr_init(struct device *dev)
 	if (!tdx_supports_runtime_update(tdx_sysinfo))
 		return 0;
 
+	/*
+	 * Calling P-SEAMLDR on CPUs with the seamret_invd_vmcs bug clears
+	 * the current VMCS, which breaks KVM. Verify the erratum is not
+	 * present before exposing P-SEAMLDR features.
+	 */
+	if (boot_cpu_has_bug(X86_BUG_SEAMRET_INVD_VMCS))
+		return 0;
+
 	tdx_fwl = firmware_upload_register(THIS_MODULE, dev, "tdx_module",
 					   &tdx_fw_ops, NULL);
 	if (IS_ERR(tdx_fwl))
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v5 19/22] x86/virt/tdx: Enable TDX module runtime updates
  2026-03-15 13:58 [PATCH v5 00/22] Runtime TDX module update support Chao Gao
                   ` (17 preceding siblings ...)
  2026-03-15 13:58 ` [PATCH v5 18/22] coco/tdx-host: Don't expose P-SEAMLDR features on CPUs with erratum Chao Gao
@ 2026-03-15 13:58 ` Chao Gao
  2026-03-19 14:03   ` Kiryl Shutsemau
  2026-03-15 13:58 ` [PATCH v5 20/22] coco/tdx-host: Document TDX module update compatibility criteria Chao Gao
                   ` (2 subsequent siblings)
  21 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
  To: linux-kernel, linux-coco, kvm
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Chao Gao, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	x86, H. Peter Anvin

All pieces of TDX module runtime updates are in place. Enable it if it
is supported.

Signed-off-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
---
 arch/x86/include/asm/tdx.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index 4c4f7acd4044..386097b2e01b 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -36,6 +36,7 @@
 #define TDX_UPDATE_COMPAT_SENSITIVE	0x8000051200000000ULL
 
 /* Bit definitions of TDX_FEATURES0 metadata field */
+#define TDX_FEATURES0_TD_PRESERVING	BIT_ULL(1)
 #define TDX_FEATURES0_NO_RBP_MOD	BIT_ULL(18)
 #define TDX_FEATURES0_UPDATE_COMPAT	BIT_ULL(47)
 
@@ -112,8 +113,7 @@ const struct tdx_sys_info *tdx_get_sysinfo(void);
 
 static inline bool tdx_supports_runtime_update(const struct tdx_sys_info *sysinfo)
 {
-	 /* To be enabled when kernel is ready. */
-	return false;
+	return sysinfo->features.tdx_features0 & TDX_FEATURES0_TD_PRESERVING;
 }
 
 static inline bool tdx_supports_update_compatibility(const struct tdx_sys_info *sysinfo)
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v5 20/22] coco/tdx-host: Document TDX module update compatibility criteria
  2026-03-15 13:58 [PATCH v5 00/22] Runtime TDX module update support Chao Gao
                   ` (18 preceding siblings ...)
  2026-03-15 13:58 ` [PATCH v5 19/22] x86/virt/tdx: Enable TDX module runtime updates Chao Gao
@ 2026-03-15 13:58 ` Chao Gao
  2026-03-19 14:04   ` Kiryl Shutsemau
  2026-03-15 13:58 ` [PATCH v5 21/22] x86/virt/tdx: Document TDX module update Chao Gao
  2026-03-15 13:58 ` [PATCH v5 22/22] x86/virt/seamldr: Log TDX module update failures Chao Gao
  21 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
  To: x86, linux-coco, kvm, linux-kernel
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Chao Gao

The TDX module update protocol facilitates compatible runtime updates.

Document the compatibility criteria and indicators of various update
failures, including violations of the compatibility criteria.

Note that runtime TDX module updates are an "update at your own risk"
operation; userspace must enforce all of the above compatibility
criteria.

Signed-off-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
---
v5:
 - drop "dead documentation" about tdxctl
 - add a note in the changelog clarifying that users update at their own risk
 - revise the error code for update limit exhaustion—it changed after
   dropping the related patch.
v4:
 - Drop "compat_capable" kernel ABI [Dan]
 - Document Linux compatibility expectations and results of violating
   them [Dan]
---
 .../ABI/testing/sysfs-devices-faux-tdx-host   | 46 +++++++++++++++++++
 1 file changed, 46 insertions(+)

diff --git a/Documentation/ABI/testing/sysfs-devices-faux-tdx-host b/Documentation/ABI/testing/sysfs-devices-faux-tdx-host
index 44b8356aed6b..97840db794c0 100644
--- a/Documentation/ABI/testing/sysfs-devices-faux-tdx-host
+++ b/Documentation/ABI/testing/sysfs-devices-faux-tdx-host
@@ -27,3 +27,49 @@ Description:	(RO) Report the number of remaining updates. TDX maintains a
 		Interface Specification, Revision 343755-003, Chapter 3.3
 		"SEAMLDR_INFO" and Chapter 4.2 "SEAMLDR.INSTALL" for more
 		information.
+
+What:		/sys/devices/faux/tdx_host/firmware/tdx_module
+Contact:	linux-coco@lists.linux.dev
+Description:	(Directory) The tdx_module directory implements the fw_upload
+		sysfs ABI, see Documentation/ABI/testing/sysfs-class-firmware
+		for the general description of the attributes @data, @cancel,
+		@error, @loading, @remaining_size, and @status. This ABI
+		facilitates "Compatible TDX Module Updates". A compatible update
+		is one that meets the following criteria:
+
+		   Does not interrupt or interfere with any current TDX
+		   operation or TD VM.
+
+		   Does not invalidate any previously consumed Module metadata
+		   values outside of the TEE_TCB_SVN_2 field (updated Security
+		   Version Number) in TD Quotes.
+
+		   Does not require validation of new Module metadata fields. By
+		   implication, new Module features and capabilities are only
+		   available by installing the Module at reboot (BIOS or EFI
+		   helper loaded).
+
+		See tdx_host/firmware/tdx_module/error for information on
+		compatibility check failures.
+
+What:		/sys/devices/faux/tdx_host/firmware/tdx_module/error
+Contact:	linux-coco@lists.linux.dev
+Description:	(RO) See Documentation/ABI/testing/sysfs-class-firmware for
+		baseline expectations for this file. The <ERROR> part in the
+		<STATUS>:<ERROR> format can be:
+
+		   "device-busy": Compatibility checks failed.
+
+		   "read-write-error": Memory allocation failed.
+
+		   "hw-error": Cannot communicate with P-SEAMLDR or TDX module.
+
+		   "firmware-invalid": The provided TDX module update is invalid,
+		                       or the number of updates reached the limit,
+				       or other unexpected errors occurred.
+
+		"hw-error" or "firmware-invalid" may be fatal, causing all TDs
+		and the TDX module to be lost and preventing further TDX
+		operations. This occurs when reading
+		/sys/devices/faux/tdx_host/version returns -ENXIO. For other
+		errors, TDs and the (previous) TDX module stay running.
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v5 21/22] x86/virt/tdx: Document TDX module update
  2026-03-15 13:58 [PATCH v5 00/22] Runtime TDX module update support Chao Gao
                   ` (19 preceding siblings ...)
  2026-03-15 13:58 ` [PATCH v5 20/22] coco/tdx-host: Document TDX module update compatibility criteria Chao Gao
@ 2026-03-15 13:58 ` Chao Gao
  2026-03-19 14:05   ` Kiryl Shutsemau
  2026-03-15 13:58 ` [PATCH v5 22/22] x86/virt/seamldr: Log TDX module update failures Chao Gao
  21 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
  To: linux-kernel, linux-doc, linux-coco, kvm
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Chao Gao, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	x86, H. Peter Anvin, Jonathan Corbet, Shuah Khan

Document TDX module update as a subsection of "TDX Host Kernel Support" to
provide background information and cover key points that developers and
users may need to know, for example:

 - update is done in stop_machine() context
 - update instructions and results
 - update policy and tooling

Signed-off-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Kai Huang <kai.huang@intel.com>
---
v5:
 - use "update" when refer to the update feature/concept [Kai]
---
 Documentation/arch/x86/tdx.rst | 36 ++++++++++++++++++++++++++++++++++
 1 file changed, 36 insertions(+)

diff --git a/Documentation/arch/x86/tdx.rst b/Documentation/arch/x86/tdx.rst
index 61670e7df2f7..d4e257542d4c 100644
--- a/Documentation/arch/x86/tdx.rst
+++ b/Documentation/arch/x86/tdx.rst
@@ -99,6 +99,42 @@ initialize::
 
   [..] virt/tdx: module initialization failed ...
 
+TDX module Runtime Update
+-------------------------
+
+The TDX architecture includes a persistent SEAM loader (P-SEAMLDR) that
+runs in SEAM mode separately from the TDX module. The kernel can
+communicate with P-SEAMLDR to perform runtime updates of the TDX module.
+
+During update, the TDX module becomes unresponsive to other TDX operations.
+To prevent components using TDX (such as KVM) from experiencing unexpected
+errors during updates, updates are performed in stop_machine() context.
+
+TDX module update has complex compatibility requirements; the new module
+must be compatible with the current CPU, P-SEAMLDR, and running TDX module.
+Rather than implementing complex module selection and policy enforcement
+logic in the kernel, userspace is responsible for auditing and selecting
+appropriate updates.
+
+Updates use the standard firmware upload interface. See
+Documentation/driver-api/firmware/fw_upload.rst for detailed instructions
+
+Successful updates are logged in dmesg:
+  [..] virt/tdx: version 1.5.20 -> 1.5.24
+
+If updates failed, running TDs may be killed and further TDX operations may
+be not possible until reboot. For detailed error information, see
+Documentation/ABI/testing/sysfs-devices-faux-tdx-host.
+
+Given the risk of losing existing TDs, userspace should verify that the
+update is compatible with the current system and properly validated before
+applying it.
+
+A reference userspace tool that implements necessary checks is available
+at:
+
+  https://github.com/intel/tdx-module-binaries
+
 TDX Interaction to Other Kernel Components
 ------------------------------------------
 
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* [PATCH v5 22/22] x86/virt/seamldr: Log TDX module update failures
  2026-03-15 13:58 [PATCH v5 00/22] Runtime TDX module update support Chao Gao
                   ` (20 preceding siblings ...)
  2026-03-15 13:58 ` [PATCH v5 21/22] x86/virt/tdx: Document TDX module update Chao Gao
@ 2026-03-15 13:58 ` Chao Gao
  2026-03-19 14:06   ` Kiryl Shutsemau
  21 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-15 13:58 UTC (permalink / raw)
  To: linux-kernel, linux-coco, kvm
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Chao Gao, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
	x86, H. Peter Anvin

Currently, there is no way to restore a TDX module from shutdown state to
running state. This means if errors occur after a successful module
shutdown, they are unrecoverable since the old module is gone but the new
module isn't installed. All subsequent SEAMCALLs to the TDX module will
fail, so TDs will be killed due to SEAMCALL failures.

Log a message to clarify that SEAMCALL errors are expected in this
scenario. This ensures that after update failures, the first message in
dmesg explains the situation rather than showing confusing call traces from
various code paths.

Signed-off-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
Acked-by: Kai Huang <kai.huang@intel.com>
---
v4:
 - Use pr_warn_once() instead of reinventing it [Yilun]
v3:
 - Rephrase the changelog to eliminate the confusing uses of 'i.e.' and 'e.g.'
   [Dave/Yilun]
---
 arch/x86/virt/vmx/tdx/seamldr.c | 7 +++++++
 1 file changed, 7 insertions(+)

diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
index e6b7af410c54..4e1ad06506cc 100644
--- a/arch/x86/virt/vmx/tdx/seamldr.c
+++ b/arch/x86/virt/vmx/tdx/seamldr.c
@@ -222,6 +222,11 @@ static void ack_state(void)
 		set_target_state(update_data.state + 1);
 }
 
+static void print_update_failure_message(void)
+{
+	pr_err_once("update failed, SEAMCALLs will report failure until TDs killed\n");
+}
+
 /*
  * See multi_cpu_stop() from where this multi-cpu state-machine was
  * adopted, and the rationale for touch_nmi_watchdog().
@@ -266,6 +271,8 @@ static int do_seamldr_install_module(void *seamldr_params)
 			if (ret) {
 				scoped_guard(raw_spinlock, &update_data.lock)
 					update_data.failed++;
+				if (curstate > MODULE_UPDATE_SHUTDOWN)
+					print_update_failure_message();
 			} else {
 				ack_state();
 			}
-- 
2.47.3


^ permalink raw reply related	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 12/22] x86/virt/tdx: Reset software states during TDX module shutdown
  2026-03-15 13:58 ` [PATCH v5 12/22] x86/virt/tdx: Reset software states during TDX module shutdown Chao Gao
@ 2026-03-16  9:06   ` Huang, Kai
  2026-03-17  8:27     ` Chao Gao
  0 siblings, 1 reply; 80+ messages in thread
From: Huang, Kai @ 2026-03-16  9:06 UTC (permalink / raw)
  To: kvm@vger.kernel.org, linux-coco@lists.linux.dev,
	linux-kernel@vger.kernel.org, Gao, Chao
  Cc: x86@kernel.org, dave.hansen@linux.intel.com, kas@kernel.org,
	seanjc@google.com, Chatre, Reinette, Weiny, Ira,
	binbin.wu@linux.intel.com, Verma, Vishal L, nik.borisov@suse.com,
	mingo@redhat.com, pbonzini@redhat.com,
	tony.lindgren@linux.intel.com, sagis@google.com,
	Annapurve, Vishal, hpa@zytor.com, Edgecombe, Rick P,
	paulmck@kernel.org, tglx@kernel.org, yilun.xu@linux.intel.com,
	Williams, Dan J, bp@alien8.de


> @@ -1179,6 +1179,7 @@ EXPORT_SYMBOL_FOR_KVM(tdx_enable);
>  int tdx_module_shutdown(void)
>  {
>  	struct tdx_module_args args = {};
> +	int ret, cpu;
>  
>  	/*
>  	 * Shut down the TDX module and prepare handoff data for the next
> @@ -1188,7 +1189,22 @@ int tdx_module_shutdown(void)
>  	 * modules as new modules likely have higher handoff version.
>  	 */
>  	args.rcx = tdx_sysinfo.handoff.module_hv;
> -	return seamcall_prerr(TDH_SYS_SHUTDOWN, &args);
> +	ret = seamcall_prerr(TDH_SYS_SHUTDOWN, &args);
> +	if (ret)
> +		return ret;
> +
> +	tdx_module_status = TDX_MODULE_UNINITIALIZED;
> +	sysinit_done = false;
> +	sysinit_ret = 0;
> +
> +	/*
> +	 * By reaching here CPUHP is disabled and all present CPUs
> +	 * are online. It's safe to just loop all online CPUs and
> +	 * reset the per-cpu flag.
> +	 */
> +	for_each_online_cpu(cpu)
> +		per_cpu(tdx_lp_initialized, cpu) = false;

Since you have removed the requirement that P-SEAMLDR.INSTALL must be done
on all CPUs, and removed the relevant patch, the "all present CPUs are
online" part isn't correct anymore.

And using for_each_online_cpu() isn't enough since this doesn't reset the
tdx_lp_initialized for offline CPUs.

One way is to just use for_each_possible_cpu() here so tdx_lp_initialized
for all CPUs are reset.  Since the "CPUHP is disabled" part is still correct
AFAICT (since stop_machine() disables CPUHP internally during the
operation), resetting tdx_lp_initialized for offline CPUs won't race with
CPUHP.

And assuming this series will be applied after Sean's VMXON series, we will
have a TDX-specific CPUHP callback tdx_online_cpu() in TDX x86 core to do
tdx_cpu_enable(), which will then enable TDX again on the new-online CPU.

Btw, w/o Sean's VMXON series, currently only KVM provides the TDX-specific
CPUHP callback.  So it seems if module update is done when KVM is not
loaded, there will be no TDX-specific CPUHP callback to re-enable TDX for
the new-online CPU.  This means any SEAMCALL on that CPU will fail before
KVM module is loaded again (which will then re-register the TDX-specific
CPUHP and run tdx_cpu_enable() for all online CPUs). 

But I don't think we should consider this case.



^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 01/22] x86/virt/tdx: Move low level SEAMCALL helpers out of <asm/tdx.h>
  2026-03-15 13:58 ` [PATCH v5 01/22] x86/virt/tdx: Move low level SEAMCALL helpers out of <asm/tdx.h> Chao Gao
@ 2026-03-16 12:41   ` Kiryl Shutsemau
  0 siblings, 0 replies; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-16 12:41 UTC (permalink / raw)
  To: Chao Gao
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Zhenzhong Duan,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
	H. Peter Anvin

On Sun, Mar 15, 2026 at 06:58:21AM -0700, Chao Gao wrote:
> From: Kai Huang <kai.huang@intel.com>
> 
> TDX host core code implements three seamcall*() helpers to make SEAMCALL
> to the TDX module.  Currently, they are implemented in <asm/tdx.h> and
> are exposed to other kernel code which includes <asm/tdx.h>.
> 
> However, other than the TDX host core, seamcall*() are not expected to
> be used by other kernel code directly.  For instance, for all SEAMCALLs
> that are used by KVM, the TDX host core exports a wrapper function for
> each of them.
> 
> Move seamcall*() and related code out of <asm/tdx.h> and make them only
> visible to TDX host core.
> 
> Since TDX host core tdx.c is already very heavy, don't put low level
> seamcall*() code there but to a new dedicated "seamcall_internal.h".  Also,
> currently tdx.c has seamcall_prerr*() helpers which additionally print
> error message when calling seamcall*() fails.  Move them to
> "seamcall_internal.h" as well. In such way all low level SEAMCALL helpers
> are in a dedicated place, which is much more readable.
> 
> Copy the copyright notice from the original files and consolidate the
> date ranges to:
> 
> 	Copyright (C) 2021-2023 Intel Corporation
> 
> Signed-off-by: Kai Huang <kai.huang@intel.com>
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Reviewed-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
> Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
> Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
> Acked-by: Dave Hansen <dave.hansen@linux.intel.com>

Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 02/22] coco/tdx-host: Introduce a "tdx_host" device
  2026-03-15 13:58 ` [PATCH v5 02/22] coco/tdx-host: Introduce a "tdx_host" device Chao Gao
@ 2026-03-16 12:48   ` Kiryl Shutsemau
  0 siblings, 0 replies; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-16 12:48 UTC (permalink / raw)
  To: Chao Gao
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Jonathan Cameron,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
	H. Peter Anvin

On Sun, Mar 15, 2026 at 06:58:22AM -0700, Chao Gao wrote:
> TDX depends on a platform firmware module that is invoked via instructions
> similar to vmenter (i.e. enter into a new privileged "root-mode" context to
> manage private memory and private device mechanisms). It is a software
> construct that depends on the CPU vmxon state to enable invocation of
> TDX module ABIs. Unlike other Trusted Execution Environment (TEE) platform
> implementations that employ a firmware module running on a PCI device with
> an MMIO mailbox for communication, TDX has no hardware device to point to
> as the TEE Secure Manager (TSM).
> 
> Create a virtual device not only to align with other implementations but
> also to make it easier to
> 
>  - expose metadata (e.g., TDX module version, seamldr version etc) to
>    the userspace as device attributes
> 
>  - implement firmware uploader APIs which are tied to a device. This is
>    needed to support TDX module runtime updates
> 
>  - enable TDX Connect which will share a common infrastructure with other
>    platform implementations. In the TDX Connect context, every
>    architecture has a TSM, represented by a PCIe or virtual device. The
>    new "tdx_host" device will serve the TSM role.
> 
> A faux device is used for TDX because the TDX module is singular within
> the system and lacks associated platform resources. Using a faux device
> eliminates the need to create a stub bus.
> 
> The call to tdx_get_sysinfo() ensures that the TDX module is ready to
> provide services.
> 
> Note that AMD has a PCI device for the PSP for SEV and ARM CCA will
> likely have a faux device [1].
> 
> Co-developed-by: Xu Yilun <yilun.xu@linux.intel.com>
> Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
> Signed-off-by: Dan Williams <dan.j.williams@intel.com>
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
> Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
> Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
> Reviewed-by: Kai Huang <kai.huang@intel.com>
> Link: https://lore.kernel.org/all/2025073035-bulginess-rematch-b92e@gregkh/ # [1]

Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 03/22] coco/tdx-host: Expose TDX module version
  2026-03-15 13:58 ` [PATCH v5 03/22] coco/tdx-host: Expose TDX module version Chao Gao
@ 2026-03-16 12:54   ` Kiryl Shutsemau
  2026-03-18 21:37   ` Huang, Kai
  1 sibling, 0 replies; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-16 12:54 UTC (permalink / raw)
  To: Chao Gao
  Cc: x86, linux-coco, kvm, linux-kernel, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu

On Sun, Mar 15, 2026 at 06:58:23AM -0700, Chao Gao wrote:
> For TDX module updates, userspace needs to select compatible update
> versions based on the current module version. This design delegates
> module selection complexity to userspace because TDX module update
> policies are complex and version series are platform-specific.
> 
> For example, the 1.5.x series is for certain platform generations, while
> the 2.0.x series is intended for others. And TDX module 1.5.x may be
> updated to 1.5.y but not to 1.5.y+1.
> 
> Expose the TDX module version to userspace via sysfs to aid module
> selection. Since the TDX faux device will drive module updates, expose
> the version as its attribute.
> 
> One bonus of exposing TDX module version via sysfs is: TDX module
> version information remains available even after dmesg logs are cleared.
> 
> == Background ==
> 
> The "faux device + device attribute" approach compares to other update
> mechanisms as follows:
> 
> 1. AMD SEV leverages an existing PCI device for the PSP to expose
>    metadata. TDX uses a faux device as it doesn't have PCI device
>    in its architecture.
> 
> 2. Microcode uses per-CPU virtual devices to report microcode revisions
>    because CPUs can have different revisions. But, there is only a
>    single TDX module, so exposing the TDX module version through a global
>    TDX faux device is appropriate
> 
> 3. ARM's CCA implementation isn't in-tree yet, but will likely follow a
>    similar faux device approach, though it's unclear whether they need
>    to expose firmware version information
> 
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
> Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
> Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
> Link: https://lore.kernel.org/all/2025073035-bulginess-rematch-b92e@gregkh/ # [1]

Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 04/22] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs
  2026-03-15 13:58 ` [PATCH v5 04/22] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs Chao Gao
@ 2026-03-16 13:05   ` Kiryl Shutsemau
  2026-03-17  0:43     ` Chao Gao
  2026-03-18  7:13   ` Xiaoyao Li
  2026-03-18 21:38   ` Huang, Kai
  2 siblings, 1 reply; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-16 13:05 UTC (permalink / raw)
  To: Chao Gao
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Farrah Chen,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
	H. Peter Anvin

On Sun, Mar 15, 2026 at 06:58:24AM -0700, Chao Gao wrote:
> The TDX architecture uses the "SEAMCALL" instruction to communicate with
> SEAM mode software. Right now, the only SEAM mode software that the kernel
> communicates with is the TDX module. But, there is actually another
> component that runs in SEAM mode but it is separate from the TDX module:
> the persistent SEAM loader or "P-SEAMLDR". Right now, the only component
> that communicates with it is the BIOS which loads the TDX module itself at
> boot. But, to support updating the TDX module, the kernel now needs to be
> able to talk to it.
> 
> P-SEAMLDR SEAMCALLs differ from TDX module SEAMCALLs in areas such as
> concurrency requirements. Add a P-SEAMLDR wrapper to handle these
> differences and prepare for implementing concrete functions.
> 
> Note that unlike P-SEAMLDR, there is also a non-persistent SEAM loader
> ("NP-SEAMLDR"). This is an authenticated code module (ACM) that is not
> callable at runtime. Only BIOS launches it to load P-SEAMLDR at boot;
> the kernel does not need to interact with it for runtime update.
> 
> For details of P-SEAMLDR SEAMCALLs, see Intel® Trust Domain CPU
> Architectural Extensions, Revision 343754-002, Chapter 2.3 "INSTRUCTION
> SET REFERENCE".
> 
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
> Tested-by: Farrah Chen <farrah.chen@intel.com>
> Link: https://cdrdv2.intel.com/v1/dl/getContent/733582 # [1]
> ---
> v5:
>  - Don't save/restore irq flags as P-SEAMLDR calls are made only in process
>    context
>  - clarify why raw_spinlock is used [Dave]
> v4:
>  - Give more background about P-SEAMLDR in changelog [Dave]
>  - Don't handle P-SEAMLDR's "no_entropy" error [Dave]
>  - Assume current VMCS is preserved across P-SEAMLDR calls [Dave]
>  - I'm not adding Reviewed-by tags as the code has changed significantly.
> v2:
>  - don't create a new, inferior framework to save/restore VMCS
>  - use human-friendly language, just "current VMCS" rather than
>    SDM term "current-VMCS pointer"
>  - don't mix guard() with goto
> ---
>  arch/x86/virt/vmx/tdx/Makefile  |  2 +-
>  arch/x86/virt/vmx/tdx/seamldr.c | 24 ++++++++++++++++++++++++
>  2 files changed, 25 insertions(+), 1 deletion(-)
>  create mode 100644 arch/x86/virt/vmx/tdx/seamldr.c
> 
> diff --git a/arch/x86/virt/vmx/tdx/Makefile b/arch/x86/virt/vmx/tdx/Makefile
> index 90da47eb85ee..d1dbc5cc5697 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 += seamcall.o tdx.o
> +obj-y += seamcall.o seamldr.o tdx.o
> diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
> new file mode 100644
> index 000000000000..7ed9be89017c
> --- /dev/null
> +++ b/arch/x86/virt/vmx/tdx/seamldr.c
> @@ -0,0 +1,24 @@
> +// SPDX-License-Identifier: GPL-2.0
> +/*
> + * P-SEAMLDR support for TDX module management features like runtime updates
> + *
> + * Copyright (C) 2025 Intel Corporation
> + */
> +#define pr_fmt(fmt)	"seamldr: " fmt
> +
> +#include <linux/spinlock.h>
> +
> +#include "seamcall_internal.h"
> +
> +/*
> + * Serialize P-SEAMLDR calls since the hardware only allows a single CPU to
> + * interact with P-SEAMLDR simultaneously. Use raw version as the calls can
> + * be made with interrupts disabled.

Hm. I am not sure how it explains use of raw_spinlock. What's wrong with
using plain spinlock with interrupts disabled?

> + */
> +static DEFINE_RAW_SPINLOCK(seamldr_lock);
> +
> +static __maybe_unused int seamldr_call(u64 fn, struct tdx_module_args *args)
> +{
> +	guard(raw_spinlock)(&seamldr_lock);
> +	return seamcall_prerr(fn, args);
> +}
> -- 
> 2.47.3
> 

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 05/22] x86/virt/seamldr: Retrieve P-SEAMLDR information
  2026-03-15 13:58 ` [PATCH v5 05/22] x86/virt/seamldr: Retrieve P-SEAMLDR information Chao Gao
@ 2026-03-16 13:12   ` Kiryl Shutsemau
  2026-03-17  1:05     ` Chao Gao
  2026-03-18  7:53   ` Xiaoyao Li
  2026-03-18 21:40   ` Huang, Kai
  2 siblings, 1 reply; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-16 13:12 UTC (permalink / raw)
  To: Chao Gao
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Farrah Chen,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
	H. Peter Anvin

On Sun, Mar 15, 2026 at 06:58:25AM -0700, Chao Gao wrote:
> P-SEAMLDR returns its information such as version number, in response to
> the SEAMLDR.INFO SEAMCALL.
> 
> This information is useful for userspace. For example, the admin can decide
> which TDX module versions are compatible with the P-SEAMLDR according to
> the P-SEAMLDR version.
> 
> Retrieve P-SEAMLDR information in preparation for exposing P-SEAMLDR
> version and other necessary information to userspace. Export the new kAPI
> for use by tdx-host.ko.
> 
> Note that there are two distinct P-SEAMLDR APIs with similar names:
> 
>   SEAMLDR.INFO: Returns a SEAMLDR_INFO structure containing SEAMLDR
>                 information such as version and remaining updates.
> 
>   SEAMLDR.SEAMINFO: Returns a SEAMLDR_SEAMINFO structure containing SEAM
>                     and system information such as Convertible Memory
> 		    Regions (CMRs) and number of CPUs and sockets.
> 
> The former is used here.
> 
> For details, see "Intel® Trust Domain Extensions - SEAM Loader (SEAMLDR)
> Interface Specification" revision 343755-003.
> 
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Tested-by: Farrah Chen <farrah.chen@intel.com>
> ---
> Kai also suggested merging this patch with the first use of the new
> kAPI, so we don't need to add a comment for slow_virt_to_phys() (as the
> reason can be seen from the call site). I am fine with it, but the
> changelog may be a bit lengthy.
> 
> v5:
>  - add a comment for slow_virt_to_phys() [Kai]
> v4:
>  - put seamldr_info on stack [Dave]
>  - improve changelogs to explain SEAMLDR.INFO and SEAMLDR.SEAMINFO [Dave]
>  - add P-SEAMLDR spec information in the changelog [Dave]
>  - add proper comments above ABI structure definition [Dave]
>  - add unused ABI structure fields rather than marking them as reserved
>    to better align with the specc [Dave] (I omitted "not used by kernel"
>    tags since there are 5-6 such fields and maintaining these tags would
>    be tedious.)
> ---
>  arch/x86/include/asm/seamldr.h  | 36 +++++++++++++++++++++++++++++++++
>  arch/x86/virt/vmx/tdx/seamldr.c | 19 ++++++++++++++++-
>  2 files changed, 54 insertions(+), 1 deletion(-)
>  create mode 100644 arch/x86/include/asm/seamldr.h
> 
> diff --git a/arch/x86/include/asm/seamldr.h b/arch/x86/include/asm/seamldr.h
> new file mode 100644
> index 000000000000..c67e5bc910a9
> --- /dev/null
> +++ b/arch/x86/include/asm/seamldr.h
> @@ -0,0 +1,36 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_X86_SEAMLDR_H
> +#define _ASM_X86_SEAMLDR_H
> +
> +#include <linux/types.h>
> +
> +/*
> + * This is called the "SEAMLDR_INFO" data structure and is defined
> + * in "SEAM Loader (SEAMLDR) Interface Specification".
> + *
> + * The SEAMLDR.INFO documentation requires this to be aligned to a
> + * 256-byte boundary.
> + */
> +struct seamldr_info {
> +	u32	version;
> +	u32	attributes;
> +	u32	vendor_id;
> +	u32	build_date;
> +	u16	build_num;
> +	u16	minor_version;
> +	u16	major_version;
> +	u16	update_version;
> +	u32	acm_x2apicid;
> +	u32	num_remaining_updates;
> +	u8	seam_info[128];
> +	u8	seam_ready;
> +	u8	seam_debug;
> +	u8	p_seam_ready;
> +	u8	reserved[93];
> +} __packed __aligned(256);
> +
> +static_assert(sizeof(struct seamldr_info) == 256);
> +
> +int seamldr_get_info(struct seamldr_info *seamldr_info);
> +
> +#endif /* _ASM_X86_SEAMLDR_H */
> diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
> index 7ed9be89017c..7c0cbab2c4c0 100644
> --- a/arch/x86/virt/vmx/tdx/seamldr.c
> +++ b/arch/x86/virt/vmx/tdx/seamldr.c
> @@ -8,8 +8,13 @@
>  
>  #include <linux/spinlock.h>
>  
> +#include <asm/seamldr.h>
> +
>  #include "seamcall_internal.h"
>  
> +/* P-SEAMLDR SEAMCALL leaf function */
> +#define P_SEAMLDR_INFO			0x8000000000000000
> +
>  /*
>   * Serialize P-SEAMLDR calls since the hardware only allows a single CPU to
>   * interact with P-SEAMLDR simultaneously. Use raw version as the calls can
> @@ -17,8 +22,20 @@
>   */
>  static DEFINE_RAW_SPINLOCK(seamldr_lock);
>  
> -static __maybe_unused int seamldr_call(u64 fn, struct tdx_module_args *args)
> +static int seamldr_call(u64 fn, struct tdx_module_args *args)
>  {
>  	guard(raw_spinlock)(&seamldr_lock);
>  	return seamcall_prerr(fn, args);
>  }
> +
> +int seamldr_get_info(struct seamldr_info *seamldr_info)
> +{
> +	/*
> +	 * Use slow_virt_to_phys() since @seamldr_info may be allocated on
> +	 * the stack.
> +	 */
> +	struct tdx_module_args args = { .rcx = slow_virt_to_phys(seamldr_info) };
> +
> +	return seamldr_call(P_SEAMLDR_INFO, &args);

On what condition this information can change?

I see the next patch calls this on every _show operation. Would we
benefit from caching the response?

> +}
> +EXPORT_SYMBOL_FOR_MODULES(seamldr_get_info, "tdx-host");
> -- 
> 2.47.3
> 

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 04/22] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs
  2026-03-16 13:05   ` Kiryl Shutsemau
@ 2026-03-17  0:43     ` Chao Gao
  2026-03-17  9:59       ` Kiryl Shutsemau
  0 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-17  0:43 UTC (permalink / raw)
  To: Kiryl Shutsemau
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Farrah Chen,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
	H. Peter Anvin

>> +/*
>> + * Serialize P-SEAMLDR calls since the hardware only allows a single CPU to
>> + * interact with P-SEAMLDR simultaneously. Use raw version as the calls can
>> + * be made with interrupts disabled.
>
>Hm. I am not sure how it explains use of raw_spinlock. What's wrong with
>using plain spinlock with interrupts disabled?

We mustn't acquire sleeping lock with interrupts disabled. in RT kernel, a plain
spinlock becomes a sleeping lock.

The lock doc [*] states:
  On PREEMPT_RT kernels, these lock types are converted to sleeping locks:
  local_lock
  spinlock_t
  rwlock_t

*:https://docs.kernel.org/locking/locktypes.html

and also see the test I did:

  https://lore.kernel.org/kvm/abPEit+Ckeqmypv+@intel.com/

How about:

/*
 * Serialize P-SEAMLDR calls since the hardware only allows a single CPU to
 * interact with P-SEAMLDR simultaneously. Use raw version as the calls can
 * be made with interrupts disabled, where plain spinlocks are prohibited in
 * PREEMPT_RT kernels as they become sleeping locks.
 */

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 05/22] x86/virt/seamldr: Retrieve P-SEAMLDR information
  2026-03-16 13:12   ` Kiryl Shutsemau
@ 2026-03-17  1:05     ` Chao Gao
  2026-03-17 10:00       ` Kiryl Shutsemau
  0 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-17  1:05 UTC (permalink / raw)
  To: Kiryl Shutsemau
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Farrah Chen,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
	H. Peter Anvin

>> +
>> +int seamldr_get_info(struct seamldr_info *seamldr_info)
>> +{
>> +	/*
>> +	 * Use slow_virt_to_phys() since @seamldr_info may be allocated on
>> +	 * the stack.
>> +	 */
>> +	struct tdx_module_args args = { .rcx = slow_virt_to_phys(seamldr_info) };
>> +
>> +	return seamldr_call(P_SEAMLDR_INFO, &args);
>
>On what condition this information can change?

After each update, the num_remaining_updates field will change.

>
>I see the next patch calls this on every _show operation. Would we
>benefit from caching the response?

Yes, caching would save a few cycles, but adds complexity. we'd need to keep
the cache synchronized and invalidate it when values change, likely requiring
additional state tracking.

Dave recommended allocating the structure on the stack [*] when I raised the
caching idea.

This isn't a hot path, so I prefer keeping it "simple and stupid".

[*]: https://lore.kernel.org/all/56a62e54-59f7-4423-9f01-4472d5c3815d@intel.com/

>
>> +}
>> +EXPORT_SYMBOL_FOR_MODULES(seamldr_get_info, "tdx-host");
>> -- 
>> 2.47.3
>> 
>
>-- 
>  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 12/22] x86/virt/tdx: Reset software states during TDX module shutdown
  2026-03-16  9:06   ` Huang, Kai
@ 2026-03-17  8:27     ` Chao Gao
  2026-03-17 11:08       ` Huang, Kai
  0 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-17  8:27 UTC (permalink / raw)
  To: Huang, Kai
  Cc: kvm@vger.kernel.org, linux-coco@lists.linux.dev,
	linux-kernel@vger.kernel.org, x86@kernel.org,
	dave.hansen@linux.intel.com, kas@kernel.org, seanjc@google.com,
	Chatre, Reinette, Weiny, Ira, binbin.wu@linux.intel.com,
	Verma, Vishal L, nik.borisov@suse.com, mingo@redhat.com,
	pbonzini@redhat.com, tony.lindgren@linux.intel.com,
	sagis@google.com, Annapurve, Vishal, hpa@zytor.com,
	Edgecombe, Rick P, paulmck@kernel.org, tglx@kernel.org,
	yilun.xu@linux.intel.com, Williams, Dan J, bp@alien8.de

On Mon, Mar 16, 2026 at 05:06:49PM +0800, Huang, Kai wrote:
>
>> @@ -1179,6 +1179,7 @@ EXPORT_SYMBOL_FOR_KVM(tdx_enable);
>>  int tdx_module_shutdown(void)
>>  {
>>  	struct tdx_module_args args = {};
>> +	int ret, cpu;
>>  
>>  	/*
>>  	 * Shut down the TDX module and prepare handoff data for the next
>> @@ -1188,7 +1189,22 @@ int tdx_module_shutdown(void)
>>  	 * modules as new modules likely have higher handoff version.
>>  	 */
>>  	args.rcx = tdx_sysinfo.handoff.module_hv;
>> -	return seamcall_prerr(TDH_SYS_SHUTDOWN, &args);
>> +	ret = seamcall_prerr(TDH_SYS_SHUTDOWN, &args);
>> +	if (ret)
>> +		return ret;
>> +
>> +	tdx_module_status = TDX_MODULE_UNINITIALIZED;
>> +	sysinit_done = false;
>> +	sysinit_ret = 0;
>> +
>> +	/*
>> +	 * By reaching here CPUHP is disabled and all present CPUs
>> +	 * are online. It's safe to just loop all online CPUs and
>> +	 * reset the per-cpu flag.
>> +	 */
>> +	for_each_online_cpu(cpu)
>> +		per_cpu(tdx_lp_initialized, cpu) = false;
>
>Since you have removed the requirement that P-SEAMLDR.INSTALL must be done
>on all CPUs, and removed the relevant patch, the "all present CPUs are
>online" part isn't correct anymore.
>
>And using for_each_online_cpu() isn't enough since this doesn't reset the
>tdx_lp_initialized for offline CPUs.
>
>One way is to just use for_each_possible_cpu() here so tdx_lp_initialized
>for all CPUs are reset.  Since the "CPUHP is disabled" part is still correct
>AFAICT (since stop_machine() disables CPUHP internally during the
>operation), resetting tdx_lp_initialized for offline CPUs won't race with
>CPUHP.
>
>And assuming this series will be applied after Sean's VMXON series, we will

Yes.

>have a TDX-specific CPUHP callback tdx_online_cpu() in TDX x86 core to do
>tdx_cpu_enable(), which will then enable TDX again on the new-online CPU.

Good point.

Clearing tdx_lp_initialized for offlined CPUs makes sense, but I'd rather not
justify this through "enabling TDX on new-online CPUs" since many details
remain unclear. For example, there will be a SEAMCALL to disable TDX per-CPU.
It should be called when CPUs go offline so that those CPUs can be exempting
from doing SEAMLDR.INSTALL during module updates. tdx_lp_initialized should
have been cleared along with that "disable TDX per-CPU" SEAMCALL for offlined
CPUs.

I'm not arguing against for_each_present_cpu(). I just think discussing how
to support TDX module update with offlined CPUs in the comment would be a bit
premature. How about keeping it simple:

/*
 * Since the TDX module is shut down and gone, mark all CPUs (including
 * offlined ones) as uninitialied. This is called in stop_machine() (where
 * CPU hotplug is disabled), preventing races with other tdx_lp_initialized
 * accesses.
 */

>
>Btw, w/o Sean's VMXON series, currently only KVM provides the TDX-specific
>CPUHP callback.  So it seems if module update is done when KVM is not
>loaded,

w/o VMXON series, module update isn't possible if KVM isn't loaded.

>there will be no TDX-specific CPUHP callback to re-enable TDX for
>the new-online CPU.  This means any SEAMCALL on that CPU will fail before
>KVM module is loaded again (which will then re-register the TDX-specific
>CPUHP and run tdx_cpu_enable() for all online CPUs). 
>
>But I don't think we should consider this case.
>
>
Agreed.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 04/22] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs
  2026-03-17  0:43     ` Chao Gao
@ 2026-03-17  9:59       ` Kiryl Shutsemau
  0 siblings, 0 replies; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-17  9:59 UTC (permalink / raw)
  To: Chao Gao
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Farrah Chen,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
	H. Peter Anvin

On Tue, Mar 17, 2026 at 08:43:31AM +0800, Chao Gao wrote:
> >> +/*
> >> + * Serialize P-SEAMLDR calls since the hardware only allows a single CPU to
> >> + * interact with P-SEAMLDR simultaneously. Use raw version as the calls can
> >> + * be made with interrupts disabled.
> >
> >Hm. I am not sure how it explains use of raw_spinlock. What's wrong with
> >using plain spinlock with interrupts disabled?
> 
> We mustn't acquire sleeping lock with interrupts disabled. in RT kernel, a plain
> spinlock becomes a sleeping lock.
> 
> The lock doc [*] states:
>   On PREEMPT_RT kernels, these lock types are converted to sleeping locks:
>   local_lock
>   spinlock_t
>   rwlock_t
> 
> *:https://docs.kernel.org/locking/locktypes.html
> 
> and also see the test I did:
> 
>   https://lore.kernel.org/kvm/abPEit+Ckeqmypv+@intel.com/
> 
> How about:
> 
> /*
>  * Serialize P-SEAMLDR calls since the hardware only allows a single CPU to
>  * interact with P-SEAMLDR simultaneously. Use raw version as the calls can
>  * be made with interrupts disabled, where plain spinlocks are prohibited in
>  * PREEMPT_RT kernels as they become sleeping locks.
>  */

Looks better. Thanks for the explanation.

Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 05/22] x86/virt/seamldr: Retrieve P-SEAMLDR information
  2026-03-17  1:05     ` Chao Gao
@ 2026-03-17 10:00       ` Kiryl Shutsemau
  0 siblings, 0 replies; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-17 10:00 UTC (permalink / raw)
  To: Chao Gao
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Farrah Chen,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
	H. Peter Anvin

On Tue, Mar 17, 2026 at 09:05:50AM +0800, Chao Gao wrote:
> >> +
> >> +int seamldr_get_info(struct seamldr_info *seamldr_info)
> >> +{
> >> +	/*
> >> +	 * Use slow_virt_to_phys() since @seamldr_info may be allocated on
> >> +	 * the stack.
> >> +	 */
> >> +	struct tdx_module_args args = { .rcx = slow_virt_to_phys(seamldr_info) };
> >> +
> >> +	return seamldr_call(P_SEAMLDR_INFO, &args);
> >
> >On what condition this information can change?
> 
> After each update, the num_remaining_updates field will change.
> 
> >
> >I see the next patch calls this on every _show operation. Would we
> >benefit from caching the response?
> 
> Yes, caching would save a few cycles, but adds complexity. we'd need to keep
> the cache synchronized and invalidate it when values change, likely requiring
> additional state tracking.
> 
> Dave recommended allocating the structure on the stack [*] when I raised the
> caching idea.
> 
> This isn't a hot path, so I prefer keeping it "simple and stupid".

Fair enough.

Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 06/22] coco/tdx-host: Expose P-SEAMLDR information via sysfs
  2026-03-15 13:58 ` [PATCH v5 06/22] coco/tdx-host: Expose P-SEAMLDR information via sysfs Chao Gao
@ 2026-03-17 10:06   ` Kiryl Shutsemau
  2026-03-17 15:34     ` Dave Hansen
  2026-03-18  6:54     ` Chao Gao
  0 siblings, 2 replies; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-17 10:06 UTC (permalink / raw)
  To: Chao Gao
  Cc: x86, linux-coco, kvm, linux-kernel, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu

On Sun, Mar 15, 2026 at 06:58:26AM -0700, Chao Gao wrote:
> TDX module updates require userspace to select the appropriate module
> to load. Expose necessary information to facilitate this decision. Two
> values are needed:
> 
> - P-SEAMLDR version: for compatibility checks between TDX module and
> 		     P-SEAMLDR
> - num_remaining_updates: indicates how many updates can be performed
> 
> Expose them as tdx-host device attributes. Register these attributes
> during device probe rather than creation, making it easier to hide them
> when P-SEAMLDR calls are unsafe (due to CPU erratum).
> 
> Signed-off-by: Chao Gao <chao.gao@intel.com>

Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>

Few nitpicks below.

> ---
> v5:
>  - fix typos [Binbin]
>  - register seamldr_group during device probe
> v4:
>  - Make seamldr attribute permission "0400" [Dave]
>  - Don't include implementation details in OS ABI docs [Dave]
>  - Tag tdx_host_group as static [Kai]
> 
> v3:
>  - use #ifdef rather than .is_visible() to control P-SEAMLDR sysfs
>    visibility [Yilun]
> ---
>  .../ABI/testing/sysfs-devices-faux-tdx-host   | 23 +++++++
>  drivers/virt/coco/tdx-host/tdx-host.c         | 68 ++++++++++++++++++-
>  2 files changed, 90 insertions(+), 1 deletion(-)
> 
> diff --git a/Documentation/ABI/testing/sysfs-devices-faux-tdx-host b/Documentation/ABI/testing/sysfs-devices-faux-tdx-host
> index 2cf682b65acf..44b8356aed6b 100644
> --- a/Documentation/ABI/testing/sysfs-devices-faux-tdx-host
> +++ b/Documentation/ABI/testing/sysfs-devices-faux-tdx-host
> @@ -4,3 +4,26 @@ Description:	(RO) Report the version of the loaded TDX module. The TDX module
>  		version is formatted as x.y.z, where "x" is the major version,
>  		"y" is the minor version and "z" is the update version. Versions
>  		are used for bug reporting, TDX module updates etc.
> +
> +What:		/sys/devices/faux/tdx_host/seamldr/version
> +Contact:	linux-coco@lists.linux.dev
> +Description:	(RO) Report the version of the loaded SEAM loader. The SEAM
> +		loader version is formatted as x.y.z, where "x" is the major
> +		version, "y" is the minor version and "z" is the update version.
> +		Versions are used for bug reporting and compatibility checks.
> +
> +What:		/sys/devices/faux/tdx_host/seamldr/num_remaining_updates
> +Contact:	linux-coco@lists.linux.dev
> +Description:	(RO) Report the number of remaining updates. TDX maintains a
> +		log about each TDX module that has been loaded. This log has
> +		a finite size, which limits the number of TDX module updates
> +		that can be performed.
> +
> +		After each successful update, the number reduces by one. Once it
> +		reaches zero, further updates will fail until next reboot. The
> +		number is always zero if the P-SEAMLDR doesn't support updates.
> +
> +		See Intel® Trust Domain Extensions - SEAM Loader (SEAMLDR)
> +		Interface Specification, Revision 343755-003, Chapter 3.3
> +		"SEAMLDR_INFO" and Chapter 4.2 "SEAMLDR.INSTALL" for more
> +		information.

Do you think revision and chapter numbers useful here?

> diff --git a/drivers/virt/coco/tdx-host/tdx-host.c b/drivers/virt/coco/tdx-host/tdx-host.c
> index 0424933b2560..8d46e3c039ba 100644
> --- a/drivers/virt/coco/tdx-host/tdx-host.c
> +++ b/drivers/virt/coco/tdx-host/tdx-host.c
> @@ -11,6 +11,7 @@
>  #include <linux/sysfs.h>
>  
>  #include <asm/cpu_device_id.h>
> +#include <asm/seamldr.h>
>  #include <asm/tdx.h>
>  
>  static const struct x86_cpu_id tdx_host_ids[] = {
> @@ -42,6 +43,71 @@ static struct attribute *tdx_host_attrs[] = {
>  };
>  ATTRIBUTE_GROUPS(tdx_host);
>  
> +static ssize_t seamldr_version_show(struct device *dev, struct device_attribute *attr,
> +				    char *buf)
> +{
> +	struct seamldr_info info;
> +	int ret;
> +
> +	ret = seamldr_get_info(&info);
> +	if (ret)
> +		return ret;
> +
> +	return sysfs_emit(buf, "%u.%u.%02u\n", info.major_version,
> +					       info.minor_version,
> +					       info.update_version);

Maybe a comment why %02u used for update_version?

> +}
> +
> +static ssize_t num_remaining_updates_show(struct device *dev,
> +					  struct device_attribute *attr,
> +					  char *buf)
> +{
> +	struct seamldr_info info;
> +	int ret;
> +
> +	ret = seamldr_get_info(&info);
> +	if (ret)
> +		return ret;
> +
> +	return sysfs_emit(buf, "%u\n", info.num_remaining_updates);
> +}
> +
> +/*
> + * Open-code DEVICE_ATTR_ADMIN_RO to specify a different 'show' function
> + * for P-SEAMLDR version as version_show() is used for TDX module version.
> + *
> + * Admin-only readable as reading these attributes calls into P-SEAMLDR,
> + * which may have potential performance and system impact.
> + */
> +static struct device_attribute dev_attr_seamldr_version =
> +	__ATTR(version, 0400, seamldr_version_show, NULL);
> +static DEVICE_ATTR_ADMIN_RO(num_remaining_updates);
> +
> +static struct attribute *seamldr_attrs[] = {
> +	&dev_attr_seamldr_version.attr,
> +	&dev_attr_num_remaining_updates.attr,
> +	NULL,
> +};
> +
> +static const struct attribute_group seamldr_group = {
> +	.name = "seamldr",
> +	.attrs = seamldr_attrs,
> +};
> +
> +static int seamldr_init(struct device *dev)
> +{
> +	return devm_device_add_group(dev, &seamldr_group);
> +}
> +
> +static int tdx_host_probe(struct faux_device *fdev)
> +{
> +	return seamldr_init(&fdev->dev);
> +}
> +
> +static const struct faux_device_ops tdx_host_ops = {
> +	.probe		= tdx_host_probe,
> +};
> +
>  static struct faux_device *fdev;
>  
>  static int __init tdx_host_init(void)
> @@ -49,7 +115,7 @@ static int __init tdx_host_init(void)
>  	if (!x86_match_cpu(tdx_host_ids) || !tdx_get_sysinfo())
>  		return -ENODEV;
>  
> -	fdev = faux_device_create_with_groups(KBUILD_MODNAME, NULL, NULL, tdx_host_groups);
> +	fdev = faux_device_create_with_groups(KBUILD_MODNAME, NULL, &tdx_host_ops, tdx_host_groups);
>  	if (!fdev)
>  		return -ENODEV;
>  
> -- 
> 2.47.3
> 

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 07/22] coco/tdx-host: Implement firmware upload sysfs ABI for TDX module updates
  2026-03-15 13:58 ` [PATCH v5 07/22] coco/tdx-host: Implement firmware upload sysfs ABI for TDX module updates Chao Gao
@ 2026-03-17 10:20   ` Kiryl Shutsemau
  2026-03-18  8:28     ` Chao Gao
  2026-03-18 21:45   ` Huang, Kai
  1 sibling, 1 reply; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-17 10:20 UTC (permalink / raw)
  To: Chao Gao
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

On Sun, Mar 15, 2026 at 06:58:27AM -0700, Chao Gao wrote:
> Linux kernel supports two primary firmware update mechanisms:
>   - request_firmware()
>   - firmware upload (or fw_upload)
> 
> The former is used by microcode updates, SEV firmware updates, etc. The
> latter is used by CXL and FPGA firmware updates.
> 
> One key difference between them is: request_firmware() loads a named
> file from the filesystem where the filename is kernel-controlled, while
> fw_upload accepts firmware data directly from userspace.
> 
> Use fw_upload for TDX module updates as loading a named file isn't
> suitable for TDX (see below for more reasons). Specifically, register
> TDX faux device with fw_upload framework to expose sysfs interfaces
> and implement operations to process data blobs supplied by userspace.
> 
> Implementation notes:
> 1. P-SEAMLDR processes the entire update at once rather than
>    chunk-by-chunk, so .write() is called only once per update; so the
>    offset should be always 0.
> 2. An update completes synchronously within .write(), meaning
>    .poll_complete() is only called after the update succeeds and so always
>    returns success
> 
> Why fw_upload instead of request_firmware()?
> ============================================
> The explicit file selection capabilities of fw_upload is preferred over
> the implicit file selection of request_firmware() for the following
> reasons:
> 
> a. Intel distributes all versions of the TDX module, allowing admins to
> load any version rather than always defaulting to the latest. This
> flexibility is necessary because future extensions may require reverting to
> a previous version to clear fatal errors.
> 
> b. Some module version series are platform-specific. For example, the 1.5.x
> series is for certain platform generations, while the 2.0.x series is
> intended for others.
> 
> c. The update policy for TDX module updates is non-linear at times. The
> latest TDX module may not be compatible. For example, TDX module 1.5.x
> may be updated to 1.5.y but not to 1.5.y+1. This policy is documented
> separately in a file released along with each TDX module release.
> 
> So, the default policy of "request_firmware()" of "always load latest", is
> not suitable for TDX. Userspace needs to deploy a more sophisticated policy
> check (e.g., latest may not be compatible), and there is potential
> operator choice to consider.
> 
> Just have userspace pick rather than add kernel mechanism to change the
> default policy of request_firmware().
> 
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>

Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>

One minor thing below.

> ---
> v5:
>  - remove a tail comment [Yan]
>  - remove is_vmalloc_addr() check [Dave]
>  - use devm_add_action_or_reset() for deinit [Yilun]
>  - remove global tdx_fwl [Yilun]
>  - clarify request_firmware() doesn't take filename from userspace
>    [Rick]
> 
> v4:
>  - make tdx_fwl static [Kai]
>  - don't support update canceling [Yilun]
>  - explain why seamldr_init() doesn't return an error [Kai]
>  - bail out if TDX module updates are not supported [Kai]
>  - name the firmware "tdx_module" instead of "seamldr_upload" [Cedric]
> 
> v3:
>  - clear "cancel_request" in the "prepare" phase [Binbin]
>  - Don't fail the whole tdx-host device if seamldr_init() met an error
>  [Yilun]
>  - Add kdoc for seamldr_install_module() and verify that the input
>    buffer is vmalloc'd. [Yilun]
> ---
>  arch/x86/include/asm/seamldr.h        |  1 +
>  arch/x86/include/asm/tdx.h            |  6 ++
>  arch/x86/virt/vmx/tdx/seamldr.c       | 15 +++++
>  drivers/virt/coco/tdx-host/Kconfig    |  2 +
>  drivers/virt/coco/tdx-host/tdx-host.c | 87 +++++++++++++++++++++++++++
>  5 files changed, 111 insertions(+)
> 
> diff --git a/arch/x86/include/asm/seamldr.h b/arch/x86/include/asm/seamldr.h
> index c67e5bc910a9..ac6f80f7208b 100644
> --- a/arch/x86/include/asm/seamldr.h
> +++ b/arch/x86/include/asm/seamldr.h
> @@ -32,5 +32,6 @@ struct seamldr_info {
>  static_assert(sizeof(struct seamldr_info) == 256);
>  
>  int seamldr_get_info(struct seamldr_info *seamldr_info);
> +int seamldr_install_module(const u8 *data, u32 size);
>  
>  #endif /* _ASM_X86_SEAMLDR_H */
> diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
> index cb2219302dfc..b3a7301e77c6 100644
> --- a/arch/x86/include/asm/tdx.h
> +++ b/arch/x86/include/asm/tdx.h
> @@ -103,6 +103,12 @@ int tdx_enable(void);
>  const char *tdx_dump_mce_info(struct mce *m);
>  const struct tdx_sys_info *tdx_get_sysinfo(void);
>  
> +static inline bool tdx_supports_runtime_update(const struct tdx_sys_info *sysinfo)
> +{
> +	 /* To be enabled when kernel is ready. */
> +	return false;
> +}
> +
>  int tdx_guest_keyid_alloc(void);
>  u32 tdx_get_nr_guest_keyids(void);
>  void tdx_guest_keyid_free(unsigned int keyid);
> diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
> index 7c0cbab2c4c0..7114326d7569 100644
> --- a/arch/x86/virt/vmx/tdx/seamldr.c
> +++ b/arch/x86/virt/vmx/tdx/seamldr.c
> @@ -6,6 +6,7 @@
>   */
>  #define pr_fmt(fmt)	"seamldr: " fmt
>  
> +#include <linux/mm.h>
>  #include <linux/spinlock.h>
>  
>  #include <asm/seamldr.h>
> @@ -39,3 +40,17 @@ int seamldr_get_info(struct seamldr_info *seamldr_info)
>  	return seamldr_call(P_SEAMLDR_INFO, &args);
>  }
>  EXPORT_SYMBOL_FOR_MODULES(seamldr_get_info, "tdx-host");
> +
> +/**
> + * seamldr_install_module - Install a new TDX module.
> + * @data: Pointer to the TDX module update blob.
> + * @size: Size of the TDX module update blob.
> + *
> + * Returns 0 on success, negative error code on failure.
> + */
> +int seamldr_install_module(const u8 *data, u32 size)
> +{
> +	/* TODO: Update TDX module here */
> +	return 0;
> +}
> +EXPORT_SYMBOL_FOR_MODULES(seamldr_install_module, "tdx-host");
> diff --git a/drivers/virt/coco/tdx-host/Kconfig b/drivers/virt/coco/tdx-host/Kconfig
> index d35d85ef91c0..ca600a39d97b 100644
> --- a/drivers/virt/coco/tdx-host/Kconfig
> +++ b/drivers/virt/coco/tdx-host/Kconfig
> @@ -1,6 +1,8 @@
>  config TDX_HOST_SERVICES
>  	tristate "TDX Host Services Driver"
>  	depends on INTEL_TDX_HOST
> +	select FW_LOADER
> +	select FW_UPLOAD
>  	default m
>  	help
>  	  Enable access to TDX host services like module update and
> diff --git a/drivers/virt/coco/tdx-host/tdx-host.c b/drivers/virt/coco/tdx-host/tdx-host.c
> index 8d46e3c039ba..1b93d20406c1 100644
> --- a/drivers/virt/coco/tdx-host/tdx-host.c
> +++ b/drivers/virt/coco/tdx-host/tdx-host.c
> @@ -6,6 +6,7 @@
>   */
>  
>  #include <linux/device/faux.h>
> +#include <linux/firmware.h>
>  #include <linux/module.h>
>  #include <linux/mod_devicetable.h>
>  #include <linux/sysfs.h>
> @@ -94,8 +95,94 @@ static const struct attribute_group seamldr_group = {
>  	.attrs = seamldr_attrs,
>  };
>  
> +static enum fw_upload_err tdx_fw_prepare(struct fw_upload *fwl,
> +					 const u8 *data, u32 size)
> +{
> +	return FW_UPLOAD_ERR_NONE;
> +}
> +
> +static enum fw_upload_err tdx_fw_write(struct fw_upload *fwl, const u8 *data,
> +				       u32 offset, u32 size, u32 *written)
> +{
> +	int ret;
> +
> +	/*
> +	 * tdx_fw_write() always processes all data on the first call with
> +	 * offset == 0. Since it never returns partial success (it either
> +	 * succeeds completely or fails), there is no subsequent call with
> +	 * non-zero offsets.
> +	 */
> +	WARN_ON_ONCE(offset);
> +	ret = seamldr_install_module(data, size);
> +	switch (ret) {
> +	case 0:
> +		*written = size;
> +		return FW_UPLOAD_ERR_NONE;
> +	case -EBUSY:
> +		return FW_UPLOAD_ERR_BUSY;
> +	case -EIO:
> +		return FW_UPLOAD_ERR_HW_ERROR;
> +	case -ENOSPC:
> +		return FW_UPLOAD_ERR_WEAROUT;
> +	case -ENOMEM:
> +		return FW_UPLOAD_ERR_RW_ERROR;
> +	default:
> +		return FW_UPLOAD_ERR_FW_INVALID;
> +	}
> +}
> +
> +static enum fw_upload_err tdx_fw_poll_complete(struct fw_upload *fwl)
> +{
> +	/*
> +	 * TDX module updates are completed in the previous phase
> +	 * (tdx_fw_write()). If any error occurred, the previous phase
> +	 * would return an error code to abort the update process. In
> +	 * other words, reaching this point means the update succeeded.
> +	 */
> +	return FW_UPLOAD_ERR_NONE;
> +}
> +
> +/*
> + * TDX module updates cannot be cancelled. Provide a stub function since
> + * the firmware upload framework requires a .cancel operation.
> + */
> +static void tdx_fw_cancel(struct fw_upload *fwl)
> +{
> +}
> +
> +static const struct fw_upload_ops tdx_fw_ops = {
> +	.prepare	= tdx_fw_prepare,
> +	.write		= tdx_fw_write,
> +	.poll_complete	= tdx_fw_poll_complete,
> +	.cancel		= tdx_fw_cancel,
> +};
> +
> +static void seamldr_deinit(void *tdx_fwl)
> +{
> +	firmware_upload_unregister(tdx_fwl);
> +}
> +
>  static int seamldr_init(struct device *dev)
>  {
> +	const struct tdx_sys_info *tdx_sysinfo = tdx_get_sysinfo();
> +	struct fw_upload *tdx_fwl;
> +	int ret;
> +
> +	if (WARN_ON_ONCE(!tdx_sysinfo))
> +		return -EIO;
> +
> +	if (!tdx_supports_runtime_update(tdx_sysinfo))
> +		return 0;

Hm. Do we still want to register seamldr_group for this case?

Maybe move it up before the check?

> +
> +	tdx_fwl = firmware_upload_register(THIS_MODULE, dev, "tdx_module",
> +					   &tdx_fw_ops, NULL);
> +	if (IS_ERR(tdx_fwl))
> +		return PTR_ERR(tdx_fwl);
> +
> +	ret = devm_add_action_or_reset(dev, seamldr_deinit, tdx_fwl);
> +	if (ret)
> +		return ret;
> +
>  	return devm_device_add_group(dev, &seamldr_group);
>  }
>  
> -- 
> 2.47.3
> 

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 08/22] x86/virt/seamldr: Allocate and populate a module update request
  2026-03-15 13:58 ` [PATCH v5 08/22] x86/virt/seamldr: Allocate and populate a module update request Chao Gao
@ 2026-03-17 10:59   ` Kiryl Shutsemau
  2026-03-18  8:50     ` Chao Gao
  2026-03-18 21:36   ` Huang, Kai
  1 sibling, 1 reply; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-17 10:59 UTC (permalink / raw)
  To: Chao Gao
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

On Sun, Mar 15, 2026 at 06:58:28AM -0700, Chao Gao wrote:
> P-SEAMLDR uses the SEAMLDR_PARAMS structure to describe TDX module
> update requests. This structure contains physical addresses pointing to
> the module binary and its signature file (or sigstruct), along with an
> update scenario field.
> 
> TDX modules are distributed in the tdx_blob format defined in
> blob_structure.txt from the "Intel TDX module Binaries Repository". A
> tdx_blob contains a header, sigstruct, and module binary. This is also the
> format supplied by the userspace to the kernel.
> 
> Parse the tdx_blob format and populate a SEAMLDR_PARAMS structure
> accordingly. This structure will be passed to P-SEAMLDR to initiate the
> update.
> 
> Note that the sigstruct_pa field in SEAMLDR_PARAMS has been extended to
> a 4-element array. The updated "SEAM Loader (SEAMLDR) Interface
> Specification" will be published separately. P-SEAMLDR compatibility
> validation (such as 4KB vs 16KB sigstruct support) is left to userspace,
> which must verify the P-SEAMLDR version meets the TDX module's minimum
> requirements.
> 
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
> Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
> ---
> v5:
>  - use a macro for tdx_blob version (0x100) [Yan]
>  - don't do alignment checking for the binary/sigstruct [Rick]
>  - drop blob's sigstruct and validation checking
>  - set seamldr_params.version to 1 when necessary
>  - drop the link to blob_structure.txt which might be unstable [Kai]
> 
> v4:
>  - Remove checksum verification as it is optional
>  - Convert comments to is_vmalloc_addr() checks [Kai]
>  - Explain size/alignment checks in alloc_seamldr_params() [Kai]
> 
> v3:
>  - Print tdx_blob version in hex [Binbin]
>  - Drop redundant sigstruct alignment check [Yilun]
>  - Note buffers passed from firmware upload infrastructure are
>    vmalloc()'d above alloc_seamldr_params()
> ---
>  arch/x86/virt/vmx/tdx/seamldr.c | 141 ++++++++++++++++++++++++++++++++
>  1 file changed, 141 insertions(+)
> 
> diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
> index 7114326d7569..20cb6c797ce5 100644
> --- a/arch/x86/virt/vmx/tdx/seamldr.c
> +++ b/arch/x86/virt/vmx/tdx/seamldr.c
> @@ -7,6 +7,7 @@
>  #define pr_fmt(fmt)	"seamldr: " fmt
>  
>  #include <linux/mm.h>
> +#include <linux/slab.h>
>  #include <linux/spinlock.h>
>  
>  #include <asm/seamldr.h>
> @@ -16,6 +17,33 @@
>  /* P-SEAMLDR SEAMCALL leaf function */
>  #define P_SEAMLDR_INFO			0x8000000000000000
>  
> +#define SEAMLDR_MAX_NR_MODULE_4KB_PAGES	496
> +#define SEAMLDR_MAX_NR_SIG_4KB_PAGES	4
> +
> +/*
> + * The seamldr_params "scenario" field specifies the operation mode:
> + * 0: Install TDX module from scratch (not used by kernel)
> + * 1: Update existing TDX module to a compatible version
> + */
> +#define SEAMLDR_SCENARIO_UPDATE		1
> +
> +/*
> + * This is called the "SEAMLDR_PARAMS" data structure and is defined
> + * in "SEAM Loader (SEAMLDR) Interface Specification".
> + *
> + * It describes the TDX module that will be installed.
> + */
> +struct seamldr_params {
> +	u32	version;
> +	u32	scenario;
> +	u64	sigstruct_pa[SEAMLDR_MAX_NR_SIG_4KB_PAGES];
> +	u8	reserved[80];
> +	u64	num_module_pages;
> +	u64	mod_pages_pa_list[SEAMLDR_MAX_NR_MODULE_4KB_PAGES];
> +} __packed;
> +
> +static_assert(sizeof(struct seamldr_params) == 4096);
> +
>  /*
>   * Serialize P-SEAMLDR calls since the hardware only allows a single CPU to
>   * interact with P-SEAMLDR simultaneously. Use raw version as the calls can
> @@ -41,6 +69,114 @@ int seamldr_get_info(struct seamldr_info *seamldr_info)
>  }
>  EXPORT_SYMBOL_FOR_MODULES(seamldr_get_info, "tdx-host");
>  
> +static void free_seamldr_params(struct seamldr_params *params)
> +{
> +	free_page((unsigned long)params);
> +}
> +
> +static struct seamldr_params *alloc_seamldr_params(const void *module, unsigned int module_size,
> +						   const void *sig, unsigned int sig_size)
> +{
> +	struct seamldr_params *params;
> +	const u8 *ptr;
> +	int i;
> +
> +	if (module_size > SEAMLDR_MAX_NR_MODULE_4KB_PAGES * SZ_4K)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (sig_size > SEAMLDR_MAX_NR_SIG_4KB_PAGES * SZ_4K)
> +		return ERR_PTR(-EINVAL);
> +
> +	params = (struct seamldr_params *)get_zeroed_page(GFP_KERNEL);
> +	if (!params)
> +		return ERR_PTR(-ENOMEM);
> +
> +	/*
> +	 * Only use version 1 when required (sigstruct > 4KB) for backward
> +	 * compatibility with P-SEAMLDR that lacks version 1 support.
> +	 */
> +	if (sig_size > SZ_4K)
> +		params->version = 1;
> +	else
> +		params->version = 0;
> +
> +	params->scenario = SEAMLDR_SCENARIO_UPDATE;
> +
> +	ptr = sig;
> +	for (i = 0; i < sig_size / SZ_4K; i++) {
> +		/*
> +		 * Don't assume @sig is page-aligned although it is 4KB-aligned.
> +		 * Always add the in-page offset to get the physical address.
> +		 */

I don't follow this. If @sig is 4k aligned in VA, it is page aligned.

If you want to handle case when @sig is not 4k aligned, than this is
broken. You need to bump ptr to the next 4k boundary, not by 4k.

> +		params->sigstruct_pa[i] = (vmalloc_to_pfn(ptr) << PAGE_SHIFT) +
> +					  ((unsigned long)ptr & ~PAGE_MASK);
> +		ptr += SZ_4K;
> +	}
> +
> +	params->num_module_pages = module_size / SZ_4K;
> +
> +	ptr = module;
> +	for (i = 0; i < params->num_module_pages; i++) {
> +		params->mod_pages_pa_list[i] = (vmalloc_to_pfn(ptr) << PAGE_SHIFT) +
> +					       ((unsigned long)ptr & ~PAGE_MASK);
> +		ptr += SZ_4K;

Same here.

> +	}
> +
> +	return params;
> +}
> +
> +/*
> + * Intel TDX module blob. Its format is defined at:
> + * https://github.com/intel/tdx-module-binaries/blob/main/blob_structure.txt
> + *
> + * Note this structure differs from the reference above: the two variable-length
> + * fields "@sigstruct" and "@module" are represented as a single "@data" field
> + * here and split programmatically using the offset_of_module value.
> + */
> +struct tdx_blob {
> +	u16	version;
> +	u16	checksum;
> +	u32	offset_of_module;
> +	u8	signature[8];
> +	u32	length;
> +	u32	reserved0;
> +	u64	reserved1[509];
> +	u8	data[];
> +} __packed;
> +
> +/* Supported versions of the tdx_blob */
> +#define TDX_BLOB_VERSION_1	0x100
> +
> +static struct seamldr_params *init_seamldr_params(const u8 *data, u32 size)
> +{
> +	const struct tdx_blob *blob = (const void *)data;
> +	int module_size, sig_size;
> +	const void *sig, *module;
> +
> +	/* Ensure the size is valid otherwise reading any field from the blob may overflow. */
> +	if (size <= sizeof(struct tdx_blob) || size <= blob->offset_of_module)
> +		return ERR_PTR(-EINVAL);
> +
> +	if (blob->version != TDX_BLOB_VERSION_1) {
> +		pr_err("unsupported blob version: %x\n", blob->version);
> +		return ERR_PTR(-EINVAL);
> +	}
> +
> +	/* Split the blob into a sigstruct and a module. */
> +	sig		= blob->data;
> +	sig_size	= blob->offset_of_module - sizeof(struct tdx_blob);
> +	module		= data + blob->offset_of_module;
> +	module_size	= size - blob->offset_of_module;
> +
> +	if (sig_size <= 0 || module_size <= 0 || blob->length != size)
> +		return ERR_PTR(-EINVAL);

Maybe add a comment somewhere that block->offset_of_module is relative
to start of struct tdx_blob, not blob->data and blob->length includes
length of struct tdx_blob.

It can be either way and it is better to give a reader a hint.

> +
> +	return alloc_seamldr_params(module, module_size, sig, sig_size);
> +}
> +
> +DEFINE_FREE(free_seamldr_params, struct seamldr_params *,
> +	    if (!IS_ERR_OR_NULL(_T)) free_seamldr_params(_T))
> +
>  /**
>   * seamldr_install_module - Install a new TDX module.
>   * @data: Pointer to the TDX module update blob.
> @@ -50,6 +186,11 @@ EXPORT_SYMBOL_FOR_MODULES(seamldr_get_info, "tdx-host");
>   */
>  int seamldr_install_module(const u8 *data, u32 size)
>  {
> +	struct seamldr_params *params __free(free_seamldr_params) =
> +						init_seamldr_params(data, size);
> +	if (IS_ERR(params))
> +		return PTR_ERR(params);
> +
>  	/* TODO: Update TDX module here */
>  	return 0;
>  }
> -- 
> 2.47.3
> 

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 12/22] x86/virt/tdx: Reset software states during TDX module shutdown
  2026-03-17  8:27     ` Chao Gao
@ 2026-03-17 11:08       ` Huang, Kai
  0 siblings, 0 replies; 80+ messages in thread
From: Huang, Kai @ 2026-03-17 11:08 UTC (permalink / raw)
  To: Gao, Chao
  Cc: kvm@vger.kernel.org, linux-coco@lists.linux.dev,
	yilun.xu@linux.intel.com, dave.hansen@linux.intel.com,
	bp@alien8.de, tony.lindgren@linux.intel.com, mingo@redhat.com,
	Weiny, Ira, pbonzini@redhat.com, seanjc@google.com,
	Verma, Vishal L, nik.borisov@suse.com, binbin.wu@linux.intel.com,
	kas@kernel.org, sagis@google.com, Annapurve, Vishal,
	hpa@zytor.com, Edgecombe, Rick P, linux-kernel@vger.kernel.org,
	Chatre, Reinette, tglx@kernel.org, paulmck@kernel.org,
	x86@kernel.org, Williams, Dan J

On Tue, 2026-03-17 at 16:27 +0800, Gao, Chao wrote:
> On Mon, Mar 16, 2026 at 05:06:49PM +0800, Huang, Kai wrote:
> > 
> > > @@ -1179,6 +1179,7 @@ EXPORT_SYMBOL_FOR_KVM(tdx_enable);
> > >  int tdx_module_shutdown(void)
> > >  {
> > >  	struct tdx_module_args args = {};
> > > +	int ret, cpu;
> > >  
> > >  	/*
> > >  	 * Shut down the TDX module and prepare handoff data for the next
> > > @@ -1188,7 +1189,22 @@ int tdx_module_shutdown(void)
> > >  	 * modules as new modules likely have higher handoff version.
> > >  	 */
> > >  	args.rcx = tdx_sysinfo.handoff.module_hv;
> > > -	return seamcall_prerr(TDH_SYS_SHUTDOWN, &args);
> > > +	ret = seamcall_prerr(TDH_SYS_SHUTDOWN, &args);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	tdx_module_status = TDX_MODULE_UNINITIALIZED;
> > > +	sysinit_done = false;
> > > +	sysinit_ret = 0;
> > > +
> > > +	/*
> > > +	 * By reaching here CPUHP is disabled and all present CPUs
> > > +	 * are online. It's safe to just loop all online CPUs and
> > > +	 * reset the per-cpu flag.
> > > +	 */
> > > +	for_each_online_cpu(cpu)
> > > +		per_cpu(tdx_lp_initialized, cpu) = false;
> > 
> > Since you have removed the requirement that P-SEAMLDR.INSTALL must be done
> > on all CPUs, and removed the relevant patch, the "all present CPUs are
> > online" part isn't correct anymore.
> > 
> > And using for_each_online_cpu() isn't enough since this doesn't reset the
> > tdx_lp_initialized for offline CPUs.
> > 
> > One way is to just use for_each_possible_cpu() here so tdx_lp_initialized
> > for all CPUs are reset.  Since the "CPUHP is disabled" part is still correct
> > AFAICT (since stop_machine() disables CPUHP internally during the
> > operation), resetting tdx_lp_initialized for offline CPUs won't race with
> > CPUHP.
> > 
> > And assuming this series will be applied after Sean's VMXON series, we will
> 
> Yes.
> 
> > have a TDX-specific CPUHP callback tdx_online_cpu() in TDX x86 core to do
> > tdx_cpu_enable(), which will then enable TDX again on the new-online CPU.
> 
> Good point.
> 
> Clearing tdx_lp_initialized for offlined CPUs makes sense, but I'd rather not
> justify this through "enabling TDX on new-online CPUs" since many details
> remain unclear. For example, there will be a SEAMCALL to disable TDX per-CPU.

Sorry which SEAMCALL are you referring to?

> It should be called when CPUs go offline so that those CPUs can be exempting
> from doing SEAMLDR.INSTALL during module updates. tdx_lp_initialized should
> have been cleared along with that "disable TDX per-CPU" SEAMCALL for offlined
> CPUs.

Hmm.. It sounds like we are missing some background here.  Could you
elaborate what are the steps to update module on a subset of CPUs?


^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 06/22] coco/tdx-host: Expose P-SEAMLDR information via sysfs
  2026-03-17 10:06   ` Kiryl Shutsemau
@ 2026-03-17 15:34     ` Dave Hansen
  2026-03-18  6:54     ` Chao Gao
  1 sibling, 0 replies; 80+ messages in thread
From: Dave Hansen @ 2026-03-17 15:34 UTC (permalink / raw)
  To: Kiryl Shutsemau, Chao Gao
  Cc: x86, linux-coco, kvm, linux-kernel, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu

On 3/17/26 03:06, Kiryl Shutsemau wrote:
>> +	return sysfs_emit(buf, "%u.%u.%02u\n", info.major_version,
>> +					       info.minor_version,
>> +					       info.update_version);
> Maybe a comment why %02u used for update_version?

Could we just stick this in a:

#define TDX_VERSION_FMT	"%u.%u.%02u"

and document it there, once and for all?

Users can do:

	return sysfs_emit(buf, TDX_VERSION_FMT "\n", ...

There are going to be a couple of these, I expect.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 06/22] coco/tdx-host: Expose P-SEAMLDR information via sysfs
  2026-03-17 10:06   ` Kiryl Shutsemau
  2026-03-17 15:34     ` Dave Hansen
@ 2026-03-18  6:54     ` Chao Gao
  2026-03-18  8:20       ` Xiaoyao Li
  1 sibling, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-18  6:54 UTC (permalink / raw)
  To: Kiryl Shutsemau
  Cc: x86, linux-coco, kvm, linux-kernel, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu

>> +
>> +What:		/sys/devices/faux/tdx_host/seamldr/version
>> +Contact:	linux-coco@lists.linux.dev
>> +Description:	(RO) Report the version of the loaded SEAM loader. The SEAM
>> +		loader version is formatted as x.y.z, where "x" is the major
>> +		version, "y" is the minor version and "z" is the update version.
>> +		Versions are used for bug reporting and compatibility checks.
>> +
>> +What:		/sys/devices/faux/tdx_host/seamldr/num_remaining_updates
>> +Contact:	linux-coco@lists.linux.dev
>> +Description:	(RO) Report the number of remaining updates. TDX maintains a
>> +		log about each TDX module that has been loaded. This log has
>> +		a finite size, which limits the number of TDX module updates
>> +		that can be performed.
>> +
>> +		After each successful update, the number reduces by one. Once it
>> +		reaches zero, further updates will fail until next reboot. The
>> +		number is always zero if the P-SEAMLDR doesn't support updates.
>> +
>> +		See Intel® Trust Domain Extensions - SEAM Loader (SEAMLDR)
>> +		Interface Specification, Revision 343755-003, Chapter 3.3
>> +		"SEAMLDR_INFO" and Chapter 4.2 "SEAMLDR.INSTALL" for more
>> +		information.
>
>Do you think revision and chapter numbers useful here?

I think it's nice-to-have. Without specific references, people would need to
read the entire 26-page spec. But I can drop them if they make it too verbose.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 04/22] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs
  2026-03-15 13:58 ` [PATCH v5 04/22] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs Chao Gao
  2026-03-16 13:05   ` Kiryl Shutsemau
@ 2026-03-18  7:13   ` Xiaoyao Li
  2026-03-18  9:34     ` Chao Gao
  2026-03-18 21:38   ` Huang, Kai
  2 siblings, 1 reply; 80+ messages in thread
From: Xiaoyao Li @ 2026-03-18  7:13 UTC (permalink / raw)
  To: Chao Gao, linux-kernel, linux-coco, kvm
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Farrah Chen, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, x86, H. Peter Anvin

On 3/15/2026 9:58 PM, Chao Gao wrote:
> The TDX architecture uses the "SEAMCALL" instruction to communicate with
> SEAM mode software. Right now, the only SEAM mode software that the kernel
> communicates with is the TDX module. But, there is actually another
> component that runs in SEAM mode but it is separate from the TDX module:
> the persistent SEAM loader or "P-SEAMLDR". Right now, the only component
> that communicates with it is the BIOS which loads the TDX module itself at
> boot. But, to support updating the TDX module, the kernel now needs to be
> able to talk to it.
> 
> P-SEAMLDR SEAMCALLs differ from TDX module SEAMCALLs in areas such as
> concurrency requirements. Add a P-SEAMLDR wrapper to handle these
> differences and prepare for implementing concrete functions.
> 
> Note that unlike P-SEAMLDR, there is also a non-persistent SEAM loader
> ("NP-SEAMLDR"). This is an authenticated code module (ACM) that is not
> callable at runtime. Only BIOS launches it to load P-SEAMLDR at boot;
> the kernel does not need to interact with it for runtime update.
> 
> For details of P-SEAMLDR SEAMCALLs, see Intel® Trust Domain CPU
> Architectural Extensions, Revision 343754-002, Chapter 2.3 "INSTRUCTION
> SET REFERENCE".

SDM started to contain SEAMCALL definitions. How about just dropping 
this paragraph to avoid people from reading the old doc?

...

> +static __maybe_unused int seamldr_call(u64 fn, struct tdx_module_args *args)
> +{
> +	guard(raw_spinlock)(&seamldr_lock);
> +	return seamcall_prerr(fn, args);

How about adding the reason of why choosing seamcall_prerr() instead of 
seamcall_prerr_ret() in the changelog?



^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 05/22] x86/virt/seamldr: Retrieve P-SEAMLDR information
  2026-03-15 13:58 ` [PATCH v5 05/22] x86/virt/seamldr: Retrieve P-SEAMLDR information Chao Gao
  2026-03-16 13:12   ` Kiryl Shutsemau
@ 2026-03-18  7:53   ` Xiaoyao Li
  2026-03-18  8:57     ` Chao Gao
  2026-03-18 21:40   ` Huang, Kai
  2 siblings, 1 reply; 80+ messages in thread
From: Xiaoyao Li @ 2026-03-18  7:53 UTC (permalink / raw)
  To: Chao Gao, linux-kernel, linux-coco, kvm
  Cc: binbin.wu, dan.j.williams, dave.hansen, ira.weiny, kai.huang, kas,
	nik.borisov, paulmck, pbonzini, reinette.chatre, rick.p.edgecombe,
	sagis, seanjc, tony.lindgren, vannapurve, vishal.l.verma,
	yilun.xu, Farrah Chen, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, x86, H. Peter Anvin

On 3/15/2026 9:58 PM, Chao Gao wrote:
> P-SEAMLDR returns its information such as version number, in response to
> the SEAMLDR.INFO SEAMCALL.
> 
> This information is useful for userspace. For example, the admin can decide
> which TDX module versions are compatible with the P-SEAMLDR according to
> the P-SEAMLDR version.
> 
> Retrieve P-SEAMLDR information in preparation for exposing P-SEAMLDR

This patch only implements the function but nowhere calls it. Please 
adjust the wording and the PATCH subject.

...

> +
> +/*
> + * This is called the "SEAMLDR_INFO" data structure and is defined

I'm curious why you changed "This called" to "This is called" in this 
v5. In v4[1] you just used what Dave provided to v3[2]

[1] https://lore.kernel.org/kvm/20260212143606.534586-6-chao.gao@intel.com/
[2] 
https://lore.kernel.org/all/b2e2fd5e-8aff-4eda-a648-9ae9f8234d25@intel.com/

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 06/22] coco/tdx-host: Expose P-SEAMLDR information via sysfs
  2026-03-18  6:54     ` Chao Gao
@ 2026-03-18  8:20       ` Xiaoyao Li
  2026-03-18  9:10         ` Chao Gao
  0 siblings, 1 reply; 80+ messages in thread
From: Xiaoyao Li @ 2026-03-18  8:20 UTC (permalink / raw)
  To: Chao Gao, Kiryl Shutsemau
  Cc: x86, linux-coco, kvm, linux-kernel, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu

On 3/18/2026 2:54 PM, Chao Gao wrote:
>>> +
>>> +What:		/sys/devices/faux/tdx_host/seamldr/version
>>> +Contact:	linux-coco@lists.linux.dev
>>> +Description:	(RO) Report the version of the loaded SEAM loader. The SEAM
>>> +		loader version is formatted as x.y.z, where "x" is the major
>>> +		version, "y" is the minor version and "z" is the update version.
>>> +		Versions are used for bug reporting and compatibility checks.
>>> +
>>> +What:		/sys/devices/faux/tdx_host/seamldr/num_remaining_updates
>>> +Contact:	linux-coco@lists.linux.dev
>>> +Description:	(RO) Report the number of remaining updates. TDX maintains a
>>> +		log about each TDX module that has been loaded. This log has
>>> +		a finite size, which limits the number of TDX module updates
>>> +		that can be performed.
>>> +
>>> +		After each successful update, the number reduces by one. Once it
>>> +		reaches zero, further updates will fail until next reboot. The
>>> +		number is always zero if the P-SEAMLDR doesn't support updates.
>>> +
>>> +		See Intel® Trust Domain Extensions - SEAM Loader (SEAMLDR)
>>> +		Interface Specification, Revision 343755-003, Chapter 3.3
>>> +		"SEAMLDR_INFO" and Chapter 4.2 "SEAMLDR.INSTALL" for more
>>> +		information.
>>
>> Do you think revision and chapter numbers useful here?
> 
> I think it's nice-to-have. Without specific references, people would need to
> read the entire 26-page spec. But I can drop them if they make it too verbose.

I have some concerns about the "revision". The good thing is that it can 
tell what the attribute was built against while the bad thing is that it 
might not be easy for people to find an old revision years later.


^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 07/22] coco/tdx-host: Implement firmware upload sysfs ABI for TDX module updates
  2026-03-17 10:20   ` Kiryl Shutsemau
@ 2026-03-18  8:28     ` Chao Gao
  0 siblings, 0 replies; 80+ messages in thread
From: Chao Gao @ 2026-03-18  8:28 UTC (permalink / raw)
  To: Kiryl Shutsemau
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

>> Signed-off-by: Chao Gao <chao.gao@intel.com>
>> Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
>
>Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>

Thanks a lot for your reviews.

<snip>

>>  static int seamldr_init(struct device *dev)
>>  {
>> +	const struct tdx_sys_info *tdx_sysinfo = tdx_get_sysinfo();
>> +	struct fw_upload *tdx_fwl;
>> +	int ret;
>> +
>> +	if (WARN_ON_ONCE(!tdx_sysinfo))
>> +		return -EIO;
>> +
>> +	if (!tdx_supports_runtime_update(tdx_sysinfo))
>> +		return 0;
>
>Hm. Do we still want to register seamldr_group for this case?

seamldr_group currently serves only module updates, so registering it when
updates aren't supported seems unnecessary.

>
>Maybe move it up before the check?

If new use cases emerge and need seamldr version etc, we can do the
changes.

FWIW, seamldr_group visibility does matter in one case: it must be
hidden on CPUs with an erratum (see
https://lore.kernel.org/kvm/20260315135920.354657-19-chao.gao@intel.com/)

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 08/22] x86/virt/seamldr: Allocate and populate a module update request
  2026-03-17 10:59   ` Kiryl Shutsemau
@ 2026-03-18  8:50     ` Chao Gao
  2026-03-18 10:58       ` Kiryl Shutsemau
  0 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-18  8:50 UTC (permalink / raw)
  To: Kiryl Shutsemau
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

>> +	ptr = sig;
>> +	for (i = 0; i < sig_size / SZ_4K; i++) {
>> +		/*
>> +		 * Don't assume @sig is page-aligned although it is 4KB-aligned.
>> +		 * Always add the in-page offset to get the physical address.
>> +		 */
>
>I don't follow this. If @sig is 4k aligned in VA, it is page aligned.

Dan's concern was that PAGE_SIZE is not guaranteed to be 4096.

I agree that PAGE_SIZE is 4K on x86 today. But to address that concern, I saw
two options:

  1. Add WARN_ON_ONCE(PAGE_SIZE != SZ_4K), or
  2. Handle it as in the code above.

I didn't find existing code using option 1 in x86, so I chose option 2.

>
>If you want to handle case when @sig is not 4k aligned, than this is
>broken. You need to bump ptr to the next 4k boundary, not by 4k.

@sig is 4KB aligned.

<snip>

>> +static struct seamldr_params *init_seamldr_params(const u8 *data, u32 size)
>> +{
>> +	const struct tdx_blob *blob = (const void *)data;
>> +	int module_size, sig_size;
>> +	const void *sig, *module;
>> +
>> +	/* Ensure the size is valid otherwise reading any field from the blob may overflow. */
>> +	if (size <= sizeof(struct tdx_blob) || size <= blob->offset_of_module)
>> +		return ERR_PTR(-EINVAL);
>> +
>> +	if (blob->version != TDX_BLOB_VERSION_1) {
>> +		pr_err("unsupported blob version: %x\n", blob->version);
>> +		return ERR_PTR(-EINVAL);
>> +	}
>> +
>> +	/* Split the blob into a sigstruct and a module. */
>> +	sig		= blob->data;
>> +	sig_size	= blob->offset_of_module - sizeof(struct tdx_blob);
>> +	module		= data + blob->offset_of_module;
>> +	module_size	= size - blob->offset_of_module;
>> +
>> +	if (sig_size <= 0 || module_size <= 0 || blob->length != size)
>> +		return ERR_PTR(-EINVAL);
>
>Maybe add a comment somewhere that block->offset_of_module is relative
>to start of struct tdx_blob, not blob->data and blob->length includes
>length of struct tdx_blob.
>
>It can be either way and it is better to give a reader a hint.

Sure. Will do.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 05/22] x86/virt/seamldr: Retrieve P-SEAMLDR information
  2026-03-18  7:53   ` Xiaoyao Li
@ 2026-03-18  8:57     ` Chao Gao
  0 siblings, 0 replies; 80+ messages in thread
From: Chao Gao @ 2026-03-18  8:57 UTC (permalink / raw)
  To: Xiaoyao Li
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, kas, nik.borisov, paulmck,
	pbonzini, reinette.chatre, rick.p.edgecombe, sagis, seanjc,
	tony.lindgren, vannapurve, vishal.l.verma, yilun.xu, Farrah Chen,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
	H. Peter Anvin

On Wed, Mar 18, 2026 at 03:53:26PM +0800, Xiaoyao Li wrote:
>On 3/15/2026 9:58 PM, Chao Gao wrote:
>> P-SEAMLDR returns its information such as version number, in response to
>> the SEAMLDR.INFO SEAMCALL.
>> 
>> This information is useful for userspace. For example, the admin can decide
>> which TDX module versions are compatible with the P-SEAMLDR according to
>> the P-SEAMLDR version.
>> 
>> Retrieve P-SEAMLDR information in preparation for exposing P-SEAMLDR
>
>This patch only implements the function but nowhere calls it. Please adjust
>the wording and the PATCH subject.

How about:

	Add a helper to retrieve ...?

>
>...
>
>> +
>> +/*
>> + * This is called the "SEAMLDR_INFO" data structure and is defined
>
>I'm curious why you changed "This called" to "This is called" in this v5. In
>v4[1] you just used what Dave provided to v3[2]

I ran the patches through Copilot before posting, and it flagged "This called"
as a typo, so I fixed it.

>
>[1] https://lore.kernel.org/kvm/20260212143606.534586-6-chao.gao@intel.com/
>[2]
>https://lore.kernel.org/all/b2e2fd5e-8aff-4eda-a648-9ae9f8234d25@intel.com/

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 06/22] coco/tdx-host: Expose P-SEAMLDR information via sysfs
  2026-03-18  8:20       ` Xiaoyao Li
@ 2026-03-18  9:10         ` Chao Gao
  2026-03-18  9:28           ` Kiryl Shutsemau
  0 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-18  9:10 UTC (permalink / raw)
  To: Xiaoyao Li
  Cc: Kiryl Shutsemau, x86, linux-coco, kvm, linux-kernel, binbin.wu,
	dan.j.williams, dave.hansen, ira.weiny, kai.huang, nik.borisov,
	paulmck, pbonzini, reinette.chatre, rick.p.edgecombe, sagis,
	seanjc, tony.lindgren, vannapurve, vishal.l.verma, yilun.xu

On Wed, Mar 18, 2026 at 04:20:54PM +0800, Xiaoyao Li wrote:
>On 3/18/2026 2:54 PM, Chao Gao wrote:
>> > > +
>> > > +What:		/sys/devices/faux/tdx_host/seamldr/version
>> > > +Contact:	linux-coco@lists.linux.dev
>> > > +Description:	(RO) Report the version of the loaded SEAM loader. The SEAM
>> > > +		loader version is formatted as x.y.z, where "x" is the major
>> > > +		version, "y" is the minor version and "z" is the update version.
>> > > +		Versions are used for bug reporting and compatibility checks.
>> > > +
>> > > +What:		/sys/devices/faux/tdx_host/seamldr/num_remaining_updates
>> > > +Contact:	linux-coco@lists.linux.dev
>> > > +Description:	(RO) Report the number of remaining updates. TDX maintains a
>> > > +		log about each TDX module that has been loaded. This log has
>> > > +		a finite size, which limits the number of TDX module updates
>> > > +		that can be performed.
>> > > +
>> > > +		After each successful update, the number reduces by one. Once it
>> > > +		reaches zero, further updates will fail until next reboot. The
>> > > +		number is always zero if the P-SEAMLDR doesn't support updates.
>> > > +
>> > > +		See Intel® Trust Domain Extensions - SEAM Loader (SEAMLDR)
>> > > +		Interface Specification, Revision 343755-003, Chapter 3.3
>> > > +		"SEAMLDR_INFO" and Chapter 4.2 "SEAMLDR.INSTALL" for more
>> > > +		information.
>> > 
>> > Do you think revision and chapter numbers useful here?
>> 
>> I think it's nice-to-have. Without specific references, people would need to
>> read the entire 26-page spec. But I can drop them if they make it too verbose.
>
>I have some concerns about the "revision". The good thing is that it can tell
>what the attribute was built against while the bad thing is that it might not
>be easy for people to find an old revision years later.

I'm okay with dropping the revision number.

The intent is not to require readers to find the exact same revision. If they
can find that exact revision, great. If not, the chapter numbers may differ
in newer revisions.

Kirill, do you mean dropping the numbers but keeping the chapter titles:

		See Intel® Trust Domain Extensions - SEAM Loader (SEAMLDR)
		Interface Specification, Chapter "SEAMLDR_INFO" and Chapter
		"SEAMLDR.INSTALL" for more information.

This keeps a targeted reference so readers do not need to scan the entire spec.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 06/22] coco/tdx-host: Expose P-SEAMLDR information via sysfs
  2026-03-18  9:10         ` Chao Gao
@ 2026-03-18  9:28           ` Kiryl Shutsemau
  0 siblings, 0 replies; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-18  9:28 UTC (permalink / raw)
  To: Chao Gao
  Cc: Xiaoyao Li, x86, linux-coco, kvm, linux-kernel, binbin.wu,
	dan.j.williams, dave.hansen, ira.weiny, kai.huang, nik.borisov,
	paulmck, pbonzini, reinette.chatre, rick.p.edgecombe, sagis,
	seanjc, tony.lindgren, vannapurve, vishal.l.verma, yilun.xu

On Wed, Mar 18, 2026 at 05:10:21PM +0800, Chao Gao wrote:
> On Wed, Mar 18, 2026 at 04:20:54PM +0800, Xiaoyao Li wrote:
> >On 3/18/2026 2:54 PM, Chao Gao wrote:
> >> > > +
> >> > > +What:		/sys/devices/faux/tdx_host/seamldr/version
> >> > > +Contact:	linux-coco@lists.linux.dev
> >> > > +Description:	(RO) Report the version of the loaded SEAM loader. The SEAM
> >> > > +		loader version is formatted as x.y.z, where "x" is the major
> >> > > +		version, "y" is the minor version and "z" is the update version.
> >> > > +		Versions are used for bug reporting and compatibility checks.
> >> > > +
> >> > > +What:		/sys/devices/faux/tdx_host/seamldr/num_remaining_updates
> >> > > +Contact:	linux-coco@lists.linux.dev
> >> > > +Description:	(RO) Report the number of remaining updates. TDX maintains a
> >> > > +		log about each TDX module that has been loaded. This log has
> >> > > +		a finite size, which limits the number of TDX module updates
> >> > > +		that can be performed.
> >> > > +
> >> > > +		After each successful update, the number reduces by one. Once it
> >> > > +		reaches zero, further updates will fail until next reboot. The
> >> > > +		number is always zero if the P-SEAMLDR doesn't support updates.
> >> > > +
> >> > > +		See Intel® Trust Domain Extensions - SEAM Loader (SEAMLDR)
> >> > > +		Interface Specification, Revision 343755-003, Chapter 3.3
> >> > > +		"SEAMLDR_INFO" and Chapter 4.2 "SEAMLDR.INSTALL" for more
> >> > > +		information.
> >> > 
> >> > Do you think revision and chapter numbers useful here?
> >> 
> >> I think it's nice-to-have. Without specific references, people would need to
> >> read the entire 26-page spec. But I can drop them if they make it too verbose.
> >
> >I have some concerns about the "revision". The good thing is that it can tell
> >what the attribute was built against while the bad thing is that it might not
> >be easy for people to find an old revision years later.
> 
> I'm okay with dropping the revision number.
> 
> The intent is not to require readers to find the exact same revision. If they
> can find that exact revision, great. If not, the chapter numbers may differ
> in newer revisions.
> 
> Kirill, do you mean dropping the numbers but keeping the chapter titles:
> 
> 		See Intel® Trust Domain Extensions - SEAM Loader (SEAMLDR)
> 		Interface Specification, Chapter "SEAMLDR_INFO" and Chapter
> 		"SEAMLDR.INSTALL" for more information.
> 
> This keeps a targeted reference so readers do not need to scan the entire spec.

Yeah, looks good to me.

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 04/22] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs
  2026-03-18  7:13   ` Xiaoyao Li
@ 2026-03-18  9:34     ` Chao Gao
  2026-03-19  3:02       ` Xiaoyao Li
  0 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-18  9:34 UTC (permalink / raw)
  To: Xiaoyao Li
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, kas, nik.borisov, paulmck,
	pbonzini, reinette.chatre, rick.p.edgecombe, sagis, seanjc,
	tony.lindgren, vannapurve, vishal.l.verma, yilun.xu, Farrah Chen,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
	H. Peter Anvin

On Wed, Mar 18, 2026 at 03:13:06PM +0800, Xiaoyao Li wrote:
>On 3/15/2026 9:58 PM, Chao Gao wrote:
>> The TDX architecture uses the "SEAMCALL" instruction to communicate with
>> SEAM mode software. Right now, the only SEAM mode software that the kernel
>> communicates with is the TDX module. But, there is actually another
>> component that runs in SEAM mode but it is separate from the TDX module:
>> the persistent SEAM loader or "P-SEAMLDR". Right now, the only component
>> that communicates with it is the BIOS which loads the TDX module itself at
>> boot. But, to support updating the TDX module, the kernel now needs to be
>> able to talk to it.
>> 
>> P-SEAMLDR SEAMCALLs differ from TDX module SEAMCALLs in areas such as
>> concurrency requirements. Add a P-SEAMLDR wrapper to handle these
>> differences and prepare for implementing concrete functions.
>> 
>> Note that unlike P-SEAMLDR, there is also a non-persistent SEAM loader
>> ("NP-SEAMLDR"). This is an authenticated code module (ACM) that is not
>> callable at runtime. Only BIOS launches it to load P-SEAMLDR at boot;
>> the kernel does not need to interact with it for runtime update.
>> 
>> For details of P-SEAMLDR SEAMCALLs, see Intel® Trust Domain CPU
>> Architectural Extensions, Revision 343754-002, Chapter 2.3 "INSTRUCTION
>> SET REFERENCE".
>
>SDM started to contain SEAMCALL definitions. How about just dropping this
>paragraph to avoid people from reading the old doc?

I didn't realize that. Thanks for the information.

But I don't think this is a stale reference. The SDM description is high-level
and points to the same spec for details:

  The details of such transitions are specified in the Intel® Trust Domain CPU
  Architectural Extensions.

>
>...
>
>> +static __maybe_unused int seamldr_call(u64 fn, struct tdx_module_args *args)
>> +{
>> +	guard(raw_spinlock)(&seamldr_lock);
>> +	return seamcall_prerr(fn, args);
>
>How about adding the reason of why choosing seamcall_prerr() instead of
>seamcall_prerr_ret() in the changelog?

Sure. Will add:

Use seamcall_prerr() (not '_ret') because current P-SEAMLDR calls do not use
any output registers other than RAX.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 08/22] x86/virt/seamldr: Allocate and populate a module update request
  2026-03-18  8:50     ` Chao Gao
@ 2026-03-18 10:58       ` Kiryl Shutsemau
  2026-03-19  7:24         ` Chao Gao
  0 siblings, 1 reply; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-18 10:58 UTC (permalink / raw)
  To: Chao Gao
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

On Wed, Mar 18, 2026 at 04:50:34PM +0800, Chao Gao wrote:
> >> +	ptr = sig;
> >> +	for (i = 0; i < sig_size / SZ_4K; i++) {
> >> +		/*
> >> +		 * Don't assume @sig is page-aligned although it is 4KB-aligned.
> >> +		 * Always add the in-page offset to get the physical address.
> >> +		 */
> >
> >I don't follow this. If @sig is 4k aligned in VA, it is page aligned.
> 
> Dan's concern was that PAGE_SIZE is not guaranteed to be 4096.
> 
> I agree that PAGE_SIZE is 4K on x86 today. But to address that concern, I saw
> two options:
> 
>   1. Add WARN_ON_ONCE(PAGE_SIZE != SZ_4K), or
>   2. Handle it as in the code above.
> 
> I didn't find existing code using option 1 in x86, so I chose option 2.

Please, make it clear in the comment that you are talking about PAGE_SIZE != SZ_4K.

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 08/22] x86/virt/seamldr: Allocate and populate a module update request
  2026-03-15 13:58 ` [PATCH v5 08/22] x86/virt/seamldr: Allocate and populate a module update request Chao Gao
  2026-03-17 10:59   ` Kiryl Shutsemau
@ 2026-03-18 21:36   ` Huang, Kai
  1 sibling, 0 replies; 80+ messages in thread
From: Huang, Kai @ 2026-03-18 21:36 UTC (permalink / raw)
  To: kvm@vger.kernel.org, linux-coco@lists.linux.dev,
	linux-kernel@vger.kernel.org, Gao, Chao
  Cc: x86@kernel.org, dave.hansen@linux.intel.com, kas@kernel.org,
	seanjc@google.com, Chatre, Reinette, Weiny, Ira,
	binbin.wu@linux.intel.com, Verma, Vishal L, nik.borisov@suse.com,
	mingo@redhat.com, pbonzini@redhat.com,
	tony.lindgren@linux.intel.com, sagis@google.com,
	Annapurve, Vishal, hpa@zytor.com, Edgecombe, Rick P,
	paulmck@kernel.org, tglx@kernel.org, yilun.xu@linux.intel.com,
	Williams, Dan J, bp@alien8.de

On Sun, 2026-03-15 at 06:58 -0700, Chao Gao wrote:
> P-SEAMLDR uses the SEAMLDR_PARAMS structure to describe TDX module
> update requests. This structure contains physical addresses pointing to
> the module binary and its signature file (or sigstruct), along with an
> update scenario field.
> 
> TDX modules are distributed in the tdx_blob format defined in
> blob_structure.txt from the "Intel TDX module Binaries Repository". A
> tdx_blob contains a header, sigstruct, and module binary. This is also the
> format supplied by the userspace to the kernel.
> 
> Parse the tdx_blob format and populate a SEAMLDR_PARAMS structure
> accordingly. This structure will be passed to P-SEAMLDR to initiate the
> update.
> 
> Note that the sigstruct_pa field in SEAMLDR_PARAMS has been extended to
> a 4-element array. The updated "SEAM Loader (SEAMLDR) Interface
> Specification" will be published separately. P-SEAMLDR compatibility
> validation (such as 4KB vs 16KB sigstruct support) is left to userspace,
> which must verify the P-SEAMLDR version meets the TDX module's minimum
> requirements.
> 
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
> Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
> 

Reviewed-by: Kai Huang <kai.huang@intel.com>

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 03/22] coco/tdx-host: Expose TDX module version
  2026-03-15 13:58 ` [PATCH v5 03/22] coco/tdx-host: Expose TDX module version Chao Gao
  2026-03-16 12:54   ` Kiryl Shutsemau
@ 2026-03-18 21:37   ` Huang, Kai
  1 sibling, 0 replies; 80+ messages in thread
From: Huang, Kai @ 2026-03-18 21:37 UTC (permalink / raw)
  To: kvm@vger.kernel.org, linux-coco@lists.linux.dev,
	linux-kernel@vger.kernel.org, Gao, Chao, x86@kernel.org
  Cc: dave.hansen@linux.intel.com, kas@kernel.org, seanjc@google.com,
	Chatre, Reinette, Weiny, Ira, binbin.wu@linux.intel.com,
	Verma, Vishal L, nik.borisov@suse.com, pbonzini@redhat.com,
	tony.lindgren@linux.intel.com, sagis@google.com,
	Annapurve, Vishal, Edgecombe, Rick P, paulmck@kernel.org,
	yilun.xu@linux.intel.com, Williams, Dan J

On Sun, 2026-03-15 at 06:58 -0700, Chao Gao wrote:
> For TDX module updates, userspace needs to select compatible update
> versions based on the current module version. This design delegates
> module selection complexity to userspace because TDX module update
> policies are complex and version series are platform-specific.
> 
> For example, the 1.5.x series is for certain platform generations, while
> the 2.0.x series is intended for others. And TDX module 1.5.x may be
> updated to 1.5.y but not to 1.5.y+1.
> 
> Expose the TDX module version to userspace via sysfs to aid module
> selection. Since the TDX faux device will drive module updates, expose
> the version as its attribute.
> 
> One bonus of exposing TDX module version via sysfs is: TDX module
> version information remains available even after dmesg logs are cleared.
> 
> == Background ==
> 
> The "faux device + device attribute" approach compares to other update
> mechanisms as follows:
> 
> 1. AMD SEV leverages an existing PCI device for the PSP to expose
>    metadata. TDX uses a faux device as it doesn't have PCI device
>    in its architecture.
> 
> 2. Microcode uses per-CPU virtual devices to report microcode revisions
>    because CPUs can have different revisions. But, there is only a
>    single TDX module, so exposing the TDX module version through a global
>    TDX faux device is appropriate
> 
> 3. ARM's CCA implementation isn't in-tree yet, but will likely follow a
>    similar faux device approach, though it's unclear whether they need
>    to expose firmware version information
> 
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
> Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
> Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
> Link: https://lore.kernel.org/all/2025073035-bulginess-rematch-b92e@gregkh/ # [1]
> 

Reviewed-by: Kai Huang <kai.huang@intel.com>

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 04/22] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs
  2026-03-15 13:58 ` [PATCH v5 04/22] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs Chao Gao
  2026-03-16 13:05   ` Kiryl Shutsemau
  2026-03-18  7:13   ` Xiaoyao Li
@ 2026-03-18 21:38   ` Huang, Kai
  2 siblings, 0 replies; 80+ messages in thread
From: Huang, Kai @ 2026-03-18 21:38 UTC (permalink / raw)
  To: kvm@vger.kernel.org, linux-coco@lists.linux.dev,
	linux-kernel@vger.kernel.org, Gao, Chao
  Cc: x86@kernel.org, dave.hansen@linux.intel.com, kas@kernel.org,
	seanjc@google.com, Chatre, Reinette, Weiny, Ira,
	binbin.wu@linux.intel.com, Verma, Vishal L, nik.borisov@suse.com,
	mingo@redhat.com, pbonzini@redhat.com,
	tony.lindgren@linux.intel.com, sagis@google.com,
	Annapurve, Vishal, Chen, Farrah, Edgecombe, Rick P,
	paulmck@kernel.org, hpa@zytor.com, tglx@kernel.org,
	yilun.xu@linux.intel.com, Williams, Dan J, bp@alien8.de

On Sun, 2026-03-15 at 06:58 -0700, Chao Gao wrote:
> The TDX architecture uses the "SEAMCALL" instruction to communicate with
> SEAM mode software. Right now, the only SEAM mode software that the kernel
> communicates with is the TDX module. But, there is actually another
> component that runs in SEAM mode but it is separate from the TDX module:
> the persistent SEAM loader or "P-SEAMLDR". Right now, the only component
> that communicates with it is the BIOS which loads the TDX module itself at
> boot. But, to support updating the TDX module, the kernel now needs to be
> able to talk to it.
> 
> P-SEAMLDR SEAMCALLs differ from TDX module SEAMCALLs in areas such as
> concurrency requirements. Add a P-SEAMLDR wrapper to handle these
> differences and prepare for implementing concrete functions.
> 
> Note that unlike P-SEAMLDR, there is also a non-persistent SEAM loader
> ("NP-SEAMLDR"). This is an authenticated code module (ACM) that is not
> callable at runtime. Only BIOS launches it to load P-SEAMLDR at boot;
> the kernel does not need to interact with it for runtime update.
> 
> For details of P-SEAMLDR SEAMCALLs, see Intel® Trust Domain CPU
> Architectural Extensions, Revision 343754-002, Chapter 2.3 "INSTRUCTION
> SET REFERENCE".
> 
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Reviewed-by: Binbin Wu <binbin.wu@linux.intel.com>
> Tested-by: Farrah Chen <farrah.chen@intel.com>
> Link: https://cdrdv2.intel.com/v1/dl/getContent/733582 # [1]

Reviewed-by: Kai Huang <kai.huang@intel.com>

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 05/22] x86/virt/seamldr: Retrieve P-SEAMLDR information
  2026-03-15 13:58 ` [PATCH v5 05/22] x86/virt/seamldr: Retrieve P-SEAMLDR information Chao Gao
  2026-03-16 13:12   ` Kiryl Shutsemau
  2026-03-18  7:53   ` Xiaoyao Li
@ 2026-03-18 21:40   ` Huang, Kai
  2 siblings, 0 replies; 80+ messages in thread
From: Huang, Kai @ 2026-03-18 21:40 UTC (permalink / raw)
  To: kvm@vger.kernel.org, linux-coco@lists.linux.dev,
	linux-kernel@vger.kernel.org, Gao, Chao
  Cc: x86@kernel.org, dave.hansen@linux.intel.com, kas@kernel.org,
	seanjc@google.com, Chatre, Reinette, Weiny, Ira,
	binbin.wu@linux.intel.com, Verma, Vishal L, nik.borisov@suse.com,
	mingo@redhat.com, pbonzini@redhat.com,
	tony.lindgren@linux.intel.com, sagis@google.com,
	Annapurve, Vishal, Chen, Farrah, Edgecombe, Rick P,
	paulmck@kernel.org, hpa@zytor.com, tglx@kernel.org,
	yilun.xu@linux.intel.com, Williams, Dan J, bp@alien8.de

On Sun, 2026-03-15 at 06:58 -0700, Chao Gao wrote:
> P-SEAMLDR returns its information such as version number, in response to
> the SEAMLDR.INFO SEAMCALL.
> 
> This information is useful for userspace. For example, the admin can decide
> which TDX module versions are compatible with the P-SEAMLDR according to
> the P-SEAMLDR version.
> 
> Retrieve P-SEAMLDR information in preparation for exposing P-SEAMLDR
> version and other necessary information to userspace. Export the new kAPI
> for use by tdx-host.ko.
> 
> Note that there are two distinct P-SEAMLDR APIs with similar names:
> 
>   SEAMLDR.INFO: Returns a SEAMLDR_INFO structure containing SEAMLDR
>                 information such as version and remaining updates.
> 
>   SEAMLDR.SEAMINFO: Returns a SEAMLDR_SEAMINFO structure containing SEAM
>                     and system information such as Convertible Memory
> 		    Regions (CMRs) and number of CPUs and sockets.
> 
> The former is used here.
> 
> For details, see "Intel® Trust Domain Extensions - SEAM Loader (SEAMLDR)
> Interface Specification" revision 343755-003.
> 
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Tested-by: Farrah Chen <farrah.chen@intel.com>
> 

Reviewed-by: Kai Huang <kai.huang@intel.com>

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 07/22] coco/tdx-host: Implement firmware upload sysfs ABI for TDX module updates
  2026-03-15 13:58 ` [PATCH v5 07/22] coco/tdx-host: Implement firmware upload sysfs ABI for TDX module updates Chao Gao
  2026-03-17 10:20   ` Kiryl Shutsemau
@ 2026-03-18 21:45   ` Huang, Kai
  1 sibling, 0 replies; 80+ messages in thread
From: Huang, Kai @ 2026-03-18 21:45 UTC (permalink / raw)
  To: kvm@vger.kernel.org, linux-coco@lists.linux.dev,
	linux-kernel@vger.kernel.org, Gao, Chao
  Cc: x86@kernel.org, dave.hansen@linux.intel.com, kas@kernel.org,
	seanjc@google.com, Chatre, Reinette, Weiny, Ira,
	binbin.wu@linux.intel.com, Verma, Vishal L, nik.borisov@suse.com,
	mingo@redhat.com, pbonzini@redhat.com,
	tony.lindgren@linux.intel.com, sagis@google.com,
	Annapurve, Vishal, hpa@zytor.com, Edgecombe, Rick P,
	paulmck@kernel.org, tglx@kernel.org, yilun.xu@linux.intel.com,
	Williams, Dan J, bp@alien8.de

On Sun, 2026-03-15 at 06:58 -0700, Chao Gao wrote:
> Linux kernel supports two primary firmware update mechanisms:
>   - request_firmware()
>   - firmware upload (or fw_upload)
> 
> The former is used by microcode updates, SEV firmware updates, etc. The
> latter is used by CXL and FPGA firmware updates.
> 
> One key difference between them is: request_firmware() loads a named
> file from the filesystem where the filename is kernel-controlled, while
> fw_upload accepts firmware data directly from userspace.
> 
> Use fw_upload for TDX module updates as loading a named file isn't
> suitable for TDX (see below for more reasons). Specifically, register
> TDX faux device with fw_upload framework to expose sysfs interfaces
> and implement operations to process data blobs supplied by userspace.
> 
> Implementation notes:
> 1. P-SEAMLDR processes the entire update at once rather than
>    chunk-by-chunk, so .write() is called only once per update; so the
>    offset should be always 0.
> 2. An update completes synchronously within .write(), meaning
>    .poll_complete() is only called after the update succeeds and so always
>    returns success
> 
> Why fw_upload instead of request_firmware()?
> ============================================
> The explicit file selection capabilities of fw_upload is preferred over
> the implicit file selection of request_firmware() for the following
> reasons:
> 
> a. Intel distributes all versions of the TDX module, allowing admins to
> load any version rather than always defaulting to the latest. This
> flexibility is necessary because future extensions may require reverting to
> a previous version to clear fatal errors.
> 
> b. Some module version series are platform-specific. For example, the 1.5.x
> series is for certain platform generations, while the 2.0.x series is
> intended for others.
> 
> c. The update policy for TDX module updates is non-linear at times. The
> latest TDX module may not be compatible. For example, TDX module 1.5.x
> may be updated to 1.5.y but not to 1.5.y+1. This policy is documented
> separately in a file released along with each TDX module release.
> 
> So, the default policy of "request_firmware()" of "always load latest", is
> not suitable for TDX. Userspace needs to deploy a more sophisticated policy
> check (e.g., latest may not be compatible), and there is potential
> operator choice to consider.
> 
> Just have userspace pick rather than add kernel mechanism to change the
> default policy of request_firmware().
> 
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
> 

Reviewed-by: Kai Huang <kai.huang@intel.com>

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 09/22] x86/virt/seamldr: Introduce skeleton for TDX module updates
  2026-03-15 13:58 ` [PATCH v5 09/22] x86/virt/seamldr: Introduce skeleton for TDX module updates Chao Gao
@ 2026-03-18 22:11   ` Huang, Kai
  2026-03-19 13:15   ` Kiryl Shutsemau
  1 sibling, 0 replies; 80+ messages in thread
From: Huang, Kai @ 2026-03-18 22:11 UTC (permalink / raw)
  To: kvm@vger.kernel.org, linux-coco@lists.linux.dev,
	linux-kernel@vger.kernel.org, Gao, Chao
  Cc: x86@kernel.org, dave.hansen@linux.intel.com, kas@kernel.org,
	seanjc@google.com, Chatre, Reinette, Weiny, Ira,
	binbin.wu@linux.intel.com, Verma, Vishal L, nik.borisov@suse.com,
	mingo@redhat.com, pbonzini@redhat.com,
	tony.lindgren@linux.intel.com, sagis@google.com,
	Annapurve, Vishal, hpa@zytor.com, Edgecombe, Rick P,
	paulmck@kernel.org, tglx@kernel.org, yilun.xu@linux.intel.com,
	Williams, Dan J, bp@alien8.de


> +static struct {
> +	enum module_update_state state;
> +	int thread_ack;
> +	/*
> +	 * Protect update_data. Raw spinlock as it will be acquired from
> +	 * interrupt-disabled contexts.
> +	 */
> +	raw_spinlock_t lock;
> +} update_data = {
> +	.lock = __RAW_SPIN_LOCK_UNLOCKED(update_data.lock)
> +};
> +
> +static void set_target_state(enum module_update_state state)
> +{
> +	/* Reset ack counter. */
> +	update_data.thread_ack = num_online_cpus();
> +	update_data.state = state;
> +}
> +
> +/* Last one to ack a state moves to the next state. */
> +static void ack_state(void)
> +{
> +	guard(raw_spinlock)(&update_data.lock);
> +	update_data.thread_ack--;
> +	if (!update_data.thread_ack)
> +		set_target_state(update_data.state + 1);
> +}
> +
> +/*
> + * See multi_cpu_stop() from where this multi-cpu state-machine was
> + * adopted, and the rationale for touch_nmi_watchdog().
> + */
> +static int do_seamldr_install_module(void *seamldr_params)
> +{
> +	enum module_update_state newstate, curstate = MODULE_UPDATE_START;
> +	int ret = 0;
> +
> +	do {
> +		/* Chill out and re-read update_data. */
> +		cpu_relax();
> +		newstate = READ_ONCE(update_data.state);
> +
> +		if (newstate != curstate) {
> +			curstate = newstate;
> +			switch (curstate) {
> +			/* TODO: add the update steps. */
> +			default:
> +				break;
> +			}
> +
> +			ack_state();
> +		} else {
> +			touch_nmi_watchdog();
> +			rcu_momentary_eqs();
> +		}
> +	} while (curstate != MODULE_UPDATE_DONE);
> +
> +	return ret;
> +}

The read 

    newstate = READ_ONCE(update_data.state);

.. is done out of the spinlock, but AFAICT it is fine.

The worst case is couple of additional loops on old state.  The thread_ack
is protected by the lock thus no ack will get lost.

Reviewed-by: Kai Huang <kai.huang@intel.com>

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 04/22] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs
  2026-03-18  9:34     ` Chao Gao
@ 2026-03-19  3:02       ` Xiaoyao Li
  2026-03-19  7:14         ` Chao Gao
  0 siblings, 1 reply; 80+ messages in thread
From: Xiaoyao Li @ 2026-03-19  3:02 UTC (permalink / raw)
  To: Chao Gao
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, kas, nik.borisov, paulmck,
	pbonzini, reinette.chatre, rick.p.edgecombe, sagis, seanjc,
	tony.lindgren, vannapurve, vishal.l.verma, yilun.xu, Farrah Chen,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
	H. Peter Anvin

On 3/18/2026 5:34 PM, Chao Gao wrote:
> On Wed, Mar 18, 2026 at 03:13:06PM +0800, Xiaoyao Li wrote:
>> On 3/15/2026 9:58 PM, Chao Gao wrote:
>>> The TDX architecture uses the "SEAMCALL" instruction to communicate with
>>> SEAM mode software. Right now, the only SEAM mode software that the kernel
>>> communicates with is the TDX module. But, there is actually another
>>> component that runs in SEAM mode but it is separate from the TDX module:
>>> the persistent SEAM loader or "P-SEAMLDR". Right now, the only component
>>> that communicates with it is the BIOS which loads the TDX module itself at
>>> boot. But, to support updating the TDX module, the kernel now needs to be
>>> able to talk to it.
>>>
>>> P-SEAMLDR SEAMCALLs differ from TDX module SEAMCALLs in areas such as
>>> concurrency requirements. Add a P-SEAMLDR wrapper to handle these
>>> differences and prepare for implementing concrete functions.
>>>
>>> Note that unlike P-SEAMLDR, there is also a non-persistent SEAM loader
>>> ("NP-SEAMLDR"). This is an authenticated code module (ACM) that is not
>>> callable at runtime. Only BIOS launches it to load P-SEAMLDR at boot;
>>> the kernel does not need to interact with it for runtime update.
>>>
>>> For details of P-SEAMLDR SEAMCALLs, see Intel® Trust Domain CPU
>>> Architectural Extensions, Revision 343754-002, Chapter 2.3 "INSTRUCTION
>>> SET REFERENCE".
>>
>> SDM started to contain SEAMCALL definitions. How about just dropping this
>> paragraph to avoid people from reading the old doc?
> 
> I didn't realize that. Thanks for the information.
> 
> But I don't think this is a stale reference. The SDM description is high-level
> and points to the same spec for details:
> 
>    The details of such transitions are specified in the Intel® Trust Domain CPU
>    Architectural Extensions.

The old "Intel® Trust Domain CPU Architectural Extensions" spec has 
bugs. Remember 
https://lore.kernel.org/all/20251014231042.1399849-1-seanjc@google.com/ 
? They have been corrected in SDM.

I'm not trying to say it's a stale reference. I just think directing 
people to an old doc (especially with an exact revision number) can make 
them get outdated and incorrect information.

>>
>> ...
>>
>>> +static __maybe_unused int seamldr_call(u64 fn, struct tdx_module_args *args)
>>> +{
>>> +	guard(raw_spinlock)(&seamldr_lock);
>>> +	return seamcall_prerr(fn, args);
>>
>> How about adding the reason of why choosing seamcall_prerr() instead of
>> seamcall_prerr_ret() in the changelog?
> 
> Sure. Will add:
> 
> Use seamcall_prerr() (not '_ret') because current P-SEAMLDR calls do not use
> any output registers other than RAX.

looks good to me.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 04/22] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs
  2026-03-19  3:02       ` Xiaoyao Li
@ 2026-03-19  7:14         ` Chao Gao
  0 siblings, 0 replies; 80+ messages in thread
From: Chao Gao @ 2026-03-19  7:14 UTC (permalink / raw)
  To: Xiaoyao Li
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, kas, nik.borisov, paulmck,
	pbonzini, reinette.chatre, rick.p.edgecombe, sagis, seanjc,
	tony.lindgren, vannapurve, vishal.l.verma, yilun.xu, Farrah Chen,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
	H. Peter Anvin

>> I didn't realize that. Thanks for the information.
>> 
>> But I don't think this is a stale reference. The SDM description is high-level
>> and points to the same spec for details:
>> 
>>    The details of such transitions are specified in the Intel® Trust Domain CPU
>>    Architectural Extensions.
>
>The old "Intel® Trust Domain CPU Architectural Extensions" spec has bugs.
>Remember
>https://lore.kernel.org/all/20251014231042.1399849-1-seanjc@google.com/ ?
>They have been corrected in SDM.
>
>I'm not trying to say it's a stale reference. I just think directing people
>to an old doc (especially with an exact revision number) can make them get
>outdated and incorrect information.

Ok. Let me drop the whole paragraph.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 08/22] x86/virt/seamldr: Allocate and populate a module update request
  2026-03-18 10:58       ` Kiryl Shutsemau
@ 2026-03-19  7:24         ` Chao Gao
  2026-03-19 12:58           ` Kiryl Shutsemau
  0 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-19  7:24 UTC (permalink / raw)
  To: Kiryl Shutsemau
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

On Wed, Mar 18, 2026 at 10:58:44AM +0000, Kiryl Shutsemau wrote:
>On Wed, Mar 18, 2026 at 04:50:34PM +0800, Chao Gao wrote:
>> >> +	ptr = sig;
>> >> +	for (i = 0; i < sig_size / SZ_4K; i++) {
>> >> +		/*
>> >> +		 * Don't assume @sig is page-aligned although it is 4KB-aligned.
>> >> +		 * Always add the in-page offset to get the physical address.
>> >> +		 */
>> >
>> >I don't follow this. If @sig is 4k aligned in VA, it is page aligned.
>> 
>> Dan's concern was that PAGE_SIZE is not guaranteed to be 4096.
>> 
>> I agree that PAGE_SIZE is 4K on x86 today. But to address that concern, I saw
>> two options:
>> 
>>   1. Add WARN_ON_ONCE(PAGE_SIZE != SZ_4K), or
>>   2. Handle it as in the code above.
>> 
>> I didn't find existing code using option 1 in x86, so I chose option 2.
>
>Please, make it clear in the comment that you are talking about PAGE_SIZE != SZ_4K.

Sure. How about:

		/*
		 * @sig is 4KB-aligned, but that does not imply PAGE_SIZE
		 * alignment when PAGE_SIZE != SZ_4K. Always include the
		 * in-page offset.
		 */


^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 08/22] x86/virt/seamldr: Allocate and populate a module update request
  2026-03-19  7:24         ` Chao Gao
@ 2026-03-19 12:58           ` Kiryl Shutsemau
  0 siblings, 0 replies; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-19 12:58 UTC (permalink / raw)
  To: Chao Gao
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

On Thu, Mar 19, 2026 at 03:24:52PM +0800, Chao Gao wrote:
> On Wed, Mar 18, 2026 at 10:58:44AM +0000, Kiryl Shutsemau wrote:
> >On Wed, Mar 18, 2026 at 04:50:34PM +0800, Chao Gao wrote:
> >> >> +	ptr = sig;
> >> >> +	for (i = 0; i < sig_size / SZ_4K; i++) {
> >> >> +		/*
> >> >> +		 * Don't assume @sig is page-aligned although it is 4KB-aligned.
> >> >> +		 * Always add the in-page offset to get the physical address.
> >> >> +		 */
> >> >
> >> >I don't follow this. If @sig is 4k aligned in VA, it is page aligned.
> >> 
> >> Dan's concern was that PAGE_SIZE is not guaranteed to be 4096.
> >> 
> >> I agree that PAGE_SIZE is 4K on x86 today. But to address that concern, I saw
> >> two options:
> >> 
> >>   1. Add WARN_ON_ONCE(PAGE_SIZE != SZ_4K), or
> >>   2. Handle it as in the code above.
> >> 
> >> I didn't find existing code using option 1 in x86, so I chose option 2.
> >
> >Please, make it clear in the comment that you are talking about PAGE_SIZE != SZ_4K.
> 
> Sure. How about:
> 
> 		/*
> 		 * @sig is 4KB-aligned, but that does not imply PAGE_SIZE
> 		 * alignment when PAGE_SIZE != SZ_4K. Always include the
> 		 * in-page offset.
> 		 */

Ack.

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 09/22] x86/virt/seamldr: Introduce skeleton for TDX module updates
  2026-03-15 13:58 ` [PATCH v5 09/22] x86/virt/seamldr: Introduce skeleton for TDX module updates Chao Gao
  2026-03-18 22:11   ` Huang, Kai
@ 2026-03-19 13:15   ` Kiryl Shutsemau
  2026-03-20  8:10     ` Chao Gao
  1 sibling, 1 reply; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-19 13:15 UTC (permalink / raw)
  To: Chao Gao
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

On Sun, Mar 15, 2026 at 06:58:29AM -0700, Chao Gao wrote:
> TDX module updates require careful synchronization with other TDX
> operations. The requirements are (#1/#2 reflect current behavior that
> must be preserved):
> 
> 1. SEAMCALLs need to be callable from both process and IRQ contexts.
> 2. SEAMCALLs need to be able to run concurrently across CPUs
> 3. During updates, only update-related SEAMCALLs are permitted; all
>    other SEAMCALLs shouldn't be called.
> 4. During updates, all online CPUs must participate in the update work.
> 
> No single lock primitive satisfies all requirements. For instance,
> rwlock_t handles #1/#2 but fails #4: CPUs spinning with IRQs disabled
> cannot be directed to perform update work.
> 
> Use stop_machine() as it is the only well-understood mechanism that can
> meet all requirements.
> 
> And TDX module updates consist of several steps (See Intel® Trust Domain
> Extensions (Intel® TDX) Module Base Architecture Specification, Revision
> 348549-007, Chapter 4.5 "TD-Preserving TDX module Update"). Ordering
> requirements between steps mandate lockstep synchronization across all
> CPUs.
> 
> multi_cpu_stop() is a good example of performing a multi-step task in
> lockstep. But it doesn't synchronize steps within the callback function
> it takes. So, implement one based on its pattern to establish the
> skeleton for TDX module updates. Specifically, add a global state
> machine where each state represents a step in the update flow. The state
> advances only after all CPUs acknowledge completing their work in the
> current state. This acknowledgment mechanism is what ensures lockstep
> execution.
> 
> Potential alternative to stop_machine()
> =======================================
> An alternative approach is to lock all KVM entry points and kick all
> vCPUs. Here, KVM entry points refer to KVM VM/vCPU ioctl entry points,
> implemented in KVM common code (virt/kvm). Adding a locking mechanism
> there would affect all architectures KVM supports. And to lock only TDX
> vCPUs, new logic would be needed to identify TDX vCPUs, which the KVM
> common code currently lacks. This would add significant complexity and
> maintenance overhead to KVM for this TDX-specific use case.
> 
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
> Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>

Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>

One question below.

> +static struct {
> +	enum module_update_state state;
> +	int thread_ack;
> +	/*
> +	 * Protect update_data. Raw spinlock as it will be acquired from
> +	 * interrupt-disabled contexts.
> +	 */
> +	raw_spinlock_t lock;
> +} update_data = {
> +	.lock = __RAW_SPIN_LOCK_UNLOCKED(update_data.lock)
> +};

multi_stop_cpu() used atomic_t for thread_ack insead of spinlock.
Any particular reason you took different direction?

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 10/22] x86/virt/seamldr: Abort updates if errors occurred midway
  2026-03-15 13:58 ` [PATCH v5 10/22] x86/virt/seamldr: Abort updates if errors occurred midway Chao Gao
@ 2026-03-19 13:19   ` Kiryl Shutsemau
  2026-03-20  8:12     ` Chao Gao
  0 siblings, 1 reply; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-19 13:19 UTC (permalink / raw)
  To: Chao Gao
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

On Sun, Mar 15, 2026 at 06:58:30AM -0700, Chao Gao wrote:
> diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
> index 978fcca92128..e195703398e7 100644
> --- a/arch/x86/virt/vmx/tdx/seamldr.c
> +++ b/arch/x86/virt/vmx/tdx/seamldr.c
> @@ -190,6 +190,7 @@ enum module_update_state {
>  static struct {
>  	enum module_update_state state;
>  	int thread_ack;
> +	int failed;

bool is enough, right?

>  	/*
>  	 * Protect update_data. Raw spinlock as it will be acquired from
>  	 * interrupt-disabled contexts.
> @@ -237,12 +238,17 @@ static int do_seamldr_install_module(void *seamldr_params)
>  				break;
>  			}
>  
> -			ack_state();
> +			if (ret) {
> +				scoped_guard(raw_spinlock, &update_data.lock)
> +					update_data.failed++;

I don't see a reason in spin lock here. Just WRITE_ONCE() would work
fine.


-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 11/22] x86/virt/seamldr: Shut down the current TDX module
  2026-03-15 13:58 ` [PATCH v5 11/22] x86/virt/seamldr: Shut down the current TDX module Chao Gao
@ 2026-03-19 13:24   ` Kiryl Shutsemau
  2026-03-20  8:21     ` Chao Gao
  0 siblings, 1 reply; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-19 13:24 UTC (permalink / raw)
  To: Chao Gao
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

On Sun, Mar 15, 2026 at 06:58:31AM -0700, Chao Gao wrote:
> The first step of TDX module updates is shutting down the current TDX
> Module. This step also packs state information that needs to be
> preserved across updates as handoff data, which will be consumed by the
> updated module. The handoff data is stored internally in the SEAM range
> and is hidden from the kernel.
> 
> To ensure a successful update, the new module must be able to consume
> the handoff data generated by the old module. Since handoff data layout
> may change between modules, the handoff data is versioned. Each module
> has a native handoff version and provides backward support for several
> older versions.
> 
> The complete handoff versioning protocol is complex as it supports both
> module upgrades and downgrades. See details in Intel® Trust Domain
> Extensions (Intel® TDX) Module Base Architecture Specification, Revision
> 348549-007, Chapter 4.5.3 "Handoff Versioning".
> 
> Ideally, the kernel needs to retrieve the handoff versions supported by
> the current module and the new module and select a version supported by
> both. But, since this implementation chooses to only support module
> upgrades, simply request the current module to generate handoff data
> using its highest supported version, expecting that the new module will
> likely support it.
> 
> Note that only one CPU needs to call the TDX module's shutdown API.
> 
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
> Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
> Reviewed-by: Kai Huang <kai.huang@intel.com>

Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>

Nit is below.

> @@ -100,6 +100,17 @@ static int get_tdx_sys_info_td_conf(struct tdx_sys_info_td_conf *sysinfo_td_conf
>  	return ret;
>  }
>  
> +static int get_tdx_sys_info_handoff(struct tdx_sys_info_handoff *sysinfo_handoff)
> +{
> +	int ret = 0;
> +	u64 val;
> +
> +	if (!ret && !(ret = read_sys_metadata_field(0x8900000100000000, &val)))

!ret check is redundant as well as the ret initialization above.

> +		sysinfo_handoff->module_hv = val;
> +
> +	return ret;
> +}
> +
>  static int get_tdx_sys_info(struct tdx_sys_info *sysinfo)
>  {
>  	int ret = 0;
> @@ -116,5 +127,12 @@ static int get_tdx_sys_info(struct tdx_sys_info *sysinfo)

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 13/22] x86/virt/seamldr: Install a new TDX module
  2026-03-15 13:58 ` [PATCH v5 13/22] x86/virt/seamldr: Install a new TDX module Chao Gao
@ 2026-03-19 13:32   ` Kiryl Shutsemau
  2026-03-23  2:14     ` Chao Gao
  0 siblings, 1 reply; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-19 13:32 UTC (permalink / raw)
  To: Chao Gao
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

On Sun, Mar 15, 2026 at 06:58:33AM -0700, Chao Gao wrote:
> @@ -225,6 +227,7 @@ static void ack_state(void)
>  static int do_seamldr_install_module(void *seamldr_params)
>  {
>  	enum module_update_state newstate, curstate = MODULE_UPDATE_START;
> +	struct tdx_module_args args = {};
>  	int cpu = smp_processor_id();
>  	bool primary;
>  	int ret = 0;
> @@ -243,6 +246,10 @@ static int do_seamldr_install_module(void *seamldr_params)
>  				if (primary)
>  					ret = tdx_module_shutdown();
>  				break;
> +			case MODULE_UPDATE_CPU_INSTALL:
> +				args.rcx = __pa(seamldr_params);
> +				ret = seamldr_call(P_SEAMLDR_INSTALL, &args);

I think it should be in a helper alongside with the tdx_module_args.

> +				break;
>  			default:
>  				break;
>  			}

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 14/22] x86/virt/seamldr: Do TDX per-CPU initialization after updates
  2026-03-15 13:58 ` [PATCH v5 14/22] x86/virt/seamldr: Do TDX per-CPU initialization after updates Chao Gao
@ 2026-03-19 13:33   ` Kiryl Shutsemau
  0 siblings, 0 replies; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-19 13:33 UTC (permalink / raw)
  To: Chao Gao
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

On Sun, Mar 15, 2026 at 06:58:34AM -0700, Chao Gao wrote:
> After installing the new TDX module, each CPU needs to be initialized
> again to make the CPU ready to run any other SEAMCALLs. So, call
> tdx_cpu_enable() on all CPUs.
> 
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
> Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
> Reviewed-by: Kai Huang <kai.huang@intel.com>

Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 15/22] x86/virt/tdx: Restore TDX module state
  2026-03-15 13:58 ` [PATCH v5 15/22] x86/virt/tdx: Restore TDX module state Chao Gao
@ 2026-03-19 13:37   ` Kiryl Shutsemau
  0 siblings, 0 replies; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-19 13:37 UTC (permalink / raw)
  To: Chao Gao
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

On Sun, Mar 15, 2026 at 06:58:35AM -0700, Chao Gao wrote:
> TDX module state was packed as handoff data during module shutdown. After
> per-CPU initialization, the new module can restore TDX module state from
> handoff data to preserve running TDs.
> 
> Once the restoration is done, the TDX module update is complete, which
> means the new module is ready to handle requests from the host and guests.
> 
> Implement the new TDH.SYS.UPDATE SEAMCALL to restore TDX module state
> and invoke it on one CPU since it only needs to be called once.
> 
> Note that Intel® Trust Domain Extensions (Intel® TDX) Module Base
> Architecture Specification, Revision 348549-007, Chapter 4.5.5 states:
> 
>   If TDH.SYS.UPDATE returns an error, then the host VMM can continue
>   with the non-update sequence (TDH.SYS.CONFIG, 15 TDH.SYS.KEY.CONFIG
>   etc.). In this case all existing TDs are lost. Alternatively, the host
>   VMM can request the P-SEAMLDR to update to another TDX module. If that
>   update is successful, existing TDs are preserved
> 
> Don't implement the two alternatives due to their complexity and unclear
> benefits.

Make it clear which option you've took.

> 
> Also note that the location and the format of handoff data is defined by
> the TDX module. The new module knows where to get handoff data and how
> to parse it. The kernel doesn't need to provide its location, format etc.
> 
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
> Reviewed-by: Kai Huang <kai.huang@intel.com>

Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 16/22] x86/virt/tdx: Update tdx_sysinfo and check features post-update
  2026-03-15 13:58 ` [PATCH v5 16/22] x86/virt/tdx: Update tdx_sysinfo and check features post-update Chao Gao
@ 2026-03-19 13:43   ` Kiryl Shutsemau
  0 siblings, 0 replies; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-19 13:43 UTC (permalink / raw)
  To: Chao Gao
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

On Sun, Mar 15, 2026 at 06:58:36AM -0700, Chao Gao wrote:
> tdx_sysinfo contains all metadata of the active TDX module, including
> versions, supported features, and TDMR/TDCS/TDVPS information etc. These
> values may change over updates. Blindly refreshing the entire tdx_sysinfo
> could disrupt running software, as it may subtly rely on the previous state
> unless proven otherwise.
> 
> Adopt a conservative approach, like microcode updates, by only refreshing
> version information that does not affect functionality, while ignoring
> all other changes. This is acceptable as new modules are required to
> maintain backward compatibility.
> 
> Any updates to metadata beyond versions should be justified and reviewed on
> a case-by-case basis.
> 
> Note that preallocating a tdx_sys_info buffer before updates is to avoid
> having to handle -ENOMEM when updating tdx_sysinfo after a successful
> update.
> 
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
> Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
> Reviewed-by: Kai Huang <kai.huang@intel.com>
> Reviewed-by: Rick Edgecombe <rick.p.edgecombe@intel.com>

Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 17/22] x86/virt/tdx: Avoid updates during update-sensitive operations
  2026-03-15 13:58 ` [PATCH v5 17/22] x86/virt/tdx: Avoid updates during update-sensitive operations Chao Gao
@ 2026-03-19 14:00   ` Kiryl Shutsemau
  2026-03-20  8:00     ` Chao Gao
  0 siblings, 1 reply; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-19 14:00 UTC (permalink / raw)
  To: Chao Gao
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

On Sun, Mar 15, 2026 at 06:58:37AM -0700, Chao Gao wrote:
> diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
> index b3a7301e77c6..4c4f7acd4044 100644
> --- a/arch/x86/include/asm/tdx.h
> +++ b/arch/x86/include/asm/tdx.h
> @@ -26,11 +26,18 @@
>  #define TDX_SEAMCALL_GP			(TDX_SW_ERROR | X86_TRAP_GP)
>  #define TDX_SEAMCALL_UD			(TDX_SW_ERROR | X86_TRAP_UD)
>  
> +#define TDX_SEAMCALL_STATUS_MASK		0xFFFFFFFF00000000ULL
> +
>  /*
>   * TDX module SEAMCALL leaf function error codes
>   */
> -#define TDX_SUCCESS		0ULL
> -#define TDX_RND_NO_ENTROPY	0x8000020300000000ULL
> +#define TDX_SUCCESS			0ULL
> +#define TDX_RND_NO_ENTROPY		0x8000020300000000ULL
> +#define TDX_UPDATE_COMPAT_SENSITIVE	0x8000051200000000ULL

This competes with other patchset[1].

[1] https://lore.kernel.org/all/20260307010358.819645-1-rick.p.edgecombe@intel.com

> @@ -1189,9 +1192,21 @@ int tdx_module_shutdown(void)
>  	 * modules as new modules likely have higher handoff version.
>  	 */
>  	args.rcx = tdx_sysinfo.handoff.module_hv;
> -	ret = seamcall_prerr(TDH_SYS_SHUTDOWN, &args);
> -	if (ret)
> -		return ret;
> +
> +	if (tdx_supports_update_compatibility(&tdx_sysinfo))
> +		args.rcx |= TDX_SYS_SHUTDOWN_AVOID_COMPAT_SENSITIVE;

Hm. So what happens if the module doesn't support it? We just ignore
problem?

Maybe we should just block updates on such modules?

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 18/22] coco/tdx-host: Don't expose P-SEAMLDR features on CPUs with erratum
  2026-03-15 13:58 ` [PATCH v5 18/22] coco/tdx-host: Don't expose P-SEAMLDR features on CPUs with erratum Chao Gao
@ 2026-03-19 14:02   ` Kiryl Shutsemau
  0 siblings, 0 replies; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-19 14:02 UTC (permalink / raw)
  To: Chao Gao
  Cc: linux-kernel, kvm, linux-coco, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

On Sun, Mar 15, 2026 at 06:58:38AM -0700, Chao Gao wrote:
> Some TDX-capable CPUs have an erratum, as documented in Intel® Trust
> Domain CPU Architectural Extensions (May 2021 edition) Chapter 2.3:
> 
>   SEAMRET from the P-SEAMLDR clears the current VMCS structure pointed
>   to by the current-VMCS pointer. A VMM that invokes the P-SEAMLDR using
>   SEAMCALL must reload the current-VMCS, if required, using the VMPTRLD
>   instruction.
> 
> Clearing the current VMCS behind KVM's back will break KVM.
> 
> This erratum is not present when IA32_VMX_BASIC[60] is set. Add a CPU
> bug bit for this erratum and refuse to expose P-SEAMLDR features (e.g.,
> TDX module updates) on affected CPUs.
> 
> == Alternatives ==
> Two workarounds were considered but both were rejected:
> 
> 1. Save/restore the current VMCS around P-SEAMLDR calls. This produces ugly
>    assembly code [1] and doesn't play well with #MCE or #NMI if they
>    need to use the current VMCS.
> 
> 2. Move KVM's VMCS tracking logic to the TDX core code, which would break
>    the boundary between KVM and the TDX core code [2].
> 
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Reviewed-by: Kai Huang <kai.huang@intel.com>
> Link: https://lore.kernel.org/kvm/fedb3192-e68c-423c-93b2-a4dc2f964148@intel.com/ # [1]
> Link: https://lore.kernel.org/kvm/aYIXFmT-676oN6j0@google.com/ # [2]

Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 19/22] x86/virt/tdx: Enable TDX module runtime updates
  2026-03-15 13:58 ` [PATCH v5 19/22] x86/virt/tdx: Enable TDX module runtime updates Chao Gao
@ 2026-03-19 14:03   ` Kiryl Shutsemau
  0 siblings, 0 replies; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-19 14:03 UTC (permalink / raw)
  To: Chao Gao
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

On Sun, Mar 15, 2026 at 06:58:39AM -0700, Chao Gao wrote:
> All pieces of TDX module runtime updates are in place. Enable it if it
> is supported.
> 
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Reviewed-by: Xu Yilun <yilun.xu@linux.intel.com>
> Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>

Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 20/22] coco/tdx-host: Document TDX module update compatibility criteria
  2026-03-15 13:58 ` [PATCH v5 20/22] coco/tdx-host: Document TDX module update compatibility criteria Chao Gao
@ 2026-03-19 14:04   ` Kiryl Shutsemau
  0 siblings, 0 replies; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-19 14:04 UTC (permalink / raw)
  To: Chao Gao
  Cc: x86, linux-coco, kvm, linux-kernel, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu

On Sun, Mar 15, 2026 at 06:58:40AM -0700, Chao Gao wrote:
> The TDX module update protocol facilitates compatible runtime updates.
> 
> Document the compatibility criteria and indicators of various update
> failures, including violations of the compatibility criteria.
> 
> Note that runtime TDX module updates are an "update at your own risk"
> operation; userspace must enforce all of the above compatibility
> criteria.
> 
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Reviewed-by: Dan Williams <dan.j.williams@intel.com>

Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 21/22] x86/virt/tdx: Document TDX module update
  2026-03-15 13:58 ` [PATCH v5 21/22] x86/virt/tdx: Document TDX module update Chao Gao
@ 2026-03-19 14:05   ` Kiryl Shutsemau
  0 siblings, 0 replies; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-19 14:05 UTC (permalink / raw)
  To: Chao Gao
  Cc: linux-kernel, linux-doc, linux-coco, kvm, binbin.wu,
	dan.j.williams, dave.hansen, ira.weiny, kai.huang, nik.borisov,
	paulmck, pbonzini, reinette.chatre, rick.p.edgecombe, sagis,
	seanjc, tony.lindgren, vannapurve, vishal.l.verma, yilun.xu,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, x86,
	H. Peter Anvin, Jonathan Corbet, Shuah Khan

On Sun, Mar 15, 2026 at 06:58:41AM -0700, Chao Gao wrote:
> Document TDX module update as a subsection of "TDX Host Kernel Support" to
> provide background information and cover key points that developers and
> users may need to know, for example:
> 
>  - update is done in stop_machine() context
>  - update instructions and results
>  - update policy and tooling
> 
> Signed-off-by: Chao Gao <chao.gao@intel.com>
> Reviewed-by: Kai Huang <kai.huang@intel.com>

Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 22/22] x86/virt/seamldr: Log TDX module update failures
  2026-03-15 13:58 ` [PATCH v5 22/22] x86/virt/seamldr: Log TDX module update failures Chao Gao
@ 2026-03-19 14:06   ` Kiryl Shutsemau
  2026-03-20  8:31     ` Chao Gao
  0 siblings, 1 reply; 80+ messages in thread
From: Kiryl Shutsemau @ 2026-03-19 14:06 UTC (permalink / raw)
  To: Chao Gao
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

On Sun, Mar 15, 2026 at 06:58:42AM -0700, Chao Gao wrote:
> diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
> index e6b7af410c54..4e1ad06506cc 100644
> --- a/arch/x86/virt/vmx/tdx/seamldr.c
> +++ b/arch/x86/virt/vmx/tdx/seamldr.c
> @@ -222,6 +222,11 @@ static void ack_state(void)
>  		set_target_state(update_data.state + 1);
>  }
>  
> +static void print_update_failure_message(void)
> +{
> +	pr_err_once("update failed, SEAMCALLs will report failure until TDs killed\n");

Is it useful to indicate which step has failed?

> 

-- 
  Kiryl Shutsemau / Kirill A. Shutemov

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 17/22] x86/virt/tdx: Avoid updates during update-sensitive operations
  2026-03-19 14:00   ` Kiryl Shutsemau
@ 2026-03-20  8:00     ` Chao Gao
  0 siblings, 0 replies; 80+ messages in thread
From: Chao Gao @ 2026-03-20  8:00 UTC (permalink / raw)
  To: Kiryl Shutsemau
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

On Thu, Mar 19, 2026 at 02:00:00PM +0000, Kiryl Shutsemau wrote:
>On Sun, Mar 15, 2026 at 06:58:37AM -0700, Chao Gao wrote:
>> diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
>> index b3a7301e77c6..4c4f7acd4044 100644
>> --- a/arch/x86/include/asm/tdx.h
>> +++ b/arch/x86/include/asm/tdx.h
>> @@ -26,11 +26,18 @@
>>  #define TDX_SEAMCALL_GP			(TDX_SW_ERROR | X86_TRAP_GP)
>>  #define TDX_SEAMCALL_UD			(TDX_SW_ERROR | X86_TRAP_UD)
>>  
>> +#define TDX_SEAMCALL_STATUS_MASK		0xFFFFFFFF00000000ULL
>> +
>>  /*
>>   * TDX module SEAMCALL leaf function error codes
>>   */
>> -#define TDX_SUCCESS		0ULL
>> -#define TDX_RND_NO_ENTROPY	0x8000020300000000ULL
>> +#define TDX_SUCCESS			0ULL
>> +#define TDX_RND_NO_ENTROPY		0x8000020300000000ULL
>> +#define TDX_UPDATE_COMPAT_SENSITIVE	0x8000051200000000ULL
>
>This competes with other patchset[1].
>
>[1] https://lore.kernel.org/all/20260307010358.819645-1-rick.p.edgecombe@intel.com

Got it. But I suppose the conflicts can be addressed when maintainers merge
the two series.

Dave asked me to remove all (false) dependencies to make this series move
reviewable since v3. So I think we don't need to rebase onto that patchset.

>
>> @@ -1189,9 +1192,21 @@ int tdx_module_shutdown(void)
>>  	 * modules as new modules likely have higher handoff version.
>>  	 */
>>  	args.rcx = tdx_sysinfo.handoff.module_hv;
>> -	ret = seamcall_prerr(TDH_SYS_SHUTDOWN, &args);
>> -	if (ret)
>> -		return ret;
>> +
>> +	if (tdx_supports_update_compatibility(&tdx_sysinfo))
>> +		args.rcx |= TDX_SYS_SHUTDOWN_AVOID_COMPAT_SENSITIVE;
>
>Hm. So what happens if the module doesn't support it? We just ignore
>problem?

Yes. The kernel ignores the problem and leaves the decision (whether to
update modules) to userspace.

>
>Maybe we should just block updates on such modules?

Kai made the same suggestion, but Dan rejected it [1][2]. Dan's position is
to avoid kernel complexity and let userspace handle the check, updating at
their own risk.

I've prepared a patch for the userspace tool [3] to check if the feature is
supported and will push it.

[1]: https://lore.kernel.org/kvm/699fe97dc212f_2f4a100b@dwillia2-mobl4.notmuch/
[2]: https://lore.kernel.org/kvm/69a0c3d24310_1cc5100d1@dwillia2-mobl4.notmuch/
[3]: https://github.com/intel/confidential-computing.tdx.tdx-module.binaries/blob/main/version_select_and_load.py

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 09/22] x86/virt/seamldr: Introduce skeleton for TDX module updates
  2026-03-19 13:15   ` Kiryl Shutsemau
@ 2026-03-20  8:10     ` Chao Gao
  0 siblings, 0 replies; 80+ messages in thread
From: Chao Gao @ 2026-03-20  8:10 UTC (permalink / raw)
  To: Kiryl Shutsemau
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

>> +static struct {
>> +	enum module_update_state state;
>> +	int thread_ack;
>> +	/*
>> +	 * Protect update_data. Raw spinlock as it will be acquired from
>> +	 * interrupt-disabled contexts.
>> +	 */
>> +	raw_spinlock_t lock;
>> +} update_data = {
>> +	.lock = __RAW_SPIN_LOCK_UNLOCKED(update_data.lock)
>> +};
>
>multi_stop_cpu() used atomic_t for thread_ack insead of spinlock.
>Any particular reason you took different direction?

I switched from atomic_t to spinlock in v5 after Dave complained [*] that using
atomic_t and memory barriers is "overly complicated".

Testing both approaches showed no scalability issues, so I chose spinlock for
better readability.

*: https://lore.kernel.org/kvm/abP%2F2nPh9qkElV4L@intel.com/

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 10/22] x86/virt/seamldr: Abort updates if errors occurred midway
  2026-03-19 13:19   ` Kiryl Shutsemau
@ 2026-03-20  8:12     ` Chao Gao
  0 siblings, 0 replies; 80+ messages in thread
From: Chao Gao @ 2026-03-20  8:12 UTC (permalink / raw)
  To: Kiryl Shutsemau
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

On Thu, Mar 19, 2026 at 01:19:35PM +0000, Kiryl Shutsemau wrote:
>On Sun, Mar 15, 2026 at 06:58:30AM -0700, Chao Gao wrote:
>> diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
>> index 978fcca92128..e195703398e7 100644
>> --- a/arch/x86/virt/vmx/tdx/seamldr.c
>> +++ b/arch/x86/virt/vmx/tdx/seamldr.c
>> @@ -190,6 +190,7 @@ enum module_update_state {
>>  static struct {
>>  	enum module_update_state state;
>>  	int thread_ack;
>> +	int failed;
>
>bool is enough, right?

Yes.

>
>>  	/*
>>  	 * Protect update_data. Raw spinlock as it will be acquired from
>>  	 * interrupt-disabled contexts.
>> @@ -237,12 +238,17 @@ static int do_seamldr_install_module(void *seamldr_params)
>>  				break;
>>  			}
>>  
>> -			ack_state();
>> +			if (ret) {
>> +				scoped_guard(raw_spinlock, &update_data.lock)
>> +					update_data.failed++;
>
>I don't see a reason in spin lock here. Just WRITE_ONCE() would work
>fine.

Sure. Will use a bool and WRITE_ONCE() here.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 11/22] x86/virt/seamldr: Shut down the current TDX module
  2026-03-19 13:24   ` Kiryl Shutsemau
@ 2026-03-20  8:21     ` Chao Gao
  2026-03-23  1:33       ` Chao Gao
  0 siblings, 1 reply; 80+ messages in thread
From: Chao Gao @ 2026-03-20  8:21 UTC (permalink / raw)
  To: Kiryl Shutsemau
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

>> +static int get_tdx_sys_info_handoff(struct tdx_sys_info_handoff *sysinfo_handoff)
>> +{
>> +	int ret = 0;
>> +	u64 val;
>> +
>> +	if (!ret && !(ret = read_sys_metadata_field(0x8900000100000000, &val)))
>
>!ret check is redundant as well as the ret initialization above.

Ok. Will remove them:

static int get_tdx_sys_info_handoff(struct tdx_sys_info_handoff *sysinfo_handoff)
{
	int ret;
	u64 val;

	if (!(ret = read_sys_metadata_field(0x8900000100000000, &val)))
		sysinfo_handoff->module_hv = val;
	return ret;
}

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 22/22] x86/virt/seamldr: Log TDX module update failures
  2026-03-19 14:06   ` Kiryl Shutsemau
@ 2026-03-20  8:31     ` Chao Gao
  0 siblings, 0 replies; 80+ messages in thread
From: Chao Gao @ 2026-03-20  8:31 UTC (permalink / raw)
  To: Kiryl Shutsemau
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

On Thu, Mar 19, 2026 at 02:06:36PM +0000, Kiryl Shutsemau wrote:
>On Sun, Mar 15, 2026 at 06:58:42AM -0700, Chao Gao wrote:
>> diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
>> index e6b7af410c54..4e1ad06506cc 100644
>> --- a/arch/x86/virt/vmx/tdx/seamldr.c
>> +++ b/arch/x86/virt/vmx/tdx/seamldr.c
>> @@ -222,6 +222,11 @@ static void ack_state(void)
>>  		set_target_state(update_data.state + 1);
>>  }
>>  
>> +static void print_update_failure_message(void)
>> +{
>> +	pr_err_once("update failed, SEAMCALLs will report failure until TDs killed\n");
>
>Is it useful to indicate which step has failed?

For now, all failures should be from SEAMCALL failures. The kernel already
prints debug info (SEAMCALL leaf number, error code etc.), so it is quite easy
to find out which specific SEAMCALL failed (then the failing step should be
clear). So I think there is no need to print step information in this log.

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 11/22] x86/virt/seamldr: Shut down the current TDX module
  2026-03-20  8:21     ` Chao Gao
@ 2026-03-23  1:33       ` Chao Gao
  0 siblings, 0 replies; 80+ messages in thread
From: Chao Gao @ 2026-03-23  1:33 UTC (permalink / raw)
  To: Kiryl Shutsemau
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

On Fri, Mar 20, 2026 at 04:22:10PM +0800, Chao Gao wrote:
>>> +static int get_tdx_sys_info_handoff(struct tdx_sys_info_handoff *sysinfo_handoff)
>>> +{
>>> +	int ret = 0;
>>> +	u64 val;
>>> +
>>> +	if (!ret && !(ret = read_sys_metadata_field(0x8900000100000000, &val)))
>>
>>!ret check is redundant as well as the ret initialization above.
>
>Ok. Will remove them:
>
>static int get_tdx_sys_info_handoff(struct tdx_sys_info_handoff *sysinfo_handoff)
>{
>	int ret;
>	u64 val;
>
>	if (!(ret = read_sys_metadata_field(0x8900000100000000, &val)))
>		sysinfo_handoff->module_hv = val;
>	return ret;
>}

While making this change, I'll also fix the checkpatch.pl error:

	ERROR: do not use assignment in if condition
	#23: FILE: arch/x86/virt/vmx/tdx/tdx_global_metadata.c:108:
	+       if (!(ret = read_sys_metadata_field(0x8900000100000000, &val)))


Updated version:

static int get_tdx_sys_info_handoff(struct tdx_sys_info_handoff *sysinfo_handoff)
{
	int ret;
	u64 val;

	ret = read_sys_metadata_field(0x8900000100000000, &val);
	if (ret)
		return ret;

	sysinfo_handoff->module_hv = val;
	return 0;
}

^ permalink raw reply	[flat|nested] 80+ messages in thread

* Re: [PATCH v5 13/22] x86/virt/seamldr: Install a new TDX module
  2026-03-19 13:32   ` Kiryl Shutsemau
@ 2026-03-23  2:14     ` Chao Gao
  0 siblings, 0 replies; 80+ messages in thread
From: Chao Gao @ 2026-03-23  2:14 UTC (permalink / raw)
  To: Kiryl Shutsemau
  Cc: linux-kernel, linux-coco, kvm, binbin.wu, dan.j.williams,
	dave.hansen, ira.weiny, kai.huang, nik.borisov, paulmck, pbonzini,
	reinette.chatre, rick.p.edgecombe, sagis, seanjc, tony.lindgren,
	vannapurve, vishal.l.verma, yilun.xu, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, x86, H. Peter Anvin

On Thu, Mar 19, 2026 at 01:32:07PM +0000, Kiryl Shutsemau wrote:
>On Sun, Mar 15, 2026 at 06:58:33AM -0700, Chao Gao wrote:
>> @@ -225,6 +227,7 @@ static void ack_state(void)
>>  static int do_seamldr_install_module(void *seamldr_params)
>>  {
>>  	enum module_update_state newstate, curstate = MODULE_UPDATE_START;
>> +	struct tdx_module_args args = {};
>>  	int cpu = smp_processor_id();
>>  	bool primary;
>>  	int ret = 0;
>> @@ -243,6 +246,10 @@ static int do_seamldr_install_module(void *seamldr_params)
>>  				if (primary)
>>  					ret = tdx_module_shutdown();
>>  				break;
>> +			case MODULE_UPDATE_CPU_INSTALL:
>> +				args.rcx = __pa(seamldr_params);
>> +				ret = seamldr_call(P_SEAMLDR_INSTALL, &args);
>
>I think it should be in a helper alongside with the tdx_module_args.

Will do. Here is the updated version:

diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
index bb4aa6327eee..cd2aa2eabb65 100644
--- a/arch/x86/virt/vmx/tdx/seamldr.c
+++ b/arch/x86/virt/vmx/tdx/seamldr.c
@@ -19,6 +19,7 @@
 
 /* P-SEAMLDR SEAMCALL leaf function */
 #define P_SEAMLDR_INFO			0x8000000000000000
+#define P_SEAMLDR_INSTALL		0x8000000000000001
 
 #define SEAMLDR_MAX_NR_MODULE_4KB_PAGES	496
 #define SEAMLDR_MAX_NR_SIG_4KB_PAGES	4
@@ -72,6 +73,13 @@ int seamldr_get_info(struct seamldr_info *seamldr_info)
 }
 EXPORT_SYMBOL_FOR_MODULES(seamldr_get_info, "tdx-host");
 
+static int seamldr_install(const struct seamldr_params *params)
+{
+	struct tdx_module_args args = { .rcx = __pa(params) };
+
+	return seamldr_call(P_SEAMLDR_INSTALL, &args);
+}
+
 static void free_seamldr_params(struct seamldr_params *params)
 {
	free_page((unsigned long)params);
@@ -186,6 +194,7 @@ static struct seamldr_params *init_seamldr_params(const u8 *data, u32 size)
 enum module_update_state {
	MODULE_UPDATE_START,
	MODULE_UPDATE_SHUTDOWN,
+	MODULE_UPDATE_CPU_INSTALL,
	MODULE_UPDATE_DONE,
 };
 
@@ -243,6 +252,9 @@ static int do_seamldr_install_module(void *seamldr_params)
				if (primary)
					ret = tdx_module_shutdown();
				break;
+			case MODULE_UPDATE_CPU_INSTALL:
+				ret = seamldr_install(seamldr_params);
+				break;
			default:
				break;
			}


^ permalink raw reply related	[flat|nested] 80+ messages in thread

end of thread, other threads:[~2026-03-23  2:15 UTC | newest]

Thread overview: 80+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-15 13:58 [PATCH v5 00/22] Runtime TDX module update support Chao Gao
2026-03-15 13:58 ` [PATCH v5 01/22] x86/virt/tdx: Move low level SEAMCALL helpers out of <asm/tdx.h> Chao Gao
2026-03-16 12:41   ` Kiryl Shutsemau
2026-03-15 13:58 ` [PATCH v5 02/22] coco/tdx-host: Introduce a "tdx_host" device Chao Gao
2026-03-16 12:48   ` Kiryl Shutsemau
2026-03-15 13:58 ` [PATCH v5 03/22] coco/tdx-host: Expose TDX module version Chao Gao
2026-03-16 12:54   ` Kiryl Shutsemau
2026-03-18 21:37   ` Huang, Kai
2026-03-15 13:58 ` [PATCH v5 04/22] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs Chao Gao
2026-03-16 13:05   ` Kiryl Shutsemau
2026-03-17  0:43     ` Chao Gao
2026-03-17  9:59       ` Kiryl Shutsemau
2026-03-18  7:13   ` Xiaoyao Li
2026-03-18  9:34     ` Chao Gao
2026-03-19  3:02       ` Xiaoyao Li
2026-03-19  7:14         ` Chao Gao
2026-03-18 21:38   ` Huang, Kai
2026-03-15 13:58 ` [PATCH v5 05/22] x86/virt/seamldr: Retrieve P-SEAMLDR information Chao Gao
2026-03-16 13:12   ` Kiryl Shutsemau
2026-03-17  1:05     ` Chao Gao
2026-03-17 10:00       ` Kiryl Shutsemau
2026-03-18  7:53   ` Xiaoyao Li
2026-03-18  8:57     ` Chao Gao
2026-03-18 21:40   ` Huang, Kai
2026-03-15 13:58 ` [PATCH v5 06/22] coco/tdx-host: Expose P-SEAMLDR information via sysfs Chao Gao
2026-03-17 10:06   ` Kiryl Shutsemau
2026-03-17 15:34     ` Dave Hansen
2026-03-18  6:54     ` Chao Gao
2026-03-18  8:20       ` Xiaoyao Li
2026-03-18  9:10         ` Chao Gao
2026-03-18  9:28           ` Kiryl Shutsemau
2026-03-15 13:58 ` [PATCH v5 07/22] coco/tdx-host: Implement firmware upload sysfs ABI for TDX module updates Chao Gao
2026-03-17 10:20   ` Kiryl Shutsemau
2026-03-18  8:28     ` Chao Gao
2026-03-18 21:45   ` Huang, Kai
2026-03-15 13:58 ` [PATCH v5 08/22] x86/virt/seamldr: Allocate and populate a module update request Chao Gao
2026-03-17 10:59   ` Kiryl Shutsemau
2026-03-18  8:50     ` Chao Gao
2026-03-18 10:58       ` Kiryl Shutsemau
2026-03-19  7:24         ` Chao Gao
2026-03-19 12:58           ` Kiryl Shutsemau
2026-03-18 21:36   ` Huang, Kai
2026-03-15 13:58 ` [PATCH v5 09/22] x86/virt/seamldr: Introduce skeleton for TDX module updates Chao Gao
2026-03-18 22:11   ` Huang, Kai
2026-03-19 13:15   ` Kiryl Shutsemau
2026-03-20  8:10     ` Chao Gao
2026-03-15 13:58 ` [PATCH v5 10/22] x86/virt/seamldr: Abort updates if errors occurred midway Chao Gao
2026-03-19 13:19   ` Kiryl Shutsemau
2026-03-20  8:12     ` Chao Gao
2026-03-15 13:58 ` [PATCH v5 11/22] x86/virt/seamldr: Shut down the current TDX module Chao Gao
2026-03-19 13:24   ` Kiryl Shutsemau
2026-03-20  8:21     ` Chao Gao
2026-03-23  1:33       ` Chao Gao
2026-03-15 13:58 ` [PATCH v5 12/22] x86/virt/tdx: Reset software states during TDX module shutdown Chao Gao
2026-03-16  9:06   ` Huang, Kai
2026-03-17  8:27     ` Chao Gao
2026-03-17 11:08       ` Huang, Kai
2026-03-15 13:58 ` [PATCH v5 13/22] x86/virt/seamldr: Install a new TDX module Chao Gao
2026-03-19 13:32   ` Kiryl Shutsemau
2026-03-23  2:14     ` Chao Gao
2026-03-15 13:58 ` [PATCH v5 14/22] x86/virt/seamldr: Do TDX per-CPU initialization after updates Chao Gao
2026-03-19 13:33   ` Kiryl Shutsemau
2026-03-15 13:58 ` [PATCH v5 15/22] x86/virt/tdx: Restore TDX module state Chao Gao
2026-03-19 13:37   ` Kiryl Shutsemau
2026-03-15 13:58 ` [PATCH v5 16/22] x86/virt/tdx: Update tdx_sysinfo and check features post-update Chao Gao
2026-03-19 13:43   ` Kiryl Shutsemau
2026-03-15 13:58 ` [PATCH v5 17/22] x86/virt/tdx: Avoid updates during update-sensitive operations Chao Gao
2026-03-19 14:00   ` Kiryl Shutsemau
2026-03-20  8:00     ` Chao Gao
2026-03-15 13:58 ` [PATCH v5 18/22] coco/tdx-host: Don't expose P-SEAMLDR features on CPUs with erratum Chao Gao
2026-03-19 14:02   ` Kiryl Shutsemau
2026-03-15 13:58 ` [PATCH v5 19/22] x86/virt/tdx: Enable TDX module runtime updates Chao Gao
2026-03-19 14:03   ` Kiryl Shutsemau
2026-03-15 13:58 ` [PATCH v5 20/22] coco/tdx-host: Document TDX module update compatibility criteria Chao Gao
2026-03-19 14:04   ` Kiryl Shutsemau
2026-03-15 13:58 ` [PATCH v5 21/22] x86/virt/tdx: Document TDX module update Chao Gao
2026-03-19 14:05   ` Kiryl Shutsemau
2026-03-15 13:58 ` [PATCH v5 22/22] x86/virt/seamldr: Log TDX module update failures Chao Gao
2026-03-19 14:06   ` Kiryl Shutsemau
2026-03-20  8:31     ` Chao Gao

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox