Re: [PATCH v2 02/17] x86/virt/tdx: Configure add-on features on TDX module init and update
From: Xiaoyao Li
Date: Fri Jul 24 2026 - 04:23:47 EST
On 6/18/2026 4:13 PM, Xu Yilun wrote:
In addition to basic TDX functionalities, TDX module provides add-on
features that can be progressively enabled as the kernel supports them.
"add-on features" looks like a new term introduced by this sereis for TDX. So what is add-on features? all the features defined in TDX_FEATURE0/1? Or only the features needs to be explicitly enabled by R9 and R10 of TDH.SYS.CONFIG? ...
The kernel should explicitly configure these features at boot or
post-update initialization time.
... So the answer is the latter. Then why only these bits are add-on features while the rest in TDX_FEATURES01 are not?
btw, s/should/needs/ is better?
Configuring an add-on feature, such as
TDX Quoting, that uses extension SEAMCALLs is the prerequisite for
initializing TDX module extensions.
Though the statement is right, it leads to the impression that the reason we are configuring the add-on feature is to initialize the TDX module extensions.
However, the truth is kenrel wants to enable/use an add-on feature and the add-on feature requires the functionalities provided by some TDX module extension. So kernel needs to enable the TDX module extensions.
TDX Quoting is the target feature to
enable but defer it for now until full kernel support is in place.
TDX module extends TDH.SYS.CONFIG and TDH.SYS.UPDATE with new bitmap
input parameters to specify which add-on features to configure. The
bitmap uses the same definitions as TDX_FEATURES0.
For runtime update, Linux applies a policy that no newer features should
be added after update to avoid disrupting live TDX operations. To adhere
to this, TDH.SYS.UPDATE must configure the same features as the
TDH.SYS.CONFIG. Record the kernel required add-on feature bitmap in a
global var so that both phases can use it.
TDX module advances the version of TDH.SYS.CONFIG and TDH.SYS.UPDATE for
the change, so use the latest version (v1) for add-on feature enabling.
But supporting existing modules which only support v0 is still necessary
until they are deprecated. In fact, it is unlikely that TDH.SYS.CONFIG
ever needs to change again and the code would stay in v1. So there is
little value in worrying about deprecating v0 to save a couple lines of
code in 5-7 years when these original TDX platforms sunset.
Signed-off-by: Xu Yilun <yilun.xu@xxxxxxxxxxxxxxx>
---
arch/x86/virt/vmx/tdx/tdx.h | 6 ++++--
arch/x86/virt/vmx/tdx/tdx.c | 28 ++++++++++++++++++++++++++--
2 files changed, 30 insertions(+), 4 deletions(-)
diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h
index fbb520704662..a47e872480c7 100644
--- a/arch/x86/virt/vmx/tdx/tdx.h
+++ b/arch/x86/virt/vmx/tdx/tdx.h
@@ -58,9 +58,11 @@
#define TDH_PHYMEM_CACHE_WB 40
#define TDH_PHYMEM_PAGE_WBINVD 41
#define TDH_VP_WR 43
-#define TDH_SYS_CONFIG 45
+#define TDH_SYS_CONFIG_V0 45
+#define TDH_SYS_CONFIG SEAMCALL_LEAF_VER(TDH_SYS_CONFIG_V0, 1)
#define TDH_SYS_SHUTDOWN 52
-#define TDH_SYS_UPDATE 53
+#define TDH_SYS_UPDATE_V0 53
+#define TDH_SYS_UPDATE SEAMCALL_LEAF_VER(TDH_SYS_UPDATE_V0, 1)
#define TDH_SYS_DISABLE 69
/* TDX page types */
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index 2a03152796e6..92305b5ea90d 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -57,6 +57,7 @@ static struct tdx_module_state tdx_module_state;
static u32 tdx_global_keyid __ro_after_init;
static u32 tdx_guest_keyid_start __ro_after_init;
static u32 tdx_nr_guest_keyids __ro_after_init;
+static u64 tdx_addon_feature0 __ro_after_init;
static DEFINE_IDA(tdx_guest_keyid_pool);
@@ -1004,9 +1005,18 @@ static __init int construct_tdmrs(struct list_head *tmb_list,
return ret;
}
+static __init void set_tdx_addon_features(void)
+{
+ /*
+ * To add DICE-based TDX Quoting feature bit in tdx_addon_feature0 when
+ * kernel is ready.
+ */
+}
+
static __init int config_tdx_module(struct tdmr_info_list *tdmr_list,
u64 global_keyid)
{
+ u64 seamcall_fn = TDH_SYS_CONFIG_V0;
struct tdx_module_args args = {};
u64 *tdmr_pa_array;
size_t array_sz;
@@ -1032,7 +1042,15 @@ static __init int config_tdx_module(struct tdmr_info_list *tdmr_list,
args.rcx = __pa(tdmr_pa_array);
args.rdx = tdmr_list->nr_consumed_tdmrs;
args.r8 = global_keyid;
- ret = seamcall_prerr(TDH_SYS_CONFIG, &args);
+
+ set_tdx_addon_features();
Maybe move the set_tdx_addon_features() out of config_tdx_module()? how about putting it after check_features(). config_tdx_module() looks like just a wrapper to invoke TDH.SYS.CONFIG, while the params of it are determined outside of it.
Just my feeling.
+
+ if (tdx_addon_feature0) {
+ args.r9 = tdx_addon_feature0;
+ seamcall_fn = TDH_SYS_CONFIG;
+ }
+
+ ret = seamcall_prerr(seamcall_fn, &args);
/* Free the array as it is not required anymore. */
kfree(tdmr_pa_array);
@@ -1314,10 +1332,16 @@ int tdx_module_shutdown(void)
int tdx_module_run_update(void)
{
+ u64 seamcall_fn = TDH_SYS_UPDATE_V0;
struct tdx_module_args args = {};
int ret;
- ret = seamcall_prerr(TDH_SYS_UPDATE, &args);
+ if (tdx_addon_feature0) {
+ args.r9 = tdx_addon_feature0;
+ seamcall_fn = TDH_SYS_UPDATE;
+ }
+
+ ret = seamcall_prerr(seamcall_fn, &args);
if (ret)
return ret;