* [PATCH v3 11/26] x86/virt/seamldr: Block TDX Module updates if any CPU is offline
From: Chao Gao @ 2026-01-23 14:55 UTC (permalink / raw)
To: linux-coco, linux-kernel, kvm, x86
Cc: reinette.chatre, ira.weiny, kai.huang, dan.j.williams, yilun.xu,
sagis, vannapurve, paulmck, nik.borisov, zhenzhong.duan, seanjc,
rick.p.edgecombe, kas, dave.hansen, vishal.l.verma, Chao Gao,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin
In-Reply-To: <20260123145645.90444-1-chao.gao@intel.com>
P-SEAMLDR requires every CPU to call the SEAMLDR.INSTALL SEAMCALL during
updates. So, every CPU should be online.
Check if all CPUs are online and abort the update if any CPU is offline at
the very beginning. Without this check, P-SEAMLDR will report failure at a
later phase where the old TDX module is gone and TDs have to be killed.
Signed-off-by: Chao Gao <chao.gao@intel.com>
---
arch/x86/virt/vmx/tdx/seamldr.c | 8 ++++++++
1 file changed, 8 insertions(+)
diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
index af7a6621e5e0..88388aa0fb5f 100644
--- a/arch/x86/virt/vmx/tdx/seamldr.c
+++ b/arch/x86/virt/vmx/tdx/seamldr.c
@@ -6,6 +6,8 @@
*/
#define pr_fmt(fmt) "seamldr: " fmt
+#include <linux/cpuhplock.h>
+#include <linux/cpumask.h>
#include <linux/irqflags.h>
#include <linux/mm.h>
#include <linux/types.h>
@@ -84,6 +86,12 @@ int seamldr_install_module(const u8 *data, u32 size)
if (!is_vmalloc_addr(data))
return -EINVAL;
+ guard(cpus_read_lock)();
+ if (!cpumask_equal(cpu_online_mask, cpu_present_mask)) {
+ pr_err("Cannot update TDX module if any CPU is offline\n");
+ return -EBUSY;
+ }
+
/* TODO: Update TDX Module here */
return 0;
}
--
2.47.3
^ permalink raw reply related
* [PATCH v3 10/26] coco/tdx-host: Implement FW_UPLOAD sysfs ABI for TDX Module updates
From: Chao Gao @ 2026-01-23 14:55 UTC (permalink / raw)
To: linux-coco, linux-kernel, kvm, x86
Cc: reinette.chatre, ira.weiny, kai.huang, dan.j.williams, yilun.xu,
sagis, vannapurve, paulmck, nik.borisov, zhenzhong.duan, seanjc,
rick.p.edgecombe, kas, dave.hansen, vishal.l.verma, Chao Gao,
Farrah Chen, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
H. Peter Anvin
In-Reply-To: <20260123145645.90444-1-chao.gao@intel.com>
The firmware upload framework provides a standard mechanism for firmware
updates by allowing device drivers to expose sysfs interfaces for
user-initiated updates.
Register with this framework to expose sysfs interfaces for TDX Module
updates and implement operations to process data blobs supplied by
userspace.
Note that:
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. TDX Module Updates complete synchronously within .write(), meaning
.poll_complete() is only called after successful updates and therefore
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>
Tested-by: Farrah Chen <farrah.chen@intel.com>
---
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 | 2 +
arch/x86/include/asm/tdx.h | 5 ++
arch/x86/virt/vmx/tdx/seamldr.c | 19 ++++
drivers/virt/coco/tdx-host/Kconfig | 2 +
drivers/virt/coco/tdx-host/tdx-host.c | 124 +++++++++++++++++++++++++-
5 files changed, 151 insertions(+), 1 deletion(-)
diff --git a/arch/x86/include/asm/seamldr.h b/arch/x86/include/asm/seamldr.h
index d1e9f6e16e8d..692bde5e9bb4 100644
--- a/arch/x86/include/asm/seamldr.h
+++ b/arch/x86/include/asm/seamldr.h
@@ -20,8 +20,10 @@ struct seamldr_info {
#ifdef CONFIG_INTEL_TDX_MODULE_UPDATE
const struct seamldr_info *seamldr_get_info(void);
+int seamldr_install_module(const u8 *data, u32 size);
#else
static inline const struct seamldr_info *seamldr_get_info(void) { return NULL; }
+static inline int seamldr_install_module(const u8 *data, u32 size) { return -EOPNOTSUPP; }
#endif
#endif
diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index cb2219302dfc..ffadbf64d0c1 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -103,6 +103,11 @@ 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)
+{
+ return false; /* To be enabled when kernel is ready */
+}
+
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 6a83ae405fac..af7a6621e5e0 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/irqflags.h>
+#include <linux/mm.h>
#include <linux/types.h>
#include <asm/seamldr.h>
@@ -69,3 +70,21 @@ const struct seamldr_info *seamldr_get_info(void)
return seamldr_call(P_SEAMLDR_INFO, &args) ? NULL : &seamldr_info;
}
EXPORT_SYMBOL_FOR_MODULES(seamldr_get_info, "tdx-host");
+
+/**
+ * seamldr_install_module - Install a new TDX module
+ * @data: Pointer to the TDX module binary data. It should be vmalloc'd
+ * memory.
+ * @size: Size of the TDX module binary data
+ *
+ * Returns 0 on success, negative error code on failure.
+ */
+int seamldr_install_module(const u8 *data, u32 size)
+{
+ if (!is_vmalloc_addr(data))
+ return -EINVAL;
+
+ /* 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 6a9199e6c2c6..59aaca2252b0 100644
--- a/drivers/virt/coco/tdx-host/Kconfig
+++ b/drivers/virt/coco/tdx-host/Kconfig
@@ -12,6 +12,8 @@ config TDX_HOST_SERVICES
config INTEL_TDX_MODULE_UPDATE
bool "Intel TDX module runtime update"
depends on TDX_HOST_SERVICES
+ select FW_LOADER
+ select FW_UPLOAD
help
This enables the kernel to support TDX module runtime update. This
allows the admin to update the TDX module to another compatible
diff --git a/drivers/virt/coco/tdx-host/tdx-host.c b/drivers/virt/coco/tdx-host/tdx-host.c
index f4ce89522806..06487de2ebfe 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>
@@ -20,6 +21,13 @@ static const struct x86_cpu_id tdx_host_ids[] = {
};
MODULE_DEVICE_TABLE(x86cpu, tdx_host_ids);
+struct tdx_fw_upload_status {
+ bool cancel_request;
+};
+
+struct fw_upload *tdx_fwl;
+static struct tdx_fw_upload_status tdx_fw_upload_status;
+
static ssize_t version_show(struct device *dev, struct device_attribute *attr,
char *buf)
{
@@ -100,6 +108,120 @@ static const struct attribute_group *tdx_host_groups[] = {
NULL,
};
+static enum fw_upload_err tdx_fw_prepare(struct fw_upload *fwl,
+ const u8 *data, u32 size)
+{
+ struct tdx_fw_upload_status *status = fwl->dd_handle;
+
+ status->cancel_request = false;
+
+ 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)
+{
+ struct tdx_fw_upload_status *status = fwl->dd_handle;
+ int ret;
+
+ if (status->cancel_request) {
+ status->cancel_request = false;
+ return FW_UPLOAD_ERR_CANCELED;
+ }
+
+ /*
+ * 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;
+}
+
+static void tdx_fw_cancel(struct fw_upload *fwl)
+{
+ struct tdx_fw_upload_status *status = fwl->dd_handle;
+
+ status->cancel_request = true;
+}
+
+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_init(struct device *dev)
+{
+ const struct tdx_sys_info *tdx_sysinfo = tdx_get_sysinfo();
+ int ret;
+
+ if (WARN_ON_ONCE(!tdx_sysinfo))
+ return;
+
+ if (!IS_ENABLED(CONFIG_INTEL_TDX_MODULE_UPDATE))
+ return;
+
+ if (!tdx_supports_runtime_update(tdx_sysinfo))
+ pr_info("Current TDX Module cannot be updated. Consider BIOS updates\n");
+
+ tdx_fwl = firmware_upload_register(THIS_MODULE, dev, "seamldr_upload",
+ &tdx_fw_ops, &tdx_fw_upload_status);
+ ret = PTR_ERR_OR_ZERO(tdx_fwl);
+ if (ret)
+ pr_err("failed to register module uploader %d\n", ret);
+}
+
+static void seamldr_deinit(void)
+{
+ if (tdx_fwl)
+ firmware_upload_unregister(tdx_fwl);
+}
+
+static int tdx_host_probe(struct faux_device *fdev)
+{
+ seamldr_init(&fdev->dev);
+ return 0;
+}
+
+static void tdx_host_remove(struct faux_device *fdev)
+{
+ seamldr_deinit();
+}
+
+static struct faux_device_ops tdx_host_ops = {
+ .probe = tdx_host_probe,
+ .remove = tdx_host_remove,
+};
+
static struct faux_device *fdev;
static int __init tdx_host_init(void)
@@ -107,7 +229,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
* [PATCH v3 09/26] coco/tdx-host: Expose P-SEAMLDR information via sysfs
From: Chao Gao @ 2026-01-23 14:55 UTC (permalink / raw)
To: linux-coco, linux-kernel, kvm, x86
Cc: reinette.chatre, ira.weiny, kai.huang, dan.j.williams, yilun.xu,
sagis, vannapurve, paulmck, nik.borisov, zhenzhong.duan, seanjc,
rick.p.edgecombe, kas, dave.hansen, vishal.l.verma, Chao Gao,
Farrah Chen
In-Reply-To: <20260123145645.90444-1-chao.gao@intel.com>
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.
Signed-off-by: Chao Gao <chao.gao@intel.com>
Tested-by: Farrah Chen <farrah.chen@intel.com>
---
v3:
- use #ifdef rather than .is_visible() to control P-SEAMLDR sysfs
visibility [Yilun]
---
.../ABI/testing/sysfs-devices-faux-tdx-host | 25 ++++++++
drivers/virt/coco/tdx-host/tdx-host.c | 60 ++++++++++++++++++-
2 files changed, 84 insertions(+), 1 deletion(-)
diff --git a/Documentation/ABI/testing/sysfs-devices-faux-tdx-host b/Documentation/ABI/testing/sysfs-devices-faux-tdx-host
index 901abbae2e61..a3f155977016 100644
--- a/Documentation/ABI/testing/sysfs-devices-faux-tdx-host
+++ b/Documentation/ABI/testing/sysfs-devices-faux-tdx-host
@@ -4,3 +4,28 @@ 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 and 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 check.
+
+What: /sys/devices/faux/tdx_host/seamldr/num_remaining_updates
+Contact: linux-coco@lists.linux.dev
+Description: (RO) Report the number of remaining updates that can be performed.
+ The CPU keeps track of TCB versions for each TDX Module that
+ has been loaded. Since this tracking database has finite
+ capacity, there's a maximum number of 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 P-SEAMLDR doesn't support updates.
+
+ See Intel® Trust Domain Extensions - SEAM Loader (SEAMLDR)
+ Interface Specification Chapter 3.3 "SEAMLDR_INFO" and Chapter
+ 4.2 "SEAMLDR.INSTALL" for more information. The documentation is
+ available at:
+ https://cdrdv2-public.intel.com/739045/intel-tdx-seamldr-interface-specification.pdf
diff --git a/drivers/virt/coco/tdx-host/tdx-host.c b/drivers/virt/coco/tdx-host/tdx-host.c
index 0424933b2560..f4ce89522806 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[] = {
@@ -40,7 +41,64 @@ static struct attribute *tdx_host_attrs[] = {
&dev_attr_version.attr,
NULL,
};
-ATTRIBUTE_GROUPS(tdx_host);
+
+struct attribute_group tdx_host_group = {
+ .attrs = tdx_host_attrs,
+};
+
+#ifdef CONFIG_INTEL_TDX_MODULE_UPDATE
+static ssize_t seamldr_version_show(struct device *dev, struct device_attribute *attr,
+ char *buf)
+{
+ const struct seamldr_info *info = seamldr_get_info();
+
+ if (!info)
+ return -ENXIO;
+
+ 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)
+{
+ const struct seamldr_info *info = seamldr_get_info();
+
+ if (!info)
+ return -ENXIO;
+
+ return sysfs_emit(buf, "%u\n", info->num_remaining_updates);
+}
+
+/*
+ * Open-code DEVICE_ATTR_RO to specify a different 'show' function for
+ * P-SEAMLDR version as version_show() is used for TDX Module version.
+ */
+static struct device_attribute dev_attr_seamldr_version =
+ __ATTR(version, 0444, seamldr_version_show, NULL);
+static DEVICE_ATTR_RO(num_remaining_updates);
+
+static struct attribute *seamldr_attrs[] = {
+ &dev_attr_seamldr_version.attr,
+ &dev_attr_num_remaining_updates.attr,
+ NULL,
+};
+
+static struct attribute_group seamldr_group = {
+ .name = "seamldr",
+ .attrs = seamldr_attrs,
+};
+#endif /* CONFIG_INTEL_TDX_MODULE_UPDATE */
+
+static const struct attribute_group *tdx_host_groups[] = {
+ &tdx_host_group,
+#ifdef CONFIG_INTEL_TDX_MODULE_UPDATE
+ &seamldr_group,
+#endif
+ NULL,
+};
static struct faux_device *fdev;
--
2.47.3
^ permalink raw reply related
* [PATCH v3 08/26] x86/virt/seamldr: Retrieve P-SEAMLDR information
From: Chao Gao @ 2026-01-23 14:55 UTC (permalink / raw)
To: linux-coco, linux-kernel, kvm, x86
Cc: reinette.chatre, ira.weiny, kai.huang, dan.j.williams, yilun.xu,
sagis, vannapurve, paulmck, nik.borisov, zhenzhong.duan, seanjc,
rick.p.edgecombe, kas, dave.hansen, vishal.l.verma, Chao Gao,
Farrah Chen, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
H. Peter Anvin
In-Reply-To: <20260123145645.90444-1-chao.gao@intel.com>
P-SEAMLDR returns its information e.g., version and supported features, 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.
Add and export seamldr_get_info() which retrieves P-SEAMLDR information by
invoking SEAMLDR.INFO SEAMCALL in preparation for exposing P-SEAMLDR
version and other necessary information to userspace.
Signed-off-by: Chao Gao <chao.gao@intel.com>
Tested-by: Farrah Chen <farrah.chen@intel.com>
---
arch/x86/include/asm/seamldr.h | 27 +++++++++++++++++++++++++++
arch/x86/virt/vmx/tdx/seamldr.c | 17 ++++++++++++++++-
2 files changed, 43 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..d1e9f6e16e8d
--- /dev/null
+++ b/arch/x86/include/asm/seamldr.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_SEAMLDR_H
+#define _ASM_X86_SEAMLDR_H
+
+#include <linux/types.h>
+
+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;
+ u8 reserved0[4];
+ u32 num_remaining_updates;
+ u8 reserved1[224];
+} __packed;
+
+#ifdef CONFIG_INTEL_TDX_MODULE_UPDATE
+const struct seamldr_info *seamldr_get_info(void);
+#else
+static inline const struct seamldr_info *seamldr_get_info(void) { return NULL; }
+#endif
+
+#endif
diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
index b99d73f7bb08..6a83ae405fac 100644
--- a/arch/x86/virt/vmx/tdx/seamldr.c
+++ b/arch/x86/virt/vmx/tdx/seamldr.c
@@ -9,9 +9,16 @@
#include <linux/irqflags.h>
#include <linux/types.h>
+#include <asm/seamldr.h>
+
#include "seamcall.h"
-static __maybe_unused int seamldr_call(u64 fn, struct tdx_module_args *args)
+/* P-SEAMLDR SEAMCALL leaf function */
+#define P_SEAMLDR_INFO 0x8000000000000000
+
+static struct seamldr_info seamldr_info __aligned(256);
+
+static inline int seamldr_call(u64 fn, struct tdx_module_args *args)
{
unsigned long flags;
u64 vmcs;
@@ -54,3 +61,11 @@ static __maybe_unused int seamldr_call(u64 fn, struct tdx_module_args *args)
WARN_ONCE(1, "Failed to save/restore the current VMCS");
return -EIO;
}
+
+const struct seamldr_info *seamldr_get_info(void)
+{
+ struct tdx_module_args args = { .rcx = __pa(&seamldr_info) };
+
+ return seamldr_call(P_SEAMLDR_INFO, &args) ? NULL : &seamldr_info;
+}
+EXPORT_SYMBOL_FOR_MODULES(seamldr_get_info, "tdx-host");
--
2.47.3
^ permalink raw reply related
* [PATCH v3 07/26] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs
From: Chao Gao @ 2026-01-23 14:55 UTC (permalink / raw)
To: linux-coco, linux-kernel, kvm, x86
Cc: reinette.chatre, ira.weiny, kai.huang, dan.j.williams, yilun.xu,
sagis, vannapurve, paulmck, nik.borisov, zhenzhong.duan, seanjc,
rick.p.edgecombe, kas, dave.hansen, vishal.l.verma, Chao Gao,
Farrah Chen, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
H. Peter Anvin
In-Reply-To: <20260123145645.90444-1-chao.gao@intel.com>
Software needs to talk with P-SEAMLDR via P-SEAMLDR SEAMCALLs. So, add a
wrapper for P-SEAMLDR SEAMCALLs.
Save and restore the current VMCS using VMPTRST and VMPTRLD instructions
to avoid breaking KVM. Doing so is because P-SEAMLDR SEAMCALLs would
invalidate the current VMCS as documented in Intel® Trust Domain CPU
Architectural Extensions (May 2021 edition) Chapter 2.3 [1]:
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.
Disable interrupts to prevent KVM code from interfering with P-SEAMLDR
SEAMCALLs. For example, if a vCPU is scheduled before the current VMCS is
restored, it may encounter an invalid current VMCS, causing its VMX
instruction to fail. Additionally, if KVM sends IPIs to invalidate a
current VMCS and the invalidation occurs right after the current VMCS is
saved, that VMCS will be reloaded after P-SEAMLDR SEAMCALLs, leading to
unexpected behavior.
NMIs are not a problem, as the only scenario where instructions relying on
the current-VMCS are used is during guest PMI handling in KVM. This occurs
immediately after VM exits with IRQ and NMI disabled, ensuring no
interference with P-SEAMLDR SEAMCALLs.
Signed-off-by: Chao Gao <chao.gao@intel.com>
Tested-by: Farrah Chen <farrah.chen@intel.com>
Link: https://cdrdv2.intel.com/v1/dl/getContent/733582 # [1]
---
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 | 1 +
arch/x86/virt/vmx/tdx/seamldr.c | 56 ++++++++++++++++++++++++++++++
drivers/virt/coco/tdx-host/Kconfig | 10 ++++++
3 files changed, 67 insertions(+)
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..26aea3531c36 100644
--- a/arch/x86/virt/vmx/tdx/Makefile
+++ b/arch/x86/virt/vmx/tdx/Makefile
@@ -1,2 +1,3 @@
# SPDX-License-Identifier: GPL-2.0-only
obj-y += seamcall.o tdx.o
+obj-$(CONFIG_INTEL_TDX_MODULE_UPDATE) += seamldr.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..b99d73f7bb08
--- /dev/null
+++ b/arch/x86/virt/vmx/tdx/seamldr.c
@@ -0,0 +1,56 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright(c) 2025 Intel Corporation.
+ *
+ * Intel TDX module runtime update
+ */
+#define pr_fmt(fmt) "seamldr: " fmt
+
+#include <linux/irqflags.h>
+#include <linux/types.h>
+
+#include "seamcall.h"
+
+static __maybe_unused int seamldr_call(u64 fn, struct tdx_module_args *args)
+{
+ unsigned long flags;
+ u64 vmcs;
+ int ret;
+
+ if (!is_seamldr_call(fn))
+ return -EINVAL;
+
+ /*
+ * SEAMRET from P-SEAMLDR invalidates the current VMCS. Save/restore
+ * the VMCS across P-SEAMLDR SEAMCALLs to avoid clobbering KVM state.
+ * Disable interrupts as KVM is allowed to do VMREAD/VMWRITE in IRQ
+ * context (but not NMI context).
+ */
+ local_irq_save(flags);
+
+ asm goto("1: vmptrst %0\n\t"
+ _ASM_EXTABLE(1b, %l[error])
+ : "=m" (vmcs) : : "cc" : error);
+
+ ret = seamldr_prerr(fn, args);
+
+ /*
+ * Restore the current VMCS pointer. VMPTSTR "returns" all ones if the
+ * current VMCS is invalid.
+ */
+ if (vmcs != -1ULL) {
+ asm goto("1: vmptrld %0\n\t"
+ "jna %l[error]\n\t"
+ _ASM_EXTABLE(1b, %l[error])
+ : : "m" (vmcs) : "cc" : error);
+ }
+
+ local_irq_restore(flags);
+ return ret;
+
+error:
+ local_irq_restore(flags);
+
+ WARN_ONCE(1, "Failed to save/restore the current VMCS");
+ return -EIO;
+}
diff --git a/drivers/virt/coco/tdx-host/Kconfig b/drivers/virt/coco/tdx-host/Kconfig
index e58bad148a35..6a9199e6c2c6 100644
--- a/drivers/virt/coco/tdx-host/Kconfig
+++ b/drivers/virt/coco/tdx-host/Kconfig
@@ -8,3 +8,13 @@ config TDX_HOST_SERVICES
Say y or m if enabling support for confidential virtual machine
support (CONFIG_INTEL_TDX_HOST). The module is called tdx_host.ko
+
+config INTEL_TDX_MODULE_UPDATE
+ bool "Intel TDX module runtime update"
+ depends on TDX_HOST_SERVICES
+ help
+ This enables the kernel to support TDX module runtime update. This
+ allows the admin to update the TDX module to another compatible
+ version without the need to terminate running TDX guests.
+
+ If unsure, say N.
--
2.47.3
^ permalink raw reply related
* [PATCH v3 06/26] x86/virt/tdx: Prepare to support P-SEAMLDR SEAMCALLs
From: Chao Gao @ 2026-01-23 14:55 UTC (permalink / raw)
To: linux-coco, linux-kernel, kvm, x86
Cc: reinette.chatre, ira.weiny, kai.huang, dan.j.williams, yilun.xu,
sagis, vannapurve, paulmck, nik.borisov, zhenzhong.duan, seanjc,
rick.p.edgecombe, kas, dave.hansen, vishal.l.verma, Chao Gao,
Farrah Chen, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
H. Peter Anvin
In-Reply-To: <20260123145645.90444-1-chao.gao@intel.com>
P-SEAMLDR is another component alongside the TDX module within the
protected SEAM range. P-SEAMLDR can update the TDX module at runtime.
Software can talk with P-SEAMLDR via SEAMCALLs with the bit 63 of RAX
(leaf number) set to 1 (a.k.a P-SEAMLDR SEAMCALLs).
P-SEAMLDR SEAMCALLs differ from SEAMCALLs of the TDX module in terms of
error codes and the handling of the current VMCS.
In preparation for adding support for P-SEAMLDR SEAMCALLs, do the two
following changes to SEAMCALL low-level helpers:
1) Tweak sc_retry() to retry on "lack of entropy" errors reported by
P-SEAMLDR because it uses a different error code.
2) Add seamldr_err() to log error messages on P-SEAMLDR SEAMCALL failures.
Signed-off-by: Chao Gao <chao.gao@intel.com>
Tested-by: Farrah Chen <farrah.chen@intel.com>
---
Add seamldr_prerr() as a macro to be consistent with existing code. If
maintainers would like to switch these to static inline functions then I
would be happy to add a new patch to convert existing macros to static
inline functions and build on that.
v3:
- print P-SEAMLDR leaf numbers in hex
- use %# to print error code [Binbin]
- mark the is_seamldr_call() call as unlikely [Binbin]
- remove the function to get the error code for retry from leaf numbers
[Yilun]
v2:
- use a macro rather than an inline function for seamldr_err() for
consistency.
---
arch/x86/virt/vmx/tdx/seamcall.h | 28 +++++++++++++++++++++++++++-
1 file changed, 27 insertions(+), 1 deletion(-)
diff --git a/arch/x86/virt/vmx/tdx/seamcall.h b/arch/x86/virt/vmx/tdx/seamcall.h
index 0912e03fabfe..256f71d6ca70 100644
--- a/arch/x86/virt/vmx/tdx/seamcall.h
+++ b/arch/x86/virt/vmx/tdx/seamcall.h
@@ -34,15 +34,28 @@ static __always_inline u64 __seamcall_dirty_cache(sc_func_t func, u64 fn,
return func(fn, args);
}
+#define SEAMLDR_RND_NO_ENTROPY 0x8000000000030001ULL
+
+#define SEAMLDR_SEAMCALL_MASK _BITUL(63)
+
+static inline bool is_seamldr_call(u64 fn)
+{
+ return fn & SEAMLDR_SEAMCALL_MASK;
+}
+
static __always_inline u64 sc_retry(sc_func_t func, u64 fn,
struct tdx_module_args *args)
{
+ u64 retry_code = TDX_RND_NO_ENTROPY;
int retry = RDRAND_RETRY_LOOPS;
u64 ret;
+ if (unlikely(is_seamldr_call(fn)))
+ retry_code = SEAMLDR_RND_NO_ENTROPY;
+
do {
ret = func(fn, args);
- } while (ret == TDX_RND_NO_ENTROPY && --retry);
+ } while (ret == retry_code && --retry);
return ret;
}
@@ -68,6 +81,16 @@ static inline void seamcall_err_ret(u64 fn, u64 err,
args->r9, args->r10, args->r11);
}
+static inline void seamldr_err(u64 fn, u64 err, struct tdx_module_args *args)
+{
+ /*
+ * Note: P-SEAMLDR leaf numbers are printed in hex as they have
+ * bit 63 set, making them hard to read and understand if printed
+ * in decimal
+ */
+ pr_err("P-SEAMLDR (%llx) failed: %#016llx\n", fn, err);
+}
+
static __always_inline int sc_retry_prerr(sc_func_t func,
sc_err_func_t err_func,
u64 fn, struct tdx_module_args *args)
@@ -96,4 +119,7 @@ static __always_inline int sc_retry_prerr(sc_func_t func,
#define seamcall_prerr_ret(__fn, __args) \
sc_retry_prerr(__seamcall_ret, seamcall_err_ret, (__fn), (__args))
+#define seamldr_prerr(__fn, __args) \
+ sc_retry_prerr(__seamcall, seamldr_err, (__fn), (__args))
+
#endif
--
2.47.3
^ permalink raw reply related
* [PATCH v3 05/26] coco/tdx-host: Expose TDX Module version
From: Chao Gao @ 2026-01-23 14:55 UTC (permalink / raw)
To: linux-coco, linux-kernel, kvm, x86
Cc: reinette.chatre, ira.weiny, kai.huang, dan.j.williams, yilun.xu,
sagis, vannapurve, paulmck, nik.borisov, zhenzhong.duan, seanjc,
rick.p.edgecombe, kas, dave.hansen, vishal.l.verma, Chao Gao
In-Reply-To: <20260123145645.90444-1-chao.gao@intel.com>
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.
This approach follows the pattern used by microcode updates and other
CoCo implementations:
1. AMD has a PCI device for the PSP for SEV which provides an existing
place to hang their equivalent metadata.
2. ARM CCA will likely have a faux device (although it isn't obvious if
they have a need to export version information there) [1]
3. Microcode revisions are exposed as CPU device attributes
One bonus of exposing TDX Module version via sysfs is: TDX Module
version information remains available even after dmesg logs are cleared.
Signed-off-by: Chao Gao <chao.gao@intel.com>
Link: https://lore.kernel.org/all/2025073035-bulginess-rematch-b92e@gregkh/ # [1]
---
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..901abbae2e61
--- /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 and 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
* [PATCH v3 04/26] coco/tdx-host: Introduce a "tdx_host" device
From: Chao Gao @ 2026-01-23 14:55 UTC (permalink / raw)
To: linux-coco, linux-kernel, kvm, x86
Cc: reinette.chatre, ira.weiny, kai.huang, dan.j.williams, yilun.xu,
sagis, vannapurve, paulmck, nik.borisov, zhenzhong.duan, seanjc,
rick.p.edgecombe, kas, dave.hansen, vishal.l.verma, Chao Gao,
Jonathan Cameron, Thomas Gleixner, Ingo Molnar, Borislav Petkov,
H. Peter Anvin
In-Reply-To: <20260123145645.90444-1-chao.gao@intel.com>
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 as 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>
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 b44723ef4a14..a0990c5dd78d 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -1434,7 +1434,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..e58bad148a35
--- /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
* [PATCH v3 02/26] x86/virt/tdx: Use %# prefix for hex values in SEAMCALL error messages
From: Chao Gao @ 2026-01-23 14:55 UTC (permalink / raw)
To: linux-coco, linux-kernel, kvm, x86
Cc: reinette.chatre, ira.weiny, kai.huang, dan.j.williams, yilun.xu,
sagis, vannapurve, paulmck, nik.borisov, zhenzhong.duan, seanjc,
rick.p.edgecombe, kas, dave.hansen, vishal.l.verma, Chao Gao,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin
In-Reply-To: <20260123145645.90444-1-chao.gao@intel.com>
"%#" format specifier automatically adds the "0x" prefix and has one less
character than "0x%".
For conciseness, replace "0x%" with "%#" when printing hexadecimal values
in SEAMCALL error messages.
Suggested-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Chao Gao <chao.gao@intel.com>
---
"0x%" is also used to print TDMR ranges. I didn't convert them to reduce
code churn, but if they should be converted for consistency, I'm happy
to do that.
v2: new
---
arch/x86/virt/vmx/tdx/tdx.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index dbc7cb08ca53..2218bb42af40 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -63,16 +63,16 @@ 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 (%llu) failed: 0x%016llx\n", fn, err);
+ pr_err("SEAMCALL (%llu) failed: %#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",
+ pr_err("RCX %#016llx RDX %#016llx R08 %#016llx\n",
args->rcx, args->rdx, args->r8);
- pr_err("R09 0x%016llx R10 0x%016llx R11 0x%016llx\n",
+ pr_err("R09 %#016llx R10 %#016llx R11 %#016llx\n",
args->r9, args->r10, args->r11);
}
--
2.47.3
^ permalink raw reply related
* [PATCH v3 03/26] x86/virt/tdx: Move low level SEAMCALL helpers out of <asm/tdx.h>
From: Chao Gao @ 2026-01-23 14:55 UTC (permalink / raw)
To: linux-coco, linux-kernel, kvm, x86
Cc: reinette.chatre, ira.weiny, kai.huang, dan.j.williams, yilun.xu,
sagis, vannapurve, paulmck, nik.borisov, zhenzhong.duan, seanjc,
rick.p.edgecombe, kas, dave.hansen, vishal.l.verma, Chao Gao,
Thomas Gleixner, Ingo Molnar, Borislav Petkov, H. Peter Anvin
In-Reply-To: <20260123145645.90444-1-chao.gao@intel.com>
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.h". Also,
currently tdx.c has seamcall_prerr*() helpers which additionally print
error message when calling seamcall*() fails. Move them to "seamcall.h"
as well. In such way all low level SEAMCALL helpers are in a dedicated
place, which is much more readable.
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>
---
v2:
- new
---
arch/x86/include/asm/tdx.h | 47 ---------------
arch/x86/virt/vmx/tdx/seamcall.h | 99 ++++++++++++++++++++++++++++++++
arch/x86/virt/vmx/tdx/tdx.c | 46 +--------------
3 files changed, 100 insertions(+), 92 deletions(-)
create mode 100644 arch/x86/virt/vmx/tdx/seamcall.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.h b/arch/x86/virt/vmx/tdx/seamcall.h
new file mode 100644
index 000000000000..0912e03fabfe
--- /dev/null
+++ b/arch/x86/virt/vmx/tdx/seamcall.h
@@ -0,0 +1,99 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/* Copyright (C) 2025 Intel Corporation */
+#ifndef _X86_VIRT_SEAMCALL_H
+#define _X86_VIRT_SEAMCALL_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 {
+ ret = func(fn, args);
+ } 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 (%llu) failed: %#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 %#016llx RDX %#016llx R08 %#016llx\n",
+ args->rcx, args->rdx, args->r8);
+ pr_err("R09 %#016llx R10 %#016llx R11 %#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
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index 2218bb42af40..b44723ef4a14 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 "seamcall.h"
#include "tdx.h"
static u32 tdx_global_keyid __ro_after_init;
@@ -59,51 +60,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 (%llu) failed: %#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 %#016llx RDX %#016llx R08 %#016llx\n",
- args->rcx, args->rdx, args->r8);
- pr_err("R09 %#016llx R10 %#016llx R11 %#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
* [PATCH v3 01/26] x86/virt/tdx: Print SEAMCALL leaf numbers in decimal
From: Chao Gao @ 2026-01-23 14:55 UTC (permalink / raw)
To: linux-coco, linux-kernel, kvm, x86
Cc: reinette.chatre, ira.weiny, kai.huang, dan.j.williams, yilun.xu,
sagis, vannapurve, paulmck, nik.borisov, zhenzhong.duan, seanjc,
rick.p.edgecombe, kas, dave.hansen, vishal.l.verma, Chao Gao,
Kirill A. Shutemov, Farrah Chen, Thomas Gleixner, Ingo Molnar,
Borislav Petkov, H. Peter Anvin
In-Reply-To: <20260123145645.90444-1-chao.gao@intel.com>
Both TDX spec and kernel defines SEAMCALL leaf numbers as decimal. Printing
them in hex makes no sense. Correct it.
Suggested-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com>
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>
Reviewed-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
---
v2:
- print leaf numbers with %llu
---
arch/x86/virt/vmx/tdx/tdx.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index 5ce4ebe99774..dbc7cb08ca53 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -63,7 +63,7 @@ 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);
+ pr_err("SEAMCALL (%llu) failed: 0x%016llx\n", fn, err);
}
static inline void seamcall_err_ret(u64 fn, u64 err,
--
2.47.3
^ permalink raw reply related
* [PATCH v3 00/26] Runtime TDX Module update support
From: Chao Gao @ 2026-01-23 14:55 UTC (permalink / raw)
To: linux-coco, linux-kernel, kvm, x86
Cc: reinette.chatre, ira.weiny, kai.huang, dan.j.williams, yilun.xu,
sagis, vannapurve, paulmck, nik.borisov, zhenzhong.duan, seanjc,
rick.p.edgecombe, kas, dave.hansen, vishal.l.verma, Chao Gao,
Borislav Petkov, H. Peter Anvin, Ingo Molnar, Paolo Bonzini,
Thomas Gleixner
Hi Reviewers,
With this posting, I'm hoping to collect more Reviewed-by or Acked-by tags.
Dave, since this version is still light on acks, it might not be ready for
your review.
Changelog:
v2->v3:
- Make this series self-contained and independently runnable, testable and
reviewable by
* Including dependent patches such as TDX Module version exposure and TDX
faux device creation
* Removing dependency on Sean's VMXON cleanups for now, the tdx-host device
simply checks that the TDX module is initialized, regardless of when or
who performed the initialization.
Note: If the KVM module is unloaded, all services exposed by the tdx-host
device will fail. This shouldn't be a big issue since proper errors will
be returned to userspace, similar to other failure cases.
- Handle updates during update-sensitive times and documented expectations for
TDX Module updates
- Rework how updates are aborted when errors occur midway
- Map Linux error codes to firmware upload error codes
- Preserve bit 63 in P-SEAMLDR SEAMCALL leaf numbers and display them in hex
- Do not fail the entire tdx-host device when update features encounter errors
- Drop superfluous is_visible() function for P-SEAMLDR sysfs nodes
- Add support for sigstruct sizes up to 16KB
- Move CONFIG_INTEL_TDX_MODULE_UPDATE kconfig entry under TDX_HOST_SERVICES
- Various cleanups and changelog improvements for clarity and consistency
- Collect review tags from ZhenZhong and Jonathan
- v2: https://lore.kernel.org/linux-coco/20251001025442.427697-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-v3/
== 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 require 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 more in patch 8). By
doing so, much of this complexity is shifted out of the kernel. The kernel
need 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
== 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 (25):
x86/virt/tdx: Print SEAMCALL leaf numbers in decimal
x86/virt/tdx: Use %# prefix for hex values in SEAMCALL error messages
coco/tdx-host: Introduce a "tdx_host" device
coco/tdx-host: Expose TDX Module version
x86/virt/tdx: Prepare to support P-SEAMLDR SEAMCALLs
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 FW_UPLOAD sysfs ABI for TDX Module updates
x86/virt/seamldr: Block TDX Module updates if any CPU is offline
x86/virt/seamldr: Verify availability of slots 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 after TDX module shutdown
x86/virt/seamldr: Log TDX Module update failures
x86/virt/seamldr: Install a new TDX Module
x86/virt/seamldr: Do TDX per-CPU initialization after updates
x86/virt/tdx: Establish contexts for the new TDX Module
x86/virt/tdx: Update tdx_sysinfo and check features post-update
x86/virt/tdx: Enable TDX Module runtime updates
x86/virt/seamldr: Extend sigstruct to 16KB
x86/virt/tdx: Avoid updates during update-sensitive operations
coco/tdx-host: Set and document TDX Module update expectations
Kai Huang (1):
x86/virt/tdx: Move low level SEAMCALL helpers out of <asm/tdx.h>
.../ABI/testing/sysfs-devices-faux-tdx-host | 76 ++++
arch/x86/include/asm/seamldr.h | 29 ++
arch/x86/include/asm/tdx.h | 66 +--
arch/x86/include/asm/tdx_global_metadata.h | 5 +
arch/x86/kvm/vmx/tdx_errno.h | 2 -
arch/x86/virt/vmx/tdx/Makefile | 1 +
arch/x86/virt/vmx/tdx/seamcall.h | 125 ++++++
arch/x86/virt/vmx/tdx/seamldr.c | 398 ++++++++++++++++++
arch/x86/virt/vmx/tdx/tdx.c | 153 ++++---
arch/x86/virt/vmx/tdx/tdx.h | 11 +-
arch/x86/virt/vmx/tdx/tdx_global_metadata.c | 13 +
drivers/virt/coco/Kconfig | 2 +
drivers/virt/coco/Makefile | 1 +
drivers/virt/coco/tdx-host/Kconfig | 22 +
drivers/virt/coco/tdx-host/Makefile | 1 +
drivers/virt/coco/tdx-host/tdx-host.c | 260 ++++++++++++
16 files changed, 1064 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.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
* Re: [PATCH v2] PCI/IDE: Fix duplicate stream symlink names for TSM class devices
From: Xu Yilun @ 2026-01-23 6:40 UTC (permalink / raw)
To: dan.j.williams
Cc: linux-coco, linux-pci, yilun.xu, baolu.lu, zhenzhong.duan,
linux-kernel, yi1.lai, helgaas
In-Reply-To: <6972c872acbb9_1d3310035@dwillia2-mobl4.notmuch>
> That is all a bit too much to do at this late date, so I think for
> v6.19-final just delete this ABI, and try again for v7.0.
I agree.
>
> -- 8< --
> From 2d236b203ea155d16d3251bd0e3bf4eeab2fcf6b Mon Sep 17 00:00:00 2001
> From: Dan Williams <dan.j.williams@intel.com>
> Date: Thu, 22 Jan 2026 16:35:56 -0800
> Subject: [PATCH] Revert "PCI/TSM: Report active IDE streams"
Tested, no problem.
^ permalink raw reply
* [PATCH kernel 2/2] crypto/ccp: Allow multiple streams on the same root bridge
From: Alexey Kardashevskiy @ 2026-01-23 5:30 UTC (permalink / raw)
To: linux-crypto
Cc: linux-kernel, Ashish Kalra, Tom Lendacky, John Allen, Herbert Xu,
David S. Miller, Dan Williams, Alexey Kardashevskiy, x86,
linux-coco, Pratik R . Sampat
In-Reply-To: <20260123053057.1350569-1-aik@amd.com>
IDE stream IDs are responsibility of a platform and in some cases TSM
allocates the numbers. AMD SEV TIO though leaves it to the host OS.
Mistakenly stream ID is hard coded to be the same as a traffic class.
Use the host bridge stream index for a newly allocated stream ID.
Fixes: 4be423572da1 ("crypto/ccp: Implement SEV-TIO PCIe IDE (phase1)")
Signed-off-by: Alexey Kardashevskiy <aik@amd.com>
---
drivers/crypto/ccp/sev-dev-tsm.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)
diff --git a/drivers/crypto/ccp/sev-dev-tsm.c b/drivers/crypto/ccp/sev-dev-tsm.c
index 7407b77c2ef2..40d02adaf3f6 100644
--- a/drivers/crypto/ccp/sev-dev-tsm.c
+++ b/drivers/crypto/ccp/sev-dev-tsm.c
@@ -198,8 +198,7 @@ static int stream_alloc(struct pci_dev *pdev, struct pci_ide **ide,
if (!ide1)
return -EFAULT;
- /* Blindly assign streamid=0 to TC=0, and so on */
- ide1->stream_id = tc;
+ ide1->stream_id = ide1->host_bridge_stream;
ide[tc] = ide1;
--
2.52.0
^ permalink raw reply related
* [PATCH kernel 1/2] crypto/ccp: Use PCI bridge defaults for IDE
From: Alexey Kardashevskiy @ 2026-01-23 5:30 UTC (permalink / raw)
To: linux-crypto
Cc: linux-kernel, Ashish Kalra, Tom Lendacky, John Allen, Herbert Xu,
David S. Miller, Dan Williams, Alexey Kardashevskiy, x86,
linux-coco, Pratik R . Sampat
In-Reply-To: <20260123053057.1350569-1-aik@amd.com>
The current number of streams in AMD TSM is 1 which is too little,
the core uses 255. Also, even if the module parameter is increased,
calling pci_ide_set_nr_streams() second time triggers WARN_ON.
Simplify the code by sticking to the PCI core defaults.
Fixes: 4be423572da1 ("crypto/ccp: Implement SEV-TIO PCIe IDE (phase1)")
Signed-off-by: Alexey Kardashevskiy <aik@amd.com>
---
drivers/crypto/ccp/sev-dev-tsm.c | 12 ------------
1 file changed, 12 deletions(-)
diff --git a/drivers/crypto/ccp/sev-dev-tsm.c b/drivers/crypto/ccp/sev-dev-tsm.c
index ea29cd5d0ff9..7407b77c2ef2 100644
--- a/drivers/crypto/ccp/sev-dev-tsm.c
+++ b/drivers/crypto/ccp/sev-dev-tsm.c
@@ -19,12 +19,6 @@
MODULE_IMPORT_NS("PCI_IDE");
-#define TIO_DEFAULT_NR_IDE_STREAMS 1
-
-static uint nr_ide_streams = TIO_DEFAULT_NR_IDE_STREAMS;
-module_param_named(ide_nr, nr_ide_streams, uint, 0644);
-MODULE_PARM_DESC(ide_nr, "Set the maximum number of IDE streams per PHB");
-
#define dev_to_sp(dev) ((struct sp_device *)dev_get_drvdata(dev))
#define dev_to_psp(dev) ((struct psp_device *)(dev_to_sp(dev)->psp_data))
#define dev_to_sev(dev) ((struct sev_device *)(dev_to_psp(dev)->sev_data))
@@ -193,7 +187,6 @@ static void streams_teardown(struct pci_ide **ide)
static int stream_alloc(struct pci_dev *pdev, struct pci_ide **ide,
unsigned int tc)
{
- struct pci_dev *rp = pcie_find_root_port(pdev);
struct pci_ide *ide1;
if (ide[tc]) {
@@ -201,11 +194,6 @@ static int stream_alloc(struct pci_dev *pdev, struct pci_ide **ide,
return -EBUSY;
}
- /* FIXME: find a better way */
- if (nr_ide_streams != TIO_DEFAULT_NR_IDE_STREAMS)
- pci_notice(pdev, "Enable non-default %d streams", nr_ide_streams);
- pci_ide_set_nr_streams(to_pci_host_bridge(rp->bus->bridge), nr_ide_streams);
-
ide1 = pci_ide_stream_alloc(pdev);
if (!ide1)
return -EFAULT;
--
2.52.0
^ permalink raw reply related
* [PATCH kernel 0/2] crypto/ccp: Fixes for PCI IDE
From: Alexey Kardashevskiy @ 2026-01-23 5:30 UTC (permalink / raw)
To: linux-crypto
Cc: linux-kernel, Ashish Kalra, Tom Lendacky, John Allen, Herbert Xu,
David S. Miller, Dan Williams, Alexey Kardashevskiy, x86,
linux-coco, Pratik R . Sampat
A couple of fixes for bugs discovered recently as we got more of
these devices and tested more configurations with multiple devices
on same and different bridges.
This is based on sha1
0499add8efd7 Paolo Bonzini Merge tag 'kvm-x86-fixes-6.19-rc1' of htts://github.com/kvm-x86/linux into HEAD
Please comment. Thanks.
Alexey Kardashevskiy (2):
crypto/ccp: Use PCI bridge defaults for IDE
crypto/ccp: Allow multiple streams on the same root bridge
drivers/crypto/ccp/sev-dev-tsm.c | 15 +--------------
1 file changed, 1 insertion(+), 14 deletions(-)
--
2.52.0
^ permalink raw reply
* Re: [PATCH v2] PCI/IDE: Fix duplicate stream symlink names for TSM class devices
From: dan.j.williams @ 2026-01-23 5:07 UTC (permalink / raw)
To: Xu Yilun, dan.j.williams
Cc: linux-coco, linux-pci, yilun.xu, baolu.lu, zhenzhong.duan,
linux-kernel, yi1.lai, helgaas
In-Reply-To: <aXLtILY85oMU5qlb@yilunxu-OptiPlex-7050>
Xu Yilun wrote:
> On Thu, Jan 22, 2026 at 05:07:01PM -0800, dan.j.williams@intel.com wrote:
> > dan.j.williams@ wrote:
> > [..]
> > > However, after seeing Jonathan's feedback and noticing that he missed
> > > that 'H' 'R' and 'E' are documented in the host bridge ABI I think it
> > > would be better to simplify this to just a link back to the host bridge.
> > >
> > > /sys/class/tsm/tsmN/pciDDDD:BB => /sys/devices/pciDDDD:BB
> > >
> > > That achieves the same result and is easier to document as "When a TSM
> > > has a established any IDE stream it links to the host bridge. When the
> > > last stream is removed the link is removed." It achieves the goal of
> > > letting an admin do "ls /sys/class/tsm/tsmN/*/stream*" to get a survey
> > > of all consumed stream resources in the system.
> >
> > In fact it does not even need to be dynamic. At tsm_register() time when
> > @pci_ops is provided, link all host bridges. Unlink them at unregister
>
> I'm sort of supporting dynamic. My DUT has 40 host bridges registered,
> most of them has nothing to do with TSM/IDE, so I'm afraid if it is
> overkill to list them all, and bury the real TSM capable bridge in the
> noise.
>
> And if TSM always list all bridges then why we need these symlinks, we
> can just:
>
> ls -d /sys/devices/pci*\:*/stream*
>
>
> I assume the annoying part of dynamic is we need to refcount, which IMHO
> unnecessarily complex and you are trying to avoid, is it?
I am ok with a simple xarray of registered host bridges that gets
cleaned up when the last stream leaves.
The end goal is "ls /sys/class/tsm/tsmN/*/stream*" gives valuable signal to
the user, and yes 40 host bridges of noise should be avoided.
^ permalink raw reply
* Re: [PATCH v2] PCI/IDE: Fix duplicate stream symlink names for TSM class devices
From: Xu Yilun @ 2026-01-23 3:38 UTC (permalink / raw)
To: dan.j.williams
Cc: linux-coco, linux-pci, yilun.xu, baolu.lu, zhenzhong.duan,
linux-kernel, yi1.lai, helgaas
In-Reply-To: <6972c9b522ef_1d3310053@dwillia2-mobl4.notmuch>
On Thu, Jan 22, 2026 at 05:07:01PM -0800, dan.j.williams@intel.com wrote:
> dan.j.williams@ wrote:
> [..]
> > However, after seeing Jonathan's feedback and noticing that he missed
> > that 'H' 'R' and 'E' are documented in the host bridge ABI I think it
> > would be better to simplify this to just a link back to the host bridge.
> >
> > /sys/class/tsm/tsmN/pciDDDD:BB => /sys/devices/pciDDDD:BB
> >
> > That achieves the same result and is easier to document as "When a TSM
> > has a established any IDE stream it links to the host bridge. When the
> > last stream is removed the link is removed." It achieves the goal of
> > letting an admin do "ls /sys/class/tsm/tsmN/*/stream*" to get a survey
> > of all consumed stream resources in the system.
>
> In fact it does not even need to be dynamic. At tsm_register() time when
> @pci_ops is provided, link all host bridges. Unlink them at unregister
I'm sort of supporting dynamic. My DUT has 40 host bridges registered,
most of them has nothing to do with TSM/IDE, so I'm afraid if it is
overkill to list them all, and bury the real TSM capable bridge in the
noise.
And if TSM always list all bridges then why we need these symlinks, we
can just:
ls -d /sys/devices/pci*\:*/stream*
I assume the annoying part of dynamic is we need to refcount, which IMHO
unnecessarily complex and you are trying to avoid, is it?
> time. The only driving need for it to be dynamic is if there is ever a
> platform that supports multiple TSMs each supporting a different set of
> host bridges. Can cross that bridge later.
^ permalink raw reply
* Re: [PATCH 1/1] PCI/IDE: Fix reading a wrong reg for unused sel stream initialization
From: dan.j.williams @ 2026-01-23 1:40 UTC (permalink / raw)
To: dan.j.williams, Bjorn Helgaas, Li Ming
Cc: dan.j.williams, linux-pci, linux-coco, linux-kernel
In-Reply-To: <6967c10429f19_34d2a10027@dwillia2-mobl4.notmuch>
dan.j.williams@ wrote:
> Bjorn Helgaas wrote:
> > On Sun, Jan 11, 2026 at 03:38:23PM +0800, Li Ming wrote:
> > > During pci_ide_init(), it will write PCI_ID_RESERVED_STREAM_ID into all
> > > unused selective IDE stream blocks. In a selective IDE stream block, IDE
> > > stream ID field is in selective IDE stream control register instead of
> > > selective IDE stream capability register.
> > >
> > > Fixes: 079115370d00 ("PCI/IDE: Initialize an ID for all IDE streams")
> > > Signed-off-by: Li Ming <ming.li@zohomail.com>
> >
> > Acked-by: Bjorn Helgaas <bhelgaas@google.com>
> >
> > Dan, I assume you'll take this? It looks like you've merged
> > everything to do with ide.c.
>
> Yes, I have cleared some CXL backlog from over the holidays and will get
> this queued.
Now applied and will show up soon in tsm.git.
^ permalink raw reply
* Re: [PATCH v2 1/1] PCI/IDE: Fix using wrong VF ID for RID range calculation
From: dan.j.williams @ 2026-01-23 1:35 UTC (permalink / raw)
To: Li Ming, helgaas, dan.j.williams
Cc: linux-pci, linux-coco, linux-kernel, Li Ming
In-Reply-To: <20260114111455.550984-1-ming.li@zohomail.com>
I will change this subject to "PCI/IDE: Fix off by one error calculating VF RID range"
Li Ming wrote:
> When allocate a new IDE stream for a PCI device in SR-IOV case, the RID
> range of the new IDE stream should cover all VFs of the device. VF ID
> range of a PCI device is [0, num_VFs - 1], so should use (num_VFs - 1)
> as the last VF's ID.
This can be even more succinct / to the point:
---
The VF ID range of an SR-IOV device is [0, num_VFs - 1].
pci_ide_stream_alloc() mistakenly uses num_VFs to represent the last ID.
Fix that off by one error to stay in bounds of the range.
---
...but otherwise this looks good to me. Thanks!
^ permalink raw reply
* Re: [PATCH v2] PCI/IDE: Fix duplicate stream symlink names for TSM class devices
From: dan.j.williams @ 2026-01-23 1:07 UTC (permalink / raw)
To: dan.j.williams, Xu Yilun, linux-coco, linux-pci, dan.j.williams
Cc: yilun.xu, yilun.xu, baolu.lu, zhenzhong.duan, linux-kernel,
yi1.lai, helgaas
In-Reply-To: <6972c872acbb9_1d3310035@dwillia2-mobl4.notmuch>
dan.j.williams@ wrote:
[..]
> However, after seeing Jonathan's feedback and noticing that he missed
> that 'H' 'R' and 'E' are documented in the host bridge ABI I think it
> would be better to simplify this to just a link back to the host bridge.
>
> /sys/class/tsm/tsmN/pciDDDD:BB => /sys/devices/pciDDDD:BB
>
> That achieves the same result and is easier to document as "When a TSM
> has a established any IDE stream it links to the host bridge. When the
> last stream is removed the link is removed." It achieves the goal of
> letting an admin do "ls /sys/class/tsm/tsmN/*/stream*" to get a survey
> of all consumed stream resources in the system.
In fact it does not even need to be dynamic. At tsm_register() time when
@pci_ops is provided, link all host bridges. Unlink them at unregister
time. The only driving need for it to be dynamic is if there is ever a
platform that supports multiple TSMs each supporting a different set of
host bridges. Can cross that bridge later.
^ permalink raw reply
* Re: [PATCH v2] PCI/IDE: Fix duplicate stream symlink names for TSM class devices
From: dan.j.williams @ 2026-01-23 1:01 UTC (permalink / raw)
To: Xu Yilun, linux-coco, linux-pci, dan.j.williams
Cc: yilun.xu, yilun.xu, baolu.lu, zhenzhong.duan, linux-kernel,
yi1.lai, helgaas
In-Reply-To: <20260105093516.2645397-1-yilun.xu@linux.intel.com>
Xu Yilun wrote:
> The name streamH.R.E is used for 2 symlinks:
>
> 1. TSM class devices: /sys/class/tsm/tsmN/streamH.R.E
> 2. host bridge devices: /sys/devices/pciDDDD:BB/streamH.R.E
>
> The first usage is broken cause streamH.R.E is only unique within a
> specific host bridge but not across the system. Error occurs e.g. when
> creating the first stream on a second host bridge:
>
> sysfs: cannot create duplicate filename '/devices/faux/tdx_host/tsm/tsm0/stream0.0.0'
First thanks for fixing this, a significant oversight on my part. I will
add this to the devsec-sample tests as penance.
> Fix this by adding host bridge name into symlink name for TSM class
> devices so they show up as:
>
> /sys/class/tsm/tsmN/pciDDDD:BB:streamH.R.E
I do not like that we have this large combo name and the confusion it
causes in the code as Bjorn tripped over it.
> It should be OK to change the uAPI since it's new and has few users.
A better reason is that this ABI has never seen a released kernel.
> The symlink name for host bridge devices keeps unchanged. Keep concise
> as it is already in host bridge context.
>
> Internally in the IDE library, store the full name in struct pci_ide
> so TSM symlinks can use it directly as before, while host bridge
> symlinks use only the streamH.R.E portion to preserve the existing name.
I think what I would rather do is just back out this ABI for v6.19,
since it is late in the cycle, and fix this properly.
My initial thought of a better way to achieve the same is to create a
kobject named for the host-bridge to namespace the streams. For example:
/sys/class/tsm/tsmN/pciDDDD:BB/streamH.R.E
However, after seeing Jonathan's feedback and noticing that he missed
that 'H' 'R' and 'E' are documented in the host bridge ABI I think it
would be better to simplify this to just a link back to the host bridge.
/sys/class/tsm/tsmN/pciDDDD:BB => /sys/devices/pciDDDD:BB
That achieves the same result and is easier to document as "When a TSM
has a established any IDE stream it links to the host bridge. When the
last stream is removed the link is removed." It achieves the goal of
letting an admin do "ls /sys/class/tsm/tsmN/*/stream*" to get a survey
of all consumed stream resources in the system.
That is all a bit too much to do at this late date, so I think for
v6.19-final just delete this ABI, and try again for v7.0.
-- 8< --
From 2d236b203ea155d16d3251bd0e3bf4eeab2fcf6b Mon Sep 17 00:00:00 2001
From: Dan Williams <dan.j.williams@intel.com>
Date: Thu, 22 Jan 2026 16:35:56 -0800
Subject: [PATCH] Revert "PCI/TSM: Report active IDE streams"
The proposed ABI failed to account for multiple host bridges with the same
stream name. The fix needs to namespace streams or otherwise link back to
the host bridge, but a change like that is too big for a fix. Given this
ABI never saw a released kernel, delete it for now and bring it back later
with this issue addressed.
Reported-by: Xu Yilun <yilun.xu@linux.intel.com>
Reported-by: Yi Lai <yi1.lai@intel.com>
Closes: http://lore.kernel.org/20251223085601.2607455-1-yilun.xu@linux.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
---
Documentation/ABI/testing/sysfs-class-tsm | 10 --------
include/linux/pci-ide.h | 2 --
include/linux/tsm.h | 3 ---
drivers/pci/ide.c | 4 ----
drivers/virt/coco/tsm-core.c | 28 -----------------------
5 files changed, 47 deletions(-)
diff --git a/Documentation/ABI/testing/sysfs-class-tsm b/Documentation/ABI/testing/sysfs-class-tsm
index 6fc1a5ac6da1..2949468deaf7 100644
--- a/Documentation/ABI/testing/sysfs-class-tsm
+++ b/Documentation/ABI/testing/sysfs-class-tsm
@@ -7,13 +7,3 @@ Description:
signals when the PCI layer is able to support establishment of
link encryption and other device-security features coordinated
through a platform tsm.
-
-What: /sys/class/tsm/tsmN/streamH.R.E
-Contact: linux-pci@vger.kernel.org
-Description:
- (RO) When a host bridge has established a secure connection via
- the platform TSM, symlink appears. The primary function of this
- is have a system global review of TSM resource consumption
- across host bridges. The link points to the endpoint PCI device
- and matches the same link published by the host bridge. See
- Documentation/ABI/testing/sysfs-devices-pci-host-bridge.
diff --git a/include/linux/pci-ide.h b/include/linux/pci-ide.h
index 37a1ad9501b0..5d4d56ed088d 100644
--- a/include/linux/pci-ide.h
+++ b/include/linux/pci-ide.h
@@ -82,7 +82,6 @@ struct pci_ide_regs {
* @host_bridge_stream: allocated from host bridge @ide_stream_ida pool
* @stream_id: unique Stream ID (within Partner Port pairing)
* @name: name of the established Selective IDE Stream in sysfs
- * @tsm_dev: For TSM established IDE, the TSM device context
*
* Negative @stream_id values indicate "uninitialized" on the
* expectation that with TSM established IDE the TSM owns the stream_id
@@ -94,7 +93,6 @@ struct pci_ide {
u8 host_bridge_stream;
int stream_id;
const char *name;
- struct tsm_dev *tsm_dev;
};
/*
diff --git a/include/linux/tsm.h b/include/linux/tsm.h
index a3b7ab668eff..22e05b2aac69 100644
--- a/include/linux/tsm.h
+++ b/include/linux/tsm.h
@@ -123,7 +123,4 @@ int tsm_report_unregister(const struct tsm_report_ops *ops);
struct tsm_dev *tsm_register(struct device *parent, struct pci_tsm_ops *ops);
void tsm_unregister(struct tsm_dev *tsm_dev);
struct tsm_dev *find_tsm_dev(int id);
-struct pci_ide;
-int tsm_ide_stream_register(struct pci_ide *ide);
-void tsm_ide_stream_unregister(struct pci_ide *ide);
#endif /* __TSM_H */
diff --git a/drivers/pci/ide.c b/drivers/pci/ide.c
index f0ef474e1a0d..280941b05969 100644
--- a/drivers/pci/ide.c
+++ b/drivers/pci/ide.c
@@ -11,7 +11,6 @@
#include <linux/pci_regs.h>
#include <linux/slab.h>
#include <linux/sysfs.h>
-#include <linux/tsm.h>
#include "pci.h"
@@ -373,9 +372,6 @@ void pci_ide_stream_release(struct pci_ide *ide)
if (ide->partner[PCI_IDE_EP].enable)
pci_ide_stream_disable(pdev, ide);
- if (ide->tsm_dev)
- tsm_ide_stream_unregister(ide);
-
if (ide->partner[PCI_IDE_RP].setup)
pci_ide_stream_teardown(rp, ide);
diff --git a/drivers/virt/coco/tsm-core.c b/drivers/virt/coco/tsm-core.c
index f027876a2f19..0e705f3067a1 100644
--- a/drivers/virt/coco/tsm-core.c
+++ b/drivers/virt/coco/tsm-core.c
@@ -4,13 +4,11 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/tsm.h>
-#include <linux/pci.h>
#include <linux/rwsem.h>
#include <linux/device.h>
#include <linux/module.h>
#include <linux/cleanup.h>
#include <linux/pci-tsm.h>
-#include <linux/pci-ide.h>
static struct class *tsm_class;
static DECLARE_RWSEM(tsm_rwsem);
@@ -108,32 +106,6 @@ void tsm_unregister(struct tsm_dev *tsm_dev)
}
EXPORT_SYMBOL_GPL(tsm_unregister);
-/* must be invoked between tsm_register / tsm_unregister */
-int tsm_ide_stream_register(struct pci_ide *ide)
-{
- struct pci_dev *pdev = ide->pdev;
- struct pci_tsm *tsm = pdev->tsm;
- struct tsm_dev *tsm_dev = tsm->tsm_dev;
- int rc;
-
- rc = sysfs_create_link(&tsm_dev->dev.kobj, &pdev->dev.kobj, ide->name);
- if (rc)
- return rc;
-
- ide->tsm_dev = tsm_dev;
- return 0;
-}
-EXPORT_SYMBOL_GPL(tsm_ide_stream_register);
-
-void tsm_ide_stream_unregister(struct pci_ide *ide)
-{
- struct tsm_dev *tsm_dev = ide->tsm_dev;
-
- ide->tsm_dev = NULL;
- sysfs_remove_link(&tsm_dev->dev.kobj, ide->name);
-}
-EXPORT_SYMBOL_GPL(tsm_ide_stream_unregister);
-
static void tsm_release(struct device *dev)
{
struct tsm_dev *tsm_dev = container_of(dev, typeof(*tsm_dev), dev);
--
2.52.0
^ permalink raw reply related
* re: [PATCH v1 08/14] x86: make CONFIG_EFI_STUB unconditional
From: H. Peter Anvin @ 2026-01-23 0:11 UTC (permalink / raw)
To: Simon Glass, ubizjak, linux-kernel
Cc: akpm, bp, dave.hansen, kas, kees, linux-coco, mingo, nathan,
peterz, pmladek, rick.p.edgecombe, tglx, x86
In-Reply-To: <20260122185740.50298-1-sjg@chromium.org>
On January 22, 2026 10:57:39 AM PST, Simon Glass <sjg@chromium.org> wrote:
>Hi Peter,
>
>On Tue, Jan 20, 2026 at 8:54 PM H. Peter Anvin <hpa@zytor.com> wrote:
>>
>> The EFI stub code is mature, most current x86 systems require EFI to
>> boot, and as it is exclusively preboot code, it doesn't affect the
>> runtime memory footprint at all.
>>
>> It makes absolutely no sense to omit it anymore, so make it
>> unconditional.
>>
>> Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
>> ---
>> arch/x86/Kconfig | 14 ++------------
>> arch/x86/boot/compressed/Makefile | 2 --
>> arch/x86/boot/compressed/error.c | 2 --
>> arch/x86/boot/header.S | 3 ---
>> 4 files changed, 2 insertions(+), 19 deletions(-)
>
>At least with QEMU the EFI protocol adds quite a lot of overhead.
>
>Is there any actual need for this?
>
>Regards,
>Simon
>
Including the EFI stub doesn't mean using EFI to boot is required.
^ permalink raw reply
* re: [PATCH v1 08/14] x86: make CONFIG_EFI_STUB unconditional
From: Simon Glass @ 2026-01-22 18:57 UTC (permalink / raw)
To: ubizjak, linux-kernel
Cc: akpm, bp, dave.hansen, hpa, kas, kees, linux-coco, mingo, nathan,
peterz, pmladek, rick.p.edgecombe, tglx, x86, Simon Glass
In-Reply-To: <CAFULd4bV6jKqHb-vC47skjNvbctit3VccXpF02oYt0icaq1r-Q@mail.gmail.com>
Hi Peter,
On Tue, Jan 20, 2026 at 8:54 PM H. Peter Anvin <hpa@zytor.com> wrote:
>
> The EFI stub code is mature, most current x86 systems require EFI to
> boot, and as it is exclusively preboot code, it doesn't affect the
> runtime memory footprint at all.
>
> It makes absolutely no sense to omit it anymore, so make it
> unconditional.
>
> Signed-off-by: H. Peter Anvin (Intel) <hpa@zytor.com>
> ---
> arch/x86/Kconfig | 14 ++------------
> arch/x86/boot/compressed/Makefile | 2 --
> arch/x86/boot/compressed/error.c | 2 --
> arch/x86/boot/header.S | 3 ---
> 4 files changed, 2 insertions(+), 19 deletions(-)
At least with QEMU the EFI protocol adds quite a lot of overhead.
Is there any actual need for this?
Regards,
Simon
^ permalink raw reply
* Re: SVSM Development Call January 21, 2026
From: Jörg Rödel @ 2026-01-22 12:55 UTC (permalink / raw)
To: coconut-svsm, linux-coco
In-Reply-To: <4uhsm4wvzsoto4e6koyccvsdqcg2pber4s4oexclhywps7pz5l@tpkfglmsge45>
Meeting minutes are available here:
https://github.com/coconut-svsm/governance/pull/93
-Joerg
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox