Re: [PATCH v2] x86/virt/tdx: Formalize SEAMCALL version encoding support

From: Xu Yilun

Date: Tue Jul 14 2026 - 07:19:46 EST


On Mon, Jul 13, 2026 at 12:38:02PM +0100, Kiryl Shutsemau wrote:
> On Mon, Jul 13, 2026 at 05:21:01PM +0800, Xu Yilun wrote:
> > > The commit message covers the mechanics, but is silent on compatibility
> > > with older TDX modules. That context matters for the design choice, so
> > > regardless of where the implementation discussion lands, I think it
> > > needs to be spelled out here.
> > >
> > > Who is responsible for picking a version the module supports?
> > >
> > > TDH.VP.INIT can hardcode version 1 only because KVM already refuses to
> > > enable TDX on modules without TOPOLOGY_ENUM.
> > >
> > > The TDH.SYS.UPDATE user from [1] is the opposite case: it has to pick
> > > version 0 or 1 at runtime depending on whether add-on features are
> > > configured, to keep working on modules that don't support them.
> > >
> > > The second point is the actual argument for a version field in struct
> > > tdx_module_args rather than encoding the version in the leaf defines:
> > > the version is not always a compile-time property of the call site.
> >
> > That's good point. I'll add the TDX module compatibility argument in
> > changelog:
> >
> > One concern is the compatibility with older TDX modules which don't
> > recognize the new SEAMCALLs. The kernel should decide which SEAMCALL
> > version to use at runtime, selecting the minimum version number for the
> > required functionality. It can't overwrite the function number with a
> > new value at compile time.
>
> There are two policies, not one: make the new version a hard
> requirement at init time as we did with TDH.VP.INIT, or fall back to
> version 0 at runtime like your TDH.SYS.UPDATE user does. Both are valid,
> and the changelog should not claim runtime selection is the rule.

Maybe we don't need 2 policies. This first policy is only helpful if we
don't keep version history at all, we always update to the newest (from
Linux POV) version and forget about old module compatibility.

Otherwise, we use the 2nd policy. Vx as the first version accepted by Linux,
Vy as the latest version accepted by Linux. We should maintain
module compatibility between [Vy, Vx]. TDH.VP.INIT has only V1
because the accepted version range is [V1, V1]. If there is a case in
future that requires TDH.VP.INIT v2, then it changes to [V1, V2].

TDH.SYS.UPDATE V0 is the first accepted version, so it will be [V0, V1].

I don't think we have to use different policies for each SEAMCALL,
1st policy is simple but I see problem - the newest module is not always
available. 2nd policy has better compatibility. Now I sort of like 2nd
policy - the runtime selection.

>
> BTW, we might eventually switch TDH.SYS.UPDATE to hardcoded v1 once we
> stop caring about older modules.

Maybe we don't have to. If we want compatibility, I don't see immediate
benifit to shrink the compatibility.

[...]

>
> > > Without TDH.SYS.UPDATE context, the patch seems pointless.
> >
> > mm.. It's true one target is to address the compatibility with old
> > module. But is the other concern valid?
> >
> > Another concern is the obscure usage of the 'fn' parameter for seamcall
> > wrappers. An existing caller for TDH.VP.INIT packs the version into the
> > 'fn' to match the low-level TDX ABI RAX layout. The RAX layout
> > interprets some bits differently, such as INTERRUPT_MODE, SEAMLDR flag,
> > which are not a good fit for the function number definition.
> >
> > Is this a blocker for you as an independent cleanup patch?
>
> Not a blocker. But respinning now seems premature: the shape of v3
> depends entirely on where the RAX composition discussion lands --
> args.version with FIELD_MODIFY(), a version macro in 'fn', or Dave's
> rax-in-the-struct. I'd wait for that to settle first.

Thanks for clarification.