Linux Confidential Computing Development
 help / color / mirror / Atom feed
From: Chao Gao <chao.gao@intel.com>
To: kvm@vger.kernel.org, linux-coco@lists.linux.dev,
	linux-kernel@vger.kernel.org
Cc: binbin.wu@linux.intel.com, dave.hansen@linux.intel.com,
	djbw@kernel.org, ira.weiny@intel.com, kai.huang@intel.com,
	kas@kernel.org, nik.borisov@suse.com, paulmck@kernel.org,
	pbonzini@redhat.com, reinette.chatre@intel.com,
	rick.p.edgecombe@intel.com, sagis@google.com, seanjc@google.com,
	tony.lindgren@linux.intel.com, vannapurve@google.com,
	vishal.l.verma@intel.com, yilun.xu@linux.intel.com,
	xiaoyao.li@intel.com, yan.y.zhao@intel.com,
	Chao Gao <chao.gao@intel.com>, Thomas Gleixner <tglx@kernel.org>,
	Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>,
	x86@kernel.org, "H. Peter Anvin" <hpa@zytor.com>
Subject: [PATCH v10 13/25] x86/virt/seamldr: Allocate and populate a module update request
Date: Wed, 20 May 2026 06:38:16 -0700	[thread overview]
Message-ID: <20260520133909.409394-14-chao.gao@intel.com> (raw)
In-Reply-To: <20260520133909.409394-1-chao.gao@intel.com>

There are two important ABIs here:

'struct tdx_image'	- The on-disk and in-memory format for a TDX
			  module update image.
'struct seamldr_params'	- The in-memory ABI passed to the TDX module
			  loader. Points to a single 'struct tdx_image'
			  broken up into 4k pages.

Userspace supplies the update image in struct tdx_image format. The
image consists of a header followed by a sigstruct and the module
binary. P-SEAMLDR, however, consumes struct seamldr_params rather than
the image directly.

Parse the struct tdx_image provided by userspace and populate a matching
struct seamldr_params.

The 'tdx_image' ABI is versioned. Two public versions exist today: 0x100
and 0x200. This kernel only accepts 0x200. The older 0x100 format is being
deprecated and is intentionally not supported here. Future versions of the
module might be able to use the same ABIs (user/kernel and kernel/SEAMLDR)
but they will not be able to use this kernel code.

Reject module images without that specific version. This ensures that the
kernel is able to understand the passed-in format.

Validate the struct tdx_image header before using it, because the header is
consumed solely by the kernel to locate the sigstruct and module within
the image. Do not validate the payload itself. The sigstruct and module
pages are passed through to P-SEAMLDR, which validates them as part of the
update flow.

sigstruct_pages_pa_list currently has only one entry, but it will grow to
four pages in the future. Keep it as an array for symmetry with
module_pages_pa_list and for extensibility.

Signed-off-by: Chao Gao <chao.gao@intel.com>
---
v10:
 - Add comments for init_seamldr_params() and its call site [Dave]
 - Use data_len/image_len rather than size [Dave]
 - Do bounds check rather than implicitly truncat the update image [Dave]
 - Explain why the header version is checked in changelog [Dave]
 - make init_seamldr_params() accept a tdx_image pointer [Dave]
 - vertical alignment for code has a pattern [Dave]
---
 arch/x86/virt/vmx/tdx/seamldr.c | 145 +++++++++++++++++++++++++++++++-
 1 file changed, 144 insertions(+), 1 deletion(-)

diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
index d3880b0f93aa..11bd28e8370c 100644
--- a/arch/x86/virt/vmx/tdx/seamldr.c
+++ b/arch/x86/virt/vmx/tdx/seamldr.c
@@ -6,6 +6,8 @@
  */
 #define pr_fmt(fmt)	"seamldr: " fmt
 
+#include <linux/mm.h>
+#include <linux/slab.h>
 #include <linux/spinlock.h>
 
 #include <asm/seamldr.h>
