* [PATCH v6 00/22] Runtime TDX module update support
@ 2026-03-26 8:43 Chao Gao
2026-03-26 8:44 ` [PATCH v6 21/22] x86/virt/tdx: Document TDX module update Chao Gao
2026-03-26 8:52 ` [PATCH v6 00/22] Runtime TDX module update support Chao Gao
0 siblings, 2 replies; 3+ messages in thread
From: Chao Gao @ 2026-03-26 8:43 UTC (permalink / raw)
To: kvm, linux-coco, linux-doc, linux-kernel, linux-rt-devel, 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, xiaoyao.li, yan.y.zhao, Chao Gao, Borislav Petkov,
Clark Williams, H. Peter Anvin, Ingo Molnar, Jonathan Corbet,
Sebastian Andrzej Siewior, Shuah Khan, Steven Rostedt,
Thomas Gleixner
Hi Reviewers,
Please review patches 6 and 17; others already have 2+ RB tags.
Patch 6 was reworked to use is_visible() for attribute visibility (which is
the standard practice), so previous RB tags were dropped. Patch 17 has
fewer reviews so far and needs another look.
I believe this series is quite mature and also self-contained (no impact to
the rest of kernel unless an update is triggered through the dedicated
sysfs ABIs). I'm hoping it can be merged for 7.1.
Changelog:
v5->v6:
- use TDX_VERSION_FMT macro [Dave/Kiryl]
- use is_visible() to control seamldr attribute visibility [Yilun]
- drop revision/chapter numbers when referring to a spec [Kiryl/Xiaoyao]
- change update failure indicator from int to boolean [Kiryl]
- reset tdx_lp_initialized for offlined CPUs [Kai]
- add a wrapper for seamldr_call(P_SEAMLDR_INSTALL..) [Kiryl]
- clarify the "do nothing" choice when collision detection isn't
supported [Kai/Kiryl]
- other minor code changes, changelog improvements and typo fixes [Kiryl/Kai/Xiaoyao]
- collect review tags from Kiryl/Kai
- v5: https://lore.kernel.org/kvm/20260315135920.354657-1-chao.gao@intel.com/
(For transparency, note that I used AI tools to help proofread this
cover-letter and commit messages)
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-v6/
== 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: Add a helper to 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 | 64 +---
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 | 335 ++++++++++++++++++
arch/x86/virt/vmx/tdx/tdx.c | 166 ++++++---
arch/x86/virt/vmx/tdx/tdx.h | 11 +-
arch/x86/virt/vmx/tdx/tdx_global_metadata.c | 20 ++
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 | 250 +++++++++++++
19 files changed, 1027 insertions(+), 103 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
base-commit: 0f409eaea53e49932cf92a761de66345c9a4b4be
--
2.47.3
^ permalink raw reply related [flat|nested] 3+ messages in thread
* [PATCH v6 21/22] x86/virt/tdx: Document TDX module update
2026-03-26 8:43 [PATCH v6 00/22] Runtime TDX module update support Chao Gao
@ 2026-03-26 8:44 ` Chao Gao
2026-03-26 8:52 ` [PATCH v6 00/22] Runtime TDX module update support Chao Gao
1 sibling, 0 replies; 3+ messages in thread
From: Chao Gao @ 2026-03-26 8:44 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, xiaoyao.li, yan.y.zhao, 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>
Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
---
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] 3+ messages in thread
* Re: [PATCH v6 00/22] Runtime TDX module update support
2026-03-26 8:43 [PATCH v6 00/22] Runtime TDX module update support Chao Gao
2026-03-26 8:44 ` [PATCH v6 21/22] x86/virt/tdx: Document TDX module update Chao Gao
@ 2026-03-26 8:52 ` Chao Gao
1 sibling, 0 replies; 3+ messages in thread
From: Chao Gao @ 2026-03-26 8:52 UTC (permalink / raw)
To: kvm, linux-coco, linux-doc, linux-kernel, linux-rt-devel, 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, xiaoyao.li, yan.y.zhao, Borislav Petkov, Clark Williams,
H. Peter Anvin, Ingo Molnar, Jonathan Corbet,
Sebastian Andrzej Siewior, Shuah Khan, Steven Rostedt,
Thomas Gleixner
On Thu, Mar 26, 2026 at 01:43:51AM -0700, Chao Gao wrote:
>Hi Reviewers,
>
>Please review patches 6 and 17; others already have 2+ RB tags.
>
>Patch 6 was reworked to use is_visible() for attribute visibility (which is
>the standard practice), so previous RB tags were dropped. Patch 17 has
>fewer reviews so far and needs another look.
>
>I believe this series is quite mature and also self-contained (no impact to
>the rest of kernel unless an update is triggered through the dedicated
>sysfs ABIs). I'm hoping it can be merged for 7.1.
>
>Changelog:
>v5->v6:
Below is the diff between v5 and v6:
diff --git a/Documentation/ABI/testing/sysfs-devices-faux-tdx-host b/Documentation/ABI/testing/sysfs-devices-faux-tdx-host
index 97840db794c0..e1a2f3b2ea65 100644
--- a/Documentation/ABI/testing/sysfs-devices-faux-tdx-host
+++ b/Documentation/ABI/testing/sysfs-devices-faux-tdx-host
@@ -24,9 +24,8 @@ Description: (RO) Report the number of remaining updates. TDX maintains a
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.
+ Interface Specification, Chapter "SEAMLDR_INFO" and Chapter
+ "SEAMLDR.INSTALL" for more information.
What: /sys/devices/faux/tdx_host/firmware/tdx_module
Contact: linux-coco@lists.linux.dev
@@ -58,14 +57,15 @@ 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.
+ "device-busy": Conflicting operations are in progress, e.g., TD
+ build or TD migration.
"read-write-error": Memory allocation failed.
- "hw-error": Cannot communicate with P-SEAMLDR or TDX module.
+ "hw-error": Communication with P-SEAMLDR or TDX module failed
+ or update limit exhausted.
"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
diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index 386097b2e01b..6351d2c21513 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -116,11 +116,6 @@ static inline bool tdx_supports_runtime_update(const struct tdx_sys_info *sysinf
return sysinfo->features.tdx_features0 & TDX_FEATURES0_TD_PRESERVING;
}
-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/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
index 4e1ad06506cc..276330179783 100644
--- a/arch/x86/virt/vmx/tdx/seamldr.c
+++ b/arch/x86/virt/vmx/tdx/seamldr.c
@@ -51,7 +51,8 @@ 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
- * be made with interrupts disabled.
+ * be made with interrupts disabled, where plain spinlocks are prohibited in
+ * PREEMPT_RT kernels as they become sleeping locks.
*/
static DEFINE_RAW_SPINLOCK(seamldr_lock);
@@ -73,6 +74,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);
@@ -109,8 +117,9 @@ static struct seamldr_params *alloc_seamldr_params(const void *module, unsigned
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.
+ * @sig is 4KB-aligned, but that does not imply PAGE_SIZE
+ * alignment when PAGE_SIZE != SZ_4K. Always include the
+ * in-page offset.
*/
params->sigstruct_pa[i] = (vmalloc_to_pfn(ptr) << PAGE_SHIFT) +
((unsigned long)ptr & ~PAGE_MASK);
@@ -136,6 +145,10 @@ static struct seamldr_params *alloc_seamldr_params(const void *module, unsigned
* 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.
+ *
+ * Note @offset_of_module is relative to the start of struct tdx_blob, not
+ * @data, and @length is the total length of the blob, not the length of
+ * @data.
*/
struct tdx_blob {
u16 version;
@@ -196,7 +209,7 @@ enum module_update_state {
static struct {
enum module_update_state state;
int thread_ack;
- int failed;
+ bool failed;
/*
* Protect update_data. Raw spinlock as it will be acquired from
* interrupt-disabled contexts.
@@ -234,7 +247,6 @@ static void print_update_failure_message(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;
@@ -254,8 +266,7 @@ static int do_seamldr_install_module(void *seamldr_params)
ret = tdx_module_shutdown();
break;
case MODULE_UPDATE_CPU_INSTALL:
- args.rcx = __pa(seamldr_params);
- ret = seamldr_call(P_SEAMLDR_INSTALL, &args);
+ ret = seamldr_install(seamldr_params);
break;
case MODULE_UPDATE_CPU_INIT:
ret = tdx_cpu_enable();
@@ -269,8 +280,7 @@ static int do_seamldr_install_module(void *seamldr_params)
}
if (ret) {
- scoped_guard(raw_spinlock, &update_data.lock)
- update_data.failed++;
+ WRITE_ONCE(update_data.failed, true);
if (curstate > MODULE_UPDATE_SHUTDOWN)
print_update_failure_message();
} else {
@@ -314,7 +324,7 @@ int seamldr_install_module(const u8 *data, u32 size)
if (IS_ERR(params))
return PTR_ERR(params);
- update_data.failed = 0;
+ update_data.failed = false;
set_target_state(MODULE_UPDATE_START + 1);
ret = stop_machine(do_seamldr_install_module, params, cpu_online_mask);
if (ret)
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index b76b8c393425..3f4221098b78 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -1194,7 +1194,7 @@ int tdx_module_shutdown(void)
*/
args.rcx = tdx_sysinfo.handoff.module_hv;
- if (tdx_supports_update_compatibility(&tdx_sysinfo))
+ if (tdx_sysinfo.features.tdx_features0 & TDX_FEATURES0_UPDATE_COMPAT)
args.rcx |= TDX_SYS_SHUTDOWN_AVOID_COMPAT_SENSITIVE;
ret = seamcall(TDH_SYS_SHUTDOWN, &args);
@@ -1214,11 +1214,12 @@ int tdx_module_shutdown(void)
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.
+ * 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.
*/
- for_each_online_cpu(cpu)
+ for_each_possible_cpu(cpu)
per_cpu(tdx_lp_initialized, cpu) = false;
return 0;
}
diff --git a/arch/x86/virt/vmx/tdx/tdx_global_metadata.c b/arch/x86/virt/vmx/tdx/tdx_global_metadata.c
index d6a4fa8deb5e..1b6f9b80b197 100644
--- a/arch/x86/virt/vmx/tdx/tdx_global_metadata.c
+++ b/arch/x86/virt/vmx/tdx/tdx_global_metadata.c
@@ -102,13 +102,15 @@ static int get_tdx_sys_info_td_conf(struct tdx_sys_info_td_conf *sysinfo_td_conf
static int get_tdx_sys_info_handoff(struct tdx_sys_info_handoff *sysinfo_handoff)
{
- int ret = 0;
+ int ret;
u64 val;
- if (!ret && !(ret = read_sys_metadata_field(0x8900000100000000, &val)))
- sysinfo_handoff->module_hv = val;
+ ret = read_sys_metadata_field(0x8900000100000000, &val);
+ if (ret)
+ return ret;
- return ret;
+ sysinfo_handoff->module_hv = val;
+ return 0;
}
static int get_tdx_sys_info(struct tdx_sys_info *sysinfo)
diff --git a/drivers/virt/coco/tdx-host/tdx-host.c b/drivers/virt/coco/tdx-host/tdx-host.c
index 8cf3cc99024a..f236119c2748 100644
--- a/drivers/virt/coco/tdx-host/tdx-host.c
+++ b/drivers/virt/coco/tdx-host/tdx-host.c
@@ -21,6 +21,12 @@ static const struct x86_cpu_id tdx_host_ids[] = {
};
MODULE_DEVICE_TABLE(x86cpu, tdx_host_ids);
+/*
+ * TDX module and P-SEAMLDR version convention: "major.minor.update"
+ * (e.g., "1.5.08") with zero-padded two-digit update field.
+ */
+#define TDX_VERSION_FMT "%u.%u.%02u"
+
static ssize_t version_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -32,9 +38,9 @@ static ssize_t version_show(struct device *dev, struct device_attribute *attr,
ver = &tdx_sysinfo->version;
- return sysfs_emit(buf, "%u.%u.%02u\n", ver->major_version,
- ver->minor_version,
- ver->update_version);
+ return sysfs_emit(buf, TDX_VERSION_FMT"\n", ver->major_version,
+ ver->minor_version,
+ ver->update_version);
}
static DEVICE_ATTR_RO(version);
@@ -42,7 +48,10 @@ static struct attribute *tdx_host_attrs[] = {
&dev_attr_version.attr,
NULL,
};
-ATTRIBUTE_GROUPS(tdx_host);
+
+static const struct attribute_group tdx_host_group = {
+ .attrs = tdx_host_attrs,
+};
static ssize_t seamldr_version_show(struct device *dev, struct device_attribute *attr,
char *buf)
@@ -54,9 +63,9 @@ static ssize_t seamldr_version_show(struct device *dev, struct device_attribute
if (ret)
return ret;
- return sysfs_emit(buf, "%u.%u.%02u\n", info.major_version,
- info.minor_version,
- info.update_version);
+ return sysfs_emit(buf, TDX_VERSION_FMT"\n", info.major_version,
+ info.minor_version,
+ info.update_version);
}
static ssize_t num_remaining_updates_show(struct device *dev,
@@ -90,9 +99,41 @@ static struct attribute *seamldr_attrs[] = {
NULL,
};
+static bool can_expose_seamldr(void)
+{
+ const struct tdx_sys_info *sysinfo = tdx_get_sysinfo();
+
+ if (!sysinfo)
+ return false;
+
+ /*
+ * 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 false;
+
+ return tdx_supports_runtime_update(sysinfo);
+}
+
+static bool seamldr_group_visible(struct kobject *kobj)
+{
+ return can_expose_seamldr();
+}
+
+DEFINE_SIMPLE_SYSFS_GROUP_VISIBLE(seamldr);
+
static const struct attribute_group seamldr_group = {
.name = "seamldr",
.attrs = seamldr_attrs,
+ .is_visible = SYSFS_GROUP_VISIBLE(seamldr),
+};
+
+static const struct attribute_group *tdx_host_groups[] = {
+ &tdx_host_group,
+ &seamldr_group,
+ NULL,
};
static enum fw_upload_err tdx_fw_prepare(struct fw_upload *fwl,
@@ -122,8 +163,6 @@ static enum fw_upload_err tdx_fw_write(struct fw_upload *fwl, const u8 *data,
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:
@@ -164,22 +203,9 @@ static void seamldr_deinit(void *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;
-
- /*
- * 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))
+ if (!can_expose_seamldr())
return 0;
tdx_fwl = firmware_upload_register(THIS_MODULE, dev, "tdx_module",
@@ -187,11 +213,7 @@ static int seamldr_init(struct device *dev)
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);
+ return devm_add_action_or_reset(dev, seamldr_deinit, tdx_fwl);
}
static int tdx_host_probe(struct faux_device *fdev)
^ permalink raw reply related [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-03-26 8:52 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-03-26 8:43 [PATCH v6 00/22] Runtime TDX module update support Chao Gao
2026-03-26 8:44 ` [PATCH v6 21/22] x86/virt/tdx: Document TDX module update Chao Gao
2026-03-26 8:52 ` [PATCH v6 00/22] Runtime TDX module update support Chao Gao
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox