* [PATCH 01/15] x86/virt/tdx: Read global metadata for TDX Module Extensions
2026-05-22 3:41 [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting Xu Yilun
@ 2026-05-22 3:41 ` Xu Yilun
2026-05-25 6:24 ` Xiaoyao Li
` (3 more replies)
2026-05-22 3:41 ` [PATCH 02/15] x86/virt/tdx: Add extra memory to TDX Module for Extensions Xu Yilun
` (15 subsequent siblings)
16 siblings, 4 replies; 64+ messages in thread
From: Xu Yilun @ 2026-05-22 3:41 UTC (permalink / raw)
To: kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, yilun.xu,
baolu.lu, zhenzhong.duan, xiaoyao.li
Add reading of the global metadata for TDX Module Extensions.
TDX Module Extensions is an add-on feature enumerated by TDX_FEATURES0.
But for the Module's integrity, Linux requires that all features that a
Module advertises must have a complete, valid set of metadata, and the
validation must succeed at core TDX initialization time.
Check TDX_FEATURES0 before reading these metadata. If a feature is
advertised, a failure in reading associated metadata causes the entire
TDX initialization to fail, otherwise skip.
Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
---
arch/x86/include/asm/tdx_global_metadata.h | 6 ++++++
arch/x86/virt/vmx/tdx/tdx.h | 1 +
arch/x86/virt/vmx/tdx/tdx_global_metadata.c | 16 ++++++++++++++++
3 files changed, 23 insertions(+)
diff --git a/arch/x86/include/asm/tdx_global_metadata.h b/arch/x86/include/asm/tdx_global_metadata.h
index 40689c8dc67e..533afe50a3f1 100644
--- a/arch/x86/include/asm/tdx_global_metadata.h
+++ b/arch/x86/include/asm/tdx_global_metadata.h
@@ -40,12 +40,18 @@ struct tdx_sys_info_td_conf {
u64 cpuid_config_values[128][2];
};
+struct tdx_sys_info_ext {
+ u16 memory_pool_required_pages;
+ u8 ext_required;
+};
+
struct tdx_sys_info {
struct tdx_sys_info_version version;
struct tdx_sys_info_features features;
struct tdx_sys_info_tdmr tdmr;
struct tdx_sys_info_td_ctrl td_ctrl;
struct tdx_sys_info_td_conf td_conf;
+ struct tdx_sys_info_ext ext;
};
#endif
diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h
index e2cf2dd48755..a5eec8e3cc71 100644
--- a/arch/x86/virt/vmx/tdx/tdx.h
+++ b/arch/x86/virt/vmx/tdx/tdx.h
@@ -87,6 +87,7 @@ struct tdmr_info {
/* Bit definitions of TDX_FEATURES0 metadata field */
#define TDX_FEATURES0_NO_RBP_MOD BIT(18)
+#define TDX_FEATURES0_EXT BIT_ULL(39)
/*
* Do not put any hardware-defined TDX structure representations below
diff --git a/arch/x86/virt/vmx/tdx/tdx_global_metadata.c b/arch/x86/virt/vmx/tdx/tdx_global_metadata.c
index c7db393a9cfb..3d3b56ef3d2f 100644
--- a/arch/x86/virt/vmx/tdx/tdx_global_metadata.c
+++ b/arch/x86/virt/vmx/tdx/tdx_global_metadata.c
@@ -100,6 +100,19 @@ static __init int get_tdx_sys_info_td_conf(struct tdx_sys_info_td_conf *sysinfo_
return ret;
}
+static __init int get_tdx_sys_info_ext(struct tdx_sys_info_ext *sysinfo_ext)
+{
+ int ret = 0;
+ u64 val;
+
+ if (!ret && !(ret = read_sys_metadata_field(0x3100000100000000, &val)))
+ sysinfo_ext->memory_pool_required_pages = val;
+ if (!ret && !(ret = read_sys_metadata_field(0x3100000000000001, &val)))
+ sysinfo_ext->ext_required = val;
+
+ return ret;
+}
+
static __init int get_tdx_sys_info(struct tdx_sys_info *sysinfo)
{
int ret = 0;
@@ -116,5 +129,8 @@ static __init int get_tdx_sys_info(struct tdx_sys_info *sysinfo)
ret = ret ?: get_tdx_sys_info_td_ctrl(&sysinfo->td_ctrl);
ret = ret ?: get_tdx_sys_info_td_conf(&sysinfo->td_conf);
+ if (sysinfo->features.tdx_features0 & TDX_FEATURES0_EXT)
+ ret = ret ?: get_tdx_sys_info_ext(&sysinfo->ext);
+
return ret;
}
--
2.25.1
^ permalink raw reply related [flat|nested] 64+ messages in thread* Re: [PATCH 01/15] x86/virt/tdx: Read global metadata for TDX Module Extensions
2026-05-22 3:41 ` [PATCH 01/15] x86/virt/tdx: Read global metadata for TDX Module Extensions Xu Yilun
@ 2026-05-25 6:24 ` Xiaoyao Li
2026-05-25 6:54 ` Xiaoyao Li
` (2 subsequent siblings)
3 siblings, 0 replies; 64+ messages in thread
From: Xiaoyao Li @ 2026-05-25 6:24 UTC (permalink / raw)
To: Xu Yilun, kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan
On 5/22/2026 11:41 AM, Xu Yilun wrote:
> Add reading of the global metadata for TDX Module Extensions.
>
> TDX Module Extensions is an add-on feature enumerated by TDX_FEATURES0.
> But for the Module's integrity, Linux requires that all features that a
> Module advertises must have a complete, valid set of metadata,
I doubt on this.
1. Is it a must that any new feature introduces new metadata field?
2. Linux only cares the integrity for the features it uses, not for all
the features.
> and the
> validation must succeed at core TDX initialization time.
>
> Check TDX_FEATURES0 before reading these metadata. If a feature is
> advertised, a failure in reading associated metadata causes the entire
> TDX initialization to fail, otherwise skip.
I'm not sure why we need to explain the behavior when the reading fails.
It's not different to other existing fields.
Instead, I think you can explain why we need to check TDX_FEATURES0_EXT
at first.
Anyway, I don't read it as a good changelog. It event doesn't tell what
the added fields are and why we need them.
^ permalink raw reply [flat|nested] 64+ messages in thread* Re: [PATCH 01/15] x86/virt/tdx: Read global metadata for TDX Module Extensions
2026-05-22 3:41 ` [PATCH 01/15] x86/virt/tdx: Read global metadata for TDX Module Extensions Xu Yilun
2026-05-25 6:24 ` Xiaoyao Li
@ 2026-05-25 6:54 ` Xiaoyao Li
2026-05-27 15:35 ` Kiryl Shutsemau
2026-05-27 6:05 ` Sohil Mehta
2026-05-28 21:00 ` Edgecombe, Rick P
3 siblings, 1 reply; 64+ messages in thread
From: Xiaoyao Li @ 2026-05-25 6:54 UTC (permalink / raw)
To: Xu Yilun, kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan
On 5/22/2026 11:41 AM, Xu Yilun wrote:
...
> +static __init int get_tdx_sys_info_ext(struct tdx_sys_info_ext *sysinfo_ext)
> +{
> + int ret = 0;
> + u64 val;
> +
> + if (!ret && !(ret = read_sys_metadata_field(0x3100000100000000, &val)))
> + sysinfo_ext->memory_pool_required_pages = val;
> + if (!ret && !(ret = read_sys_metadata_field(0x3100000000000001, &val)))
> + sysinfo_ext->ext_required = val;
> +
> + return ret;
> +}
> +
> static __init int get_tdx_sys_info(struct tdx_sys_info *sysinfo)
> {
> int ret = 0;
> @@ -116,5 +129,8 @@ static __init int get_tdx_sys_info(struct tdx_sys_info *sysinfo)
> ret = ret ?: get_tdx_sys_info_td_ctrl(&sysinfo->td_ctrl);
> ret = ret ?: get_tdx_sys_info_td_conf(&sysinfo->td_conf);
>
> + if (sysinfo->features.tdx_features0 & TDX_FEATURES0_EXT)
> + ret = ret ?: get_tdx_sys_info_ext(&sysinfo->ext);
Is it correct to read "memory_pool_required_pages" and "ext_required" so
early in get_tdx_sys_info()? get_tdx_sys_info() is called before
config_tdx_module() which calls TDH.SYS.CONFIG.
If I read the TDX module base spec correctly, the amount of memory for
extensions and EXT_REQUIRED field depends on the enabled features, which
is determined by TDH.SYS.CONFIG/TDH.SYS.UPDATE ?
> return ret;
> }
^ permalink raw reply [flat|nested] 64+ messages in thread* Re: [PATCH 01/15] x86/virt/tdx: Read global metadata for TDX Module Extensions
2026-05-25 6:54 ` Xiaoyao Li
@ 2026-05-27 15:35 ` Kiryl Shutsemau
2026-05-28 4:25 ` Xu Yilun
0 siblings, 1 reply; 64+ messages in thread
From: Kiryl Shutsemau @ 2026-05-27 15:35 UTC (permalink / raw)
To: Xiaoyao Li
Cc: Xu Yilun, djbw, rick.p.edgecombe, x86, peter.fang, linux-coco,
linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan
On Mon, May 25, 2026 at 02:54:40PM +0800, Xiaoyao Li wrote:
> On 5/22/2026 11:41 AM, Xu Yilun wrote:
> ...
> > +static __init int get_tdx_sys_info_ext(struct tdx_sys_info_ext *sysinfo_ext)
> > +{
> > + int ret = 0;
> > + u64 val;
> > +
> > + if (!ret && !(ret = read_sys_metadata_field(0x3100000100000000, &val)))
> > + sysinfo_ext->memory_pool_required_pages = val;
> > + if (!ret && !(ret = read_sys_metadata_field(0x3100000000000001, &val)))
> > + sysinfo_ext->ext_required = val;
> > +
> > + return ret;
> > +}
> > +
> > static __init int get_tdx_sys_info(struct tdx_sys_info *sysinfo)
> > {
> > int ret = 0;
> > @@ -116,5 +129,8 @@ static __init int get_tdx_sys_info(struct tdx_sys_info *sysinfo)
> > ret = ret ?: get_tdx_sys_info_td_ctrl(&sysinfo->td_ctrl);
> > ret = ret ?: get_tdx_sys_info_td_conf(&sysinfo->td_conf);
> > + if (sysinfo->features.tdx_features0 & TDX_FEATURES0_EXT)
> > + ret = ret ?: get_tdx_sys_info_ext(&sysinfo->ext);
>
> Is it correct to read "memory_pool_required_pages" and "ext_required" so
> early in get_tdx_sys_info()? get_tdx_sys_info() is called before
> config_tdx_module() which calls TDH.SYS.CONFIG.
>
> If I read the TDX module base spec correctly, the amount of memory for
> extensions and EXT_REQUIRED field depends on the enabled features, which is
> determined by TDH.SYS.CONFIG/TDH.SYS.UPDATE ?
This is my read too. Looks like we need a separate step after
config_tdx_module() to readout config-dependatant metadata.
--
Kiryl Shutsemau / Kirill A. Shutemov
^ permalink raw reply [flat|nested] 64+ messages in thread* Re: [PATCH 01/15] x86/virt/tdx: Read global metadata for TDX Module Extensions
2026-05-27 15:35 ` Kiryl Shutsemau
@ 2026-05-28 4:25 ` Xu Yilun
2026-05-28 21:17 ` Edgecombe, Rick P
0 siblings, 1 reply; 64+ messages in thread
From: Xu Yilun @ 2026-05-28 4:25 UTC (permalink / raw)
To: Kiryl Shutsemau
Cc: Xiaoyao Li, djbw, rick.p.edgecombe, x86, peter.fang, linux-coco,
linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan
On Wed, May 27, 2026 at 04:35:36PM +0100, Kiryl Shutsemau wrote:
> On Mon, May 25, 2026 at 02:54:40PM +0800, Xiaoyao Li wrote:
> > On 5/22/2026 11:41 AM, Xu Yilun wrote:
> > ...
> > > +static __init int get_tdx_sys_info_ext(struct tdx_sys_info_ext *sysinfo_ext)
> > > +{
> > > + int ret = 0;
> > > + u64 val;
> > > +
> > > + if (!ret && !(ret = read_sys_metadata_field(0x3100000100000000, &val)))
> > > + sysinfo_ext->memory_pool_required_pages = val;
> > > + if (!ret && !(ret = read_sys_metadata_field(0x3100000000000001, &val)))
> > > + sysinfo_ext->ext_required = val;
> > > +
> > > + return ret;
> > > +}
> > > +
> > > static __init int get_tdx_sys_info(struct tdx_sys_info *sysinfo)
> > > {
> > > int ret = 0;
> > > @@ -116,5 +129,8 @@ static __init int get_tdx_sys_info(struct tdx_sys_info *sysinfo)
> > > ret = ret ?: get_tdx_sys_info_td_ctrl(&sysinfo->td_ctrl);
> > > ret = ret ?: get_tdx_sys_info_td_conf(&sysinfo->td_conf);
> > > + if (sysinfo->features.tdx_features0 & TDX_FEATURES0_EXT)
> > > + ret = ret ?: get_tdx_sys_info_ext(&sysinfo->ext);
> >
> > Is it correct to read "memory_pool_required_pages" and "ext_required" so
> > early in get_tdx_sys_info()? get_tdx_sys_info() is called before
> > config_tdx_module() which calls TDH.SYS.CONFIG.
> >
> > If I read the TDX module base spec correctly, the amount of memory for
> > extensions and EXT_REQUIRED field depends on the enabled features, which is
> > determined by TDH.SYS.CONFIG/TDH.SYS.UPDATE ?
Yes.
>
> This is my read too. Looks like we need a separate step after
> config_tdx_module() to readout config-dependatant metadata.
The timing for when metadata becomes valid is now variable, e.g., the
TDX QUOTING metadata is only valid after TDH.QUOTE.INIT [1].
Based on recent discussion, I think we should introduce runtime metadata
reading interfaces for specific metadata sets as needed, rather than
another catch-all step right after config_tdx_module(). See [2] for the
proposed approach for Extensions metadata.
[1]: https://lore.kernel.org/all/20260522034128.3144354-7-yilun.xu@linux.intel.com/
[2]: https://lore.kernel.org/all/ahXAL41ZmIDHmgfu@yilunxu-OptiPlex-7050/
^ permalink raw reply [flat|nested] 64+ messages in thread* Re: [PATCH 01/15] x86/virt/tdx: Read global metadata for TDX Module Extensions
2026-05-28 4:25 ` Xu Yilun
@ 2026-05-28 21:17 ` Edgecombe, Rick P
2026-05-29 15:34 ` Xu Yilun
0 siblings, 1 reply; 64+ messages in thread
From: Edgecombe, Rick P @ 2026-05-28 21:17 UTC (permalink / raw)
To: kas@kernel.org, yilun.xu@linux.intel.com
Cc: Xu, Yilun, x86@kernel.org, baolu.lu@linux.intel.com, Li, Xiaoyao,
djbw@kernel.org, linux-kernel@vger.kernel.org, Duan, Zhenzhong,
Mehta, Sohil, kvm@vger.kernel.org, linux-coco@lists.linux.dev,
Fang, Peter
On Thu, 2026-05-28 at 12:25 +0800, Xu Yilun wrote:
> > >
> > > If I read the TDX module base spec correctly, the amount of memory for
> > > extensions and EXT_REQUIRED field depends on the enabled features, which
> > > is
> > > determined by TDH.SYS.CONFIG/TDH.SYS.UPDATE ?
>
> Yes.
>
> >
> > This is my read too. Looks like we need a separate step after
> > config_tdx_module() to readout config-dependatant metadata.
>
>
> The timing for when metadata becomes valid is now variable, e.g., the
> TDX QUOTING metadata is only valid after TDH.QUOTE.INIT [1].
>
> Based on recent discussion, I think we should introduce runtime metadata
> reading interfaces for specific metadata sets as needed, rather than
> another catch-all step right after config_tdx_module(). See [2] for the
> proposed approach for Extensions metadata.
>
> [1]:
> https://lore.kernel.org/all/20260522034128.3144354-7-yilun.xu@linux.intel.com/
> [2]: https://lore.kernel.org/all/ahXAL41ZmIDHmgfu@yilunxu-OptiPlex-7050/
Yea It is going to get confusing as to which metadata is populated at which
step. And if anything updates it.
I'm not sure we need to have all the metadata stored permanently. Some of the
metadata is needed for KVM and someday TSM. But a lot of it is onetime internal
use. There is some handiness in referring to a global var, but also those
reference add confusion as to when it got populated.
We only use ext_required, max_quote_size and memory_pool_required_pages each
once. So why not just read them to the stack and leave them out of struct
tdx_sys_info? Making it so there is not confusion of when it was read. And also
saving a global var that is never used again is a bit wrong.
How about for struct tdx_sys_info_ext read it to the stack in init_tdx_ext() and
pass it into init_tdx_ext_features(). For max_quote_size read it where it is
already read, but not into the global struct.
Do you see a problem?
^ permalink raw reply [flat|nested] 64+ messages in thread
* Re: [PATCH 01/15] x86/virt/tdx: Read global metadata for TDX Module Extensions
2026-05-28 21:17 ` Edgecombe, Rick P
@ 2026-05-29 15:34 ` Xu Yilun
0 siblings, 0 replies; 64+ messages in thread
From: Xu Yilun @ 2026-05-29 15:34 UTC (permalink / raw)
To: Edgecombe, Rick P
Cc: kas@kernel.org, Xu, Yilun, x86@kernel.org,
baolu.lu@linux.intel.com, Li, Xiaoyao, djbw@kernel.org,
linux-kernel@vger.kernel.org, Duan, Zhenzhong, Mehta, Sohil,
kvm@vger.kernel.org, linux-coco@lists.linux.dev, Fang, Peter
> Yea It is going to get confusing as to which metadata is populated at which
> step. And if anything updates it.
>
> I'm not sure we need to have all the metadata stored permanently. Some of the
> metadata is needed for KVM and someday TSM. But a lot of it is onetime internal
> use. There is some handiness in referring to a global var, but also those
> reference add confusion as to when it got populated.
>
> We only use ext_required, max_quote_size and memory_pool_required_pages each
> once. So why not just read them to the stack and leave them out of struct
> tdx_sys_info? Making it so there is not confusion of when it was read. And also
> saving a global var that is never used again is a bit wrong.
>
> How about for struct tdx_sys_info_ext read it to the stack in init_tdx_ext() and
> pass it into init_tdx_ext_features(). For max_quote_size read it where it is
I think you mean "pass it into tdx_ext_mem_setup(). Yes, good to me.
> already read, but not into the global struct.
^ permalink raw reply [flat|nested] 64+ messages in thread
* Re: [PATCH 01/15] x86/virt/tdx: Read global metadata for TDX Module Extensions
2026-05-22 3:41 ` [PATCH 01/15] x86/virt/tdx: Read global metadata for TDX Module Extensions Xu Yilun
2026-05-25 6:24 ` Xiaoyao Li
2026-05-25 6:54 ` Xiaoyao Li
@ 2026-05-27 6:05 ` Sohil Mehta
2026-05-27 7:11 ` Xu Yilun
2026-05-28 21:00 ` Edgecombe, Rick P
3 siblings, 1 reply; 64+ messages in thread
From: Sohil Mehta @ 2026-05-27 6:05 UTC (permalink / raw)
To: Xu Yilun, kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, yilun.xu, baolu.lu, zhenzhong.duan,
xiaoyao.li
On 5/21/2026 8:41 PM, Xu Yilun wrote:
> Add reading of the global metadata for TDX Module Extensions.
>
> TDX Module Extensions is an add-on feature enumerated by TDX_FEATURES0.
> But for the Module's integrity, Linux requires that all features that a
> Module advertises must have a complete, valid set of metadata, and the
> validation must succeed at core TDX initialization time.
>
> Check TDX_FEATURES0 before reading these metadata. If a feature is
> advertised, a failure in reading associated metadata causes the entire
> TDX initialization to fail, otherwise skip.
>
> Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
> ---
> arch/x86/include/asm/tdx_global_metadata.h | 6 ++++++
> arch/x86/virt/vmx/tdx/tdx.h | 1 +
> arch/x86/virt/vmx/tdx/tdx_global_metadata.c | 16 ++++++++++++++++
The top comments in tdx_global_metadata.h and tdx_global_metadata.c say
that these files are autogenerated. I believe the script lives outside
the tree. Is there a plan to merge the script?
The generated code is optimized for space instead of readability. Also,
I see odd uncommented assignments u64 => u8/u16 all over the file. I am
assuming the upper bits are expected to be zero.
The patch is hard to review without the script. Can you post a link to
the updated script that led to this patch?
> 3 files changed, 23 insertions(+)
>
> diff --git a/arch/x86/include/asm/tdx_global_metadata.h b/arch/x86/include/asm/tdx_global_metadata.h
> index 40689c8dc67e..533afe50a3f1 100644
> --- a/arch/x86/include/asm/tdx_global_metadata.h
> +++ b/arch/x86/include/asm/tdx_global_metadata.h
> @@ -40,12 +40,18 @@ struct tdx_sys_info_td_conf {
> u64 cpuid_config_values[128][2];
> };
>
> +struct tdx_sys_info_ext {
> + u16 memory_pool_required_pages;
> + u8 ext_required;
The name ext_required seems like a boolean. It is also used like a
boolean later.
if (!tdx_sysinfo.ext.ext_required)
return 0;
But, IIUC, is it actually a mask that lists any feature that needs
extensions to work correctly? If so, it would be good to give it a name
that reflects its usage. Maybe:
features_requiring_ext or something better
As Xiaoyao mentioned, the struct requires a better explanation in the
commit log.
> +};
...
> static __init int get_tdx_sys_info(struct tdx_sys_info *sysinfo)
> {
> int ret = 0;
> @@ -116,5 +129,8 @@ static __init int get_tdx_sys_info(struct tdx_sys_info *sysinfo)
> ret = ret ?: get_tdx_sys_info_td_ctrl(&sysinfo->td_ctrl);
> ret = ret ?: get_tdx_sys_info_td_conf(&sysinfo->td_conf);
>
> + if (sysinfo->features.tdx_features0 & TDX_FEATURES0_EXT)
Other metadata reads aren't gated on feature checking. Is this check
manually added or autogenerated. If manually added, it should have a
code comment clarifying that.
> + ret = ret ?: get_tdx_sys_info_ext(&sysinfo->ext);
> +
> return ret;
> }
^ permalink raw reply [flat|nested] 64+ messages in thread* Re: [PATCH 01/15] x86/virt/tdx: Read global metadata for TDX Module Extensions
2026-05-27 6:05 ` Sohil Mehta
@ 2026-05-27 7:11 ` Xu Yilun
2026-05-27 17:17 ` Sohil Mehta
0 siblings, 1 reply; 64+ messages in thread
From: Xu Yilun @ 2026-05-27 7:11 UTC (permalink / raw)
To: Sohil Mehta
Cc: kas, djbw, rick.p.edgecombe, x86, peter.fang, linux-coco,
linux-kernel, kvm, yilun.xu, baolu.lu, zhenzhong.duan, xiaoyao.li
On Tue, May 26, 2026 at 11:05:48PM -0700, Sohil Mehta wrote:
> On 5/21/2026 8:41 PM, Xu Yilun wrote:
> > Add reading of the global metadata for TDX Module Extensions.
> >
> > TDX Module Extensions is an add-on feature enumerated by TDX_FEATURES0.
> > But for the Module's integrity, Linux requires that all features that a
> > Module advertises must have a complete, valid set of metadata, and the
> > validation must succeed at core TDX initialization time.
> >
> > Check TDX_FEATURES0 before reading these metadata. If a feature is
> > advertised, a failure in reading associated metadata causes the entire
> > TDX initialization to fail, otherwise skip.
> >
> > Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
> > ---
> > arch/x86/include/asm/tdx_global_metadata.h | 6 ++++++
> > arch/x86/virt/vmx/tdx/tdx.h | 1 +
> > arch/x86/virt/vmx/tdx/tdx_global_metadata.c | 16 ++++++++++++++++
>
> The top comments in tdx_global_metadata.h and tdx_global_metadata.c say
> that these files are autogenerated. I believe the script lives outside
> the tree. Is there a plan to merge the script?
No, the plan of auto-generating is deprecated. Now we switch to manual
update.
>
> The generated code is optimized for space instead of readability. Also,
> I see odd uncommented assignments u64 => u8/u16 all over the file. I am
> assuming the upper bits are expected to be zero.
>
> The patch is hard to review without the script. Can you post a link to
Yes, it is. A new plan is to refactor the file in future.
> the updated script that led to this patch?
>
>
> > 3 files changed, 23 insertions(+)
> >
> > diff --git a/arch/x86/include/asm/tdx_global_metadata.h b/arch/x86/include/asm/tdx_global_metadata.h
> > index 40689c8dc67e..533afe50a3f1 100644
> > --- a/arch/x86/include/asm/tdx_global_metadata.h
> > +++ b/arch/x86/include/asm/tdx_global_metadata.h
> > @@ -40,12 +40,18 @@ struct tdx_sys_info_td_conf {
> > u64 cpuid_config_values[128][2];
> > };
> >
> > +struct tdx_sys_info_ext {
> > + u16 memory_pool_required_pages;
> > + u8 ext_required;
>
> The name ext_required seems like a boolean. It is also used like a
> boolean later.
> if (!tdx_sysinfo.ext.ext_required)
> return 0;
>
> But, IIUC, is it actually a mask that lists any feature that needs
No it is just a bool about Extentions needs to be initialized or not.
> extensions to work correctly? If so, it would be good to give it a name
> that reflects its usage. Maybe:
> features_requiring_ext or something better
>
> As Xiaoyao mentioned, the struct requires a better explanation in the
> commit log.
Will do. I also plan to change the patch organization: instead of the
old auto-generated patch splitting style, I will switch to a human-readable
style and fold these metadata readings directly into the patches that
actually use them (e.g., DPAMT and TDX Runtime Update).
^ permalink raw reply [flat|nested] 64+ messages in thread* Re: [PATCH 01/15] x86/virt/tdx: Read global metadata for TDX Module Extensions
2026-05-27 7:11 ` Xu Yilun
@ 2026-05-27 17:17 ` Sohil Mehta
2026-05-28 3:48 ` Xu Yilun
0 siblings, 1 reply; 64+ messages in thread
From: Sohil Mehta @ 2026-05-27 17:17 UTC (permalink / raw)
To: Xu Yilun
Cc: kas, djbw, rick.p.edgecombe, x86, peter.fang, linux-coco,
linux-kernel, kvm, yilun.xu, baolu.lu, zhenzhong.duan, xiaoyao.li
On 5/27/2026 12:11 AM, Xu Yilun wrote:
>>> +struct tdx_sys_info_ext {
>>> + u16 memory_pool_required_pages;
>>> + u8 ext_required;
>>
>> The name ext_required seems like a boolean. It is also used like a
>> boolean later.
>> if (!tdx_sysinfo.ext.ext_required)
>> return 0;
>>
>> But, IIUC, is it actually a mask that lists any feature that needs
>
> No it is just a bool about Extentions needs to be initialized or not.
>
How does the kernel know which features need Extensions? Is there any
hardware enumeration or the kernel just keeps a static list?
^ permalink raw reply [flat|nested] 64+ messages in thread* Re: [PATCH 01/15] x86/virt/tdx: Read global metadata for TDX Module Extensions
2026-05-27 17:17 ` Sohil Mehta
@ 2026-05-28 3:48 ` Xu Yilun
0 siblings, 0 replies; 64+ messages in thread
From: Xu Yilun @ 2026-05-28 3:48 UTC (permalink / raw)
To: Sohil Mehta
Cc: kas, djbw, rick.p.edgecombe, x86, peter.fang, linux-coco,
linux-kernel, kvm, yilun.xu, baolu.lu, zhenzhong.duan, xiaoyao.li
On Wed, May 27, 2026 at 10:17:36AM -0700, Sohil Mehta wrote:
> On 5/27/2026 12:11 AM, Xu Yilun wrote:
>
> >>> +struct tdx_sys_info_ext {
> >>> + u16 memory_pool_required_pages;
> >>> + u8 ext_required;
> >>
> >> The name ext_required seems like a boolean. It is also used like a
> >> boolean later.
> >> if (!tdx_sysinfo.ext.ext_required)
> >> return 0;
> >>
> >> But, IIUC, is it actually a mask that lists any feature that needs
> >
> > No it is just a bool about Extentions needs to be initialized or not.
> >
> How does the kernel know which features need Extensions? Is there any
> hardware enumeration or the kernel just keeps a static list?
There is no HW enumeration, mm... seems this is an important reason that
we don't delay the Extensions enabling, kernel doesn't have to keep in
mind which features need Extensions.
^ permalink raw reply [flat|nested] 64+ messages in thread
* Re: [PATCH 01/15] x86/virt/tdx: Read global metadata for TDX Module Extensions
2026-05-22 3:41 ` [PATCH 01/15] x86/virt/tdx: Read global metadata for TDX Module Extensions Xu Yilun
` (2 preceding siblings ...)
2026-05-27 6:05 ` Sohil Mehta
@ 2026-05-28 21:00 ` Edgecombe, Rick P
2026-05-29 16:59 ` Xu Yilun
3 siblings, 1 reply; 64+ messages in thread
From: Edgecombe, Rick P @ 2026-05-28 21:00 UTC (permalink / raw)
To: Fang, Peter, kas@kernel.org, djbw@kernel.org,
yilun.xu@linux.intel.com, x86@kernel.org
Cc: Xu, Yilun, Duan, Zhenzhong, baolu.lu@linux.intel.com, Li, Xiaoyao,
linux-kernel@vger.kernel.org, Mehta, Sohil, kvm@vger.kernel.org,
linux-coco@lists.linux.dev
On Fri, 2026-05-22 at 11:41 +0800, Xu Yilun wrote:
> +struct tdx_sys_info_ext {
> + u16 memory_pool_required_pages;
> + u8 ext_required;
The docs say this is a bool.
> +};
> +
^ permalink raw reply [flat|nested] 64+ messages in thread* Re: [PATCH 01/15] x86/virt/tdx: Read global metadata for TDX Module Extensions
2026-05-28 21:00 ` Edgecombe, Rick P
@ 2026-05-29 16:59 ` Xu Yilun
0 siblings, 0 replies; 64+ messages in thread
From: Xu Yilun @ 2026-05-29 16:59 UTC (permalink / raw)
To: Edgecombe, Rick P
Cc: Fang, Peter, kas@kernel.org, djbw@kernel.org, x86@kernel.org,
Xu, Yilun, Duan, Zhenzhong, baolu.lu@linux.intel.com, Li, Xiaoyao,
linux-kernel@vger.kernel.org, Mehta, Sohil, kvm@vger.kernel.org,
linux-coco@lists.linux.dev
On Thu, May 28, 2026 at 09:00:12PM +0000, Edgecombe, Rick P wrote:
> On Fri, 2026-05-22 at 11:41 +0800, Xu Yilun wrote:
> > +struct tdx_sys_info_ext {
> > + u16 memory_pool_required_pages;
>
> > + u8 ext_required;
>
> The docs say this is a bool.
mm.. OK. We don't have to follow the auto-generated format now, so bool
is good to me.
>
> > +};
> > +
>
^ permalink raw reply [flat|nested] 64+ messages in thread
* [PATCH 02/15] x86/virt/tdx: Add extra memory to TDX Module for Extensions
2026-05-22 3:41 [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting Xu Yilun
2026-05-22 3:41 ` [PATCH 01/15] x86/virt/tdx: Read global metadata for TDX Module Extensions Xu Yilun
@ 2026-05-22 3:41 ` Xu Yilun
2026-05-25 8:56 ` Xiaoyao Li
2026-06-07 4:38 ` Kishen Maloor
2026-05-22 3:41 ` [PATCH 03/15] x86/virt/tdx: Make TDX Module initialize Extensions Xu Yilun
` (14 subsequent siblings)
16 siblings, 2 replies; 64+ messages in thread
From: Xu Yilun @ 2026-05-22 3:41 UTC (permalink / raw)
To: kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, yilun.xu,
baolu.lu, zhenzhong.duan, xiaoyao.li
TDX Module introduces a new concept called "TDX Module Extensions" to
support long running / hard-irq preemptible flows inside. This makes TDX
Module capable of handling complex tasks through "Extension SEAMCALLs".
Adding more memory to TDX Module is the first step to enable Extensions.
Currently, TDX Module memory use is relatively static. But, the
Extensions need to use memory more dynamically. While 'static' here
means the kernel provides necessary amount of memory to TDX Module for
its basic functionalities, 'dynamic' means extra memory is needed only
if new add-on features are to be enabled. So add a new memory feeding
process backed by a new SEAMCALL TDH.EXT.MEM.ADD.
The process is mostly the same as adding PAMT. The kernel queries TDX
Module how much memory needed, allocates it, hands it over, and never
gets it back.
TDH.EXT.MEM.ADD uses a new parameter type HPA_LIST_INFO to provide
control (private) pages to TDX Module. This type represents a list of
pages for TDX Module to access. It needs a 'root page' which contains
the list of HPAs of the pages. It collapses the HPA of the root page
and the number of valid HPAs into a 64 bit raw value for SEAMCALL
parameters. The root page is always a medium, TDX Module never keeps
the root page.
Introduce a tdx_clflush_hpa_list() helper to flush shared cache before
SEAMCALL, to avoid shared cache writeback damaging these private pages.
For now, TDX Module Extensions consumes relatively large amount of
memory (~50MB). Use contiguous page allocation to avoid permanently
fragment too much memory. Print the allocation amount on TDX Module
Extensions initialization for visibility.
Co-developed-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
---
arch/x86/virt/vmx/tdx/tdx.h | 1 +
arch/x86/virt/vmx/tdx/tdx.c | 118 ++++++++++++++++++++++++++++++++++++
2 files changed, 119 insertions(+)
diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h
index a5eec8e3cc71..2335f88bbb10 100644
--- a/arch/x86/virt/vmx/tdx/tdx.h
+++ b/arch/x86/virt/vmx/tdx/tdx.h
@@ -46,6 +46,7 @@
#define TDH_PHYMEM_PAGE_WBINVD 41
#define TDH_VP_WR 43
#define TDH_SYS_CONFIG 45
+#define TDH_EXT_MEM_ADD 61
#define TDH_SYS_DISABLE 69
/*
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index c0c6281b08a5..622399d8da68 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -31,6 +31,7 @@
#include <linux/syscore_ops.h>
#include <linux/idr.h>
#include <linux/kvm_types.h>
+#include <linux/bitfield.h>
#include <asm/page.h>
#include <asm/special_insns.h>
#include <asm/msr-index.h>
@@ -1179,6 +1180,123 @@ static __init int init_tdmrs(struct tdmr_info_list *tdmr_list)
return 0;
}
+static void tdx_clflush_hpa_list(struct page *root, unsigned int nr_pages)
+{
+ u64 *entries = page_to_virt(root);
+ int i;
+
+ for (i = 0; i < nr_pages; i++)
+ clflush_cache_range(__va(entries[i]), PAGE_SIZE);
+}
+
+#define HPA_LIST_INFO_FIRST_ENTRY GENMASK_U64(11, 3)
+#define HPA_LIST_INFO_PFN GENMASK_U64(51, 12)
+#define HPA_LIST_INFO_LAST_ENTRY GENMASK_U64(63, 55)
+
+static u64 to_hpa_list_info(struct page *root, unsigned int nr_pages)
+{
+ return FIELD_PREP(HPA_LIST_INFO_FIRST_ENTRY, 0) |
+ FIELD_PREP(HPA_LIST_INFO_PFN, page_to_pfn(root)) |
+ FIELD_PREP(HPA_LIST_INFO_LAST_ENTRY, nr_pages - 1);
+}
+
+static int tdx_ext_mem_add(struct page *root, unsigned int nr_pages)
+{
+ struct tdx_module_args args = {
+ .rcx = to_hpa_list_info(root, nr_pages),
+ };
+ u64 r;
+
+ tdx_clflush_hpa_list(root, nr_pages);
+
+ do {
+ /*
+ * TDH_EXT_MEM_ADD is designed to use output parameter RCX to
+ * override/update input parameter RCX, so the caller doesn't
+ * have to do manual parameter update on retry call.
+ */
+ r = seamcall_ret(TDH_EXT_MEM_ADD, &args);
+ } while (r == TDX_INTERRUPTED_RESUMABLE);
+
+ if (r != TDX_SUCCESS)
+ return -EFAULT;
+
+ return 0;
+}
+
+static int tdx_ext_mem_setup(void)
+{
+ unsigned int nr_pages;
+ struct page *page;
+ u64 *root;
+ unsigned int i;
+ int ret;
+
+ nr_pages = tdx_sysinfo.ext.memory_pool_required_pages;
+ /*
+ * memory_pool_required_pages == 0 means no need to add pages,
+ * skip the memory setup.
+ */
+ if (!nr_pages)
+ return 0;
+
+ root = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!root)
+ return -ENOMEM;
+
+ page = alloc_contig_pages(nr_pages, GFP_KERNEL, numa_mem_id(),
+ &node_online_map);
+ if (!page) {
+ ret = -ENOMEM;
+ goto out_free_root;
+ }
+
+ for (i = 0; i < nr_pages;) {
+ unsigned int nents = min(nr_pages - i,
+ PAGE_SIZE / sizeof(*root));
+ int j;
+
+ for (j = 0; j < nents; j++)
+ root[j] = page_to_phys(page + i + j);
+
+ ret = tdx_ext_mem_add(virt_to_page(root), nents);
+ /*
+ * No SEAMCALLs to reclaim the added pages. For simple error
+ * handling, leak all pages.
+ */
+ WARN_ON_ONCE(ret);
+ if (ret)
+ break;
+
+ i += nents;
+ }
+
+ /*
+ * Extensions memory can't be reclaimed once added, print out the
+ * amount, stop tracking it and free the root page, no matter success
+ * or failure.
+ */
+ pr_info("%lu KB allocated for TDX Module Extensions\n",
+ nr_pages * PAGE_SIZE / 1024);
+
+out_free_root:
+ kfree(root);
+
+ return ret;
+}
+
+static int __maybe_unused init_tdx_ext(void)
+{
+ if (!(tdx_sysinfo.features.tdx_features0 & TDX_FEATURES0_EXT))
+ return 0;
+
+ /* No feature requires TDX Module Extensions. */
+ if (!tdx_sysinfo.ext.ext_required)
+ return 0;
+
+ return tdx_ext_mem_setup();
+}
+
static __init int init_tdx_module(void)
{
int ret;
--
2.25.1
^ permalink raw reply related [flat|nested] 64+ messages in thread* Re: [PATCH 02/15] x86/virt/tdx: Add extra memory to TDX Module for Extensions
2026-05-22 3:41 ` [PATCH 02/15] x86/virt/tdx: Add extra memory to TDX Module for Extensions Xu Yilun
@ 2026-05-25 8:56 ` Xiaoyao Li
2026-05-27 3:47 ` Xu Yilun
2026-06-07 4:38 ` Kishen Maloor
1 sibling, 1 reply; 64+ messages in thread
From: Xiaoyao Li @ 2026-05-25 8:56 UTC (permalink / raw)
To: Xu Yilun, kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan
On 5/22/2026 11:41 AM, Xu Yilun wrote:
> TDX Module introduces a new concept called "TDX Module Extensions" to
> support long running / hard-irq preemptible flows inside. This makes TDX
> Module capable of handling complex tasks through "Extension SEAMCALLs".
> Adding more memory to TDX Module is the first step to enable Extensions.
>
> Currently, TDX Module memory use is relatively static. But, the
> Extensions need to use memory more dynamically. While 'static' here
> means the kernel provides necessary amount of memory to TDX Module for
> its basic functionalities, 'dynamic' means extra memory is needed only
> if new add-on features are to be enabled. So add a new memory feeding
> process backed by a new SEAMCALL TDH.EXT.MEM.ADD.
>
> The process is mostly the same as adding PAMT. The kernel queries TDX
> Module how much memory needed, allocates it, hands it over, and never
> gets it back.
>
> TDH.EXT.MEM.ADD uses a new parameter type HPA_LIST_INFO to provide
> control (private) pages to TDX Module. This type represents a list of
> pages for TDX Module to access. It needs a 'root page' which contains
> the list of HPAs of the pages. It collapses the HPA of the root page
> and the number of valid HPAs into a 64 bit raw value for SEAMCALL
> parameters. The root page is always a medium, TDX Module never keeps
> the root page.
>
> Introduce a tdx_clflush_hpa_list() helper to flush shared cache before
> SEAMCALL, to avoid shared cache writeback damaging these private pages.
>
> For now, TDX Module Extensions consumes relatively large amount of
> memory (~50MB). Use contiguous page allocation to avoid permanently
> fragment too much memory. Print the allocation amount on TDX Module
> Extensions initialization for visibility.
>
> Co-developed-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
> Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
> ---
> arch/x86/virt/vmx/tdx/tdx.h | 1 +
> arch/x86/virt/vmx/tdx/tdx.c | 118 ++++++++++++++++++++++++++++++++++++
> 2 files changed, 119 insertions(+)
>
> diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h
> index a5eec8e3cc71..2335f88bbb10 100644
> --- a/arch/x86/virt/vmx/tdx/tdx.h
> +++ b/arch/x86/virt/vmx/tdx/tdx.h
> @@ -46,6 +46,7 @@
> #define TDH_PHYMEM_PAGE_WBINVD 41
> #define TDH_VP_WR 43
> #define TDH_SYS_CONFIG 45
> +#define TDH_EXT_MEM_ADD 61
> #define TDH_SYS_DISABLE 69
>
> /*
> diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
> index c0c6281b08a5..622399d8da68 100644
> --- a/arch/x86/virt/vmx/tdx/tdx.c
> +++ b/arch/x86/virt/vmx/tdx/tdx.c
> @@ -31,6 +31,7 @@
> #include <linux/syscore_ops.h>
> #include <linux/idr.h>
> #include <linux/kvm_types.h>
> +#include <linux/bitfield.h>
> #include <asm/page.h>
> #include <asm/special_insns.h>
> #include <asm/msr-index.h>
> @@ -1179,6 +1180,123 @@ static __init int init_tdmrs(struct tdmr_info_list *tdmr_list)
> return 0;
> }
>
> +static void tdx_clflush_hpa_list(struct page *root, unsigned int nr_pages)
> +{
> + u64 *entries = page_to_virt(root);
> + int i;
> +
> + for (i = 0; i < nr_pages; i++)
> + clflush_cache_range(__va(entries[i]), PAGE_SIZE);
Is the page flush only needed when CLFLUSH_BEFORE_ALLOC is true?
If so, it inherits the same decision to always flush as what
tdx_clflush_page() did. Then, any chance we can use tdx_clflush_page()
here so that we have a single central place of the comment to explain
the kernel design decision.
> +}
> +
> +#define HPA_LIST_INFO_FIRST_ENTRY GENMASK_U64(11, 3)
> +#define HPA_LIST_INFO_PFN GENMASK_U64(51, 12)
> +#define HPA_LIST_INFO_LAST_ENTRY GENMASK_U64(63, 55)
> +
> +static u64 to_hpa_list_info(struct page *root, unsigned int nr_pages)
> +{
> + return FIELD_PREP(HPA_LIST_INFO_FIRST_ENTRY, 0) |
> + FIELD_PREP(HPA_LIST_INFO_PFN, page_to_pfn(root)) |
> + FIELD_PREP(HPA_LIST_INFO_LAST_ENTRY, nr_pages - 1);
> +}
> +
> +static int tdx_ext_mem_add(struct page *root, unsigned int nr_pages)
> +{
> + struct tdx_module_args args = {
> + .rcx = to_hpa_list_info(root, nr_pages),
> + };
> + u64 r;
> +
> + tdx_clflush_hpa_list(root, nr_pages);
> +
> + do {
> + /*
> + * TDH_EXT_MEM_ADD is designed to use output parameter RCX to
> + * override/update input parameter RCX, so the caller doesn't
> + * have to do manual parameter update on retry call.
> + */
> + r = seamcall_ret(TDH_EXT_MEM_ADD, &args);
> + } while (r == TDX_INTERRUPTED_RESUMABLE);
> +
> + if (r != TDX_SUCCESS)
> + return -EFAULT;
> +
> + return 0;
> +}
> +
> +static int tdx_ext_mem_setup(void)
> +{
> + unsigned int nr_pages;
> + struct page *page;
> + u64 *root;
> + unsigned int i;
> + int ret;
> +
> + nr_pages = tdx_sysinfo.ext.memory_pool_required_pages;
> + /*
> + * memory_pool_required_pages == 0 means no need to add pages,
> + * skip the memory setup.
> + */
> + if (!nr_pages)
> + return 0;
> +
> + root = kzalloc(PAGE_SIZE, GFP_KERNEL);
> + if (!root)
> + return -ENOMEM;
> +
> + page = alloc_contig_pages(nr_pages, GFP_KERNEL, numa_mem_id(),
> + &node_online_map);
> + if (!page) {
> + ret = -ENOMEM;
> + goto out_free_root;
> + }
> +
> + for (i = 0; i < nr_pages;) {
> + unsigned int nents = min(nr_pages - i,
> + PAGE_SIZE / sizeof(*root));
> + int j;
> +
> + for (j = 0; j < nents; j++)
> + root[j] = page_to_phys(page + i + j);
> +
> + ret = tdx_ext_mem_add(virt_to_page(root), nents);
> + /*
> + * No SEAMCALLs to reclaim the added pages. For simple error
> + * handling, leak all pages.
> + */
> + WARN_ON_ONCE(ret);
> + if (ret)
> + break;
> +
> + i += nents;
> + }
> +
> + /*
> + * Extensions memory can't be reclaimed once added, print out the
> + * amount, stop tracking it and free the root page, no matter success
> + * or failure.
> + */
> + pr_info("%lu KB allocated for TDX Module Extensions\n",
> + nr_pages * PAGE_SIZE / 1024);
> +
> +out_free_root:
> + kfree(root);
> +
> + return ret;
> +}
> +
> +static int __maybe_unused init_tdx_ext(void)
> +{
> + if (!(tdx_sysinfo.features.tdx_features0 & TDX_FEATURES0_EXT))
> + return 0;
> +
> + /* No feature requires TDX Module Extensions. */
> + if (!tdx_sysinfo.ext.ext_required)
> + return 0;
> +
> + return tdx_ext_mem_setup();
> +}
> +
> static __init int init_tdx_module(void)
> {
> int ret;
^ permalink raw reply [flat|nested] 64+ messages in thread* Re: [PATCH 02/15] x86/virt/tdx: Add extra memory to TDX Module for Extensions
2026-05-25 8:56 ` Xiaoyao Li
@ 2026-05-27 3:47 ` Xu Yilun
2026-05-27 6:38 ` Xiaoyao Li
0 siblings, 1 reply; 64+ messages in thread
From: Xu Yilun @ 2026-05-27 3:47 UTC (permalink / raw)
To: Xiaoyao Li
Cc: kas, djbw, rick.p.edgecombe, x86, peter.fang, linux-coco,
linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan
> > +static void tdx_clflush_hpa_list(struct page *root, unsigned int nr_pages)
> > +{
> > + u64 *entries = page_to_virt(root);
> > + int i;
> > +
> > + for (i = 0; i < nr_pages; i++)
> > + clflush_cache_range(__va(entries[i]), PAGE_SIZE);
>
> Is the page flush only needed when CLFLUSH_BEFORE_ALLOC is true?
>
> If so, it inherits the same decision to always flush as what
Yes it is basically the same as tdx_clflush_page().
> tdx_clflush_page() did. Then, any chance we can use tdx_clflush_page() here
But I don't think we should convert hpa/page/va back and forth just for
re-using one line of code.
> so that we have a single central place of the comment to explain the kernel
> design decision.
How about I add a comment here to connect this wrapper to
tdx_clflush_page():
/*
* Unconditionally flush the pages regardless of CLFLUSH_BEFORE_ALLOC. Inherit
* the same decision as tdx_clflush_page().
*/
static void tdx_clflush_hpa_list(struct page *root, unsigned int nr_pages)
...
^ permalink raw reply [flat|nested] 64+ messages in thread* Re: [PATCH 02/15] x86/virt/tdx: Add extra memory to TDX Module for Extensions
2026-05-27 3:47 ` Xu Yilun
@ 2026-05-27 6:38 ` Xiaoyao Li
2026-05-27 7:32 ` Xu Yilun
0 siblings, 1 reply; 64+ messages in thread
From: Xiaoyao Li @ 2026-05-27 6:38 UTC (permalink / raw)
To: Xu Yilun
Cc: kas, djbw, rick.p.edgecombe, x86, peter.fang, linux-coco,
linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan
On 5/27/2026 11:47 AM, Xu Yilun wrote:
>>> +static void tdx_clflush_hpa_list(struct page *root, unsigned int nr_pages)
>>> +{
>>> + u64 *entries = page_to_virt(root);
>>> + int i;
>>> +
>>> + for (i = 0; i < nr_pages; i++)
>>> + clflush_cache_range(__va(entries[i]), PAGE_SIZE);
>>
>> Is the page flush only needed when CLFLUSH_BEFORE_ALLOC is true?
>>
>> If so, it inherits the same decision to always flush as what
>
> Yes it is basically the same as tdx_clflush_page().
>
>> tdx_clflush_page() did. Then, any chance we can use tdx_clflush_page() here
>
> But I don't think we should convert hpa/page/va back and forth just for
> re-using one line of code.
Because we want/need to flush page as late as possible so that the page
flush needs to happen right before SEAMCALL?
How about we pass in the struct page * and number into tdx_ext_mem_add()
and construct the root page inside it?
>> so that we have a single central place of the comment to explain the kernel
>> design decision.
>
> How about I add a comment here to connect this wrapper to
> tdx_clflush_page():
>
> /*
> * Unconditionally flush the pages regardless of CLFLUSH_BEFORE_ALLOC. Inherit
> * the same decision as tdx_clflush_page().
> */
> static void tdx_clflush_hpa_list(struct page *root, unsigned int nr_pages)
> ...
It works either. I don't have strong preference. Let's see if anyone
else say something about it.
^ permalink raw reply [flat|nested] 64+ messages in thread* Re: [PATCH 02/15] x86/virt/tdx: Add extra memory to TDX Module for Extensions
2026-05-27 6:38 ` Xiaoyao Li
@ 2026-05-27 7:32 ` Xu Yilun
2026-05-27 8:18 ` Xiaoyao Li
0 siblings, 1 reply; 64+ messages in thread
From: Xu Yilun @ 2026-05-27 7:32 UTC (permalink / raw)
To: Xiaoyao Li
Cc: kas, djbw, rick.p.edgecombe, x86, peter.fang, linux-coco,
linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan
On Wed, May 27, 2026 at 02:38:27PM +0800, Xiaoyao Li wrote:
> On 5/27/2026 11:47 AM, Xu Yilun wrote:
> > > > +static void tdx_clflush_hpa_list(struct page *root, unsigned int nr_pages)
> > > > +{
> > > > + u64 *entries = page_to_virt(root);
> > > > + int i;
> > > > +
> > > > + for (i = 0; i < nr_pages; i++)
> > > > + clflush_cache_range(__va(entries[i]), PAGE_SIZE);
> > >
> > > Is the page flush only needed when CLFLUSH_BEFORE_ALLOC is true?
> > >
> > > If so, it inherits the same decision to always flush as what
> >
> > Yes it is basically the same as tdx_clflush_page().
> >
> > > tdx_clflush_page() did. Then, any chance we can use tdx_clflush_page() here
> >
> > But I don't think we should convert hpa/page/va back and forth just for
> > re-using one line of code.
>
> Because we want/need to flush page as late as possible so that the page
> flush needs to happen right before SEAMCALL?
I think so. Let the flushing be part of the tdh call semantic.
>
> How about we pass in the struct page * and number into tdx_ext_mem_add() and
> construct the root page inside it?
I assume you don't suggest allocate root page inside the call, then we
need 3 parameters for the HPA_LIST_INFO:
struct page *, unsigned int nr_pages, struct page *root
which I think too much.
I think your concern is to try not to introduce another tdx_clflush_
variant, but I believe this will happen, pfn based memory description is
on the way:
https://lore.kernel.org/all/20260430014929.24210-1-yan.y.zhao@intel.com/
^ permalink raw reply [flat|nested] 64+ messages in thread* Re: [PATCH 02/15] x86/virt/tdx: Add extra memory to TDX Module for Extensions
2026-05-27 7:32 ` Xu Yilun
@ 2026-05-27 8:18 ` Xiaoyao Li
0 siblings, 0 replies; 64+ messages in thread
From: Xiaoyao Li @ 2026-05-27 8:18 UTC (permalink / raw)
To: Xu Yilun
Cc: kas, djbw, rick.p.edgecombe, x86, peter.fang, linux-coco,
linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan
On 5/27/2026 3:32 PM, Xu Yilun wrote:
> On Wed, May 27, 2026 at 02:38:27PM +0800, Xiaoyao Li wrote:
>> On 5/27/2026 11:47 AM, Xu Yilun wrote:
>>>>> +static void tdx_clflush_hpa_list(struct page *root, unsigned int nr_pages)
>>>>> +{
>>>>> + u64 *entries = page_to_virt(root);
>>>>> + int i;
>>>>> +
>>>>> + for (i = 0; i < nr_pages; i++)
>>>>> + clflush_cache_range(__va(entries[i]), PAGE_SIZE);
>>>>
>>>> Is the page flush only needed when CLFLUSH_BEFORE_ALLOC is true?
>>>>
>>>> If so, it inherits the same decision to always flush as what
>>>
>>> Yes it is basically the same as tdx_clflush_page().
>>>
>>>> tdx_clflush_page() did. Then, any chance we can use tdx_clflush_page() here
>>>
>>> But I don't think we should convert hpa/page/va back and forth just for
>>> re-using one line of code.
>>
>> Because we want/need to flush page as late as possible so that the page
>> flush needs to happen right before SEAMCALL?
>
> I think so. Let the flushing be part of the tdh call semantic.
>
>>
>> How about we pass in the struct page * and number into tdx_ext_mem_add() and
>> construct the root page inside it?
>
> I assume you don't suggest allocate root page inside the call, then we
> need 3 parameters for the HPA_LIST_INFO:
>
> struct page *, unsigned int nr_pages, struct page *root
>
> which I think too much.
yeah, sort of.
> I think your concern is to try not to introduce another tdx_clflush_
> variant, but I believe this will happen, pfn based memory description is
> on the way:
>
> https://lore.kernel.org/all/20260430014929.24210-1-yan.y.zhao@intel.com/
I don't object the variant of tdx_clflush_hpa_list(), but suggest if
tdx_clflush_page() can be used instead of raw clflush_cache_range()
Maybe we can try to put tdx_clflush_hpa_list() along with
tdx_clflush_page() and tdx_clflush_pfn()? This way, I think we can save
the separate comment.
^ permalink raw reply [flat|nested] 64+ messages in thread
* Re: [PATCH 02/15] x86/virt/tdx: Add extra memory to TDX Module for Extensions
2026-05-22 3:41 ` [PATCH 02/15] x86/virt/tdx: Add extra memory to TDX Module for Extensions Xu Yilun
2026-05-25 8:56 ` Xiaoyao Li
@ 2026-06-07 4:38 ` Kishen Maloor
1 sibling, 0 replies; 64+ messages in thread
From: Kishen Maloor @ 2026-06-07 4:38 UTC (permalink / raw)
To: Xu Yilun, kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan, xiaoyao.li
On 5/21/26 8:41 PM, Xu Yilun wrote:
> TDX Module introduces a new concept called "TDX Module Extensions" to
> support long running / hard-irq preemptible flows inside. This makes TDX
> Module capable of handling complex tasks through "Extension SEAMCALLs".
> Adding more memory to TDX Module is the first step to enable Extensions.
>
> Currently, TDX Module memory use is relatively static. But, the
> Extensions need to use memory more dynamically. While 'static' here
> means the kernel provides necessary amount of memory to TDX Module for
> its basic functionalities, 'dynamic' means extra memory is needed only
> if new add-on features are to be enabled. So add a new memory feeding
> process backed by a new SEAMCALL TDH.EXT.MEM.ADD.
>
> The process is mostly the same as adding PAMT. The kernel queries TDX
> Module how much memory needed, allocates it, hands it over, and never
> gets it back.
>
> TDH.EXT.MEM.ADD uses a new parameter type HPA_LIST_INFO to provide
> control (private) pages to TDX Module. This type represents a list of
> pages for TDX Module to access. It needs a 'root page' which contains
> the list of HPAs of the pages. It collapses the HPA of the root page
> and the number of valid HPAs into a 64 bit raw value for SEAMCALL
> parameters. The root page is always a medium, TDX Module never keeps
> the root page.
>
> Introduce a tdx_clflush_hpa_list() helper to flush shared cache before
> SEAMCALL, to avoid shared cache writeback damaging these private pages.
>
> For now, TDX Module Extensions consumes relatively large amount of
> memory (~50MB). Use contiguous page allocation to avoid permanently
> fragment too much memory. Print the allocation amount on TDX Module
> Extensions initialization for visibility.
>
> Co-developed-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
> Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
> ---
> arch/x86/virt/vmx/tdx/tdx.h | 1 +
> arch/x86/virt/vmx/tdx/tdx.c | 118 ++++++++++++++++++++++++++++++++++++
> 2 files changed, 119 insertions(+)
>
> diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h
> index a5eec8e3cc71..2335f88bbb10 100644
> --- a/arch/x86/virt/vmx/tdx/tdx.h
> +++ b/arch/x86/virt/vmx/tdx/tdx.h
> @@ -46,6 +46,7 @@
> #define TDH_PHYMEM_PAGE_WBINVD 41
> #define TDH_VP_WR 43
> #define TDH_SYS_CONFIG 45
> +#define TDH_EXT_MEM_ADD 61
> #define TDH_SYS_DISABLE 69
>
> /*
> diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
> index c0c6281b08a5..622399d8da68 100644
> --- a/arch/x86/virt/vmx/tdx/tdx.c
> +++ b/arch/x86/virt/vmx/tdx/tdx.c
> @@ -31,6 +31,7 @@
> #include <linux/syscore_ops.h>
> #include <linux/idr.h>
> #include <linux/kvm_types.h>
> +#include <linux/bitfield.h>
> #include <asm/page.h>
> #include <asm/special_insns.h>
> #include <asm/msr-index.h>
> @@ -1179,6 +1180,123 @@ static __init int init_tdmrs(struct tdmr_info_list *tdmr_list)
> return 0;
> }
>
> +static void tdx_clflush_hpa_list(struct page *root, unsigned int nr_pages)
> +{
> + u64 *entries = page_to_virt(root);
> + int i;
> +
> + for (i = 0; i < nr_pages; i++)
> + clflush_cache_range(__va(entries[i]), PAGE_SIZE);
> +}
> +
> +#define HPA_LIST_INFO_FIRST_ENTRY GENMASK_U64(11, 3)
> +#define HPA_LIST_INFO_PFN GENMASK_U64(51, 12)
> +#define HPA_LIST_INFO_LAST_ENTRY GENMASK_U64(63, 55)
> +
> +static u64 to_hpa_list_info(struct page *root, unsigned int nr_pages)
> +{
> + return FIELD_PREP(HPA_LIST_INFO_FIRST_ENTRY, 0) |
> + FIELD_PREP(HPA_LIST_INFO_PFN, page_to_pfn(root)) |
> + FIELD_PREP(HPA_LIST_INFO_LAST_ENTRY, nr_pages - 1);
> +}
> +
> +static int tdx_ext_mem_add(struct page *root, unsigned int nr_pages)
> +{
> + struct tdx_module_args args = {
> + .rcx = to_hpa_list_info(root, nr_pages),
> + };
> + u64 r;
> +
> + tdx_clflush_hpa_list(root, nr_pages);
> +
> + do {
> + /*
> + * TDH_EXT_MEM_ADD is designed to use output parameter RCX to
> + * override/update input parameter RCX, so the caller doesn't
> + * have to do manual parameter update on retry call.
> + */
> + r = seamcall_ret(TDH_EXT_MEM_ADD, &args);
> + } while (r == TDX_INTERRUPTED_RESUMABLE);
The retry loop compares the full return value against TDX_INTERRUPTED_RESUMABLE. Should
it mask with TDX_SEAMCALL_STATUS_MASK first, in case the module sets any
lower detail bits?
Ditto for TDH.EXT.INIT in patch 3.
> +
> + if (r != TDX_SUCCESS)
> + return -EFAULT;
> +
> + return 0;
> +}
> +
> +static int tdx_ext_mem_setup(void)
> +{
> + unsigned int nr_pages;
> + struct page *page;
> + u64 *root;
> + unsigned int i;
> + int ret;
> +
> + nr_pages = tdx_sysinfo.ext.memory_pool_required_pages;
> + /*
> + * memory_pool_required_pages == 0 means no need to add pages,
> + * skip the memory setup.
> + */
> + if (!nr_pages)
> + return 0;
> +
> + root = kzalloc(PAGE_SIZE, GFP_KERNEL);
> + if (!root)
> + return -ENOMEM;
> +
> + page = alloc_contig_pages(nr_pages, GFP_KERNEL, numa_mem_id(),
> + &node_online_map);
The SEAMCALL takes a scatter list (HPA_LIST_INFO), so the module
doesn't require contiguity. If the goal is just to avoid scattering
pages across many 2MB regions, maybe dense, 2MB-aligned allocations should
achieve that without a single pool-wide contiguous block.
> + if (!page) {
> + ret = -ENOMEM;
> + goto out_free_root;
> + }
> +
> + for (i = 0; i < nr_pages;) {
> + unsigned int nents = min(nr_pages - i,
> + PAGE_SIZE / sizeof(*root));
> + int j;
> +
> + for (j = 0; j < nents; j++)
> + root[j] = page_to_phys(page + i + j);
Would it be better to allocate per-batch (i.e. one root page's worth
at a time) rather than the whole pool up front?
That way an intermediate TDH.EXT.MEM.ADD failure wouldn't leak
all nr_pages. Also, a batch is up to 512 pages (= 2MB) and its allocation
could be 2MB-aligned, addressing your fragmentation concern.
> +
> + ret = tdx_ext_mem_add(virt_to_page(root), nents);
> + /*
> + * No SEAMCALLs to reclaim the added pages. For simple error
> + * handling, leak all pages.
> + */
> + WARN_ON_ONCE(ret);
> + if (ret)
> + break;
> +
> + i += nents;
> + }
> +
> + /*
> + * Extensions memory can't be reclaimed once added, print out the
> + * amount, stop tracking it and free the root page, no matter success
> + * or failure.
> + */
> + pr_info("%lu KB allocated for TDX Module Extensions\n",
> + nr_pages * PAGE_SIZE / 1024);
> +
> +out_free_root:
> + kfree(root);
> +
> + return ret;
> +}
> +
> +static int __maybe_unused init_tdx_ext(void)
Could this be named init_tdx_extensions() instead to disambiguate
from tdx_ext_init() in patch 3?
> +{
> + if (!(tdx_sysinfo.features.tdx_features0 & TDX_FEATURES0_EXT))
> + return 0;
> +
> + /* No feature requires TDX Module Extensions. */
> + if (!tdx_sysinfo.ext.ext_required)
> + return 0;
> +
> + return tdx_ext_mem_setup();
> +}
> +
> static __init int init_tdx_module(void)
> {
> int ret;
^ permalink raw reply [flat|nested] 64+ messages in thread
* [PATCH 03/15] x86/virt/tdx: Make TDX Module initialize Extensions
2026-05-22 3:41 [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting Xu Yilun
2026-05-22 3:41 ` [PATCH 01/15] x86/virt/tdx: Read global metadata for TDX Module Extensions Xu Yilun
2026-05-22 3:41 ` [PATCH 02/15] x86/virt/tdx: Add extra memory to TDX Module for Extensions Xu Yilun
@ 2026-05-22 3:41 ` Xu Yilun
2026-05-25 8:58 ` Xiaoyao Li
2026-06-05 8:46 ` Tony Lindgren
2026-05-22 3:41 ` [PATCH 04/15] x86/virt/tdx: Enable the Extensions right after basic TDX Module init Xu Yilun
` (13 subsequent siblings)
16 siblings, 2 replies; 64+ messages in thread
From: Xu Yilun @ 2026-05-22 3:41 UTC (permalink / raw)
To: kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, yilun.xu,
baolu.lu, zhenzhong.duan, xiaoyao.li
After providing all required memory to TDX Module, initialize TDX
Module Extensions via TDH.EXT.INIT, so Extension-SEAMCALLs can be used.
Co-developed-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
---
arch/x86/virt/vmx/tdx/tdx.h | 1 +
arch/x86/virt/vmx/tdx/tdx.c | 24 +++++++++++++++++++++++-
2 files changed, 24 insertions(+), 1 deletion(-)
diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h
index 2335f88bbb10..c5bffd118145 100644
--- a/arch/x86/virt/vmx/tdx/tdx.h
+++ b/arch/x86/virt/vmx/tdx/tdx.h
@@ -46,6 +46,7 @@
#define TDH_PHYMEM_PAGE_WBINVD 41
#define TDH_VP_WR 43
#define TDH_SYS_CONFIG 45
+#define TDH_EXT_INIT 60
#define TDH_EXT_MEM_ADD 61
#define TDH_SYS_DISABLE 69
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index 622399d8da68..ff2b96c20d2b 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -1200,6 +1200,22 @@ static u64 to_hpa_list_info(struct page *root, unsigned int nr_pages)
FIELD_PREP(HPA_LIST_INFO_LAST_ENTRY, nr_pages - 1);
}
+/* Initialize the TDX Module Extensions then Extension-SEAMCALLs can be used */
+static int tdx_ext_init(void)
+{
+ struct tdx_module_args args = {};
+ u64 r;
+
+ do {
+ r = seamcall(TDH_EXT_INIT, &args);
+ } while (r == TDX_INTERRUPTED_RESUMABLE);
+
+ if (r != TDX_SUCCESS)
+ return -EFAULT;
+
+ return 0;
+}
+
static int tdx_ext_mem_add(struct page *root, unsigned int nr_pages)
{
struct tdx_module_args args = {
@@ -1287,6 +1303,8 @@ static int tdx_ext_mem_setup(void)
static int __maybe_unused init_tdx_ext(void)
{
+ int ret;
+
if (!(tdx_sysinfo.features.tdx_features0 & TDX_FEATURES0_EXT))
return 0;
@@ -1294,7 +1312,11 @@ static int __maybe_unused init_tdx_ext(void)
if (!tdx_sysinfo.ext.ext_required)
return 0;
- return tdx_ext_mem_setup();
+ ret = tdx_ext_mem_setup();
+ if (ret)
+ return ret;
+
+ return tdx_ext_init();
}
static __init int init_tdx_module(void)
--
2.25.1
^ permalink raw reply related [flat|nested] 64+ messages in thread* Re: [PATCH 03/15] x86/virt/tdx: Make TDX Module initialize Extensions
2026-05-22 3:41 ` [PATCH 03/15] x86/virt/tdx: Make TDX Module initialize Extensions Xu Yilun
@ 2026-05-25 8:58 ` Xiaoyao Li
2026-06-05 8:46 ` Tony Lindgren
1 sibling, 0 replies; 64+ messages in thread
From: Xiaoyao Li @ 2026-05-25 8:58 UTC (permalink / raw)
To: Xu Yilun, kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan
On 5/22/2026 11:41 AM, Xu Yilun wrote:
> After providing all required memory to TDX Module, initialize TDX
> Module Extensions via TDH.EXT.INIT, so Extension-SEAMCALLs can be used.
>
> Co-developed-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
> Signed-off-by: Zhenzhong Duan <zhenzhong.duan@intel.com>
> Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
Reviewed-by: Xiaoyao Li <xiaoyao.li@intel.com>
> ---
> arch/x86/virt/vmx/tdx/tdx.h | 1 +
> arch/x86/virt/vmx/tdx/tdx.c | 24 +++++++++++++++++++++++-
> 2 files changed, 24 insertions(+), 1 deletion(-)
>
> diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h
> index 2335f88bbb10..c5bffd118145 100644
> --- a/arch/x86/virt/vmx/tdx/tdx.h
> +++ b/arch/x86/virt/vmx/tdx/tdx.h
> @@ -46,6 +46,7 @@
> #define TDH_PHYMEM_PAGE_WBINVD 41
> #define TDH_VP_WR 43
> #define TDH_SYS_CONFIG 45
> +#define TDH_EXT_INIT 60
> #define TDH_EXT_MEM_ADD 61
> #define TDH_SYS_DISABLE 69
>
> diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
> index 622399d8da68..ff2b96c20d2b 100644
> --- a/arch/x86/virt/vmx/tdx/tdx.c
> +++ b/arch/x86/virt/vmx/tdx/tdx.c
> @@ -1200,6 +1200,22 @@ static u64 to_hpa_list_info(struct page *root, unsigned int nr_pages)
> FIELD_PREP(HPA_LIST_INFO_LAST_ENTRY, nr_pages - 1);
> }
>
> +/* Initialize the TDX Module Extensions then Extension-SEAMCALLs can be used */
> +static int tdx_ext_init(void)
> +{
> + struct tdx_module_args args = {};
> + u64 r;
> +
> + do {
> + r = seamcall(TDH_EXT_INIT, &args);
> + } while (r == TDX_INTERRUPTED_RESUMABLE);
> +
> + if (r != TDX_SUCCESS)
> + return -EFAULT;
> +
> + return 0;
> +}
> +
> static int tdx_ext_mem_add(struct page *root, unsigned int nr_pages)
> {
> struct tdx_module_args args = {
> @@ -1287,6 +1303,8 @@ static int tdx_ext_mem_setup(void)
>
> static int __maybe_unused init_tdx_ext(void)
> {
> + int ret;
> +
> if (!(tdx_sysinfo.features.tdx_features0 & TDX_FEATURES0_EXT))
> return 0;
>
> @@ -1294,7 +1312,11 @@ static int __maybe_unused init_tdx_ext(void)
> if (!tdx_sysinfo.ext.ext_required)
> return 0;
>
> - return tdx_ext_mem_setup();
> + ret = tdx_ext_mem_setup();
> + if (ret)
> + return ret;
> +
> + return tdx_ext_init();
> }
>
> static __init int init_tdx_module(void)
^ permalink raw reply [flat|nested] 64+ messages in thread* Re: [PATCH 03/15] x86/virt/tdx: Make TDX Module initialize Extensions
2026-05-22 3:41 ` [PATCH 03/15] x86/virt/tdx: Make TDX Module initialize Extensions Xu Yilun
2026-05-25 8:58 ` Xiaoyao Li
@ 2026-06-05 8:46 ` Tony Lindgren
1 sibling, 0 replies; 64+ messages in thread
From: Tony Lindgren @ 2026-06-05 8:46 UTC (permalink / raw)
To: Xu Yilun
Cc: kas, djbw, rick.p.edgecombe, x86, peter.fang, linux-coco,
linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan, xiaoyao.li
On Fri, May 22, 2026 at 11:41:16AM +0800, Xu Yilun wrote:
> --- a/arch/x86/virt/vmx/tdx/tdx.c
> +++ b/arch/x86/virt/vmx/tdx/tdx.c
> @@ -1200,6 +1200,22 @@ static u64 to_hpa_list_info(struct page *root, unsigned int nr_pages)
> FIELD_PREP(HPA_LIST_INFO_LAST_ENTRY, nr_pages - 1);
> }
>
> +/* Initialize the TDX Module Extensions then Extension-SEAMCALLs can be used */
> +static int tdx_ext_init(void)
> +{
> + struct tdx_module_args args = {};
> + u64 r;
> +
> + do {
> + r = seamcall(TDH_EXT_INIT, &args);
> + } while (r == TDX_INTERRUPTED_RESUMABLE);
> +
> + if (r != TDX_SUCCESS)
> + return -EFAULT;
> +
> + return 0;
> +}
> +
> static int tdx_ext_mem_add(struct page *root, unsigned int nr_pages)
> {
> struct tdx_module_args args = {
How about "Initialize the TDX Module Extensions for Extension-SEAMCALLs"
above for the comment?
Other than that:
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
^ permalink raw reply [flat|nested] 64+ messages in thread
* [PATCH 04/15] x86/virt/tdx: Enable the Extensions right after basic TDX Module init
2026-05-22 3:41 [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting Xu Yilun
` (2 preceding siblings ...)
2026-05-22 3:41 ` [PATCH 03/15] x86/virt/tdx: Make TDX Module initialize Extensions Xu Yilun
@ 2026-05-22 3:41 ` Xu Yilun
2026-05-25 6:00 ` Tony Lindgren
` (3 more replies)
2026-05-22 3:41 ` [RFC PATCH 05/15] x86/virt/tdx: Move tdx_tdr_pa() up in the file Xu Yilun
` (12 subsequent siblings)
16 siblings, 4 replies; 64+ messages in thread
From: Xu Yilun @ 2026-05-22 3:41 UTC (permalink / raw)
To: kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, yilun.xu,
baolu.lu, zhenzhong.duan, xiaoyao.li
The detailed initialization flow for TDX Module Extensions has been
fully implemented. Enable the flow after basic TDX Module
initialization.
Theoretically, the Extensions doesn't need to be enabled right after
basic TDX initialization. It could be enabled right before the first
Extension SEAMCALL is issued. That would save or postpone memory usage.
But it isn't worth the complexity, the needs for the Extensions are vast
but the savings are little for a typical TDX capable system (about
0.001% of memory). So the Linux decision is to just enable it along with
the basic TDX.
Note that the Extensions initialization flow will still not start if no
add-on features require Extensions. The enabling of add-on features will
be in later patches. Until then, the system hasn't consumed extra memory.
Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
---
arch/x86/virt/vmx/tdx/tdx.c | 16 ++++++++++------
1 file changed, 10 insertions(+), 6 deletions(-)
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index ff2b96c20d2b..dad5ec642723 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -1180,7 +1180,7 @@ static __init int init_tdmrs(struct tdmr_info_list *tdmr_list)
return 0;
}
-static void tdx_clflush_hpa_list(struct page *root, unsigned int nr_pages)
+static __init void tdx_clflush_hpa_list(struct page *root, unsigned int nr_pages)
{
u64 *entries = page_to_virt(root);
int i;
@@ -1193,7 +1193,7 @@ static void tdx_clflush_hpa_list(struct page *root, unsigned int nr_pages)
#define HPA_LIST_INFO_PFN GENMASK_U64(51, 12)
#define HPA_LIST_INFO_LAST_ENTRY GENMASK_U64(63, 55)
-static u64 to_hpa_list_info(struct page *root, unsigned int nr_pages)
+static __init u64 to_hpa_list_info(struct page *root, unsigned int nr_pages)
{
return FIELD_PREP(HPA_LIST_INFO_FIRST_ENTRY, 0) |
FIELD_PREP(HPA_LIST_INFO_PFN, page_to_pfn(root)) |
@@ -1201,7 +1201,7 @@ static u64 to_hpa_list_info(struct page *root, unsigned int nr_pages)
}
/* Initialize the TDX Module Extensions then Extension-SEAMCALLs can be used */
-static int tdx_ext_init(void)
+static __init int tdx_ext_init(void)
{
struct tdx_module_args args = {};
u64 r;
@@ -1216,7 +1216,7 @@ static int tdx_ext_init(void)
return 0;
}
-static int tdx_ext_mem_add(struct page *root, unsigned int nr_pages)
+static __init int tdx_ext_mem_add(struct page *root, unsigned int nr_pages)
{
struct tdx_module_args args = {
.rcx = to_hpa_list_info(root, nr_pages),
@@ -1240,7 +1240,7 @@ static int tdx_ext_mem_add(struct page *root, unsigned int nr_pages)
return 0;
}
-static int tdx_ext_mem_setup(void)
+static __init int tdx_ext_mem_setup(void)
{
unsigned int nr_pages;
struct page *page;
@@ -1301,7 +1301,7 @@ static int tdx_ext_mem_setup(void)
return ret;
}
-static int __maybe_unused init_tdx_ext(void)
+static __init int init_tdx_ext(void)
{
int ret;
@@ -1373,6 +1373,10 @@ static __init int init_tdx_module(void)
if (ret)
goto err_reset_pamts;
+ ret = init_tdx_ext();
+ if (ret)
+ goto err_reset_pamts;
+
pr_info("%lu KB allocated for PAMT\n", tdmrs_count_pamt_kb(&tdx_tdmr_list));
out_put_tdxmem:
--
2.25.1
^ permalink raw reply related [flat|nested] 64+ messages in thread* Re: [PATCH 04/15] x86/virt/tdx: Enable the Extensions right after basic TDX Module init
2026-05-22 3:41 ` [PATCH 04/15] x86/virt/tdx: Enable the Extensions right after basic TDX Module init Xu Yilun
@ 2026-05-25 6:00 ` Tony Lindgren
2026-05-27 4:02 ` Xu Yilun
2026-05-25 8:05 ` Xiaoyao Li
` (2 subsequent siblings)
3 siblings, 1 reply; 64+ messages in thread
From: Tony Lindgren @ 2026-05-25 6:00 UTC (permalink / raw)
To: Xu Yilun
Cc: kas, djbw, rick.p.edgecombe, x86, peter.fang, linux-coco,
linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan, xiaoyao.li
On Fri, May 22, 2026 at 11:41:17AM +0800, Xu Yilun wrote:
> The detailed initialization flow for TDX Module Extensions has been
> fully implemented. Enable the flow after basic TDX Module
> initialization.
>
> Theoretically, the Extensions doesn't need to be enabled right after
> basic TDX initialization. It could be enabled right before the first
> Extension SEAMCALL is issued. That would save or postpone memory usage.
> But it isn't worth the complexity, the needs for the Extensions are vast
> but the savings are little for a typical TDX capable system (about
> 0.001% of memory). So the Linux decision is to just enable it along with
> the basic TDX.
>
> Note that the Extensions initialization flow will still not start if no
> add-on features require Extensions. The enabling of add-on features will
> be in later patches. Until then, the system hasn't consumed extra memory.
Looking at patch 15/15, we need to reload the TDX module metadata at least
for the attestation. We need to do that early, so to me it seems that
everything can be just tagged __init from the start.
So you can just call init_tdx_ext() in patch 3/15, and this patch is not
needed at all?
Regards,
Tony
^ permalink raw reply [flat|nested] 64+ messages in thread* Re: [PATCH 04/15] x86/virt/tdx: Enable the Extensions right after basic TDX Module init
2026-05-25 6:00 ` Tony Lindgren
@ 2026-05-27 4:02 ` Xu Yilun
0 siblings, 0 replies; 64+ messages in thread
From: Xu Yilun @ 2026-05-27 4:02 UTC (permalink / raw)
To: Tony Lindgren
Cc: kas, djbw, rick.p.edgecombe, x86, peter.fang, linux-coco,
linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan, xiaoyao.li
On Mon, May 25, 2026 at 09:00:32AM +0300, Tony Lindgren wrote:
> On Fri, May 22, 2026 at 11:41:17AM +0800, Xu Yilun wrote:
> > The detailed initialization flow for TDX Module Extensions has been
> > fully implemented. Enable the flow after basic TDX Module
> > initialization.
> >
> > Theoretically, the Extensions doesn't need to be enabled right after
> > basic TDX initialization. It could be enabled right before the first
> > Extension SEAMCALL is issued. That would save or postpone memory usage.
> > But it isn't worth the complexity, the needs for the Extensions are vast
> > but the savings are little for a typical TDX capable system (about
> > 0.001% of memory). So the Linux decision is to just enable it along with
> > the basic TDX.
> >
> > Note that the Extensions initialization flow will still not start if no
> > add-on features require Extensions. The enabling of add-on features will
> > be in later patches. Until then, the system hasn't consumed extra memory.
>
> Looking at patch 15/15, we need to reload the TDX module metadata at least
> for the attestation. We need to do that early, so to me it seems that
> everything can be just tagged __init from the start.
I'm good to it. The Extension initialization will not start without
add-on features anyway. Let me move the patch as the first one to avoid
tag churn.
^ permalink raw reply [flat|nested] 64+ messages in thread
* Re: [PATCH 04/15] x86/virt/tdx: Enable the Extensions right after basic TDX Module init
2026-05-22 3:41 ` [PATCH 04/15] x86/virt/tdx: Enable the Extensions right after basic TDX Module init Xu Yilun
2026-05-25 6:00 ` Tony Lindgren
@ 2026-05-25 8:05 ` Xiaoyao Li
2026-05-28 21:32 ` Edgecombe, Rick P
2026-06-07 4:38 ` Kishen Maloor
3 siblings, 0 replies; 64+ messages in thread
From: Xiaoyao Li @ 2026-05-25 8:05 UTC (permalink / raw)
To: Xu Yilun, kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan
On 5/22/2026 11:41 AM, Xu Yilun wrote:
> The detailed initialization flow for TDX Module Extensions has been
> fully implemented. Enable the flow after basic TDX Module
> initialization.
>
> Theoretically, the Extensions doesn't need to be enabled right after
> basic TDX initialization. It could be enabled right before the first
> Extension SEAMCALL is issued. That would save or postpone memory usage.
> But it isn't worth the complexity, the needs for the Extensions are vast
> but the savings are little for a typical TDX capable system (about
> 0.001% of memory). So the Linux decision is to just enable it along with
> the basic TDX.
> Note that the Extensions initialization flow will still not start if no
> add-on features require Extensions. The enabling of add-on features will
> be in later patches. Until then, the system hasn't consumed extra memory.
based on the above, how about putting this patch before patch 02 and 03?
so that we can eliminate the churn of add "__init" and the
"__maybe_unused " in patch 02.
To be more safer, we can even make the code as
static bool tdx_supports_extension(void)
{
/* To be enabled when kernel is ready. */
return false;
}
static __init int init_tdx_ext(void)
{
if (!tdx_supports_extension())
return 0;
/* No feature requires TDX Module Extensions. */
if (!tdx_sysinfo.ext.ext_required)
return 0;
}
and after all the pieces implemented, we can change
tdx_supports_extension() to
static bool tdx_supports_extension(void)
{
/* To be enabled when kernel is ready. */
return !!(tdx_sysinfo.features.tdx_features0 & TDX_FEATURES0_EXT);
}
> Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
> ---
> arch/x86/virt/vmx/tdx/tdx.c | 16 ++++++++++------
> 1 file changed, 10 insertions(+), 6 deletions(-)
>
> diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
> index ff2b96c20d2b..dad5ec642723 100644
> --- a/arch/x86/virt/vmx/tdx/tdx.c
> +++ b/arch/x86/virt/vmx/tdx/tdx.c
> @@ -1180,7 +1180,7 @@ static __init int init_tdmrs(struct tdmr_info_list *tdmr_list)
> return 0;
> }
>
> -static void tdx_clflush_hpa_list(struct page *root, unsigned int nr_pages)
> +static __init void tdx_clflush_hpa_list(struct page *root, unsigned int nr_pages)
> {
> u64 *entries = page_to_virt(root);
> int i;
> @@ -1193,7 +1193,7 @@ static void tdx_clflush_hpa_list(struct page *root, unsigned int nr_pages)
> #define HPA_LIST_INFO_PFN GENMASK_U64(51, 12)
> #define HPA_LIST_INFO_LAST_ENTRY GENMASK_U64(63, 55)
>
> -static u64 to_hpa_list_info(struct page *root, unsigned int nr_pages)
> +static __init u64 to_hpa_list_info(struct page *root, unsigned int nr_pages)
> {
> return FIELD_PREP(HPA_LIST_INFO_FIRST_ENTRY, 0) |
> FIELD_PREP(HPA_LIST_INFO_PFN, page_to_pfn(root)) |
> @@ -1201,7 +1201,7 @@ static u64 to_hpa_list_info(struct page *root, unsigned int nr_pages)
> }
>
> /* Initialize the TDX Module Extensions then Extension-SEAMCALLs can be used */
> -static int tdx_ext_init(void)
> +static __init int tdx_ext_init(void)
> {
> struct tdx_module_args args = {};
> u64 r;
> @@ -1216,7 +1216,7 @@ static int tdx_ext_init(void)
> return 0;
> }
>
> -static int tdx_ext_mem_add(struct page *root, unsigned int nr_pages)
> +static __init int tdx_ext_mem_add(struct page *root, unsigned int nr_pages)
> {
> struct tdx_module_args args = {
> .rcx = to_hpa_list_info(root, nr_pages),
> @@ -1240,7 +1240,7 @@ static int tdx_ext_mem_add(struct page *root, unsigned int nr_pages)
> return 0;
> }
>
> -static int tdx_ext_mem_setup(void)
> +static __init int tdx_ext_mem_setup(void)
> {
> unsigned int nr_pages;
> struct page *page;
> @@ -1301,7 +1301,7 @@ static int tdx_ext_mem_setup(void)
> return ret;
> }
>
> -static int __maybe_unused init_tdx_ext(void)
> +static __init int init_tdx_ext(void)
> {
> int ret;
>
> @@ -1373,6 +1373,10 @@ static __init int init_tdx_module(void)
> if (ret)
> goto err_reset_pamts;
>
> + ret = init_tdx_ext();
> + if (ret)
> + goto err_reset_pamts;
> +
> pr_info("%lu KB allocated for PAMT\n", tdmrs_count_pamt_kb(&tdx_tdmr_list));
>
> out_put_tdxmem:
^ permalink raw reply [flat|nested] 64+ messages in thread* Re: [PATCH 04/15] x86/virt/tdx: Enable the Extensions right after basic TDX Module init
2026-05-22 3:41 ` [PATCH 04/15] x86/virt/tdx: Enable the Extensions right after basic TDX Module init Xu Yilun
2026-05-25 6:00 ` Tony Lindgren
2026-05-25 8:05 ` Xiaoyao Li
@ 2026-05-28 21:32 ` Edgecombe, Rick P
2026-05-29 17:19 ` Xu Yilun
2026-06-07 4:38 ` Kishen Maloor
3 siblings, 1 reply; 64+ messages in thread
From: Edgecombe, Rick P @ 2026-05-28 21:32 UTC (permalink / raw)
To: Fang, Peter, kas@kernel.org, djbw@kernel.org,
yilun.xu@linux.intel.com, x86@kernel.org
Cc: Xu, Yilun, Duan, Zhenzhong, baolu.lu@linux.intel.com, Li, Xiaoyao,
linux-kernel@vger.kernel.org, Mehta, Sohil, kvm@vger.kernel.org,
linux-coco@lists.linux.dev
On Fri, 2026-05-22 at 11:41 +0800, Xu Yilun wrote:
> The detailed initialization flow for TDX Module Extensions has been
> fully implemented.
>
I'm not sure what this means exactly. Why "detailed". Is that important?
> Enable the flow after basic TDX Module
> initialization.
>
> Theoretically, the Extensions doesn't need to be enabled right after
> basic TDX initialization. It could be enabled right before the first
> Extension SEAMCALL is issued. That would save or postpone memory usage.
> But it isn't worth the complexity, the needs for the Extensions are vast
> but the savings are little for a typical TDX capable system (about
> 0.001% of memory). So the Linux decision is to just enable it along with
> the basic TDX.
The Linux decision is whatever this patch turns out to be after community
review. So for the patch log we just need to justify why it's a good idea, not
not make an argument to defer to authority.
>
> Note that the Extensions initialization flow will still not start if no
> add-on features require Extensions. The enabling of add-on features will
> be in later patches. Until then, the system hasn't consumed extra memory.
Hmm, this patch reads like we are finally doing the initialization up until this
point. Then it turns out we don't actually light up the new code yet...
A lot of this diff is adding __init to the function added in the earlier
patches. Do we need to do this? Why not add them as __init in the original
patches?
I think we maybe want to say instead that we are setting up to enable extensions
at TDX module init time, and do the explanation of why. Then without the __init
stuff, the patch is just about the init time decision. Which seems about right
sized.
^ permalink raw reply [flat|nested] 64+ messages in thread
* Re: [PATCH 04/15] x86/virt/tdx: Enable the Extensions right after basic TDX Module init
2026-05-28 21:32 ` Edgecombe, Rick P
@ 2026-05-29 17:19 ` Xu Yilun
0 siblings, 0 replies; 64+ messages in thread
From: Xu Yilun @ 2026-05-29 17:19 UTC (permalink / raw)
To: Edgecombe, Rick P
Cc: Fang, Peter, kas@kernel.org, djbw@kernel.org, x86@kernel.org,
Xu, Yilun, Duan, Zhenzhong, baolu.lu@linux.intel.com, Li, Xiaoyao,
linux-kernel@vger.kernel.org, Mehta, Sohil, kvm@vger.kernel.org,
linux-coco@lists.linux.dev
On Thu, May 28, 2026 at 09:32:08PM +0000, Edgecombe, Rick P wrote:
> On Fri, 2026-05-22 at 11:41 +0800, Xu Yilun wrote:
> > The detailed initialization flow for TDX Module Extensions has been
> > fully implemented.
> >
>
> I'm not sure what this means exactly. Why "detailed". Is that important?
It's not important. I should re-phrase, The entire initialization flow...
>
> > Enable the flow after basic TDX Module
> > initialization.
> >
> > Theoretically, the Extensions doesn't need to be enabled right after
> > basic TDX initialization. It could be enabled right before the first
> > Extension SEAMCALL is issued. That would save or postpone memory usage.
> > But it isn't worth the complexity, the needs for the Extensions are vast
> > but the savings are little for a typical TDX capable system (about
> > 0.001% of memory). So the Linux decision is to just enable it along with
> > the basic TDX.
>
> The Linux decision is whatever this patch turns out to be after community
> review. So for the patch log we just need to justify why it's a good idea, not
> not make an argument to defer to authority.
Understood. I'll re-phrase this paragraph according to all the comments,
especially the last sentence.
>
> >
> > Note that the Extensions initialization flow will still not start if no
> > add-on features require Extensions. The enabling of add-on features will
> > be in later patches. Until then, the system hasn't consumed extra memory.
>
> Hmm, this patch reads like we are finally doing the initialization up until this
> point. Then it turns out we don't actually light up the new code yet...
>
> A lot of this diff is adding __init to the function added in the earlier
> patches. Do we need to do this? Why not add them as __init in the original
> patches?
>
>
> I think we maybe want to say instead that we are setting up to enable extensions
> at TDX module init time, and do the explanation of why. Then without the __init
> stuff, the patch is just about the init time decision. Which seems about right
> sized.
Yes. Since the patch doesn't actually light up anything new, I think it
could just be the first patch of Extensions so add __init at the first
place.
^ permalink raw reply [flat|nested] 64+ messages in thread
* Re: [PATCH 04/15] x86/virt/tdx: Enable the Extensions right after basic TDX Module init
2026-05-22 3:41 ` [PATCH 04/15] x86/virt/tdx: Enable the Extensions right after basic TDX Module init Xu Yilun
` (2 preceding siblings ...)
2026-05-28 21:32 ` Edgecombe, Rick P
@ 2026-06-07 4:38 ` Kishen Maloor
3 siblings, 0 replies; 64+ messages in thread
From: Kishen Maloor @ 2026-06-07 4:38 UTC (permalink / raw)
To: Xu Yilun, kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan, xiaoyao.li
On 5/21/26 8:41 PM, Xu Yilun wrote:
> The detailed initialization flow for TDX Module Extensions has been
> fully implemented. Enable the flow after basic TDX Module
> initialization.
>
> Theoretically, the Extensions doesn't need to be enabled right after
> basic TDX initialization. It could be enabled right before the first
> Extension SEAMCALL is issued. That would save or postpone memory usage.
> But it isn't worth the complexity, the needs for the Extensions are vast
> but the savings are little for a typical TDX capable system (about
> 0.001% of memory). So the Linux decision is to just enable it along with
> the basic TDX.
>
> Note that the Extensions initialization flow will still not start if no
> add-on features require Extensions. The enabling of add-on features will
> be in later patches. Until then, the system hasn't consumed extra memory.
>
> Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
> ---
> arch/x86/virt/vmx/tdx/tdx.c | 16 ++++++++++------
> 1 file changed, 10 insertions(+), 6 deletions(-)
>
> diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
> index ff2b96c20d2b..dad5ec642723 100644
> --- a/arch/x86/virt/vmx/tdx/tdx.c
> +++ b/arch/x86/virt/vmx/tdx/tdx.c
> @@ -1180,7 +1180,7 @@ static __init int init_tdmrs(struct tdmr_info_list *tdmr_list)
> return 0;
> }
>
> -static void tdx_clflush_hpa_list(struct page *root, unsigned int nr_pages)
> +static __init void tdx_clflush_hpa_list(struct page *root, unsigned int nr_pages)
> {
> u64 *entries = page_to_virt(root);
> int i;
> @@ -1193,7 +1193,7 @@ static void tdx_clflush_hpa_list(struct page *root, unsigned int nr_pages)
> #define HPA_LIST_INFO_PFN GENMASK_U64(51, 12)
> #define HPA_LIST_INFO_LAST_ENTRY GENMASK_U64(63, 55)
>
> -static u64 to_hpa_list_info(struct page *root, unsigned int nr_pages)
> +static __init u64 to_hpa_list_info(struct page *root, unsigned int nr_pages)
> {
> return FIELD_PREP(HPA_LIST_INFO_FIRST_ENTRY, 0) |
> FIELD_PREP(HPA_LIST_INFO_PFN, page_to_pfn(root)) |
> @@ -1201,7 +1201,7 @@ static u64 to_hpa_list_info(struct page *root, unsigned int nr_pages)
> }
>
> /* Initialize the TDX Module Extensions then Extension-SEAMCALLs can be used */
> -static int tdx_ext_init(void)
> +static __init int tdx_ext_init(void)
> {
> struct tdx_module_args args = {};
> u64 r;
> @@ -1216,7 +1216,7 @@ static int tdx_ext_init(void)
> return 0;
> }
>
> -static int tdx_ext_mem_add(struct page *root, unsigned int nr_pages)
> +static __init int tdx_ext_mem_add(struct page *root, unsigned int nr_pages)
> {
> struct tdx_module_args args = {
> .rcx = to_hpa_list_info(root, nr_pages),
> @@ -1240,7 +1240,7 @@ static int tdx_ext_mem_add(struct page *root, unsigned int nr_pages)
> return 0;
> }
>
> -static int tdx_ext_mem_setup(void)
> +static __init int tdx_ext_mem_setup(void)
> {
> unsigned int nr_pages;
> struct page *page;
> @@ -1301,7 +1301,7 @@ static int tdx_ext_mem_setup(void)
> return ret;
> }
>
> -static int __maybe_unused init_tdx_ext(void)
> +static __init int init_tdx_ext(void)
> {
> int ret;
>
> @@ -1373,6 +1373,10 @@ static __init int init_tdx_module(void)
> if (ret)
> goto err_reset_pamts;
>
> + ret = init_tdx_ext();
> + if (ret)
> + goto err_reset_pamts;
Is it a reasonable policy to fail TDX bringup entirely upon failing
initialization of extensions (which are "add-on features")?
The handling of tdx_quote_init() in Patch 6 suggests a more
best-effort approach.
> +
> pr_info("%lu KB allocated for PAMT\n", tdmrs_count_pamt_kb(&tdx_tdmr_list));
>
> out_put_tdxmem:
^ permalink raw reply [flat|nested] 64+ messages in thread
* [RFC PATCH 05/15] x86/virt/tdx: Move tdx_tdr_pa() up in the file
2026-05-22 3:41 [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting Xu Yilun
` (3 preceding siblings ...)
2026-05-22 3:41 ` [PATCH 04/15] x86/virt/tdx: Enable the Extensions right after basic TDX Module init Xu Yilun
@ 2026-05-22 3:41 ` Xu Yilun
2026-05-28 21:32 ` Edgecombe, Rick P
2026-05-22 3:41 ` [RFC PATCH 06/15] x86/virt/tdx: Initialize Quoting extension during bringup Xu Yilun
` (11 subsequent siblings)
16 siblings, 1 reply; 64+ messages in thread
From: Xu Yilun @ 2026-05-22 3:41 UTC (permalink / raw)
To: kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, yilun.xu,
baolu.lu, zhenzhong.duan, xiaoyao.li
From: Peter Fang <peter.fang@intel.com>
Move the tdx_tdr_pa() in preparation for upcoming changes to use them
during TDX bringup.
No functional change intended.
Signed-off-by: Peter Fang <peter.fang@intel.com>
Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
---
arch/x86/virt/vmx/tdx/tdx.c | 10 +++++-----
1 file changed, 5 insertions(+), 5 deletions(-)
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index dad5ec642723..67758adefb4a 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -1200,6 +1200,11 @@ static __init u64 to_hpa_list_info(struct page *root, unsigned int nr_pages)
FIELD_PREP(HPA_LIST_INFO_LAST_ENTRY, nr_pages - 1);
}
+static inline u64 tdx_tdr_pa(struct tdx_td *td)
+{
+ return page_to_phys(td->tdr_page);
+}
+
/* Initialize the TDX Module Extensions then Extension-SEAMCALLs can be used */
static __init int tdx_ext_init(void)
{
@@ -1725,11 +1730,6 @@ void tdx_guest_keyid_free(unsigned int keyid)
}
EXPORT_SYMBOL_FOR_KVM(tdx_guest_keyid_free);
-static inline u64 tdx_tdr_pa(struct tdx_td *td)
-{
- return page_to_phys(td->tdr_page);
-}
-
/*
* The TDX module exposes a CLFLUSH_BEFORE_ALLOC bit to specify whether
* a CLFLUSH of pages is required before handing them to the TDX module.
--
2.25.1
^ permalink raw reply related [flat|nested] 64+ messages in thread* Re: [RFC PATCH 05/15] x86/virt/tdx: Move tdx_tdr_pa() up in the file
2026-05-22 3:41 ` [RFC PATCH 05/15] x86/virt/tdx: Move tdx_tdr_pa() up in the file Xu Yilun
@ 2026-05-28 21:32 ` Edgecombe, Rick P
0 siblings, 0 replies; 64+ messages in thread
From: Edgecombe, Rick P @ 2026-05-28 21:32 UTC (permalink / raw)
To: Fang, Peter, kas@kernel.org, djbw@kernel.org,
yilun.xu@linux.intel.com, x86@kernel.org
Cc: Xu, Yilun, Duan, Zhenzhong, baolu.lu@linux.intel.com, Li, Xiaoyao,
linux-kernel@vger.kernel.org, Mehta, Sohil, kvm@vger.kernel.org,
linux-coco@lists.linux.dev
On Fri, 2026-05-22 at 11:41 +0800, Xu Yilun wrote:
> From: Peter Fang <peter.fang@intel.com>
>
> Move the tdx_tdr_pa() in preparation for upcoming changes to use them
> during TDX bringup.
>
> No functional change intended.
>
> Signed-off-by: Peter Fang <peter.fang@intel.com>
> Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
Reviewed-by: Rick Edgecombe <rick.p.edgecombe@intel.com>
^ permalink raw reply [flat|nested] 64+ messages in thread
* [RFC PATCH 06/15] x86/virt/tdx: Initialize Quoting extension during bringup
2026-05-22 3:41 [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting Xu Yilun
` (4 preceding siblings ...)
2026-05-22 3:41 ` [RFC PATCH 05/15] x86/virt/tdx: Move tdx_tdr_pa() up in the file Xu Yilun
@ 2026-05-22 3:41 ` Xu Yilun
2026-05-28 21:35 ` Edgecombe, Rick P
2026-05-22 3:41 ` [RFC PATCH 07/15] x86/virt/tdx: Prepare Quote buffer during extension bringup Xu Yilun
` (10 subsequent siblings)
16 siblings, 1 reply; 64+ messages in thread
From: Xu Yilun @ 2026-05-22 3:41 UTC (permalink / raw)
To: kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, yilun.xu,
baolu.lu, zhenzhong.duan, xiaoyao.li
From: Peter Fang <peter.fang@intel.com>
Initialize the Quoting extension and fetch its metadata during TDX
bringup.
Because Quoting is an optional TDX feature, do not let its
initialization failures cause TDX bringup to fail.
This patch does not include the opt-in portion of the initialization.
It mainly lays the groundwork for TDX Quoting support. Opt-in will be
added in a follow-up patch once the feature can be properly used by the
system.
Signed-off-by: Peter Fang <peter.fang@intel.com>
Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
---
arch/x86/include/asm/tdx_global_metadata.h | 5 ++++
arch/x86/virt/vmx/tdx/tdx.h | 1 +
arch/x86/virt/vmx/tdx/tdx.c | 29 ++++++++++++++++++++-
arch/x86/virt/vmx/tdx/tdx_global_metadata.c | 11 ++++++++
4 files changed, 45 insertions(+), 1 deletion(-)
diff --git a/arch/x86/include/asm/tdx_global_metadata.h b/arch/x86/include/asm/tdx_global_metadata.h
index 533afe50a3f1..04f515cd4c1d 100644
--- a/arch/x86/include/asm/tdx_global_metadata.h
+++ b/arch/x86/include/asm/tdx_global_metadata.h
@@ -45,6 +45,10 @@ struct tdx_sys_info_ext {
u8 ext_required;
};
+struct tdx_sys_info_quote {
+ u32 max_quote_size;
+};
+
struct tdx_sys_info {
struct tdx_sys_info_version version;
struct tdx_sys_info_features features;
@@ -52,6 +56,7 @@ struct tdx_sys_info {
struct tdx_sys_info_td_ctrl td_ctrl;
struct tdx_sys_info_td_conf td_conf;
struct tdx_sys_info_ext ext;
+ struct tdx_sys_info_quote quote;
};
#endif
diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h
index c5bffd118145..3849f4f9cc78 100644
--- a/arch/x86/virt/vmx/tdx/tdx.h
+++ b/arch/x86/virt/vmx/tdx/tdx.h
@@ -49,6 +49,7 @@
#define TDH_EXT_INIT 60
#define TDH_EXT_MEM_ADD 61
#define TDH_SYS_DISABLE 69
+#define TDH_QUOTE_INIT 100
/*
* SEAMCALL leaf:
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index 67758adefb4a..fb84fb6d952b 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -1205,6 +1205,22 @@ static inline u64 tdx_tdr_pa(struct tdx_td *td)
return page_to_phys(td->tdr_page);
}
+static void tdx_quote_init(void)
+{
+ struct tdx_module_args args = {};
+ u64 r;
+
+ do {
+ r = seamcall(TDH_QUOTE_INIT, &args);
+ } while (r == TDX_INTERRUPTED_RESUMABLE);
+
+ if (r)
+ return;
+
+ /* Quoting metadata is valid only after initialization */
+ get_tdx_sys_info_quote(&tdx_sysinfo.quote);
+}
+
/* Initialize the TDX Module Extensions then Extension-SEAMCALLs can be used */
static __init int tdx_ext_init(void)
{
@@ -1306,6 +1322,13 @@ static __init int tdx_ext_mem_setup(void)
return ret;
}
+static int init_tdx_ext_features(void)
+{
+ tdx_quote_init();
+
+ return 0;
+}
+
static __init int init_tdx_ext(void)
{
int ret;
@@ -1321,7 +1344,11 @@ static __init int init_tdx_ext(void)
if (ret)
return ret;
- return tdx_ext_init();
+ ret = tdx_ext_init();
+ if (ret)
+ return ret;
+
+ return init_tdx_ext_features();
}
static __init int init_tdx_module(void)
diff --git a/arch/x86/virt/vmx/tdx/tdx_global_metadata.c b/arch/x86/virt/vmx/tdx/tdx_global_metadata.c
index 3d3b56ef3d2f..f9cc2dd02caf 100644
--- a/arch/x86/virt/vmx/tdx/tdx_global_metadata.c
+++ b/arch/x86/virt/vmx/tdx/tdx_global_metadata.c
@@ -113,6 +113,17 @@ static __init int get_tdx_sys_info_ext(struct tdx_sys_info_ext *sysinfo_ext)
return ret;
}
+static int get_tdx_sys_info_quote(struct tdx_sys_info_quote *sysinfo_quote)
+{
+ int ret = 0;
+ u64 val;
+
+ if (!ret && !(ret = read_sys_metadata_field(0x2300000200000002, &val)))
+ sysinfo_quote->max_quote_size = val;
+
+ return ret;
+}
+
static __init int get_tdx_sys_info(struct tdx_sys_info *sysinfo)
{
int ret = 0;
--
2.25.1
^ permalink raw reply related [flat|nested] 64+ messages in thread* Re: [RFC PATCH 06/15] x86/virt/tdx: Initialize Quoting extension during bringup
2026-05-22 3:41 ` [RFC PATCH 06/15] x86/virt/tdx: Initialize Quoting extension during bringup Xu Yilun
@ 2026-05-28 21:35 ` Edgecombe, Rick P
0 siblings, 0 replies; 64+ messages in thread
From: Edgecombe, Rick P @ 2026-05-28 21:35 UTC (permalink / raw)
To: Fang, Peter, kas@kernel.org, djbw@kernel.org,
yilun.xu@linux.intel.com, x86@kernel.org
Cc: Xu, Yilun, Duan, Zhenzhong, baolu.lu@linux.intel.com, Li, Xiaoyao,
linux-kernel@vger.kernel.org, Mehta, Sohil, kvm@vger.kernel.org,
linux-coco@lists.linux.dev
On Fri, 2026-05-22 at 11:41 +0800, Xu Yilun wrote:
> From: Peter Fang <peter.fang@intel.com>
>
> Initialize the Quoting extension and fetch its metadata during TDX
> bringup.
>
> Because Quoting is an optional TDX feature, do not let its
> initialization failures cause TDX bringup to fail.
>
> This patch
>
Don't say "this patch" in tip logs. The patch is a temporary format, and some
x86 maintainers hate the term in logs.
> does not include the opt-in portion of the initialization.
> It mainly lays the groundwork for TDX Quoting support. Opt-in will be
> added in a follow-up patch once the feature can be properly used by the
> system.
This could be imperative mood.
>
> Signed-off-by: Peter Fang <peter.fang@intel.com>
> Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
^ permalink raw reply [flat|nested] 64+ messages in thread
* [RFC PATCH 07/15] x86/virt/tdx: Prepare Quote buffer during extension bringup
2026-05-22 3:41 [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting Xu Yilun
` (5 preceding siblings ...)
2026-05-22 3:41 ` [RFC PATCH 06/15] x86/virt/tdx: Initialize Quoting extension during bringup Xu Yilun
@ 2026-05-22 3:41 ` Xu Yilun
2026-05-28 22:30 ` Edgecombe, Rick P
2026-05-22 3:41 ` [RFC PATCH 08/15] x86/virt/tdx: Add interface to check Quoting availability Xu Yilun
` (9 subsequent siblings)
16 siblings, 1 reply; 64+ messages in thread
From: Xu Yilun @ 2026-05-22 3:41 UTC (permalink / raw)
To: kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, yilun.xu,
baolu.lu, zhenzhong.duan, xiaoyao.li
From: Peter Fang <peter.fang@intel.com>
The host uses a Quote buffer to communicate with the TDX module when
generating Quotes. Because the Quote buffer is shared with TDX guests,
prepare the required metadata during Quoting extension bringup.
This mostly involves determining the physical addresses of the Quote
buffer pages and arranging them in the HPA_LINKED_LIST format defined by
the Intel TDX Module ABI specification.
Signed-off-by: Peter Fang <peter.fang@intel.com>
Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
---
arch/x86/virt/vmx/tdx/tdx.c | 85 ++++++++++++++++++++++++++++++++++++-
1 file changed, 84 insertions(+), 1 deletion(-)
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index fb84fb6d952b..9d04293394d7 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -32,6 +32,7 @@
#include <linux/idr.h>
#include <linux/kvm_types.h>
#include <linux/bitfield.h>
+#include <linux/vmalloc.h>
#include <asm/page.h>
#include <asm/special_insns.h>
#include <asm/msr-index.h>
@@ -61,6 +62,13 @@ static LIST_HEAD(tdx_memlist);
static struct tdx_sys_info tdx_sysinfo __ro_after_init;
static bool tdx_module_initialized __ro_after_init;
+static struct quote_data {
+ void *buf;
+ u64 buf_len;
+ u64 *hpa_list;
+ phys_addr_t hpa_list_pa;
+} quote_data;
+
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)
@@ -1205,9 +1213,78 @@ static inline u64 tdx_tdr_pa(struct tdx_td *td)
return page_to_phys(td->tdr_page);
}
+#define HPAS_PER_PAGE (PAGE_SIZE / sizeof(u64))
+
+static int tdx_quote_create_buf(unsigned int nr_pages, struct quote_data *qdata)
+{
+ unsigned long pfn;
+ u64 qlist_npages;
+ int err, i, j;
+ u64 *qlist;
+ void *qbuf;
+
+ if (!nr_pages)
+ return -EINVAL;
+
+ /* The last entry of a linked list page points to the next page */
+ qlist_npages = (u64)DIV_ROUND_UP(nr_pages, HPAS_PER_PAGE - 1);
+
+ qlist = vmalloc_array(qlist_npages, PAGE_SIZE);
+ if (!qlist) {
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ /*
+ * Make sure unfilled entries are always -1, which means NULL in TDX.
+ * Only the last page needs to be filled. All the other pages will be
+ * fully populated.
+ */
+ memset((u8 *)qlist + (qlist_npages - 1) * PAGE_SIZE, 0xff, PAGE_SIZE);
+
+ qbuf = vcalloc(nr_pages, PAGE_SIZE);
+ if (!qbuf) {
+ err = -ENOMEM;
+ goto out_err;
+ }
+
+ /* Populate HPA_LINKED_LIST as per TDX ABI spec */
+ for (i = 0, j = 0; j < nr_pages; i++) {
+ if ((i % HPAS_PER_PAGE) == HPAS_PER_PAGE - 1) {
+ /*
+ * The last entry always points to the next page. The
+ * address of the following entry must be on next page's
+ * boundary.
+ */
+ pfn = vmalloc_to_pfn(&qlist[i + 1]);
+ qlist[i] = PFN_PHYS(pfn);
+ continue;
+ }
+
+ pfn = vmalloc_to_pfn((u8 *)qbuf + j * PAGE_SIZE);
+ qlist[i] = PFN_PHYS(pfn);
+ j++;
+ }
+
+ qdata->buf = qbuf;
+ qdata->buf_len = (u64)nr_pages * PAGE_SIZE;
+ qdata->hpa_list = qlist;
+
+ pfn = vmalloc_to_pfn(qlist);
+ qdata->hpa_list_pa = PFN_PHYS(pfn);
+
+ return 0;
+
+out_err:
+ vfree(qlist);
+
+ return err;
+}
+
static void tdx_quote_init(void)
{
struct tdx_module_args args = {};
+ unsigned int nr_quote_pages;
u64 r;
do {
@@ -1218,7 +1295,13 @@ static void tdx_quote_init(void)
return;
/* Quoting metadata is valid only after initialization */
- get_tdx_sys_info_quote(&tdx_sysinfo.quote);
+ if (get_tdx_sys_info_quote(&tdx_sysinfo.quote))
+ return;
+
+ nr_quote_pages = PAGE_ALIGN(tdx_sysinfo.quote.max_quote_size) /
+ PAGE_SIZE;
+ if (tdx_quote_create_buf(nr_quote_pages, "e_data))
+ pr_err("Failed to create quote buffer\n");
}
/* Initialize the TDX Module Extensions then Extension-SEAMCALLs can be used */
--
2.25.1
^ permalink raw reply related [flat|nested] 64+ messages in thread* Re: [RFC PATCH 07/15] x86/virt/tdx: Prepare Quote buffer during extension bringup
2026-05-22 3:41 ` [RFC PATCH 07/15] x86/virt/tdx: Prepare Quote buffer during extension bringup Xu Yilun
@ 2026-05-28 22:30 ` Edgecombe, Rick P
0 siblings, 0 replies; 64+ messages in thread
From: Edgecombe, Rick P @ 2026-05-28 22:30 UTC (permalink / raw)
To: Fang, Peter, kas@kernel.org, djbw@kernel.org,
yilun.xu@linux.intel.com, x86@kernel.org
Cc: Xu, Yilun, Duan, Zhenzhong, baolu.lu@linux.intel.com, Li, Xiaoyao,
linux-kernel@vger.kernel.org, Mehta, Sohil, kvm@vger.kernel.org,
linux-coco@lists.linux.dev
On Fri, 2026-05-22 at 11:41 +0800, Xu Yilun wrote:
> From: Peter Fang <peter.fang@intel.com>
>
> The host uses a Quote buffer to communicate with the TDX module when
> generating Quotes.
>
Can this be put in common terms. This is going to mean nothing to someone
reading this that doesn't already know the feature.
> Because the Quote buffer is shared with TDX guests,
Why capitalize "Quote"?
> prepare the required metadata during Quoting extension bringup.
What does prepare the required metadata mean?
How does it being shared with TDX guest suggest this? Just that TDX guests will
need them? Is the reason just that only one is needed, so do it during global
init?
>
> This mostly involves determining the physical addresses of the Quote
> buffer pages and arranging them in the HPA_LINKED_LIST format defined by
> the Intel TDX Module ABI specification.
>
> Signed-off-by: Peter Fang <peter.fang@intel.com>
> Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
> ---
> arch/x86/virt/vmx/tdx/tdx.c | 85 ++++++++++++++++++++++++++++++++++++-
> 1 file changed, 84 insertions(+), 1 deletion(-)
>
> diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
> index fb84fb6d952b..9d04293394d7 100644
> --- a/arch/x86/virt/vmx/tdx/tdx.c
> +++ b/arch/x86/virt/vmx/tdx/tdx.c
> @@ -32,6 +32,7 @@
> #include <linux/idr.h>
> #include <linux/kvm_types.h>
> #include <linux/bitfield.h>
> +#include <linux/vmalloc.h>
> #include <asm/page.h>
> #include <asm/special_insns.h>
> #include <asm/msr-index.h>
> @@ -61,6 +62,13 @@ static LIST_HEAD(tdx_memlist);
> static struct tdx_sys_info tdx_sysinfo __ro_after_init;
> static bool tdx_module_initialized __ro_after_init;
>
> +static struct quote_data {
> + void *buf;
> + u64 buf_len;
> + u64 *hpa_list;
> + phys_addr_t hpa_list_pa;
> +} quote_data;
Hmm, I think this should separate the type and variable declaration. It's not a
common pattern. I don't think there is an official rule.
> +
> 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)
> @@ -1205,9 +1213,78 @@ static inline u64 tdx_tdr_pa(struct tdx_td *td)
> return page_to_phys(td->tdr_page);
> }
>
> +#define HPAS_PER_PAGE (PAGE_SIZE / sizeof(u64))
> +
> +static int tdx_quote_create_buf(unsigned int nr_pages, struct quote_data *qdata)
> +{
> + unsigned long pfn;
> + u64 qlist_npages;
> + int err, i, j;
> + u64 *qlist;
> + void *qbuf;
> +
> + if (!nr_pages)
> + return -EINVAL;
> +
> + /* The last entry of a linked list page points to the next page */
> + qlist_npages = (u64)DIV_ROUND_UP(nr_pages, HPAS_PER_PAGE - 1);
> +
> + qlist = vmalloc_array(qlist_npages, PAGE_SIZE);
> + if (!qlist) {
> + err = -ENOMEM;
> + goto out_err;
Just return ENOMEM here. vfree() doesn't do any work if passed NULL, but it's
weird flow.
> + }
> +
> + /*
> + * Make sure unfilled entries are always -1, which means NULL in TDX.
Huh?
> + * Only the last page needs to be filled. All the other pages will be
> + * fully populated.
> + */
> + memset((u8 *)qlist + (qlist_npages - 1) * PAGE_SIZE, 0xff, PAGE_SIZE);
What are the entries? And what is a -1 in u8? Or is it supposed to be u64?
Please make this a lot clearer.
> +
> + qbuf = vcalloc(nr_pages, PAGE_SIZE);
> + if (!qbuf) {
> + err = -ENOMEM;
> + goto out_err;
> + }
> +
> + /* Populate HPA_LINKED_LIST as per TDX ABI spec */
> + for (i = 0, j = 0; j < nr_pages; i++) {
> + if ((i % HPAS_PER_PAGE) == HPAS_PER_PAGE - 1) {
> + /*
> + * The last entry always points to the next page. The
> + * address of the following entry must be on next page's
> + * boundary.
> + */
Can you maybe just explain this format that you are building in like one
sentence at the beginning of the function? "The quote buffer is passed to the
tdx module in a format that like... (some common terms that have no TDX
jargon)."
> + pfn = vmalloc_to_pfn(&qlist[i + 1]);
> + qlist[i] = PFN_PHYS(pfn);
> + continue;
> + }
> +
> + pfn = vmalloc_to_pfn((u8 *)qbuf + j * PAGE_SIZE);
> + qlist[i] = PFN_PHYS(pfn);
> + j++;
> + }
> +
> + qdata->buf = qbuf;
> + qdata->buf_len = (u64)nr_pages * PAGE_SIZE;
> + qdata->hpa_list = qlist;
> +
> + pfn = vmalloc_to_pfn(qlist);
Do we need a vmalloc_to_pa() helper? Maybe put it in terms of tdx format. Like
vmalloc_pfn_to_tdxpa() and keep it here? The tdx update stuff does this a bunch
too.
> + qdata->hpa_list_pa = PFN_PHYS(pfn);
> +
> + return 0;
> +
> +out_err:
> + vfree(qlist);
> +
> + return err;
It only returns -ENOMEM, so do we need the err var?
> +}
> +
> static void tdx_quote_init(void)
> {
> struct tdx_module_args args = {};
> + unsigned int nr_quote_pages;
> u64 r;
>
> do {
> @@ -1218,7 +1295,13 @@ static void tdx_quote_init(void)
> return;
>
> /* Quoting metadata is valid only after initialization */
> - get_tdx_sys_info_quote(&tdx_sysinfo.quote);
> + if (get_tdx_sys_info_quote(&tdx_sysinfo.quote))
> + return;
How come this patch gets error handling? Why is it needed now when it wasn't
before?
> +
> + nr_quote_pages = PAGE_ALIGN(tdx_sysinfo.quote.max_quote_size) /
> + PAGE_SIZE;
> + if (tdx_quote_create_buf(nr_quote_pages, "e_data))
> + pr_err("Failed to create quote buffer\n");
Err... what happens in ENOMEM scenario? NULL pointer later?
> }
>
> /* Initialize the TDX Module Extensions then Extension-SEAMCALLs can be used */
^ permalink raw reply [flat|nested] 64+ messages in thread
* [RFC PATCH 08/15] x86/virt/tdx: Add interface to check Quoting availability
2026-05-22 3:41 [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting Xu Yilun
` (6 preceding siblings ...)
2026-05-22 3:41 ` [RFC PATCH 07/15] x86/virt/tdx: Prepare Quote buffer during extension bringup Xu Yilun
@ 2026-05-22 3:41 ` Xu Yilun
2026-05-22 3:41 ` [RFC PATCH 09/15] x86/virt/tdx: Add interface to generate a Quote Xu Yilun
` (8 subsequent siblings)
16 siblings, 0 replies; 64+ messages in thread
From: Xu Yilun @ 2026-05-22 3:41 UTC (permalink / raw)
To: kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, yilun.xu,
baolu.lu, zhenzhong.duan, xiaoyao.li
From: Peter Fang <peter.fang@intel.com>
KVM needs to know if the Quoting extension is available to determine
whether userspace must be involved in Quote generation.
Since the Quote buffer is always created during Quoting extension
bringup, checking whether the buffer exists is sufficient.
Signed-off-by: Peter Fang <peter.fang@intel.com>
Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
---
arch/x86/include/asm/tdx.h | 2 ++
arch/x86/virt/vmx/tdx/tdx.c | 15 +++++++++++++++
2 files changed, 17 insertions(+)
diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index 15eac89b0afb..7b257088aa1e 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -176,6 +176,8 @@ struct tdx_vp {
struct page **tdcx_pages;
};
+bool tdx_quote_enabled(void);
+
static inline u64 mk_keyed_paddr(u16 hkid, struct page *page)
{
u64 ret;
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index 9d04293394d7..b305fa5aab5c 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -1213,6 +1213,21 @@ static inline u64 tdx_tdr_pa(struct tdx_td *td)
return page_to_phys(td->tdr_page);
}
+/**
+ * tdx_quote_enabled() - Check whether TDX Quoting extension is available
+ *
+ * Return: %true if the Quoting extension is available, otherwise %false.
+ */
+bool tdx_quote_enabled(void)
+{
+ /*
+ * No need for locking here. The quote buffer is initialized as part of
+ * core TDX bringup, which comes before KVM is ready for userspace.
+ */
+ return !!quote_data.buf;
+}
+EXPORT_SYMBOL_FOR_KVM(tdx_quote_enabled);
+
#define HPAS_PER_PAGE (PAGE_SIZE / sizeof(u64))
static int tdx_quote_create_buf(unsigned int nr_pages, struct quote_data *qdata)
--
2.25.1
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH 09/15] x86/virt/tdx: Add interface to generate a Quote
2026-05-22 3:41 [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting Xu Yilun
` (7 preceding siblings ...)
2026-05-22 3:41 ` [RFC PATCH 08/15] x86/virt/tdx: Add interface to check Quoting availability Xu Yilun
@ 2026-05-22 3:41 ` Xu Yilun
2026-05-28 22:30 ` Edgecombe, Rick P
2026-05-22 3:41 ` [RFC PATCH 10/15] x86/tdx: Move and rename Quote request structure Xu Yilun
` (7 subsequent siblings)
16 siblings, 1 reply; 64+ messages in thread
From: Xu Yilun @ 2026-05-22 3:41 UTC (permalink / raw)
To: kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, yilun.xu,
baolu.lu, zhenzhong.duan, xiaoyao.li
From: Peter Fang <peter.fang@intel.com>
Use the TDX Quoting extension's TDH.QUOTE.GET SEAMCALL to generate a
Quote. Since the interface is shared across all KVM instances,
serialize access to the SEAMCALL buffer with a mutex.
Allocate and return a per-call buffer containing the generated Quote so
callers don't need to size the Quote buffer themselves. The caller is
responsible for freeing the returned buffer.
Signed-off-by: Peter Fang <peter.fang@intel.com>
Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
---
arch/x86/include/asm/tdx.h | 2 +
arch/x86/virt/vmx/tdx/tdx.h | 1 +
arch/x86/virt/vmx/tdx/tdx.c | 82 +++++++++++++++++++++++++++++++++++++
3 files changed, 85 insertions(+)
diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index 7b257088aa1e..bc512a00a0d0 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -177,6 +177,8 @@ struct tdx_vp {
};
bool tdx_quote_enabled(void);
+void *tdx_quote_generate(struct tdx_td *td, void *in_data, u32 in_data_len,
+ u32 *quote_len);
static inline u64 mk_keyed_paddr(u16 hkid, struct page *page)
{
diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h
index 3849f4f9cc78..01a7d7d8ada9 100644
--- a/arch/x86/virt/vmx/tdx/tdx.h
+++ b/arch/x86/virt/vmx/tdx/tdx.h
@@ -49,6 +49,7 @@
#define TDH_EXT_INIT 60
#define TDH_EXT_MEM_ADD 61
#define TDH_SYS_DISABLE 69
+#define TDH_QUOTE_GET 98
#define TDH_QUOTE_INIT 100
/*
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index b305fa5aab5c..821f677e9a86 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -62,6 +62,8 @@ static LIST_HEAD(tdx_memlist);
static struct tdx_sys_info tdx_sysinfo __ro_after_init;
static bool tdx_module_initialized __ro_after_init;
+static DEFINE_MUTEX(tdx_quote_lock);
+
static struct quote_data {
void *buf;
u64 buf_len;
@@ -1228,6 +1230,86 @@ bool tdx_quote_enabled(void)
}
EXPORT_SYMBOL_FOR_KVM(tdx_quote_enabled);
+#define QUOTE_ID_MASK GENMASK_U64(47, 32)
+
+static u64 tdx_quote_get(struct tdx_td *td, u64 in_data_pa, u64 in_data_len,
+ u64 hpa_list_pa, u64 total_len, u64 *quote_len)
+{
+ struct tdx_module_args args = {
+ .rcx = tdx_tdr_pa(td),
+ /* Don't bother specifying the quote id */
+ .rdx = QUOTE_ID_MASK & (u64)-1,
+ .r8 = in_data_pa,
+ .r9 = in_data_len,
+ .r10 = hpa_list_pa,
+ .r11 = total_len,
+ };
+ u64 r;
+
+ do {
+ r = seamcall_ret(TDH_QUOTE_GET, &args);
+ } while (r == TDX_INTERRUPTED_RESUMABLE);
+
+ *quote_len = args.rcx;
+
+ return r;
+}
+
+/**
+ * tdx_quote_generate() - Generate a quote for a TD
+ * @td: The TD to generate the quote for.
+ * @in_data: Input data for the quote request.
+ * @in_data_len: Size of the input data in bytes.
+ * @quote_len: Returned size of the generated quote in bytes.
+ *
+ * Use the TDX Quoting extension to generate a TD quote. Pass the input data
+ * through the shared quote buffer and return the quote.
+ *
+ * Return: Newly allocated quote buffer or %NULL on failure.
+ * The caller must free the returned buffer with kvfree().
+ */
+void *tdx_quote_generate(struct tdx_td *td, void *in_data, u32 in_data_len,
+ u32 *quote_len)
+{
+ void *quote_dup = NULL;
+ u64 r, out_len;
+
+ if (!tdx_quote_enabled())
+ return NULL;
+
+ /* TDH.QUOTE.GET expects the input data to fit in a page */
+ if (in_data_len > PAGE_SIZE)
+ return NULL;
+
+ mutex_lock(&tdx_quote_lock);
+
+ /*
+ * Use the first page of the quote buffer for input data. The buffer
+ * must be at least one page in size. @in_data may not be page-aligned,
+ * but TDH.QUOTE.GET expects page-aligned addresses.
+ */
+ memcpy(quote_data.buf, in_data, (size_t)in_data_len);
+
+ r = tdx_quote_get(td, quote_data.hpa_list[0], (u64)in_data_len,
+ quote_data.hpa_list_pa, quote_data.buf_len, &out_len);
+ if (r || !out_len || out_len > quote_data.buf_len)
+ goto out;
+
+ /*
+ * The quote buffer is a shared resource, so use it only for the
+ * SEAMCALL and copy the data out as soon as possible.
+ */
+ quote_dup = kvmemdup(quote_data.buf, out_len, GFP_KERNEL);
+
+out:
+ mutex_unlock(&tdx_quote_lock);
+
+ *quote_len = (u32)out_len;
+
+ return quote_dup;
+}
+EXPORT_SYMBOL_FOR_KVM(tdx_quote_generate);
+
#define HPAS_PER_PAGE (PAGE_SIZE / sizeof(u64))
static int tdx_quote_create_buf(unsigned int nr_pages, struct quote_data *qdata)
--
2.25.1
^ permalink raw reply related [flat|nested] 64+ messages in thread* Re: [RFC PATCH 09/15] x86/virt/tdx: Add interface to generate a Quote
2026-05-22 3:41 ` [RFC PATCH 09/15] x86/virt/tdx: Add interface to generate a Quote Xu Yilun
@ 2026-05-28 22:30 ` Edgecombe, Rick P
0 siblings, 0 replies; 64+ messages in thread
From: Edgecombe, Rick P @ 2026-05-28 22:30 UTC (permalink / raw)
To: Fang, Peter, kas@kernel.org, djbw@kernel.org,
yilun.xu@linux.intel.com, x86@kernel.org
Cc: Xu, Yilun, Duan, Zhenzhong, baolu.lu@linux.intel.com, Li, Xiaoyao,
linux-kernel@vger.kernel.org, Mehta, Sohil, kvm@vger.kernel.org,
linux-coco@lists.linux.dev
On Fri, 2026-05-22 at 11:41 +0800, Xu Yilun wrote:
> +void *tdx_quote_generate(struct tdx_td *td, void *in_data, u32 in_data_len,
> + u32 *quote_len)
> +{
> + void *quote_dup = NULL;
> + u64 r, out_len;
> +
> + if (!tdx_quote_enabled())
> + return NULL;
> +
> + /* TDH.QUOTE.GET expects the input data to fit in a page */
> + if (in_data_len > PAGE_SIZE)
> + return NULL;
Do we really need this check? We can't trust the caller to pass the right size?
> +
> + mutex_lock(&tdx_quote_lock);
> +
> + /*
> + * Use the first page of the quote buffer for input data. The buffer
> + * must be at least one page in size. @in_data may not be page-aligned,
> + * but TDH.QUOTE.GET expects page-aligned addresses.
> + */
> + memcpy(quote_data.buf, in_data, (size_t)in_data_len);
> +
> + r = tdx_quote_get(td, quote_data.hpa_list[0], (u64)in_data_len,
> + quote_data.hpa_list_pa, quote_data.buf_len, &out_len);
> + if (r || !out_len || out_len > quote_data.buf_len)
How do these various error conditions happen?
> + goto out;
> +
> + /*
> + * The quote buffer is a shared resource, so use it only for the
> + * SEAMCALL and copy the data out as soon as possible.
> + */
> + quote_dup = kvmemdup(quote_data.buf, out_len, GFP_KERNEL);
So at init time we allocate a vmalloc for the quote and pre-populate the
hpa_list. Then we use it every time and copy the contents to a new vmalloc.
Would it really be that hard to keep the hpa list allocation around, do a
vmalloc here and update the pfn list. Then do get quote on that and pass back
the vmalloc we just allocated? Just feels like global reuse way has extra pieces
in it. Compared to the whole quoting operation, this vmalloc_to_pfn() loop is
probably not very expensive.
> +
> +out:
> + mutex_unlock(&tdx_quote_lock);
> +
> + *quote_len = (u32)out_len;
> +
> + return quote_dup;
> +}
> +EXPORT_SYMBOL_FOR_KVM(tdx_quote_generate);
> +
^ permalink raw reply [flat|nested] 64+ messages in thread
* [RFC PATCH 10/15] x86/tdx: Move and rename Quote request structure
2026-05-22 3:41 [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting Xu Yilun
` (8 preceding siblings ...)
2026-05-22 3:41 ` [RFC PATCH 09/15] x86/virt/tdx: Add interface to generate a Quote Xu Yilun
@ 2026-05-22 3:41 ` Xu Yilun
2026-05-22 3:41 ` [RFC PATCH 11/15] KVM: TDX: Factor out userspace return path from tdx_get_quote() Xu Yilun
` (6 subsequent siblings)
16 siblings, 0 replies; 64+ messages in thread
From: Xu Yilun @ 2026-05-22 3:41 UTC (permalink / raw)
To: kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, yilun.xu,
baolu.lu, zhenzhong.duan, xiaoyao.li
From: Peter Fang <peter.fang@intel.com>
struct tdx_quote_buf is currently used only by the guest, but the Quote
buffer format will also be needed by the host for in-kernel Quote
generation. Move the definition to tdx.h so it can be shared by both.
Rename the struct to tdx_quote_req to better reflect its purpose.
Signed-off-by: Peter Fang <peter.fang@intel.com>
Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
---
arch/x86/include/asm/tdx.h | 21 +++++++++++++++++++++
drivers/virt/coco/tdx-guest/tdx-guest.c | 25 +++----------------------
2 files changed, 24 insertions(+), 22 deletions(-)
diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index bc512a00a0d0..945e6817abb2 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -96,6 +96,27 @@ static inline long tdx_kvm_hypercall(unsigned int nr, unsigned long p1,
}
#endif /* CONFIG_INTEL_TDX_GUEST && CONFIG_KVM_GUEST */
+#if defined(CONFIG_INTEL_TDX_GUEST) || defined(CONFIG_KVM_INTEL_TDX)
+/* struct tdx_quote_req: Format of Quote request message.
+ * @version: Quote format version, filled by TD.
+ * @status: Status code of Quote request, filled by VMM.
+ * @in_len: Length of TDREPORT, filled by TD.
+ * @out_len: Length of Quote data, filled by VMM.
+ * @data: Quote data on output or TDREPORT on input.
+ *
+ * More details of Quote request message can be found in TDX
+ * Guest-Host Communication Interface (GHCI) for Intel TDX 1.0,
+ * section titled "TDG.VP.VMCALL<GetQuote>"
+ */
+struct tdx_quote_req {
+ u64 version;
+ u64 status;
+ u32 in_len;
+ u32 out_len;
+ u8 data[];
+};
+#endif /* CONFIG_INTEL_TDX_GUEST || CONFIG_KVM_INTEL_TDX */
+
#ifdef CONFIG_INTEL_TDX_HOST
u64 __seamcall(u64 fn, struct tdx_module_args *args);
u64 __seamcall_ret(u64 fn, struct tdx_module_args *args);
diff --git a/drivers/virt/coco/tdx-guest/tdx-guest.c b/drivers/virt/coco/tdx-guest/tdx-guest.c
index a9ecc46df187..d0ddbbc98fb8 100644
--- a/drivers/virt/coco/tdx-guest/tdx-guest.c
+++ b/drivers/virt/coco/tdx-guest/tdx-guest.c
@@ -171,26 +171,7 @@ static void tdx_mr_deinit(const struct attribute_group *mr_grp)
#define GET_QUOTE_SUCCESS 0
#define GET_QUOTE_IN_FLIGHT 0xffffffffffffffff
-#define TDX_QUOTE_MAX_LEN (GET_QUOTE_BUF_SIZE - sizeof(struct tdx_quote_buf))
-
-/* struct tdx_quote_buf: Format of Quote request buffer.
- * @version: Quote format version, filled by TD.
- * @status: Status code of Quote request, filled by VMM.
- * @in_len: Length of TDREPORT, filled by TD.
- * @out_len: Length of Quote data, filled by VMM.
- * @data: Quote data on output or TDREPORT on input.
- *
- * More details of Quote request buffer can be found in TDX
- * Guest-Host Communication Interface (GHCI) for Intel TDX 1.0,
- * section titled "TDG.VP.VMCALL<GetQuote>"
- */
-struct tdx_quote_buf {
- u64 version;
- u64 status;
- u32 in_len;
- u32 out_len;
- u8 data[];
-};
+#define TDX_QUOTE_MAX_LEN (GET_QUOTE_BUF_SIZE - sizeof(struct tdx_quote_req))
/* Quote data buffer */
static void *quote_data;
@@ -250,7 +231,7 @@ static void *alloc_quote_buf(void)
* or error code after processing is complete. So wait till the status
* changes from GET_QUOTE_IN_FLIGHT or the request being timed out.
*/
-static int wait_for_quote_completion(struct tdx_quote_buf *quote_buf, u32 timeout)
+static int wait_for_quote_completion(struct tdx_quote_req *quote_buf, u32 timeout)
{
int i = 0;
@@ -269,7 +250,7 @@ static int wait_for_quote_completion(struct tdx_quote_buf *quote_buf, u32 timeou
static int tdx_report_new_locked(struct tsm_report *report, void *data)
{
u8 *buf;
- struct tdx_quote_buf *quote_buf = quote_data;
+ struct tdx_quote_req *quote_buf = quote_data;
struct tsm_report_desc *desc = &report->desc;
u32 out_len;
int ret;
--
2.25.1
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH 11/15] KVM: TDX: Factor out userspace return path from tdx_get_quote()
2026-05-22 3:41 [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting Xu Yilun
` (9 preceding siblings ...)
2026-05-22 3:41 ` [RFC PATCH 10/15] x86/tdx: Move and rename Quote request structure Xu Yilun
@ 2026-05-22 3:41 ` Xu Yilun
2026-05-22 3:41 ` [RFC PATCH 12/15] KVM: TDX: Add in-kernel Quote generation Xu Yilun
` (5 subsequent siblings)
16 siblings, 0 replies; 64+ messages in thread
From: Xu Yilun @ 2026-05-22 3:41 UTC (permalink / raw)
To: kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, yilun.xu,
baolu.lu, zhenzhong.duan, xiaoyao.li
From: Peter Fang <peter.fang@intel.com>
Separate the logic that returns GetQuote to userspace so that
tdx_get_quote() can be extended to support in-kernel quote generation.
No functional change intended.
Signed-off-by: Peter Fang <peter.fang@intel.com>
Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
---
arch/x86/kvm/vmx/tdx.c | 25 ++++++++++++++++---------
1 file changed, 16 insertions(+), 9 deletions(-)
diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index ed12805bbb44..9f7c39e0d4b5 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -1524,6 +1524,20 @@ static int tdx_complete_simple(struct kvm_vcpu *vcpu)
return 1;
}
+static int tdx_get_quote_user(struct kvm_vcpu *vcpu, u64 gpa, u64 size)
+{
+ vcpu->run->exit_reason = KVM_EXIT_TDX;
+ vcpu->run->tdx.flags = 0;
+ vcpu->run->tdx.nr = TDVMCALL_GET_QUOTE;
+ vcpu->run->tdx.get_quote.ret = TDVMCALL_STATUS_SUBFUNC_UNSUPPORTED;
+ vcpu->run->tdx.get_quote.gpa = gpa;
+ vcpu->run->tdx.get_quote.size = size;
+
+ vcpu->arch.complete_userspace_io = tdx_complete_simple;
+
+ return 0;
+}
+
static int tdx_get_quote(struct kvm_vcpu *vcpu)
{
struct vcpu_tdx *tdx = to_tdx(vcpu);
@@ -1536,16 +1550,9 @@ static int tdx_get_quote(struct kvm_vcpu *vcpu)
return 1;
}
- vcpu->run->exit_reason = KVM_EXIT_TDX;
- vcpu->run->tdx.flags = 0;
- vcpu->run->tdx.nr = TDVMCALL_GET_QUOTE;
- vcpu->run->tdx.get_quote.ret = TDVMCALL_STATUS_SUBFUNC_UNSUPPORTED;
- vcpu->run->tdx.get_quote.gpa = gpa & ~gfn_to_gpa(kvm_gfn_direct_bits(tdx->vcpu.kvm));
- vcpu->run->tdx.get_quote.size = size;
-
- vcpu->arch.complete_userspace_io = tdx_complete_simple;
+ gpa &= ~gfn_to_gpa(kvm_gfn_direct_bits(vcpu->kvm));
- return 0;
+ return tdx_get_quote_user(vcpu, gpa, size);
}
static int tdx_setup_event_notify_interrupt(struct kvm_vcpu *vcpu)
--
2.25.1
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH 12/15] KVM: TDX: Add in-kernel Quote generation
2026-05-22 3:41 [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting Xu Yilun
` (10 preceding siblings ...)
2026-05-22 3:41 ` [RFC PATCH 11/15] KVM: TDX: Factor out userspace return path from tdx_get_quote() Xu Yilun
@ 2026-05-22 3:41 ` Xu Yilun
2026-05-22 3:41 ` [RFC PATCH 13/15] KVM: TDX: Support event-notify interrupts only with userspace quoting Xu Yilun
` (4 subsequent siblings)
16 siblings, 0 replies; 64+ messages in thread
From: Xu Yilun @ 2026-05-22 3:41 UTC (permalink / raw)
To: kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, yilun.xu,
baolu.lu, zhenzhong.duan, xiaoyao.li
From: Peter Fang <peter.fang@intel.com>
Provide an in-kernel path for TDX Quote generation when handling
TDG.VP.VMCALL<GetQuote>, without requiring an exit to userspace.
Use the core TDX API when the TDX Quoting extension is available. For
simplicity, each KVM guest checks for availability only once during
initialization. KVM does not handle Quoting service disruptions.
Signed-off-by: Peter Fang <peter.fang@intel.com>
Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
---
arch/x86/include/asm/tdx.h | 9 +++
arch/x86/kvm/vmx/tdx.h | 6 ++
arch/x86/kvm/vmx/tdx.c | 135 ++++++++++++++++++++++++++++++++++++-
virt/kvm/kvm_main.c | 1 +
4 files changed, 150 insertions(+), 1 deletion(-)
diff --git a/arch/x86/include/asm/tdx.h b/arch/x86/include/asm/tdx.h
index 945e6817abb2..5863d6748100 100644
--- a/arch/x86/include/asm/tdx.h
+++ b/arch/x86/include/asm/tdx.h
@@ -115,6 +115,15 @@ struct tdx_quote_req {
u32 out_len;
u8 data[];
};
+
+#define TDX_QUOTE_REQ_HDR_SIZE (offsetof(struct tdx_quote_req, data))
+
+/*
+ * TDG.VP.VMCALL<GetQuote> Status Codes
+ */
+#define TDX_QUOTE_STATUS_SUCCESS 0x0000000000000000ULL
+#define TDX_QUOTE_STATUS_ERROR 0x8000000000000000ULL
+#define TDX_QUOTE_STATUS_UNAVAILABLE 0x8000000000000001ULL
#endif /* CONFIG_INTEL_TDX_GUEST || CONFIG_KVM_INTEL_TDX */
#ifdef CONFIG_INTEL_TDX_HOST
diff --git a/arch/x86/kvm/vmx/tdx.h b/arch/x86/kvm/vmx/tdx.h
index ac8323a68b16..18c93e80c0ec 100644
--- a/arch/x86/kvm/vmx/tdx.h
+++ b/arch/x86/kvm/vmx/tdx.h
@@ -47,6 +47,12 @@ struct kvm_tdx {
* Set/unset is protected with kvm->mmu_lock.
*/
bool wait_for_sept_zap;
+
+ /*
+ * Whether to get TDX quote directly in kernel, without exiting to
+ * userspace.
+ */
+ bool get_quote_in_kernel;
};
/* TDX module vCPU states */
diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index 9f7c39e0d4b5..bade046da5a1 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -1538,11 +1538,133 @@ static int tdx_get_quote_user(struct kvm_vcpu *vcpu, u64 gpa, u64 size)
return 0;
}
+static bool write_quote_status_to_guest(struct kvm_vcpu *vcpu, u64 status,
+ gpa_t gpa)
+{
+ if (kvm_vcpu_write_guest(vcpu,
+ gpa + offsetof(struct tdx_quote_req, status),
+ &status, sizeof(status)))
+ return false;
+
+ return true;
+}
+
+static bool write_quote_to_guest(struct kvm_vcpu *vcpu, void *quote_data,
+ u32 quote_len, gpa_t gpa)
+{
+ if (kvm_vcpu_write_guest(vcpu,
+ gpa + TDX_QUOTE_REQ_HDR_SIZE,
+ quote_data, quote_len))
+ return false;
+
+ if (kvm_vcpu_write_guest(vcpu,
+ gpa + offsetof(struct tdx_quote_req, out_len),
+ "e_len, sizeof(quote_len)))
+ return false;
+
+ return true;
+}
+
+static u64 __get_quote_kernel(struct kvm_vcpu *vcpu, struct tdx_quote_req *req,
+ size_t req_len, gpa_t req_gpa, size_t total_len)
+{
+ struct tdx_td *td = &to_kvm_tdx(vcpu->kvm)->td;
+
+ /* Only support version 1 as defined in the GHCI spec */
+ if (req->version != 1)
+ return TDX_QUOTE_STATUS_ERROR;
+
+ if ((size_t)req->in_len + TDX_QUOTE_REQ_HDR_SIZE > req_len)
+ return TDX_QUOTE_STATUS_ERROR;
+
+ /* The caller frees the quote data */
+ void *quote_data __free(kvfree) =
+ tdx_quote_generate(td, req->data, req->in_len, &req->out_len);
+
+ if (!quote_data)
+ return TDX_QUOTE_STATUS_UNAVAILABLE;
+
+ if ((size_t)req->out_len + TDX_QUOTE_REQ_HDR_SIZE > total_len)
+ return TDX_QUOTE_STATUS_ERROR;
+
+ if (!write_quote_to_guest(vcpu, quote_data, req->out_len, req_gpa))
+ return TDX_QUOTE_STATUS_ERROR;
+
+ return TDX_QUOTE_STATUS_SUCCESS;
+}
+
+static u64 tdx_get_quote_check_args(struct kvm_vcpu *vcpu, u64 gpa, u64 size)
+{
+ gfn_t gfn_start, gfn_end;
+ u64 end;
+
+ if (!size)
+ return TDVMCALL_STATUS_INVALID_OPERAND;
+
+ if (!PAGE_ALIGNED(gpa) || !PAGE_ALIGNED(size))
+ return TDVMCALL_STATUS_ALIGN_ERROR;
+
+ if (check_add_overflow(gpa, size, &end))
+ return TDVMCALL_STATUS_INVALID_OPERAND;
+
+ gfn_start = gpa_to_gfn(gpa);
+ gfn_end = gpa_to_gfn(end);
+
+ /*
+ * Reject if the guest didn't explicitly convert its quote pages to
+ * shared.
+ */
+ if (!kvm_range_has_memory_attributes(vcpu->kvm, gfn_start, gfn_end,
+ KVM_MEMORY_ATTRIBUTE_PRIVATE, 0))
+ return TDVMCALL_STATUS_INVALID_OPERAND;
+
+ return TDVMCALL_STATUS_SUCCESS;
+}
+
+static int tdx_get_quote_kernel(struct kvm_vcpu *vcpu, u64 gpa, u64 size)
+{
+ void *first_page = NULL;
+ u64 err, qerr;
+
+ err = tdx_get_quote_check_args(vcpu, gpa, size);
+ if (err != TDVMCALL_STATUS_SUCCESS)
+ goto out;
+
+ err = TDVMCALL_STATUS_INVALID_OPERAND;
+
+ first_page = kmalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!first_page)
+ goto out;
+
+ /*
+ * Read the first GetQuote page for its header + in_data. The check
+ * above ensures that this GetQuote message is at least one page in
+ * size. in_data spanning more than a page is not supported.
+ */
+ if (kvm_vcpu_read_guest(vcpu, gpa, first_page, PAGE_SIZE))
+ goto out;
+
+ qerr = __get_quote_kernel(vcpu, first_page, PAGE_SIZE,
+ (gpa_t)gpa, size);
+
+ if (write_quote_status_to_guest(vcpu, qerr, (gpa_t)gpa) &&
+ qerr == TDX_QUOTE_STATUS_SUCCESS)
+ err = TDVMCALL_STATUS_SUCCESS;
+
+out:
+ kfree(first_page);
+ tdvmcall_set_return_code(vcpu, err);
+
+ return 1;
+}
+
static int tdx_get_quote(struct kvm_vcpu *vcpu)
{
+ struct kvm_tdx *kvm_tdx = to_kvm_tdx(vcpu->kvm);
struct vcpu_tdx *tdx = to_tdx(vcpu);
u64 gpa = tdx->vp_enter_args.r12;
u64 size = tdx->vp_enter_args.r13;
+ int ret;
/* The gpa of buffer must have shared bit set. */
if (vt_is_tdx_private_gpa(vcpu->kvm, gpa)) {
@@ -1552,7 +1674,12 @@ static int tdx_get_quote(struct kvm_vcpu *vcpu)
gpa &= ~gfn_to_gpa(kvm_gfn_direct_bits(vcpu->kvm));
- return tdx_get_quote_user(vcpu, gpa, size);
+ if (kvm_tdx->get_quote_in_kernel)
+ ret = tdx_get_quote_kernel(vcpu, gpa, size);
+ else
+ ret = tdx_get_quote_user(vcpu, gpa, size);
+
+ return ret;
}
static int tdx_setup_event_notify_interrupt(struct kvm_vcpu *vcpu)
@@ -2751,6 +2878,12 @@ static int tdx_td_init(struct kvm *kvm, struct kvm_tdx_cmd *cmd)
else
kvm->arch.gfn_direct_bits = TDX_SHARED_BIT_PWL_4;
+ /*
+ * Check only once at TD creation. If the quoting service gets disrupted
+ * during TD runtime, let the user handle it.
+ */
+ kvm_tdx->get_quote_in_kernel = tdx_quote_enabled();
+
kvm_tdx->state = TD_STATE_INITIALIZED;
out:
/* kfree() accepts NULL. */
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 89489996fbc1..599f88a13071 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -2461,6 +2461,7 @@ bool kvm_range_has_memory_attributes(struct kvm *kvm, gfn_t start, gfn_t end,
return true;
}
+EXPORT_SYMBOL_FOR_KVM_INTERNAL(kvm_range_has_memory_attributes);
static __always_inline void kvm_handle_gfn_range(struct kvm *kvm,
struct kvm_mmu_notifier_range *range)
--
2.25.1
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH 13/15] KVM: TDX: Support event-notify interrupts only with userspace quoting
2026-05-22 3:41 [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting Xu Yilun
` (11 preceding siblings ...)
2026-05-22 3:41 ` [RFC PATCH 12/15] KVM: TDX: Add in-kernel Quote generation Xu Yilun
@ 2026-05-22 3:41 ` Xu Yilun
2026-05-22 3:41 ` [RFC PATCH 14/15] x86/virt/tdx: Embed version info in SEAMCALL leaf function definitions Xu Yilun
` (3 subsequent siblings)
16 siblings, 0 replies; 64+ messages in thread
From: Xu Yilun @ 2026-05-22 3:41 UTC (permalink / raw)
To: kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, yilun.xu,
baolu.lu, zhenzhong.duan, xiaoyao.li
From: Peter Fang <peter.fang@intel.com>
Tie userspace SetupEventNotifyInterrupt support to userspace Quote
generation. Delivering event-notify interrupts via userspace breaks if
KVM never exits to userspace in the first place.
No known guest currently requires event-notify interrupt support, so
defer adding in-kernel support for now. Linux TDX guests use polling
only.
Update the KVM API Documentation to reflect the change.
Signed-off-by: Peter Fang <peter.fang@intel.com>
Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
---
Documentation/virt/kvm/api.rst | 8 +++++++-
arch/x86/kvm/vmx/tdx.c | 20 +++++++++++++++++---
2 files changed, 24 insertions(+), 4 deletions(-)
diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst
index 52bbbb553ce1..8a02745a36ee 100644
--- a/Documentation/virt/kvm/api.rst
+++ b/Documentation/virt/kvm/api.rst
@@ -7335,6 +7335,9 @@ inputs and outputs of the TDVMCALL. Currently the following values of
queued successfully, the TDX guest can poll the status field in the
shared-memory area to check whether the Quote generation is completed or
not. When completed, the generated Quote is returned via the same buffer.
+ If the host kernel generates Quotes through the TDX Quoting service provided
+ by the TDX module, KVM processes the GetQuote request and it will not appear
+ in userspace. KVM only supports version 1 of the GetQuote request.
* ``TDVMCALL_GET_TD_VM_CALL_INFO``: the guest has requested the support
status of TDVMCALLs. The output values for the given leaf should be
@@ -7342,7 +7345,10 @@ inputs and outputs of the TDVMCALL. Currently the following values of
field of the union.
* ``TDVMCALL_SETUP_EVENT_NOTIFY_INTERRUPT``: the guest has requested to
- set up a notification interrupt for vector ``vector``.
+ set up a notification interrupt for vector ``vector``. Since this TDVMCALL
+ is used to optimize ``TDVMCALL_GET_QUOTE``, KVM disables this support in
+ userspace VMM if ``TDVMCALL_GET_QUOTE`` is completely handled in the kernel.
+ KVM may add kernel support for this in the future.
KVM may add support for more values in the future that may cause a userspace
exit, even without calls to ``KVM_ENABLE_CAP`` or similar. In this case,
diff --git a/arch/x86/kvm/vmx/tdx.c b/arch/x86/kvm/vmx/tdx.c
index bade046da5a1..5aebbec7fa6e 100644
--- a/arch/x86/kvm/vmx/tdx.c
+++ b/arch/x86/kvm/vmx/tdx.c
@@ -185,7 +185,7 @@ static void td_init_cpuid_entry2(struct kvm_cpuid_entry2 *entry, unsigned char i
tdx_clear_unsupported_cpuid(entry);
}
-#define TDVMCALLINFO_SETUP_EVENT_NOTIFY_INTERRUPT BIT(1)
+#define TDVMCALLINFO_SETUP_EVENT_NOTIFY_INTERRUPT BIT_ULL(1)
static int init_kvm_tdx_caps(const struct tdx_sys_info_td_conf *td_conf,
struct kvm_tdx_capabilities *caps)
@@ -202,8 +202,15 @@ static int init_kvm_tdx_caps(const struct tdx_sys_info_td_conf *td_conf,
caps->cpuid.nent = td_conf->num_cpuid_config;
- caps->user_tdvmcallinfo_1_r11 =
- TDVMCALLINFO_SETUP_EVENT_NOTIFY_INTERRUPT;
+ /*
+ * Don't advertise userspace event-notify interrupt support if TDX
+ * quoting service is enabled, as quote generation will be done entirely
+ * in the kernel. Support in the kernel can be added later if needed.
+ */
+ if (!tdx_quote_enabled()) {
+ caps->user_tdvmcallinfo_1_r11 |=
+ TDVMCALLINFO_SETUP_EVENT_NOTIFY_INTERRUPT;
+ }
for (i = 0; i < td_conf->num_cpuid_config; i++)
td_init_cpuid_entry2(&caps->cpuid.entries[i], i);
@@ -1684,9 +1691,16 @@ static int tdx_get_quote(struct kvm_vcpu *vcpu)
static int tdx_setup_event_notify_interrupt(struct kvm_vcpu *vcpu)
{
+ struct kvm_tdx *kvm_tdx = to_kvm_tdx(vcpu->kvm);
struct vcpu_tdx *tdx = to_tdx(vcpu);
u64 vector = tdx->vp_enter_args.r12;
+ /* See init_kvm_tdx_caps() for comments */
+ if (kvm_tdx->get_quote_in_kernel) {
+ tdvmcall_set_return_code(vcpu, TDVMCALL_STATUS_SUBFUNC_UNSUPPORTED);
+ return 1;
+ }
+
if (vector < 32 || vector > 255) {
tdvmcall_set_return_code(vcpu, TDVMCALL_STATUS_INVALID_OPERAND);
return 1;
--
2.25.1
^ permalink raw reply related [flat|nested] 64+ messages in thread* [RFC PATCH 14/15] x86/virt/tdx: Embed version info in SEAMCALL leaf function definitions
2026-05-22 3:41 [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting Xu Yilun
` (12 preceding siblings ...)
2026-05-22 3:41 ` [RFC PATCH 13/15] KVM: TDX: Support event-notify interrupts only with userspace quoting Xu Yilun
@ 2026-05-22 3:41 ` Xu Yilun
2026-05-25 9:00 ` Xiaoyao Li
2026-05-22 3:41 ` [RFC PATCH 15/15] x86/virt/tdx: Enable TDX Quoting extension Xu Yilun
` (2 subsequent siblings)
16 siblings, 1 reply; 64+ messages in thread
From: Xu Yilun @ 2026-05-22 3:41 UTC (permalink / raw)
To: kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, yilun.xu,
baolu.lu, zhenzhong.duan, xiaoyao.li
Embed version information in SEAMCALL leaf function definitions rather
than let the caller open code them. For now, only TDH.VP.INIT is
involved.
Don't bother the caller to choose the SEAMCALL version if unnecessary.
New version SEAMCALLs are guaranteed to be backward compatible, so
ideally kernel doesn't need to keep version history and only uses the
latest version SEAMCALLs.
The concern is some old TDX Modules don't recognize new version
SEAMCALLs. Multiple SEAMCALL versions co-exist when kernel should
support these old Modules. As time goes by, the old Modules deprecate
and old version SEAMCALL definitions should disappear.
The old TDX Modules that only support TDH.VP.INIT v0 are all deprecated,
so only provide the latest (v1) definition.
Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
---
arch/x86/virt/vmx/tdx/tdx.h | 23 ++++++++++++++---------
arch/x86/virt/vmx/tdx/tdx.c | 4 ++--
2 files changed, 16 insertions(+), 11 deletions(-)
diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h
index 01a7d7d8ada9..10aff23cd01f 100644
--- a/arch/x86/virt/vmx/tdx/tdx.h
+++ b/arch/x86/virt/vmx/tdx/tdx.h
@@ -2,6 +2,7 @@
#ifndef _X86_VIRT_TDX_H
#define _X86_VIRT_TDX_H
+#include <linux/bitfield.h>
#include <linux/bits.h>
/*
@@ -11,6 +12,18 @@
* architectural definitions come first.
*/
+/*
+ * SEAMCALL leaf:
+ *
+ * Bit 15:0 Leaf number
+ * Bit 23:16 Version number
+ */
+#define SEAMCALL_LEAF GENMASK(15, 0)
+#define SEAMCALL_VER GENMASK(23, 16)
+
+#define SEAMCALL_LEAF_VER(l, v) (FIELD_PREP(SEAMCALL_LEAF, l) | \
+ FIELD_PREP(SEAMCALL_VER, v))
+
/*
* TDX module SEAMCALL leaf functions
*/
@@ -31,7 +44,7 @@
#define TDH_VP_CREATE 10
#define TDH_MNG_KEY_FREEID 20
#define TDH_MNG_INIT 21
-#define TDH_VP_INIT 22
+#define TDH_VP_INIT SEAMCALL_LEAF_VER(22, 1)
#define TDH_PHYMEM_PAGE_RDMD 24
#define TDH_VP_RD 26
#define TDH_PHYMEM_PAGE_RECLAIM 28
@@ -52,14 +65,6 @@
#define TDH_QUOTE_GET 98
#define TDH_QUOTE_INIT 100
-/*
- * SEAMCALL leaf:
- *
- * Bit 15:0 Leaf number
- * Bit 23:16 Version number
- */
-#define TDX_VERSION_SHIFT 16
-
/* TDX page types */
#define PT_NDA 0x0
#define PT_RSVD 0x1
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index 821f677e9a86..f7600f930c6e 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -2217,8 +2217,8 @@ u64 tdh_vp_init(struct tdx_vp *vp, u64 initial_rcx, u32 x2apicid)
.r8 = x2apicid,
};
- /* apicid requires version == 1. */
- return seamcall(TDH_VP_INIT | (1ULL << TDX_VERSION_SHIFT), &args);
+ /* apicid requires version == 1. See TDH_VP_INIT definition.*/
+ return seamcall(TDH_VP_INIT, &args);
}
EXPORT_SYMBOL_FOR_KVM(tdh_vp_init);
--
2.25.1
^ permalink raw reply related [flat|nested] 64+ messages in thread* Re: [RFC PATCH 14/15] x86/virt/tdx: Embed version info in SEAMCALL leaf function definitions
2026-05-22 3:41 ` [RFC PATCH 14/15] x86/virt/tdx: Embed version info in SEAMCALL leaf function definitions Xu Yilun
@ 2026-05-25 9:00 ` Xiaoyao Li
2026-05-27 6:45 ` Xu Yilun
0 siblings, 1 reply; 64+ messages in thread
From: Xiaoyao Li @ 2026-05-25 9:00 UTC (permalink / raw)
To: Xu Yilun, kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan
On 5/22/2026 11:41 AM, Xu Yilun wrote:
> Embed version information in SEAMCALL leaf function definitions rather
> than let the caller open code them. For now, only TDH.VP.INIT is
> involved.
>
> Don't bother the caller to choose the SEAMCALL version if unnecessary.
> New version SEAMCALLs are guaranteed to be backward compatible, so
> ideally kernel doesn't need to keep version history and only uses the
> latest version SEAMCALLs.
>
> The concern is some old TDX Modules don't recognize new version
> SEAMCALLs. Multiple SEAMCALL versions co-exist when kernel should
> support these old Modules. As time goes by, the old Modules deprecate
> and old version SEAMCALL definitions should disappear.
>
> The old TDX Modules that only support TDH.VP.INIT v0 are all deprecated,
> so only provide the latest (v1) definition.
>
> Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
> ---
> arch/x86/virt/vmx/tdx/tdx.h | 23 ++++++++++++++---------
> arch/x86/virt/vmx/tdx/tdx.c | 4 ++--
> 2 files changed, 16 insertions(+), 11 deletions(-)
>
> diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h
> index 01a7d7d8ada9..10aff23cd01f 100644
> --- a/arch/x86/virt/vmx/tdx/tdx.h
> +++ b/arch/x86/virt/vmx/tdx/tdx.h
> @@ -2,6 +2,7 @@
> #ifndef _X86_VIRT_TDX_H
> #define _X86_VIRT_TDX_H
>
> +#include <linux/bitfield.h>
> #include <linux/bits.h>
>
> /*
> @@ -11,6 +12,18 @@
> * architectural definitions come first.
> */
>
> +/*
> + * SEAMCALL leaf:
> + *
> + * Bit 15:0 Leaf number
> + * Bit 23:16 Version number
> + */
> +#define SEAMCALL_LEAF GENMASK(15, 0)
> +#define SEAMCALL_VER GENMASK(23, 16)
> +
> +#define SEAMCALL_LEAF_VER(l, v) (FIELD_PREP(SEAMCALL_LEAF, l) | \
> + FIELD_PREP(SEAMCALL_VER, v))
> +
> /*
> * TDX module SEAMCALL leaf functions
> */
> @@ -31,7 +44,7 @@
> #define TDH_VP_CREATE 10
> #define TDH_MNG_KEY_FREEID 20
> #define TDH_MNG_INIT 21
> -#define TDH_VP_INIT 22
> +#define TDH_VP_INIT SEAMCALL_LEAF_VER(22, 1)
how about
#define TDH_VP_INIT 22
#define TDH_VP_INIT_V1 SEAMCALL_LEAF_VER(TDH_VP_INIT, 1)
and use TDH_VP_INIT_V1 below?
> #define TDH_PHYMEM_PAGE_RDMD 24
> #define TDH_VP_RD 26
> #define TDH_PHYMEM_PAGE_RECLAIM 28
> @@ -52,14 +65,6 @@
> #define TDH_QUOTE_GET 98
> #define TDH_QUOTE_INIT 100
>
> -/*
> - * SEAMCALL leaf:
> - *
> - * Bit 15:0 Leaf number
> - * Bit 23:16 Version number
> - */
> -#define TDX_VERSION_SHIFT 16
> -
> /* TDX page types */
> #define PT_NDA 0x0
> #define PT_RSVD 0x1
> diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
> index 821f677e9a86..f7600f930c6e 100644
> --- a/arch/x86/virt/vmx/tdx/tdx.c
> +++ b/arch/x86/virt/vmx/tdx/tdx.c
> @@ -2217,8 +2217,8 @@ u64 tdh_vp_init(struct tdx_vp *vp, u64 initial_rcx, u32 x2apicid)
> .r8 = x2apicid,
> };
>
> - /* apicid requires version == 1. */
> - return seamcall(TDH_VP_INIT | (1ULL << TDX_VERSION_SHIFT), &args);
> + /* apicid requires version == 1. See TDH_VP_INIT definition.*/
> + return seamcall(TDH_VP_INIT, &args);
> }
> EXPORT_SYMBOL_FOR_KVM(tdh_vp_init);
>
^ permalink raw reply [flat|nested] 64+ messages in thread
* Re: [RFC PATCH 14/15] x86/virt/tdx: Embed version info in SEAMCALL leaf function definitions
2026-05-25 9:00 ` Xiaoyao Li
@ 2026-05-27 6:45 ` Xu Yilun
2026-05-27 7:44 ` Xiaoyao Li
0 siblings, 1 reply; 64+ messages in thread
From: Xu Yilun @ 2026-05-27 6:45 UTC (permalink / raw)
To: Xiaoyao Li
Cc: kas, djbw, rick.p.edgecombe, x86, peter.fang, linux-coco,
linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan
> > /*
> > * TDX module SEAMCALL leaf functions
> > */
> > @@ -31,7 +44,7 @@
> > #define TDH_VP_CREATE 10
> > #define TDH_MNG_KEY_FREEID 20
> > #define TDH_MNG_INIT 21
> > -#define TDH_VP_INIT 22
> > +#define TDH_VP_INIT SEAMCALL_LEAF_VER(22, 1)
>
> how about
>
> #define TDH_VP_INIT 22
> #define TDH_VP_INIT_V1 SEAMCALL_LEAF_VER(TDH_VP_INIT, 1)
>
> and use TDH_VP_INIT_V1 below?
I'm trying to avoid a _Vx postfix if unnecessary. Don't make callers
have to choose between versions. The main MACRO should always point to
the latest version since later versions are backward compatible.
The next patch is an exception. I've found there is no public TDX Module
release available for TDH.SYS.CONFIG v1. I expect people just use the
un-versioned MACRO for development, but have to keep the explicitly
versioned _V0 macro for compatibility for now.
^ permalink raw reply [flat|nested] 64+ messages in thread
* Re: [RFC PATCH 14/15] x86/virt/tdx: Embed version info in SEAMCALL leaf function definitions
2026-05-27 6:45 ` Xu Yilun
@ 2026-05-27 7:44 ` Xiaoyao Li
2026-05-27 11:45 ` Xu Yilun
0 siblings, 1 reply; 64+ messages in thread
From: Xiaoyao Li @ 2026-05-27 7:44 UTC (permalink / raw)
To: Xu Yilun
Cc: kas, djbw, rick.p.edgecombe, x86, peter.fang, linux-coco,
linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan
On 5/27/2026 2:45 PM, Xu Yilun wrote:
>>> /*
>>> * TDX module SEAMCALL leaf functions
>>> */
>>> @@ -31,7 +44,7 @@
>>> #define TDH_VP_CREATE 10
>>> #define TDH_MNG_KEY_FREEID 20
>>> #define TDH_MNG_INIT 21
>>> -#define TDH_VP_INIT 22
>>> +#define TDH_VP_INIT SEAMCALL_LEAF_VER(22, 1)
>>
>> how about
>>
>> #define TDH_VP_INIT 22
>> #define TDH_VP_INIT_V1 SEAMCALL_LEAF_VER(TDH_VP_INIT, 1)
>>
>> and use TDH_VP_INIT_V1 below?
>
> I'm trying to avoid a _Vx postfix if unnecessary. Don't make callers
> have to choose between versions. The main MACRO should always point to
> the latest version since later versions are backward compatible.
I don't agree.
The later versions are backwards compatible, but the later versions
might not be supported by the loaded TDX module.
Usually the callers will have to choose between versions due to the TDX
module being used varies, just like the case in the next patch.
We can make TDH_VP_INIT represent the v1 as this patch because Linux
mandates v1 when the code was merged. So it can be made the default.
> The next patch is an exception. I've found there is no public TDX Module
> release available for TDH.SYS.CONFIG v1. I expect people just use the
> un-versioned MACRO for development, but have to keep the explicitly
> versioned _V0 macro for compatibility for now.
^ permalink raw reply [flat|nested] 64+ messages in thread
* Re: [RFC PATCH 14/15] x86/virt/tdx: Embed version info in SEAMCALL leaf function definitions
2026-05-27 7:44 ` Xiaoyao Li
@ 2026-05-27 11:45 ` Xu Yilun
0 siblings, 0 replies; 64+ messages in thread
From: Xu Yilun @ 2026-05-27 11:45 UTC (permalink / raw)
To: Xiaoyao Li
Cc: kas, djbw, rick.p.edgecombe, x86, peter.fang, linux-coco,
linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan
On Wed, May 27, 2026 at 03:44:45PM +0800, Xiaoyao Li wrote:
> On 5/27/2026 2:45 PM, Xu Yilun wrote:
> > > > /*
> > > > * TDX module SEAMCALL leaf functions
> > > > */
> > > > @@ -31,7 +44,7 @@
> > > > #define TDH_VP_CREATE 10
> > > > #define TDH_MNG_KEY_FREEID 20
> > > > #define TDH_MNG_INIT 21
> > > > -#define TDH_VP_INIT 22
> > > > +#define TDH_VP_INIT SEAMCALL_LEAF_VER(22, 1)
> > >
> > > how about
> > >
> > > #define TDH_VP_INIT 22
> > > #define TDH_VP_INIT_V1 SEAMCALL_LEAF_VER(TDH_VP_INIT, 1)
> > >
> > > and use TDH_VP_INIT_V1 below?
> >
> > I'm trying to avoid a _Vx postfix if unnecessary. Don't make callers
> > have to choose between versions. The main MACRO should always point to
> > the latest version since later versions are backward compatible.
>
> I don't agree.
>
> The later versions are backwards compatible, but the later versions might
> not be supported by the loaded TDX module.
>
> Usually the callers will have to choose between versions due to the TDX
> module being used varies, just like the case in the next patch.
No, we don't choose SEAMCALL versions based on TDX module versions. The
next patch is an exception, if by the time of merging there are releases
support TDX_SYS_CONFIG v1, I'd rather delete TDX_SYS_CONFIG_V0.
^ permalink raw reply [flat|nested] 64+ messages in thread
* [RFC PATCH 15/15] x86/virt/tdx: Enable TDX Quoting extension
2026-05-22 3:41 [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting Xu Yilun
` (13 preceding siblings ...)
2026-05-22 3:41 ` [RFC PATCH 14/15] x86/virt/tdx: Embed version info in SEAMCALL leaf function definitions Xu Yilun
@ 2026-05-22 3:41 ` Xu Yilun
[not found] ` <ahPbb1Ws9hBruJ2d@tlindgre-MOBL1>
2026-06-07 4:41 ` Kishen Maloor
2026-05-27 5:23 ` [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting Sohil Mehta
2026-06-07 4:36 ` Kishen Maloor
16 siblings, 2 replies; 64+ messages in thread
From: Xu Yilun @ 2026-05-22 3:41 UTC (permalink / raw)
To: kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, yilun.xu,
baolu.lu, zhenzhong.duan, xiaoyao.li
From: Peter Fang <peter.fang@intel.com>
Enable the TDX Quoting feature via TDH.SYS.CONFIG when supported by the
TDX module.
The TDX Quoting extension generates TDX attestation Quotes via a
SEAMCALL, without using a discrete Quoting engine.
TDX Module supports add-on TDX features (e.g. TDX Quoting & TDX Module
Extensions) that should be manually enabled by host. It extends
TDH.SYS.CONFIG for host to choose to enable them on bootup.
Call TDH.SYS.CONFIG with a new bitmap input parameter to specify which
features to enable. The bitmap uses the same definitions as
TDX_FEATURES0. But note not all bits in TDX_FEATURES0 are valid for
configuration, e.g. TDX Module Extensions is a service that supports TDX
Quoting, it is implicitly enabled when TDX Quoting is enabled. Setting
TDX_FEATURES0_EXT in the bitmap has no effect.
TDX Module advances the version of TDH.SYS.CONFIG 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.
TDX Module updates global metadata when add-on features are enabled.
Host should update the cached tdx_sysinfo to reflect these changes.
Co-developed-by: Xu Yilun <yilun.xu@linux.intel.com>
Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
Signed-off-by: Peter Fang <peter.fang@intel.com>
---
arch/x86/virt/vmx/tdx/tdx.h | 4 +++-
arch/x86/virt/vmx/tdx/tdx.c | 24 ++++++++++++++++++++++--
2 files changed, 25 insertions(+), 3 deletions(-)
diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h
index 10aff23cd01f..524a14c01aa6 100644
--- a/arch/x86/virt/vmx/tdx/tdx.h
+++ b/arch/x86/virt/vmx/tdx/tdx.h
@@ -58,7 +58,8 @@
#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_EXT_INIT 60
#define TDH_EXT_MEM_ADD 61
#define TDH_SYS_DISABLE 69
@@ -97,6 +98,7 @@ struct tdmr_info {
/* Bit definitions of TDX_FEATURES0 metadata field */
#define TDX_FEATURES0_NO_RBP_MOD BIT(18)
#define TDX_FEATURES0_EXT BIT_ULL(39)
+#define TDX_FEATURES0_QUOTE BIT_ULL(50)
/*
* Do not put any hardware-defined TDX structure representations below
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index f7600f930c6e..86e5b7ad19b3 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -1049,6 +1049,7 @@ static __init int construct_tdmrs(struct list_head *tmb_list,
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;
@@ -1074,8 +1075,22 @@ 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);
+ if (tdx_sysinfo.features.tdx_features0 & TDX_FEATURES0_QUOTE) {
+ args.r9 |= TDX_FEATURES0_QUOTE;
+ /* These parameters require version >= 1 */
+ seamcall_fn = TDH_SYS_CONFIG;
+ }
+
+ ret = seamcall_prerr(seamcall_fn, &args);
+ if (ret)
+ goto free_tdmr;
+
+ /* enabling TDX Quoting may change tdx_sysinfo, update it */
+ if (tdx_sysinfo.features.tdx_features0 & TDX_FEATURES0_QUOTE)
+ ret = get_tdx_sys_info(&tdx_sysinfo);
+
+free_tdmr:
/* Free the array as it is not required anymore. */
kfree(tdmr_pa_array);
@@ -1384,12 +1399,17 @@ static void tdx_quote_init(void)
unsigned int nr_quote_pages;
u64 r;
+ if (!(tdx_sysinfo.features.tdx_features0 & TDX_FEATURES0_QUOTE))
+ return;
+
do {
r = seamcall(TDH_QUOTE_INIT, &args);
} while (r == TDX_INTERRUPTED_RESUMABLE);
- if (r)
+ if (r) {
+ pr_err("Failed to enable quoting extension: 0x%llx\n", r);
return;
+ }
/* Quoting metadata is valid only after initialization */
if (get_tdx_sys_info_quote(&tdx_sysinfo.quote))
--
2.25.1
^ permalink raw reply related [flat|nested] 64+ messages in thread[parent not found: <ahPbb1Ws9hBruJ2d@tlindgre-MOBL1>]
* Re: [RFC PATCH 15/15] x86/virt/tdx: Enable TDX Quoting extension
[not found] ` <ahPbb1Ws9hBruJ2d@tlindgre-MOBL1>
@ 2026-05-25 10:51 ` Xiaoyao Li
2026-05-26 9:00 ` Tony Lindgren
2026-05-26 15:45 ` Xu Yilun
0 siblings, 2 replies; 64+ messages in thread
From: Xiaoyao Li @ 2026-05-25 10:51 UTC (permalink / raw)
To: Tony Lindgren, Xu Yilun
Cc: kas, djbw, rick.p.edgecombe, x86, peter.fang, linux-coco,
linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan
On 5/25/2026 1:17 PM, Tony Lindgren wrote:
> On Fri, May 22, 2026 at 11:41:28AM +0800, Xu Yilun wrote:
>> From: Peter Fang <peter.fang@intel.com>
>>
>> TDX Module updates global metadata when add-on features are enabled.
>> Host should update the cached tdx_sysinfo to reflect these changes.
>
> This should be made clearer IMO. How about mention that get_tdx_sys_info()
> needs to get called again to reload the TDX module global metadata?
Ah ha! This patch answers my comment to patch 1:
https://lore.kernel.org/all/956fa1e6-2920-4b2e-8037-d4b9d812ae53@intel.com/
sysinfo_ext->memory_pool_required_pages and sysinfo_ext->ext_required
will be updated after extensions are enabled by TDH.SYS.CONFIG.
Patch 06 in this series already reads the tdx_sys_info_quote out of
get_tdx_sys_info(), which mean get_tdx_sys_info() doesn't ensure all the
global metadata will be update again.
So how about move the read of memory_pool_required_pages and
ext_required out of get_tdx_sys_info() and put them after
TDH.SYS.CONFIG, so that we don't need call get_tdx_sys_info() again?
>> --- a/arch/x86/virt/vmx/tdx/tdx.c
>> +++ b/arch/x86/virt/vmx/tdx/tdx.c
>> @@ -1049,6 +1049,7 @@ static __init int construct_tdmrs(struct list_head *tmb_list,
>> 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;
>> @@ -1074,8 +1075,22 @@ 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);
>>
>> + if (tdx_sysinfo.features.tdx_features0 & TDX_FEATURES0_QUOTE) {
>> + args.r9 |= TDX_FEATURES0_QUOTE;
>> + /* These parameters require version >= 1 */
>> + seamcall_fn = TDH_SYS_CONFIG;
>> + }
>> +
>> + ret = seamcall_prerr(seamcall_fn, &args);
>> + if (ret)
>> + goto free_tdmr;
>> +
>> + /* enabling TDX Quoting may change tdx_sysinfo, update it */
>> + if (tdx_sysinfo.features.tdx_features0 & TDX_FEATURES0_QUOTE)
>> + ret = get_tdx_sys_info(&tdx_sysinfo);
>
> The comment above helps, but the change in the handling will be easy to
> miss.
>
>> +free_tdmr:
>> /* Free the array as it is not required anymore. */
>> kfree(tdmr_pa_array);
>>
>
> So I think it would be good to also add a comment to get_tdx_sys_info()
> to make it easier for folks to follow that it may get called multiple
> times.
>
> Regards,
>
> Tony
^ permalink raw reply [flat|nested] 64+ messages in thread* Re: [RFC PATCH 15/15] x86/virt/tdx: Enable TDX Quoting extension
2026-05-25 10:51 ` Xiaoyao Li
@ 2026-05-26 9:00 ` Tony Lindgren
2026-05-26 15:45 ` Xu Yilun
1 sibling, 0 replies; 64+ messages in thread
From: Tony Lindgren @ 2026-05-26 9:00 UTC (permalink / raw)
To: Xiaoyao Li
Cc: Xu Yilun, kas, djbw, rick.p.edgecombe, x86, peter.fang,
linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan
On Mon, May 25, 2026 at 06:51:27PM +0800, Xiaoyao Li wrote:
> On 5/25/2026 1:17 PM, Tony Lindgren wrote:
> > On Fri, May 22, 2026 at 11:41:28AM +0800, Xu Yilun wrote:
> > > From: Peter Fang <peter.fang@intel.com>
> > >
> > > TDX Module updates global metadata when add-on features are enabled.
> > > Host should update the cached tdx_sysinfo to reflect these changes.
> >
> > This should be made clearer IMO. How about mention that get_tdx_sys_info()
> > needs to get called again to reload the TDX module global metadata?
>
> Ah ha! This patch answers my comment to patch 1:
> https://lore.kernel.org/all/956fa1e6-2920-4b2e-8037-d4b9d812ae53@intel.com/
>
> sysinfo_ext->memory_pool_required_pages and sysinfo_ext->ext_required will
> be updated after extensions are enabled by TDH.SYS.CONFIG.
>
> Patch 06 in this series already reads the tdx_sys_info_quote out of
> get_tdx_sys_info(), which mean get_tdx_sys_info() doesn't ensure all the
> global metadata will be update again.
>
> So how about move the read of memory_pool_required_pages and ext_required
> out of get_tdx_sys_info() and put them after TDH.SYS.CONFIG, so that we
> don't need call get_tdx_sys_info() again?
Sounds like a good idea to me.
^ permalink raw reply [flat|nested] 64+ messages in thread
* Re: [RFC PATCH 15/15] x86/virt/tdx: Enable TDX Quoting extension
2026-05-25 10:51 ` Xiaoyao Li
2026-05-26 9:00 ` Tony Lindgren
@ 2026-05-26 15:45 ` Xu Yilun
2026-05-27 1:30 ` Xiaoyao Li
1 sibling, 1 reply; 64+ messages in thread
From: Xu Yilun @ 2026-05-26 15:45 UTC (permalink / raw)
To: Xiaoyao Li
Cc: Tony Lindgren, kas, djbw, rick.p.edgecombe, x86, peter.fang,
linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan
On Mon, May 25, 2026 at 06:51:27PM +0800, Xiaoyao Li wrote:
> On 5/25/2026 1:17 PM, Tony Lindgren wrote:
> > On Fri, May 22, 2026 at 11:41:28AM +0800, Xu Yilun wrote:
> > > From: Peter Fang <peter.fang@intel.com>
> > >
> > > TDX Module updates global metadata when add-on features are enabled.
> > > Host should update the cached tdx_sysinfo to reflect these changes.
> >
> > This should be made clearer IMO. How about mention that get_tdx_sys_info()
> > needs to get called again to reload the TDX module global metadata?
>
> Ah ha! This patch answers my comment to patch 1:
> https://lore.kernel.org/all/956fa1e6-2920-4b2e-8037-d4b9d812ae53@intel.com/
>
> sysinfo_ext->memory_pool_required_pages and sysinfo_ext->ext_required will
> be updated after extensions are enabled by TDH.SYS.CONFIG.
>
> Patch 06 in this series already reads the tdx_sys_info_quote out of
> get_tdx_sys_info(), which mean get_tdx_sys_info() doesn't ensure all the
> global metadata will be update again.
>
> So how about move the read of memory_pool_required_pages and ext_required
> out of get_tdx_sys_info() and put them after TDH.SYS.CONFIG, so that we
> don't need call get_tdx_sys_info() again?
Yes, I'm good to it. I hesitated to move them out in case we need some
central control on global data. But now I see there is already a
precedent:
https://lore.kernel.org/kvm/20260520133909.409394-22-chao.gao@intel.com/
Once we've agreed on moving add-on data reading out of get_tdx_sys_info(),
we don't have to read them after TDH.SYS.CONFIG, read them when really
needed. How about the following, that makes the Extension part in this
series self-contained.
----8<----
diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
index 86e5b7ad19b3..b729c1f5ab9e 100644
--- a/arch/x86/virt/vmx/tdx/tdx.c
+++ b/arch/x86/virt/vmx/tdx/tdx.c
@@ -1536,6 +1536,10 @@ static __init int init_tdx_ext(void)
if (!(tdx_sysinfo.features.tdx_features0 & TDX_FEATURES0_EXT))
return 0;
+ ret = get_tdx_sys_info_ext(&tdx_sysinfo.ext);
+ if (ret)
+ return ret;
+
/* No feature requires TDX Module Extensions. */
if (!tdx_sysinfo.ext.ext_required)
return 0;
diff --git a/arch/x86/virt/vmx/tdx/tdx_global_metadata.c b/arch/x86/virt/vmx/tdx/tdx_global_metadata.c
index f9cc2dd02caf..e7d9e0c4b604 100644
--- a/arch/x86/virt/vmx/tdx/tdx_global_metadata.c
+++ b/arch/x86/virt/vmx/tdx/tdx_global_metadata.c
@@ -140,8 +140,5 @@ static __init int get_tdx_sys_info(struct tdx_sys_info *sysinfo)
ret = ret ?: get_tdx_sys_info_td_ctrl(&sysinfo->td_ctrl);
ret = ret ?: get_tdx_sys_info_td_conf(&sysinfo->td_conf);
- if (sysinfo->features.tdx_features0 & TDX_FEATURES0_EXT)
- ret = ret ?: get_tdx_sys_info_ext(&sysinfo->ext);
-
return ret;
}
^ permalink raw reply related [flat|nested] 64+ messages in thread* Re: [RFC PATCH 15/15] x86/virt/tdx: Enable TDX Quoting extension
2026-05-26 15:45 ` Xu Yilun
@ 2026-05-27 1:30 ` Xiaoyao Li
0 siblings, 0 replies; 64+ messages in thread
From: Xiaoyao Li @ 2026-05-27 1:30 UTC (permalink / raw)
To: Xu Yilun
Cc: Tony Lindgren, kas, djbw, rick.p.edgecombe, x86, peter.fang,
linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan
On 5/26/2026 11:45 PM, Xu Yilun wrote:
> On Mon, May 25, 2026 at 06:51:27PM +0800, Xiaoyao Li wrote:
>> On 5/25/2026 1:17 PM, Tony Lindgren wrote:
>>> On Fri, May 22, 2026 at 11:41:28AM +0800, Xu Yilun wrote:
>>>> From: Peter Fang <peter.fang@intel.com>
>>>>
>>>> TDX Module updates global metadata when add-on features are enabled.
>>>> Host should update the cached tdx_sysinfo to reflect these changes.
>>>
>>> This should be made clearer IMO. How about mention that get_tdx_sys_info()
>>> needs to get called again to reload the TDX module global metadata?
>>
>> Ah ha! This patch answers my comment to patch 1:
>> https://lore.kernel.org/all/956fa1e6-2920-4b2e-8037-d4b9d812ae53@intel.com/
>>
>> sysinfo_ext->memory_pool_required_pages and sysinfo_ext->ext_required will
>> be updated after extensions are enabled by TDH.SYS.CONFIG.
>>
>> Patch 06 in this series already reads the tdx_sys_info_quote out of
>> get_tdx_sys_info(), which mean get_tdx_sys_info() doesn't ensure all the
>> global metadata will be update again.
>>
>> So how about move the read of memory_pool_required_pages and ext_required
>> out of get_tdx_sys_info() and put them after TDH.SYS.CONFIG, so that we
>> don't need call get_tdx_sys_info() again?
>
> Yes, I'm good to it. I hesitated to move them out in case we need some
> central control on global data. But now I see there is already a
> precedent:
>
> https://lore.kernel.org/kvm/20260520133909.409394-22-chao.gao@intel.com/
>
> Once we've agreed on moving add-on data reading out of get_tdx_sys_info(),
> we don't have to read them after TDH.SYS.CONFIG, read them when really
> needed. How about the following, that makes the Extension part in this
> series self-contained.
Actually below is what I meant after TDH.SYS.CONFIG.
And I think we can re-order the patches of enabling TDX extensions by
moving the patch 04 as the first one.
> ----8<----
>
> diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
> index 86e5b7ad19b3..b729c1f5ab9e 100644
> --- a/arch/x86/virt/vmx/tdx/tdx.c
> +++ b/arch/x86/virt/vmx/tdx/tdx.c
> @@ -1536,6 +1536,10 @@ static __init int init_tdx_ext(void)
> if (!(tdx_sysinfo.features.tdx_features0 & TDX_FEATURES0_EXT))
> return 0;
>
> + ret = get_tdx_sys_info_ext(&tdx_sysinfo.ext);
> + if (ret)
> + return ret;
> +
> /* No feature requires TDX Module Extensions. */
> if (!tdx_sysinfo.ext.ext_required)
> return 0;
> diff --git a/arch/x86/virt/vmx/tdx/tdx_global_metadata.c b/arch/x86/virt/vmx/tdx/tdx_global_metadata.c
> index f9cc2dd02caf..e7d9e0c4b604 100644
> --- a/arch/x86/virt/vmx/tdx/tdx_global_metadata.c
> +++ b/arch/x86/virt/vmx/tdx/tdx_global_metadata.c
> @@ -140,8 +140,5 @@ static __init int get_tdx_sys_info(struct tdx_sys_info *sysinfo)
> ret = ret ?: get_tdx_sys_info_td_ctrl(&sysinfo->td_ctrl);
> ret = ret ?: get_tdx_sys_info_td_conf(&sysinfo->td_conf);
>
> - if (sysinfo->features.tdx_features0 & TDX_FEATURES0_EXT)
> - ret = ret ?: get_tdx_sys_info_ext(&sysinfo->ext);
> -
> return ret;
> }
^ permalink raw reply [flat|nested] 64+ messages in thread
* Re: [RFC PATCH 15/15] x86/virt/tdx: Enable TDX Quoting extension
2026-05-22 3:41 ` [RFC PATCH 15/15] x86/virt/tdx: Enable TDX Quoting extension Xu Yilun
[not found] ` <ahPbb1Ws9hBruJ2d@tlindgre-MOBL1>
@ 2026-06-07 4:41 ` Kishen Maloor
1 sibling, 0 replies; 64+ messages in thread
From: Kishen Maloor @ 2026-06-07 4:41 UTC (permalink / raw)
To: Xu Yilun, kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan, xiaoyao.li
On 5/21/26 8:41 PM, Xu Yilun wrote:
> From: Peter Fang <peter.fang@intel.com>
>
> Enable the TDX Quoting feature via TDH.SYS.CONFIG when supported by the
> TDX module.
>
> The TDX Quoting extension generates TDX attestation Quotes via a
> SEAMCALL, without using a discrete Quoting engine.
>
> TDX Module supports add-on TDX features (e.g. TDX Quoting & TDX Module
> Extensions) that should be manually enabled by host. It extends
> TDH.SYS.CONFIG for host to choose to enable them on bootup.
>
> Call TDH.SYS.CONFIG with a new bitmap input parameter to specify which
> features to enable. The bitmap uses the same definitions as
> TDX_FEATURES0. But note not all bits in TDX_FEATURES0 are valid for
> configuration, e.g. TDX Module Extensions is a service that supports TDX
> Quoting, it is implicitly enabled when TDX Quoting is enabled. Setting
> TDX_FEATURES0_EXT in the bitmap has no effect.
>
> TDX Module advances the version of TDH.SYS.CONFIG 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.
>
> TDX Module updates global metadata when add-on features are enabled.
> Host should update the cached tdx_sysinfo to reflect these changes.
>
> Co-developed-by: Xu Yilun <yilun.xu@linux.intel.com>
> Signed-off-by: Xu Yilun <yilun.xu@linux.intel.com>
> Signed-off-by: Peter Fang <peter.fang@intel.com>
> ---
> arch/x86/virt/vmx/tdx/tdx.h | 4 +++-
> arch/x86/virt/vmx/tdx/tdx.c | 24 ++++++++++++++++++++++--
> 2 files changed, 25 insertions(+), 3 deletions(-)
>
> diff --git a/arch/x86/virt/vmx/tdx/tdx.h b/arch/x86/virt/vmx/tdx/tdx.h
> index 10aff23cd01f..524a14c01aa6 100644
> --- a/arch/x86/virt/vmx/tdx/tdx.h
> +++ b/arch/x86/virt/vmx/tdx/tdx.h
> @@ -58,7 +58,8 @@
> #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
Is it necessary to add _Vx macros when multiple versions can co-exist?
Just wondering if it would be cleaner in the following way?
- Leave the macros set at the current (non-deprecated) baseline version.
- Select vX using SEAMCALL_LEAF_VER() in config_tdx_module() when a vX feature
is enabled.
u64 seamcall_fn = TDH_SYS_CONFIG;
...
if (tdx_sysinfo.features.tdx_features0 & TDX_FEATURES0_QUOTE) {
...
seamcall_fn = SEAMCALL_LEAF_VER(TDH_SYS_CONFIG, 1);
> +#define TDH_SYS_CONFIG SEAMCALL_LEAF_VER(TDH_SYS_CONFIG_V0, 1)
> #define TDH_EXT_INIT 60
> #define TDH_EXT_MEM_ADD 61
> #define TDH_SYS_DISABLE 69
> @@ -97,6 +98,7 @@ struct tdmr_info {
> /* Bit definitions of TDX_FEATURES0 metadata field */
> #define TDX_FEATURES0_NO_RBP_MOD BIT(18)
> #define TDX_FEATURES0_EXT BIT_ULL(39)
> +#define TDX_FEATURES0_QUOTE BIT_ULL(50)
>
> /*
> * Do not put any hardware-defined TDX structure representations below
> diff --git a/arch/x86/virt/vmx/tdx/tdx.c b/arch/x86/virt/vmx/tdx/tdx.c
> index f7600f930c6e..86e5b7ad19b3 100644
> --- a/arch/x86/virt/vmx/tdx/tdx.c
> +++ b/arch/x86/virt/vmx/tdx/tdx.c
> @@ -1049,6 +1049,7 @@ static __init int construct_tdmrs(struct list_head *tmb_list,
> 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;
> @@ -1074,8 +1075,22 @@ 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);
>
> + if (tdx_sysinfo.features.tdx_features0 & TDX_FEATURES0_QUOTE) {
> + args.r9 |= TDX_FEATURES0_QUOTE;
> + /* These parameters require version >= 1 */
> + seamcall_fn = TDH_SYS_CONFIG;
> + }
> +
> + ret = seamcall_prerr(seamcall_fn, &args);
> + if (ret)
> + goto free_tdmr;
> +
> + /* enabling TDX Quoting may change tdx_sysinfo, update it */
> + if (tdx_sysinfo.features.tdx_features0 & TDX_FEATURES0_QUOTE)
> + ret = get_tdx_sys_info(&tdx_sysinfo);
> +
> +free_tdmr:
> /* Free the array as it is not required anymore. */
> kfree(tdmr_pa_array);
>
> @@ -1384,12 +1399,17 @@ static void tdx_quote_init(void)
> unsigned int nr_quote_pages;
> u64 r;
>
> + if (!(tdx_sysinfo.features.tdx_features0 & TDX_FEATURES0_QUOTE))
> + return;
> +
> do {
> r = seamcall(TDH_QUOTE_INIT, &args);
> } while (r == TDX_INTERRUPTED_RESUMABLE);
>
> - if (r)
> + if (r) {
> + pr_err("Failed to enable quoting extension: 0x%llx\n", r);
> return;
> + }
>
> /* Quoting metadata is valid only after initialization */
> if (get_tdx_sys_info_quote(&tdx_sysinfo.quote))
^ permalink raw reply [flat|nested] 64+ messages in thread
* Re: [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting
2026-05-22 3:41 [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting Xu Yilun
` (14 preceding siblings ...)
2026-05-22 3:41 ` [RFC PATCH 15/15] x86/virt/tdx: Enable TDX Quoting extension Xu Yilun
@ 2026-05-27 5:23 ` Sohil Mehta
2026-05-27 10:38 ` Xu Yilun
2026-06-07 4:36 ` Kishen Maloor
16 siblings, 1 reply; 64+ messages in thread
From: Sohil Mehta @ 2026-05-27 5:23 UTC (permalink / raw)
To: Xu Yilun, kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, yilun.xu, baolu.lu, zhenzhong.duan,
xiaoyao.li
Hello,
On 5/21/2026 8:41 PM, Xu Yilun wrote:
> The first 4 patches will eventually need an ack by an x86 maintainer, so
> please review with that in mind.
>
I am looking at this from an x86 reviewer perspective with limited prior
TDX knowledge.
> == Overview ==
>
> TDX Module introduces the "TDX Module Extensions" to support long
> running / hard-irq preemptible flows inside. This makes TDX Module
> capable of handling complex tasks through "Extension SEAMCALLs".
Can we explain a bit more about why these extensions are needed or what
would happen if the kernel didn't enable them? I ran the series through
an LLM for my curiosity. I think something on the below lines might be a
good addition for the cover letter itself.
(Please verify)
The TDX module's normal SEAMCALLs are designed to be short,
non-preemptible operations. However, some newer features (like
DICE-based TDX Quoting) require complex, potentially long-running
computations that can't complete within the tight constraints of a
single non-preemptible SEAMCALL.
The "TDX Module Extensions" solve this by introducing "Extension
SEAMCALLs" — a new class of SEAMCALLs that are:
* Long-running — they may take significant time to complete (e.g.,
cryptographic operations for attestation/quoting).
* Hard-IRQ preemptible — they can be interrupted by hardware interrupts
and later resumed, so they don't monopolize the CPU or cause
unacceptable interrupt latency.
Without this mechanism, complex operations like generating DICE
attestation quotes would either block interrupts for too long
(unacceptable for a host kernel) or wouldn't be possible inside the TDX
module at all. The Extensions give the TDX module a way to handle these
heavyweight tasks while remaining cooperative with the host's
interrupt/scheduling model.
>
> TDX Module allows some add-on features to use the Extension.
s/Module/module throughout the series.
The existing kernel code predominantly uses the lower case TDX "module".
> The first feature to use Extensions is DICE-based TDX Quoting [1].
> DICE is an industry-standard, certificate-backed attestation
> framework that layers evidence through a chain of certificates.
>
> This series adds infrastructure to enable the Extensions and then
> implement DICE-based TDX Quoting.
>
> The Extensions consumes relatively large amount of memory (~50MB). So it
> is designed to be off by default. It must be enabled after basic TDX
> Module initialization and when add-on features require it. To enable
> the Extensions, host first adds extra memory to TDX Module via a
> SEAMCALL (TDH.EXT.MEM.ADD), then uses another SEAMCALL (TDH.EXT.INIT) to
> initialize Extensions, and then some add-on features, e.g. DICE, could
> use Extension SEAMCALLs for work. Note that host can never get the added
> memory back.
>
> Theoretically, the Extensions doesn't need to be enabled right after
> basic TDX initialization. It could be enabled right before the first
> Extension SEAMCALL is issued. That would save or postpone memory usage.
> But it isn't worth the complexity, the needs for the Extensions are vast
> but the savings are little for a typical TDX capable system (about
> 0.001% of memory). So the Linux decision is to just enable it along with
> the basic TDX.
>
I think enabling it by default on TDX platforms (with the module
extension) might make sense. But the explanation here is slightly
confusing.
You said earlier that "The Extensions consumes relatively large amount
of memory (~50MB)" so they must be off by default. Later you say that
"..the saving are little .."
Are you saying that the dynamic enabling of the extensions is not worth
it or the dynamic allocation of the memory needed to support them?
In addition, could you briefly describe the complexity we are trading off?
> This series has 2 distinct parts:
>
> Patches 1-4: TDX Module Extensions enabling
> Patches 5-15: DICE-based TDX Quoting, primarily Peter's work.
>
^ permalink raw reply [flat|nested] 64+ messages in thread* Re: [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting
2026-05-27 5:23 ` [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting Sohil Mehta
@ 2026-05-27 10:38 ` Xu Yilun
2026-05-27 17:09 ` Sohil Mehta
0 siblings, 1 reply; 64+ messages in thread
From: Xu Yilun @ 2026-05-27 10:38 UTC (permalink / raw)
To: Sohil Mehta
Cc: kas, djbw, rick.p.edgecombe, x86, peter.fang, linux-coco,
linux-kernel, kvm, yilun.xu, baolu.lu, zhenzhong.duan, xiaoyao.li
> > == Overview ==
> >
> > TDX Module introduces the "TDX Module Extensions" to support long
> > running / hard-irq preemptible flows inside. This makes TDX Module
> > capable of handling complex tasks through "Extension SEAMCALLs".
>
> Can we explain a bit more about why these extensions are needed or what
> would happen if the kernel didn't enable them? I ran the series through
> an LLM for my curiosity. I think something on the below lines might be a
> good addition for the cover letter itself.
>
> (Please verify)
>
> The TDX module's normal SEAMCALLs are designed to be short,
> non-preemptible operations. However, some newer features (like
> DICE-based TDX Quoting) require complex, potentially long-running
> computations that can't complete within the tight constraints of a
> single non-preemptible SEAMCALL.
>
> The "TDX Module Extensions" solve this by introducing "Extension
> SEAMCALLs" — a new class of SEAMCALLs that are:
>
> * Long-running — they may take significant time to complete (e.g.,
> cryptographic operations for attestation/quoting).
>
> * Hard-IRQ preemptible — they can be interrupted by hardware interrupts
> and later resumed, so they don't monopolize the CPU or cause
> unacceptable interrupt latency.
>
> Without this mechanism, complex operations like generating DICE
> attestation quotes would either block interrupts for too long
> (unacceptable for a host kernel) or wouldn't be possible inside the TDX
> module at all. The Extensions give the TDX module a way to handle these
> heavyweight tasks while remaining cooperative with the host's
> interrupt/scheduling model.
I'm good to these detailed description. I'll add them to the
cover-letter.
>
> >
> > TDX Module allows some add-on features to use the Extension.
>
> s/Module/module throughout the series.
>
> The existing kernel code predominantly uses the lower case TDX "module".
OK.
>
>
> > The first feature to use Extensions is DICE-based TDX Quoting [1].
> > DICE is an industry-standard, certificate-backed attestation
> > framework that layers evidence through a chain of certificates.
> >
> > This series adds infrastructure to enable the Extensions and then
> > implement DICE-based TDX Quoting.
> >
> > The Extensions consumes relatively large amount of memory (~50MB). So it
> > is designed to be off by default. It must be enabled after basic TDX
> > Module initialization and when add-on features require it. To enable
> > the Extensions, host first adds extra memory to TDX Module via a
> > SEAMCALL (TDH.EXT.MEM.ADD), then uses another SEAMCALL (TDH.EXT.INIT) to
> > initialize Extensions, and then some add-on features, e.g. DICE, could
> > use Extension SEAMCALLs for work. Note that host can never get the added
> > memory back.
> >
> > Theoretically, the Extensions doesn't need to be enabled right after
> > basic TDX initialization. It could be enabled right before the first
> > Extension SEAMCALL is issued. That would save or postpone memory usage.
> > But it isn't worth the complexity, the needs for the Extensions are vast
> > but the savings are little for a typical TDX capable system (about
> > 0.001% of memory). So the Linux decision is to just enable it along with
> > the basic TDX.
> >
>
> I think enabling it by default on TDX platforms (with the module
> extension) might make sense. But the explanation here is slightly
> confusing.
>
> You said earlier that "The Extensions consumes relatively large amount
> of memory (~50MB)" so they must be off by default. Later you say that
Sorry maybe I should say "the firmware design is: 1. Off by default.
2. Must be enabled after basic TDX module ...". I'll try to update the
words.
> "..the saving are little .."
Because for security purpose, these add-on features are always needed,
even if not all of them, so Extensions will most likely be enabled.
And even if someone switched them off all and saved the memory, compared
to the memory of a typical TDX capable system (lets say 1TB), the saving
is still little (0.001%).
>
> Are you saying that the dynamic enabling of the extensions is not worth
The dynamic enabling of the Extensions is not worth.
> it or the dynamic allocation of the memory needed to support them?
>
> In addition, could you briefly describe the complexity we are trading off?
If we delay the Extensions initialization to the first Extension
SEAMCALL, we need to maintain additional TDX state machine for
lifecycle, and we need mechanisms to synchronize parallel Extension
enabling request from multiple callers.
^ permalink raw reply [flat|nested] 64+ messages in thread
* Re: [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting
2026-05-27 10:38 ` Xu Yilun
@ 2026-05-27 17:09 ` Sohil Mehta
2026-05-28 4:52 ` Xu Yilun
0 siblings, 1 reply; 64+ messages in thread
From: Sohil Mehta @ 2026-05-27 17:09 UTC (permalink / raw)
To: Xu Yilun
Cc: kas, djbw, rick.p.edgecombe, x86, peter.fang, linux-coco,
linux-kernel, kvm, yilun.xu, baolu.lu, zhenzhong.duan, xiaoyao.li
On 5/27/2026 3:38 AM, Xu Yilun wrote:
>
> Because for security purpose, these add-on features are always needed,
> even if not all of them, so Extensions will most likely be enabled.
>
A cover letter is a good place to explain such nuances, alternate
approaches, and tradeoffs.
> And even if someone switched them off all and saved the memory, compared
> to the memory of a typical TDX capable system (lets say 1TB), the saving
> is still little (0.001%).
>
In this case percentages make it harder to understand. Does it need a
fixed amount of memory (~50MB) irrespective of the feature or the number
of features? If so, it would be good to mention that.
>> In addition, could you briefly describe the complexity we are trading off?
>
> If we delay the Extensions initialization to the first Extension
> SEAMCALL, we need to maintain additional TDX state machine for
> lifecycle, and we need mechanisms to synchronize parallel Extension
> enabling request from multiple callers.
This would be good to include in the cover as well.
^ permalink raw reply [flat|nested] 64+ messages in thread
* Re: [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting
2026-05-27 17:09 ` Sohil Mehta
@ 2026-05-28 4:52 ` Xu Yilun
2026-05-28 19:50 ` Sohil Mehta
0 siblings, 1 reply; 64+ messages in thread
From: Xu Yilun @ 2026-05-28 4:52 UTC (permalink / raw)
To: Sohil Mehta
Cc: kas, djbw, rick.p.edgecombe, x86, peter.fang, linux-coco,
linux-kernel, kvm, yilun.xu, baolu.lu, zhenzhong.duan, xiaoyao.li
On Wed, May 27, 2026 at 10:09:41AM -0700, Sohil Mehta wrote:
> On 5/27/2026 3:38 AM, Xu Yilun wrote:
> >
> > Because for security purpose, these add-on features are always needed,
> > even if not all of them, so Extensions will most likely be enabled.
> >
>
> A cover letter is a good place to explain such nuances, alternate
> approaches, and tradeoffs.
>
> > And even if someone switched them off all and saved the memory, compared
> > to the memory of a typical TDX capable system (lets say 1TB), the saving
> > is still little (0.001%).
> >
>
> In this case percentages make it harder to understand. Does it need a
> fixed amount of memory (~50MB) irrespective of the feature or the number
> of features? If so, it would be good to mention that.
No the memory needed varies depends on the feature or the number of
features. But currently I see the total requirement is ~50MB.
Yes I can drop the percentage, just state the amount in MB.
>
>
> >> In addition, could you briefly describe the complexity we are trading off?
> >
> > If we delay the Extensions initialization to the first Extension
> > SEAMCALL, we need to maintain additional TDX state machine for
> > lifecycle, and we need mechanisms to synchronize parallel Extension
> > enabling request from multiple callers.
>
> This would be good to include in the cover as well.
Yes.
^ permalink raw reply [flat|nested] 64+ messages in thread
* Re: [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting
2026-05-28 4:52 ` Xu Yilun
@ 2026-05-28 19:50 ` Sohil Mehta
2026-06-01 9:36 ` Xu Yilun
0 siblings, 1 reply; 64+ messages in thread
From: Sohil Mehta @ 2026-05-28 19:50 UTC (permalink / raw)
To: Xu Yilun
Cc: kas, djbw, rick.p.edgecombe, x86, peter.fang, linux-coco,
linux-kernel, kvm, yilun.xu, baolu.lu, zhenzhong.duan, xiaoyao.li
On 5/27/2026 9:52 PM, Xu Yilun wrote:
> No the memory needed varies depends on the feature or the number of
> features. But currently I see the total requirement is ~50MB.
>
This is important consideration when defining the default policy. Could
you please elaborate on how this will scale in the future?
How are the memory requirements expected to grow with additional features?
Let's say a future platform has a lot more features and needs
significantly more memory. Wouldn't loading a legacy kernel with this
default policy lead to excessive wastage?
Maybe I am missing something obvious. The struct in patch 1,
memory_pool_required_pages is u16. So, will the Extensions support never
require more than 256MB?
^ permalink raw reply [flat|nested] 64+ messages in thread
* Re: [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting
2026-05-28 19:50 ` Sohil Mehta
@ 2026-06-01 9:36 ` Xu Yilun
2026-06-01 20:17 ` Sohil Mehta
0 siblings, 1 reply; 64+ messages in thread
From: Xu Yilun @ 2026-06-01 9:36 UTC (permalink / raw)
To: Sohil Mehta
Cc: kas, djbw, rick.p.edgecombe, x86, peter.fang, linux-coco,
linux-kernel, kvm, yilun.xu, baolu.lu, zhenzhong.duan, xiaoyao.li
On Thu, May 28, 2026 at 12:50:34PM -0700, Sohil Mehta wrote:
> On 5/27/2026 9:52 PM, Xu Yilun wrote:
>
> > No the memory needed varies depends on the feature or the number of
> > features. But currently I see the total requirement is ~50MB.
> >
> This is important consideration when defining the default policy. Could
> you please elaborate on how this will scale in the future?
>
> How are the memory requirements expected to grow with additional features?
I queried the TDX module team, and the answer is they almost grow
linear. I measured the only feature - PCIe Link encryption (SPDM) - on
my hand again, the precise memory consumption is now 35M.
In the foreseeable future, the features are SPDM, DICE & TD Migration,
so will cost ~105M at most. I think the number still works with the
default policy.
>
> Let's say a future platform has a lot more features and needs
> significantly more memory. Wouldn't loading a legacy kernel with this
> default policy lead to excessive wastage?
A legacy kernel won't consume Extensions memory. The Extensions memory
is only required by TDX module when add-ons features are explicitly
configured via TDH.SYS.CONFIG [1]. For legacy kernel, no add-on features
configured so no memory consumption.
But yes, if the features grow rapidly out of expectation, may need new
options to switch something off. I think if we discuss later when the
need actually arises.
[1]: https://lore.kernel.org/all/20260522034128.3144354-16-yilun.xu@linux.intel.com/
>
> Maybe I am missing something obvious. The struct in patch 1,
> memory_pool_required_pages is u16. So, will the Extensions support never
> require more than 256MB?
Good catch. TDX module team admitted this is an issue. They want to
increase the size to 4 bytes for future.
^ permalink raw reply [flat|nested] 64+ messages in thread
* Re: [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting
2026-06-01 9:36 ` Xu Yilun
@ 2026-06-01 20:17 ` Sohil Mehta
2026-06-02 5:36 ` Xu Yilun
0 siblings, 1 reply; 64+ messages in thread
From: Sohil Mehta @ 2026-06-01 20:17 UTC (permalink / raw)
To: Xu Yilun
Cc: kas, djbw, rick.p.edgecombe, x86, peter.fang, linux-coco,
linux-kernel, kvm, yilun.xu, baolu.lu, zhenzhong.duan, xiaoyao.li
>>
>> Let's say a future platform has a lot more features and needs
>> significantly more memory. Wouldn't loading a legacy kernel with this
>> default policy lead to excessive wastage?
>
> A legacy kernel won't consume Extensions memory. The Extensions memory
> is only required by TDX module when add-ons features are explicitly
> configured via TDH.SYS.CONFIG [1].
So, the TDX module will only report memory_pool_required_pages for
add-on features that have been configured by the kernel? This would be
good to clarify in the cover letter.
> For legacy kernel, no add-on features configured so no memory
> consumption.
>
I was referring to the first kernel that has support for one TDX
extension. I am mainly trying to ensure that a kernel with support for
one TDX extension only consumes memory for that feature (even when it is
loaded on a hardware platform that supports multiple TDX extensions).
> But yes, if the features grow rapidly out of expectation, may need new
> options to switch something off. I think if we discuss later when the
> need actually arises.
>
^ permalink raw reply [flat|nested] 64+ messages in thread
* Re: [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting
2026-06-01 20:17 ` Sohil Mehta
@ 2026-06-02 5:36 ` Xu Yilun
0 siblings, 0 replies; 64+ messages in thread
From: Xu Yilun @ 2026-06-02 5:36 UTC (permalink / raw)
To: Sohil Mehta
Cc: kas, djbw, rick.p.edgecombe, x86, peter.fang, linux-coco,
linux-kernel, kvm, yilun.xu, baolu.lu, zhenzhong.duan, xiaoyao.li
On Mon, Jun 01, 2026 at 01:17:59PM -0700, Sohil Mehta wrote:
>
> >>
> >> Let's say a future platform has a lot more features and needs
> >> significantly more memory. Wouldn't loading a legacy kernel with this
> >> default policy lead to excessive wastage?
> >
> > A legacy kernel won't consume Extensions memory. The Extensions memory
> > is only required by TDX module when add-ons features are explicitly
> > configured via TDH.SYS.CONFIG [1].
>
> So, the TDX module will only report memory_pool_required_pages for
> add-on features that have been configured by the kernel? This would be
Correct.
> good to clarify in the cover letter.
Will do.
>
> > For legacy kernel, no add-on features configured so no memory
> > consumption.
> >
>
> I was referring to the first kernel that has support for one TDX
> extension. I am mainly trying to ensure that a kernel with support for
> one TDX extension only consumes memory for that feature (even when it is
> loaded on a hardware platform that supports multiple TDX extensions).
Yes. The first kernel that supports for one add-on feature will only
consume memory for that feature. The other HW/FW supported features
will not be configured so will not consume extra memory.
I think I should refactor the cover-letter and changelogs based on all
these comments. Thanks for all the inputs that help me see what missed.
>
> > But yes, if the features grow rapidly out of expectation, may need new
> > options to switch something off. I think if we discuss later when the
> > need actually arises.
> >
>
^ permalink raw reply [flat|nested] 64+ messages in thread
* Re: [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting
2026-05-22 3:41 [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting Xu Yilun
` (15 preceding siblings ...)
2026-05-27 5:23 ` [PATCH 00/15] Enable TDX Module Extensions and DICE-based TDX Quoting Sohil Mehta
@ 2026-06-07 4:36 ` Kishen Maloor
16 siblings, 0 replies; 64+ messages in thread
From: Kishen Maloor @ 2026-06-07 4:36 UTC (permalink / raw)
To: Xu Yilun, kas, djbw, rick.p.edgecombe, x86, peter.fang
Cc: linux-coco, linux-kernel, kvm, sohil.mehta, yilun.xu, baolu.lu,
zhenzhong.duan, xiaoyao.li
On 5/21/26 8:41 PM, Xu Yilun wrote:
> ...
> This series has 2 distinct parts:
>
> Patches 1-4: TDX Module Extensions enabling
> Patches 5-15: DICE-based TDX Quoting, primarily Peter's work.
>
Perhaps the extensions enabling patches could be organized more simply as
these three?
1. Add TDX extensions metadata structure and accessor
2. Add TDH.EXT.MEM.ADD
3. Add TDH.EXT.INIT and wire extensions init into init_tdx_module()
This introduces the SEAMCALLs and lets the wiring land with the patch
that completes the init flow, avoiding a separate "enable" patch.
^ permalink raw reply [flat|nested] 64+ messages in thread