@@ -15,6 +17,35 @@
 /* P-SEAMLDR SEAMCALL leaf function */
 #define P_SEAMLDR_INFO			0x8000000000000000
 
+#define SEAMLDR_MAX_NR_MODULE_PAGES	496
+#define SEAMLDR_MAX_NR_SIG_PAGES	1
+
+/*
+ * The seamldr_params "scenario" field specifies the operation mode:
+ * 0: Install TDX module from scratch (not used by kernel)
+ * 1: Update existing TDX module to a compatible version
+ */
+#define SEAMLDR_SCENARIO_UPDATE		1
+
+/*
+ * This is the "SEAMLDR_PARAMS" data structure defined in the
+ * "SEAM Loader (SEAMLDR) Interface Specification".
+ *
+ * It is the in-memory ABI that the kernel passes to the P-SEAMLDR
+ * to update the TDX module. It breaks the TDX module image up in
+ * page-size pieces.
+ */
+struct seamldr_params {
+	u32	version;
+	u32	scenario;
+	u64	sigstruct_pages_pa_list[SEAMLDR_MAX_NR_SIG_PAGES];
+	u8	reserved[104];
+	u64	module_nr_pages;
+	u64	module_pages_pa_list[SEAMLDR_MAX_NR_MODULE_PAGES];
+} __packed;
+
+static_assert(sizeof(struct seamldr_params) == 4096);
+
 /*
  * 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
@@ -42,6 +73,98 @@ int seamldr_get_info(struct seamldr_info *seamldr_info)
 }
 EXPORT_SYMBOL_FOR_MODULES(seamldr_get_info, "tdx-host");
 
+#define TDX_IMAGE_VERSION_2		0x200
+
+struct tdx_image_header {
+	u16	version;
+	u16	checksum;
+	u8	signature[8];
+	u32	sigstruct_nr_pages;
+	u32	module_nr_pages;
+	u8	reserved[4076];
+} __packed;
+
+#define TDX_IMAGE_HEADER_SIZE sizeof(struct tdx_image_header)
+static_assert(TDX_IMAGE_HEADER_SIZE == 4096);
+
+/*
+ * Intel TDX module update ABI structure. aka. "TDX module blob".
+ *
+ * @payload contains sigstruct pages followed by module pages.
+ */
+struct tdx_image {
+	struct tdx_image_header header;
+	u8 payload[];
+};
+
+static void populate_pa_list(u64 *pa_list, const u8 *vmalloc_addr, u32 vmalloc_len_pages)
+{
+	int i;
+
+	for (i = 0; i < vmalloc_len_pages; i++) {
+		unsigned long offset = i * PAGE_SIZE;
+		unsigned long pfn = vmalloc_to_pfn(&vmalloc_addr[offset]);
+
+		pa_list[i] = pfn << PAGE_SHIFT;
+	}
+}
+
+static void populate_seamldr_params(struct seamldr_params *params,
+				    const u8 *sig, u32 sig_nr_pages,
+				    const u8 *mod, u32 mod_nr_pages)
+{
+	params->version			= 0;
+	params->scenario		= SEAMLDR_SCENARIO_UPDATE;
+	params->module_nr_pages		= mod_nr_pages;
+
+	populate_pa_list(params->sigstruct_pages_pa_list, sig, sig_nr_pages);
+	populate_pa_list(params->module_pages_pa_list, mod, mod_nr_pages);
+}
+
+/*
+ * @image points to a vmalloc()'d 'struct tdx_image'. Transform
+ * it into @params which is the P-SEAMLDR ABI format.
+ */
+static int init_seamldr_params(struct seamldr_params *params,
+			       const struct tdx_image *image,
+			       u32 image_len)
+{
+	const struct tdx_image_header *header	= &image->header;
+
+	u32 sigstruct_len	= header->sigstruct_nr_pages * PAGE_SIZE;
+	u32 module_len		= header->module_nr_pages * PAGE_SIZE;
+
+	u8 *header_start	= (u8 *)header;
+	u8 *header_end		= header_start + TDX_IMAGE_HEADER_SIZE;
+
+	u8 *sigstruct_start	= header_end;
+	u8 *sigstruct_end	= sigstruct_start + sigstruct_len;
+
+	u8 *module_start	= sigstruct_end;
+
+	/* Check the calculated payload size against the image size. */
+	if (TDX_IMAGE_HEADER_SIZE + sigstruct_len + module_len != image_len)
+		return -EINVAL;
+
+	/* Reject unsupported tdx_image ABI versions. */
+	if (header->version != TDX_IMAGE_VERSION_2)
+		return -EINVAL;
+
+	if (header->sigstruct_nr_pages > SEAMLDR_MAX_NR_SIG_PAGES ||
+	    header->module_nr_pages > SEAMLDR_MAX_NR_MODULE_PAGES)
+		return -EINVAL;
+
+	if (memcmp(header->signature, "TDX-BLOB", sizeof(header->signature)))
+		return -EINVAL;
+
+	if (memchr_inv(header->reserved, 0, sizeof(header->reserved)))
+		return -EINVAL;
+
+	populate_seamldr_params(params, sigstruct_start, header->sigstruct_nr_pages,
+					module_start,    header->module_nr_pages);
+	return 0;
+}
+
 /**
  * seamldr_install_module - Install a new TDX module.
  * @data: Pointer to the TDX module image.
@@ -51,7 +174,27 @@ EXPORT_SYMBOL_FOR_MODULES(seamldr_get_info, "tdx-host");
  */
 int seamldr_install_module(const u8 *data, u32 data_len)
 {
+	struct seamldr_params *params;
+	const struct tdx_image *image;
+	int ret;
+
+	if (data_len < TDX_IMAGE_HEADER_SIZE)
+		return -EINVAL;
+
+	image = (const struct tdx_image *)data;
+
+	params = kzalloc_obj(*params);
+	if (!params)
+		return -ENOMEM;
+
+	/* Populate 'params' from 'image'. */
+	ret = init_seamldr_params(params, image, data_len);
+	if (ret)
+		goto out;
+
 	/* TODO: Update TDX module here */
-	return 0;
+out:
+	kfree(params);
+	return ret;
 }
 EXPORT_SYMBOL_FOR_MODULES(seamldr_install_module, "tdx-host");
