From: Chao Gao <chao.gao@intel.com>
To: <kvm@vger.kernel.org>, <linux-coco@lists.linux.dev>,
<linux-doc@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
<linux-rt-devel@lists.linux.dev>, <x86@kernel.org>
Cc: <binbin.wu@linux.intel.com>, <dan.j.williams@intel.com>,
<dave.hansen@linux.intel.com>, <ira.weiny@intel.com>,
<kai.huang@intel.com>, <kas@kernel.org>, <nik.borisov@suse.com>,
<paulmck@kernel.org>, <pbonzini@redhat.com>,
<reinette.chatre@intel.com>, <rick.p.edgecombe@intel.com>,
<sagis@google.com>, <seanjc@google.com>,
<tony.lindgren@linux.intel.com>, <vannapurve@google.com>,
<vishal.l.verma@intel.com>, <yilun.xu@linux.intel.com>,
<xiaoyao.li@intel.com>, <yan.y.zhao@intel.com>,
Borislav Petkov <bp@alien8.de>,
Clark Williams <clrkwllms@kernel.org>,
"H. Peter Anvin" <hpa@zytor.com>, Ingo Molnar <mingo@redhat.com>,
Jonathan Corbet <corbet@lwn.net>,
Sebastian Andrzej Siewior <bigeasy@linutronix.de>,
"Shuah Khan" <skhan@linuxfoundation.org>,
Steven Rostedt <rostedt@goodmis.org>,
Thomas Gleixner <tglx@kernel.org>
Subject: Re: [PATCH v6 00/22] Runtime TDX module update support
Date: Thu, 26 Mar 2026 16:52:30 +0800 [thread overview]
Message-ID: <acTzzi2vuqga1P1d@intel.com> (raw)
In-Reply-To: <20260326084448.29947-1-chao.gao@intel.com>
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)
prev parent reply other threads:[~2026-03-26 8:52 UTC|newest]
Thread overview: 27+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-03-26 8:43 [PATCH v6 00/22] Runtime TDX module update support Chao Gao
2026-03-26 8:43 ` [PATCH v6 01/22] x86/virt/tdx: Move low level SEAMCALL helpers out of <asm/tdx.h> Chao Gao
2026-03-26 8:43 ` [PATCH v6 02/22] coco/tdx-host: Introduce a "tdx_host" device Chao Gao
2026-03-26 8:43 ` [PATCH v6 03/22] coco/tdx-host: Expose TDX module version Chao Gao
2026-03-26 8:43 ` [PATCH v6 04/22] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs Chao Gao
2026-03-26 8:43 ` [PATCH v6 05/22] x86/virt/seamldr: Add a helper to retrieve P-SEAMLDR information Chao Gao
2026-03-26 8:43 ` [PATCH v6 06/22] coco/tdx-host: Expose P-SEAMLDR information via sysfs Chao Gao
2026-03-26 8:43 ` [PATCH v6 07/22] coco/tdx-host: Implement firmware upload sysfs ABI for TDX module updates Chao Gao
2026-03-26 8:43 ` [PATCH v6 08/22] x86/virt/seamldr: Allocate and populate a module update request Chao Gao
2026-03-26 8:44 ` [PATCH v6 09/22] x86/virt/seamldr: Introduce skeleton for TDX module updates Chao Gao
2026-03-26 11:47 ` Chao Gao
2026-03-26 8:44 ` [PATCH v6 10/22] x86/virt/seamldr: Abort updates if errors occurred midway Chao Gao
2026-03-26 8:44 ` [PATCH v6 11/22] x86/virt/seamldr: Shut down the current TDX module Chao Gao
2026-03-26 8:44 ` [PATCH v6 12/22] x86/virt/tdx: Reset software states during TDX module shutdown Chao Gao
2026-03-26 12:35 ` Chao Gao
2026-03-26 8:44 ` [PATCH v6 13/22] x86/virt/seamldr: Install a new TDX module Chao Gao
2026-03-26 8:44 ` [PATCH v6 14/22] x86/virt/seamldr: Do TDX per-CPU initialization after updates Chao Gao
2026-03-26 8:44 ` [PATCH v6 15/22] x86/virt/tdx: Restore TDX module state Chao Gao
2026-03-26 8:44 ` [PATCH v6 16/22] x86/virt/tdx: Update tdx_sysinfo and check features post-update Chao Gao
2026-03-26 13:03 ` Chao Gao
2026-03-26 8:44 ` [PATCH v6 17/22] x86/virt/tdx: Avoid updates during update-sensitive operations Chao Gao
2026-03-26 8:44 ` [PATCH v6 18/22] coco/tdx-host: Don't expose P-SEAMLDR features on CPUs with erratum Chao Gao
2026-03-26 8:44 ` [PATCH v6 19/22] x86/virt/tdx: Enable TDX module runtime updates Chao Gao
2026-03-26 8:44 ` [PATCH v6 20/22] coco/tdx-host: Document TDX module update compatibility criteria Chao Gao
2026-03-26 8:44 ` [PATCH v6 21/22] x86/virt/tdx: Document TDX module update Chao Gao
2026-03-26 8:44 ` [PATCH v6 22/22] x86/virt/seamldr: Log TDX module update failures Chao Gao
2026-03-26 8:52 ` Chao Gao [this message]
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=acTzzi2vuqga1P1d@intel.com \
--to=chao.gao@intel.com \
--cc=bigeasy@linutronix.de \
--cc=binbin.wu@linux.intel.com \
--cc=bp@alien8.de \
--cc=clrkwllms@kernel.org \
--cc=corbet@lwn.net \
--cc=dan.j.williams@intel.com \
--cc=dave.hansen@linux.intel.com \
--cc=hpa@zytor.com \
--cc=ira.weiny@intel.com \
--cc=kai.huang@intel.com \
--cc=kas@kernel.org \
--cc=kvm@vger.kernel.org \
--cc=linux-coco@lists.linux.dev \
--cc=linux-doc@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-rt-devel@lists.linux.dev \
--cc=mingo@redhat.com \
--cc=nik.borisov@suse.com \
--cc=paulmck@kernel.org \
--cc=pbonzini@redhat.com \
--cc=reinette.chatre@intel.com \
--cc=rick.p.edgecombe@intel.com \
--cc=rostedt@goodmis.org \
--cc=sagis@google.com \
--cc=seanjc@google.com \
--cc=skhan@linuxfoundation.org \
--cc=tglx@kernel.org \
--cc=tony.lindgren@linux.intel.com \
--cc=vannapurve@google.com \
--cc=vishal.l.verma@intel.com \
--cc=x86@kernel.org \
--cc=xiaoyao.li@intel.com \
--cc=yan.y.zhao@intel.com \
--cc=yilun.xu@linux.intel.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox