[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-ID: <20250523095322.88774-19-chao.gao@intel.com>
Date: Fri, 23 May 2025 02:52:41 -0700
From: Chao Gao <chao.gao@...el.com>
To: linux-coco@...ts.linux.dev,
x86@...nel.org,
kvm@...r.kernel.org
Cc: seanjc@...gle.com,
pbonzini@...hat.com,
eddie.dong@...el.com,
kirill.shutemov@...el.com,
dave.hansen@...el.com,
dan.j.williams@...el.com,
kai.huang@...el.com,
isaku.yamahata@...el.com,
elena.reshetova@...el.com,
rick.p.edgecombe@...el.com,
Chao Gao <chao.gao@...el.com>,
Farrah Chen <farrah.chen@...el.com>,
"Kirill A. Shutemov" <kirill.shutemov@...ux.intel.com>,
Dave Hansen <dave.hansen@...ux.intel.com>,
Thomas Gleixner <tglx@...utronix.de>,
Ingo Molnar <mingo@...hat.com>,
Borislav Petkov <bp@...en8.de>,
"H. Peter Anvin" <hpa@...or.com>,
linux-kernel@...r.kernel.org
Subject: [RFC PATCH 18/20] x86/virt/tdx: Update tdx_sysinfo and check features post-update
tdx_sysinfo contains all metadata of the active TDX module, including
versions, supported features, and TDMR/TDCS/TDVPS information. These
elements may change over updates. Blindly refreshing the entire tdx_sysinfo
could disrupt running software, as it may subtly rely on the previous state
unless proven otherwise.
Adopt a conservative approach, like microcode updates, by only refreshing
version information that does not affect functionality, while ignoring
all other changes. This is acceptable as TD-Preserving-capable modules are
required to maintain backward compatibility.
Any updates to metadata beyond versions should be justified and reviewed on
a case-by-case basis.
Note that preallocating a tdx_sys_info buffer before updates is to avoid
having to handle -ENOMEM when updating tdx_sysinfo after a successful
update.
Signed-off-by: Chao Gao <chao.gao@...el.com>
Tested-by: Farrah Chen <farrah.chen@...el.com>
---
arch/x86/virt/vmx/tdx/seamldr.c | 13 ++++++++-
arch/x86/virt/vmx/tdx/tdx.c | 51 +++++++++++++++++++++++++++++++++
arch/x86/virt/vmx/tdx/tdx.h | 1 +
3 files changed, 64 insertions(+), 1 deletion(-)
diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
index 168fd2afd0c9..93385db56281 100644
--- a/arch/x86/virt/vmx/tdx/seamldr.c
+++ b/arch/x86/virt/vmx/tdx/seamldr.c
@@ -361,9 +361,16 @@ DEFINE_FREE(free_seamldr_params, struct seamldr_params *,
static int seamldr_install_module(const u8 *data, u32 size)
{
+ struct tdx_sys_info *info __free(kfree) = kzalloc(sizeof(*info),
+ GFP_KERNEL);
+ int ret;
+
if (!td_preserving_ready)
return -EOPNOTSUPP;
+ if (!info)
+ return -ENOMEM;
+
struct seamldr_params *params __free(free_seamldr_params) =
init_seamldr_params(data, size);
if (IS_ERR(params))
@@ -371,7 +378,11 @@ static int seamldr_install_module(const u8 *data, u32 size)
atomic_set(&tdp_data.failed, 0);
set_state(TDP_START + 1);
- return stop_machine(do_seamldr_install_module, params, cpu_online_mask);
+ ret = stop_machine(do_seamldr_install_module, params, cpu_online_mask);
+ if (ret)
+ return ret;
+
+ return tdx_module_post_update(info);
}
static enum fw_upload_err tdx_fw_prepare(struct fw_upload *fwl,
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index 5f678c9da4ee..55bdc99818a1 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -1406,6 +1406,57 @@ int tdx_module_run_update(void)
return ret;
}
+/*
+ * Update tdx_sysinfo and check if any TDX module features changed after
+ * updates
+ */
+static void tdx_module_sysinfo_update_and_check(struct tdx_sys_info *info)
+{
+ struct tdx_sys_info_versions *old, *new;
+
+ guard(mutex)(&tdx_module_lock);
+
+ old = &tdx_sysinfo.versions;
+ new = &info->versions;
+ pr_info("version %d.%d.%d -> %d.%d.%d\n", old->major_version,
+ old->minor_version,
+ old->update_version,
+ new->major_version,
+ new->minor_version,
+ new->update_version);
+
+ /*
+ * Blindly refreshing the entire tdx_sysinfo could disrupt running
+ * software, as it may subtly rely on the previous state unless
+ * proven otherwise.
+ *
+ * Only refresh version information (including handoff version)
+ * that does not affect functionality, and ignore all other
+ * changes.
+ */
+ tdx_sysinfo.versions = info->versions;
+ tdx_sysinfo.handoff = info->handoff;
+
+ if (!memcmp(&tdx_sysinfo, info, sizeof(*info)))
+ return;
+
+ pr_info("TDX module features have changed after updates, but might not take effect.\n");
+ pr_info("Please consider a potential BIOS update.\n");
+}
+
+int tdx_module_post_update(struct tdx_sys_info *info)
+{
+ int ret;
+
+ /* Shouldn't fail as the update has succeeded */
+ ret = get_tdx_sys_info(info);
+ if (WARN_ON_ONCE(ret))
+ return ret;
+
+ tdx_module_sysinfo_update_and_check(info);
+ return 0;
+}
+
static bool is_pamt_page(unsigned long phys)
{
struct tdmr_info_list *tdmr_list = &tdx_tdmr_list;
diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h
index a05e3c21e7f5..57ccceba5406 100644
--- a/arch/x86/virt/vmx/tdx/tdx.h
+++ b/arch/x86/virt/vmx/tdx/tdx.h
@@ -128,5 +128,6 @@ int seamldr_prerr(u64 fn, struct tdx_module_args *args);
int tdx_module_shutdown(void);
void tdx_module_set_error(void);
int tdx_module_run_update(void);
+int tdx_module_post_update(struct tdx_sys_info *info);
#endif
--
2.47.1
Powered by blists - more mailing lists