-- 
2.52.0


  parent reply	other threads:[~2026-05-20 13:40 UTC|newest]

Thread overview: 36+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-20 13:38 [PATCH v10 00/25] Runtime TDX module update support Chao Gao
2026-05-20 13:38 ` [PATCH v10 01/25] x86/virt/tdx: Clarify try_init_module_global() result caching Chao Gao
2026-05-21 10:03   ` Xiaoyao Li
2026-05-20 13:38 ` [PATCH v10 02/25] x86/virt/tdx: Move TDX global initialization states to file scope Chao Gao
2026-05-21 10:10   ` Xiaoyao Li
2026-05-20 13:38 ` [PATCH v10 03/25] x86/virt/tdx: Consolidate TDX global initialization states Chao Gao
2026-05-21 10:11   ` Xiaoyao Li
2026-05-20 13:38 ` [PATCH v10 04/25] x86/virt/tdx: Move TDX_FEATURES0 bits to asm/tdx.h Chao Gao
2026-05-21 10:12   ` Xiaoyao Li
2026-05-20 13:38 ` [PATCH v10 05/25] x86/virt/tdx: Move low level SEAMCALL helpers out of <asm/tdx.h> Chao Gao
2026-05-20 13:38 ` [PATCH v10 06/25] coco/tdx-host: Introduce a "tdx_host" device Chao Gao
2026-05-20 13:38 ` [PATCH v10 07/25] coco/tdx-host: Expose TDX module version Chao Gao
2026-05-20 13:38 ` [PATCH v10 08/25] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs Chao Gao
2026-05-20 13:38 ` [PATCH v10 09/25] x86/virt/seamldr: Add a helper to retrieve P-SEAMLDR information Chao Gao
2026-05-20 13:38 ` [PATCH v10 10/25] coco/tdx-host: Expose P-SEAMLDR information via sysfs Chao Gao
2026-05-20 13:38 ` [PATCH v10 11/25] coco/tdx-host: Don't expose P-SEAMLDR information on CPUs with erratum Chao Gao
2026-05-20 13:38 ` [PATCH v10 12/25] coco/tdx-host: Implement firmware upload sysfs ABI for TDX module updates Chao Gao
2026-05-20 13:38 ` Chao Gao [this message]
2026-05-20 13:38 ` [PATCH v10 14/25] x86/virt/seamldr: Introduce skeleton " Chao Gao
2026-05-20 13:38 ` [PATCH v10 15/25] x86/virt/seamldr: Abort updates after a failed step Chao Gao
2026-05-20 17:38   ` Dave Hansen
2026-05-20 13:38 ` [PATCH v10 16/25] x86/virt/seamldr: Shut down the current TDX module Chao Gao
2026-05-20 13:38 ` [PATCH v10 17/25] x86/virt/tdx: Reset software states during TDX module shutdown Chao Gao
2026-05-20 13:38 ` [PATCH v10 18/25] x86/virt/seamldr: Install a new TDX module Chao Gao
2026-05-20 13:38 ` [PATCH v10 19/25] x86/virt/seamldr: Do TDX global and per-CPU init after module installation Chao Gao
2026-05-20 13:38 ` [PATCH v10 20/25] x86/virt/tdx: Restore TDX module state Chao Gao
2026-05-20 13:38 ` [PATCH v10 21/25] x86/virt/tdx: Refresh TDX module version after update Chao Gao
2026-05-20 13:38 ` [PATCH v10 22/25] x86/virt/tdx: Reject updates during compatibility-sensitive operations Chao Gao
2026-05-20 19:35   ` Dave Hansen
2026-05-21 12:04     ` Chao Gao
2026-05-20 13:38 ` [PATCH v10 23/25] x86/virt/tdx: Enable TDX module runtime updates Chao Gao
2026-05-20 13:38 ` [PATCH v10 24/25] coco/tdx-host: Document TDX module update compatibility criteria Chao Gao
2026-05-20 19:22   ` Dave Hansen
2026-05-20 13:38 ` [PATCH v10 25/25] x86/virt/tdx: Document TDX module update Chao Gao
2026-05-20 13:46 ` [PATCH v10 00/25] Runtime TDX module update support Chao Gao
2026-05-20 19:42 ` Dave Hansen

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260520133909.409394-14-chao.gao@intel.com \
    --to=chao.gao@intel.com \
    --cc=binbin.wu@linux.intel.com \
    --cc=bp@alien8.de \
    --cc=dave.hansen@linux.intel.com \
    --cc=djbw@kernel.org \
    --cc=hpa@zytor.com \
    --cc=ira.weiny@intel.com \
    --cc=kai.huang@intel.com \
    --cc=kas@kernel.org \
    --cc=kvm@vger.kernel.org \
    --cc=linux-coco@lists.linux.dev \
    --cc=linux-kernel@vger.kernel.org \
    --cc=mingo@redhat.com \
    --cc=nik.borisov@suse.com \
    --cc=paulmck@kernel.org \
    --cc=pbonzini@redhat.com \
    --cc=reinette.chatre@intel.com \
    --cc=rick.p.edgecombe@intel.com \
    --cc=sagis@google.com \
    --cc=seanjc@google.com \
    --cc=tglx@kernel.org \
    --cc=tony.lindgren@linux.intel.com \
    --cc=vannapurve@google.com \
    --cc=vishal.l.verma@intel.com \
    --cc=x86@kernel.org \
    --cc=xiaoyao.li@intel.com \
    --cc=yan.y.zhao@intel.com \
    --cc=yilun.xu@linux.intel.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox