Re: [PATCH v5 05/22] x86/virt/seamldr: Retrieve P-SEAMLDR information
From: Kiryl Shutsemau
Date: Mon Mar 16 2026 - 09:20:21 EST
On Sun, Mar 15, 2026 at 06:58:25AM -0700, Chao Gao wrote:
> P-SEAMLDR returns its information such as version number, in response to
> the SEAMLDR.INFO SEAMCALL.
>
> This information is useful for userspace. For example, the admin can decide
> which TDX module versions are compatible with the P-SEAMLDR according to
> the P-SEAMLDR version.
>
> Retrieve P-SEAMLDR information in preparation for exposing P-SEAMLDR
> version and other necessary information to userspace. Export the new kAPI
> for use by tdx-host.ko.
>
> Note that there are two distinct P-SEAMLDR APIs with similar names:
>
> SEAMLDR.INFO: Returns a SEAMLDR_INFO structure containing SEAMLDR
> information such as version and remaining updates.
>
> SEAMLDR.SEAMINFO: Returns a SEAMLDR_SEAMINFO structure containing SEAM
> and system information such as Convertible Memory
> Regions (CMRs) and number of CPUs and sockets.
>
> The former is used here.
>
> For details, see "Intel® Trust Domain Extensions - SEAM Loader (SEAMLDR)
> Interface Specification" revision 343755-003.
>
> Signed-off-by: Chao Gao <chao.gao@xxxxxxxxx>
> Tested-by: Farrah Chen <farrah.chen@xxxxxxxxx>
> ---
> Kai also suggested merging this patch with the first use of the new
> kAPI, so we don't need to add a comment for slow_virt_to_phys() (as the
> reason can be seen from the call site). I am fine with it, but the
> changelog may be a bit lengthy.
>
> v5:
> - add a comment for slow_virt_to_phys() [Kai]
> v4:
> - put seamldr_info on stack [Dave]
> - improve changelogs to explain SEAMLDR.INFO and SEAMLDR.SEAMINFO [Dave]
> - add P-SEAMLDR spec information in the changelog [Dave]
> - add proper comments above ABI structure definition [Dave]
> - add unused ABI structure fields rather than marking them as reserved
> to better align with the specc [Dave] (I omitted "not used by kernel"
> tags since there are 5-6 such fields and maintaining these tags would
> be tedious.)
> ---
> arch/x86/include/asm/seamldr.h | 36 +++++++++++++++++++++++++++++++++
> arch/x86/virt/vmx/tdx/seamldr.c | 19 ++++++++++++++++-
> 2 files changed, 54 insertions(+), 1 deletion(-)
> create mode 100644 arch/x86/include/asm/seamldr.h
>
> diff --git a/arch/x86/include/asm/seamldr.h b/arch/x86/include/asm/seamldr.h
> new file mode 100644
> index 000000000000..c67e5bc910a9
> --- /dev/null
> +++ b/arch/x86/include/asm/seamldr.h
> @@ -0,0 +1,36 @@
> +/* SPDX-License-Identifier: GPL-2.0 */
> +#ifndef _ASM_X86_SEAMLDR_H
> +#define _ASM_X86_SEAMLDR_H
> +
> +#include <linux/types.h>
> +
> +/*
> + * This is called the "SEAMLDR_INFO" data structure and is defined
> + * in "SEAM Loader (SEAMLDR) Interface Specification".
> + *
> + * The SEAMLDR.INFO documentation requires this to be aligned to a
> + * 256-byte boundary.
> + */
> +struct seamldr_info {
> + u32 version;
> + u32 attributes;
> + u32 vendor_id;
> + u32 build_date;
> + u16 build_num;
> + u16 minor_version;
> + u16 major_version;
> + u16 update_version;
> + u32 acm_x2apicid;
> + u32 num_remaining_updates;
> + u8 seam_info[128];
> + u8 seam_ready;
> + u8 seam_debug;
> + u8 p_seam_ready;
> + u8 reserved[93];
> +} __packed __aligned(256);
> +
> +static_assert(sizeof(struct seamldr_info) == 256);
> +
> +int seamldr_get_info(struct seamldr_info *seamldr_info);
> +
> +#endif /* _ASM_X86_SEAMLDR_H */
> diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
> index 7ed9be89017c..7c0cbab2c4c0 100644
> --- a/arch/x86/virt/vmx/tdx/seamldr.c
> +++ b/arch/x86/virt/vmx/tdx/seamldr.c
> @@ -8,8 +8,13 @@
>
> #include <linux/spinlock.h>
>
> +#include <asm/seamldr.h>
> +
> #include "seamcall_internal.h"
>
> +/* P-SEAMLDR SEAMCALL leaf function */
> +#define P_SEAMLDR_INFO 0x8000000000000000
> +
> /*
> * Serialize P-SEAMLDR calls since the hardware only allows a single CPU to
> * interact with P-SEAMLDR simultaneously. Use raw version as the calls can
> @@ -17,8 +22,20 @@
> */
> static DEFINE_RAW_SPINLOCK(seamldr_lock);
>
> -static __maybe_unused int seamldr_call(u64 fn, struct tdx_module_args *args)
> +static int seamldr_call(u64 fn, struct tdx_module_args *args)
> {
> guard(raw_spinlock)(&seamldr_lock);
> return seamcall_prerr(fn, args);
> }
> +
> +int seamldr_get_info(struct seamldr_info *seamldr_info)
> +{
> + /*
> + * Use slow_virt_to_phys() since @seamldr_info may be allocated on
> + * the stack.
> + */
> + struct tdx_module_args args = { .rcx = slow_virt_to_phys(seamldr_info) };
> +
> + return seamldr_call(P_SEAMLDR_INFO, &args);
On what condition this information can change?
I see the next patch calls this on every _show operation. Would we
benefit from caching the response?
> +}
> +EXPORT_SYMBOL_FOR_MODULES(seamldr_get_info, "tdx-host");
> --
> 2.47.3
>
--
Kiryl Shutsemau / Kirill A. Shutemov