x86/virt/tdx: Restore TDX module state

After per-CPU initialization, the module is nearly functional. It is
in a similar state to TDX initialization before TDH.SYS.CONFIG.

At this point, the kernel _could_ just repeat the boot-time sequence,
but that would land the new module in a slightly different state than
the old module.  This would leave old TDs unrunnable, which is not a
good outcome.

Thankfully, the "handoff" data saved during module shutdown should
contain all the information needed to restore the TDX module state to
exactly what it was before the update.

Restore TDX module state. The TDX module only needs a single copy so
only do this on the lead CPU.

Restoration errors can theoretically be handled in a few ways. For
instance, userspace could try to load a different TDX module version.
Or, the kernel could give up on the handoff process and just
reinitialize the new module from scratch, which would lose all
existing TDs.

Simply propagate errors to userspace. Ignore the idea of a
TD-destroying reinitialization. It would destroy data like a reboot
and if things have gone that wrong a reboot is probably the best
option anyway.

Note: the location and the format of handoff data is defined by the
TDX module. The new module knows where to get handoff data and how to
parse it. The kernel does not touch it at all.

Signed-off-by: Chao Gao <chao.gao@intel.com>
Signed-off-by: Dave Hansen <dave.hansen@linux.intel.com>
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
Reviewed-by: Kai Huang <kai.huang@intel.com>
Reviewed-by: Kiryl Shutsemau (Meta) <kas@kernel.org>
Reviewed-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
Link: https://patch.msgid.link/20260520133909.409394-21-chao.gao@intel.com
This commit is contained in:
Chao Gao 2026-05-20 15:29:10 -07:00 committed by Dave Hansen
parent bf7c0ed2c3
commit b344c50a1a
3 changed files with 20 additions and 0 deletions

View File

@ -210,6 +210,7 @@ enum module_update_state {
MODULE_UPDATE_SHUTDOWN,
MODULE_UPDATE_CPU_INSTALL,
MODULE_UPDATE_CPU_INIT,
MODULE_UPDATE_RUN_UPDATE,
MODULE_UPDATE_DONE,
};
@ -291,6 +292,10 @@ static int do_seamldr_install_module(void *seamldr_params)
case MODULE_UPDATE_CPU_INIT:
ret = tdx_cpu_enable();
break;
case MODULE_UPDATE_RUN_UPDATE:
if (is_lead_cpu)
ret = tdx_module_run_update();
break;
default:
break;
}

View File

@ -1312,6 +1312,19 @@ int tdx_module_shutdown(void)
return 0;
}
int tdx_module_run_update(void)
{
struct tdx_module_args args = {};
int ret;
ret = seamcall_prerr(TDH_SYS_UPDATE, &args);
if (ret)
return ret;
tdx_module_state.initialized = true;
return 0;
}
static bool is_pamt_page(unsigned long phys)
{
struct tdmr_info_list *tdmr_list = &tdx_tdmr_list;

View File

@ -47,6 +47,7 @@
#define TDH_VP_WR 43
#define TDH_SYS_CONFIG 45
#define TDH_SYS_SHUTDOWN 52
#define TDH_SYS_UPDATE 53
#define TDH_SYS_DISABLE 69
/*
@ -110,5 +111,6 @@ struct tdmr_info_list {
};
int tdx_module_shutdown(void);
int tdx_module_run_update(void);
#endif