mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Chao Gao <chao.gao@intel.com>
To: linux-coco@lists.linux.dev, linux-kernel@vger.kernel.org,
	kvm@vger.kernel.org, x86@kernel.org
Cc: reinette.chatre@intel.com, ira.weiny@intel.com,
	kai.huang@intel.com, dan.j.williams@intel.com,
	yilun.xu@linux.intel.com, sagis@google.com,
	vannapurve@google.com, paulmck@kernel.org, nik.borisov@suse.com,
	zhenzhong.duan@intel.com, seanjc@google.com,
	rick.p.edgecombe@intel.com, kas@kernel.org,
	dave.hansen@linux.intel.com, vishal.l.verma@intel.com,
	binbin.wu@linux.intel.com, tony.lindgren@linux.intel.com,
	Chao Gao <chao.gao@intel.com>, Thomas Gleixner <tglx@kernel.org>,
	Ingo Molnar <mingo@redhat.com>, Borislav Petkov <bp@alien8.de>,
	"H. Peter Anvin" <hpa@zytor.com>
Subject: [PATCH v4 10/24] x86/virt/seamldr: Allocate and populate a module update request
Date: Thu, 12 Feb 2026 06:35:13 -0800	[thread overview]
Message-ID: <20260212143606.534586-11-chao.gao@intel.com> (raw)
In-Reply-To: <20260212143606.534586-1-chao.gao@intel.com>

P-SEAMLDR uses the SEAMLDR_PARAMS structure to describe TDX Module
update requests. This structure contains physical addresses pointing to
the module binary and its signature file (or sigstruct), along with an
update scenario field.

TDX Modules are distributed in the tdx_blob format defined at [1]. A
tdx_blob contains a header, sigstruct, and module binary. This is also
the format supplied by the userspace to the kernel.

Parse the tdx_blob format and populate a SEAMLDR_PARAMS structure
accordingly. This structure will be passed to P-SEAMLDR to initiate the
update.

Note that the sigstruct_pa field in SEAMLDR_PARAMS has been extended to
a 4-element array. The updated "SEAM Loader (SEAMLDR) Interface
Specification" will be published separately. The kernel does not
validate P-SEAMLDR compatibility (for example, whether it supports 4KB
or 16KB sigstruct); userspace must ensure the P-SEAMLDR version is
compatible with the selected TDX Module by checking the minimum
P-SEAMLDR version requirements at [2].

Signed-off-by: Chao Gao <chao.gao@intel.com>
Reviewed-by: Tony Lindgren <tony.lindgren@linux.intel.com>
Link: https://github.com/intel/confidential-computing.tdx.tdx-module.binaries/blob/main/blob_structure.txt # [1]
Link: https://github.com/intel/confidential-computing.tdx.tdx-module.binaries/blob/main/mapping_file.json # [2]
---
v4:
 - Remove checksum verification as it is optional
 - Convert comments to is_vmalloc_addr() checks [Kai]
 - Explain size/alignment checks in alloc_seamldr_params() [Kai]

v3:
 - Print tdx_blob version in hex [Binbin]
 - Drop redundant sigstruct alignment check [Yilun]
 - Note buffers passed from firmware upload infrastructure are
   vmalloc()'d above alloc_seamldr_params()
---
 arch/x86/virt/vmx/tdx/seamldr.c | 152 ++++++++++++++++++++++++++++++++
 1 file changed, 152 insertions(+)

diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
index 733b13215691..718cb8396057 100644
--- a/arch/x86/virt/vmx/tdx/seamldr.c
+++ b/arch/x86/virt/vmx/tdx/seamldr.c
@@ -6,9 +6,11 @@
  */
 #define pr_fmt(fmt)	"seamldr: " fmt
 
+#include <linux/cleanup.h>
 #include <linux/cpuhplock.h>
 #include <linux/cpumask.h>
 #include <linux/mm.h>
+#include <linux/slab.h>
 #include <linux/spinlock.h>
 
 #include <asm/seamldr.h>
@@ -18,6 +20,33 @@
 /* P-SEAMLDR SEAMCALL leaf function */
 #define P_SEAMLDR_INFO			0x8000000000000000
 
+#define SEAMLDR_MAX_NR_MODULE_4KB_PAGES	496
+#define SEAMLDR_MAX_NR_SIG_4KB_PAGES	4
+
+/*
+ * 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 called the "SEAMLDR_PARAMS" data structure and is defined
+ * in "SEAM Loader (SEAMLDR) Interface Specification".
+ *
+ * It describes the TDX Module that will be installed.
+ */
+struct seamldr_params {
+	u32	version;
+	u32	scenario;
+	u64	sigstruct_pa[SEAMLDR_MAX_NR_SIG_4KB_PAGES];
+	u8	reserved[80];
+	u64	num_module_pages;
+	u64	mod_pages_pa_list[SEAMLDR_MAX_NR_MODULE_4KB_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.
@@ -42,6 +71,124 @@ int seamldr_get_info(struct seamldr_info *seamldr_info)
 }
 EXPORT_SYMBOL_FOR_MODULES(seamldr_get_info, "tdx-host");
 
+static void free_seamldr_params(struct seamldr_params *params)
+{
+	free_page((unsigned long)params);
+}
+
+static struct seamldr_params *alloc_seamldr_params(const void *module, unsigned int module_size,
+						   const void *sig, unsigned int sig_size)
+{
+	struct seamldr_params *params;
+	const u8 *ptr;
+	int i;
+
+	if (WARN_ON_ONCE(!is_vmalloc_addr(module) || !is_vmalloc_addr(sig)))
+		return ERR_PTR(-EINVAL);
+
+	if (module_size > SEAMLDR_MAX_NR_MODULE_4KB_PAGES * SZ_4K)
+		return ERR_PTR(-EINVAL);
+
+	if (sig_size > SEAMLDR_MAX_NR_SIG_4KB_PAGES * SZ_4K)
+		return ERR_PTR(-EINVAL);
+
+	/*
+	 * Check that input buffers satisfy P-SEAMLDR's size and alignment
+	 * constraints so they can be passed directly to P-SEAMLDR without
+	 * relocation or copy.
+	 */
+	if (!IS_ALIGNED(module_size, SZ_4K) || !IS_ALIGNED(sig_size, SZ_4K) ||
+	    !IS_ALIGNED((unsigned long)module, SZ_4K) ||
+	    !IS_ALIGNED((unsigned long)sig, SZ_4K))
+		return ERR_PTR(-EINVAL);
+
+	params = (struct seamldr_params *)get_zeroed_page(GFP_KERNEL);
+	if (!params)
+		return ERR_PTR(-ENOMEM);
+
+	params->scenario = SEAMLDR_SCENARIO_UPDATE;
+
+	ptr = sig;
+	for (i = 0; i < sig_size / SZ_4K; i++) {
+		/*
+		 * Don't assume @sig is page-aligned although it is 4KB-aligned.
+		 * Always add the in-page offset to get the physical address.
+		 */
+		params->sigstruct_pa[i] = (vmalloc_to_pfn(ptr) << PAGE_SHIFT) +
+					  ((unsigned long)ptr & ~PAGE_MASK);
+		ptr += SZ_4K;
+	}
+
+	params->num_module_pages = module_size / SZ_4K;
+
+	ptr = module;
+	for (i = 0; i < params->num_module_pages; i++) {
+		params->mod_pages_pa_list[i] = (vmalloc_to_pfn(ptr) << PAGE_SHIFT) +
+					       ((unsigned long)ptr & ~PAGE_MASK);
+		ptr += SZ_4K;
+	}
+
+	return params;
+}
+
+/*
+ * Intel TDX Module blob. Its format is defined at:
+ * https://github.com/intel/tdx-module-binaries/blob/main/blob_structure.txt
+ *
+ * Note this structure differs from the reference above: the two variable-length
+ * fields "@sigstruct" and "@module" are represented as a single "@data" field
+ * here and split programmatically using the offset_of_module value.
+ */
+struct tdx_blob {
+	u16	version;
+	u16	checksum;
+	u32	offset_of_module;
+	u8	signature[8];
+	u32	length;
+	u32	resv0;
+	u64	resv1[509];
+	u8	data[];
+} __packed;
+
+static struct seamldr_params *init_seamldr_params(const u8 *data, u32 size)
+{
+	const struct tdx_blob *blob = (const void *)data;
+	int module_size, sig_size;
+	const void *sig, *module;
+
+	if (size < sizeof(struct tdx_blob) || blob->offset_of_module >= size)
+		return ERR_PTR(-EINVAL);
+
+	if (blob->version != 0x100) {
+		pr_err("unsupported blob version: %x\n", blob->version);
+		return ERR_PTR(-EINVAL);
+	}
+
+	if (blob->resv0 || memchr_inv(blob->resv1, 0, sizeof(blob->resv1))) {
+		pr_err("non-zero reserved fields\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	/* Split the blob into a sigstruct and a module */
+	sig		= blob->data;
+	sig_size	= blob->offset_of_module - sizeof(struct tdx_blob);
+	module		= data + blob->offset_of_module;
+	module_size	= size - blob->offset_of_module;
+
+	if (sig_size <= 0 || module_size <= 0 || blob->length != size)
+		return ERR_PTR(-EINVAL);
+
+	if (memcmp(blob->signature, "TDX-BLOB", 8)) {
+		pr_err("invalid signature\n");
+		return ERR_PTR(-EINVAL);
+	}
+
+	return alloc_seamldr_params(module, module_size, sig, sig_size);
+}
+
+DEFINE_FREE(free_seamldr_params, struct seamldr_params *,
+	    if (!IS_ERR_OR_NULL(_T)) free_seamldr_params(_T))
+
 /**
  * seamldr_install_module - Install a new TDX module
  * @data: Pointer to the TDX module update blob. It should be vmalloc'd
@@ -65,6 +212,11 @@ int seamldr_install_module(const u8 *data, u32 size)
 	if (WARN_ON_ONCE(!is_vmalloc_addr(data)))
 		return -EINVAL;
 
+	struct seamldr_params *params __free(free_seamldr_params) =
+						init_seamldr_params(data, size);
+	if (IS_ERR(params))
+		return PTR_ERR(params);
+
 	guard(cpus_read_lock)();
 	if (!cpumask_equal(cpu_online_mask, cpu_present_mask)) {
 		pr_err("Cannot update the TDX Module if any CPU is offline\n");
-- 
2.47.3


  parent reply	other threads:[~2026-02-12 14:36 UTC|newest]

Thread overview: 115+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-02-12 14:35 [PATCH v4 00/24] Runtime TDX Module update support Chao Gao
2026-02-12 14:35 ` [PATCH v4 01/24] x86/virt/tdx: Move low level SEAMCALL helpers out of <asm/tdx.h> Chao Gao
2026-03-02 12:24   ` Chao Gao
2026-03-05  9:24   ` Binbin Wu
2026-02-12 14:35 ` [PATCH v4 02/24] coco/tdx-host: Introduce a "tdx_host" device Chao Gao
2026-02-20  0:15   ` Huang, Kai
2026-02-24  1:11     ` Chao Gao
2026-03-05  9:25   ` Binbin Wu
2026-03-06  2:13     ` Chao Gao
2026-03-06  4:17       ` Dave Hansen
2026-03-06  5:12         ` Chao Gao
2026-02-12 14:35 ` [PATCH v4 03/24] coco/tdx-host: Expose TDX Module version Chao Gao
2026-02-20  0:40   ` Huang, Kai
2026-02-24  2:02     ` Chao Gao
2026-02-24 10:18       ` Huang, Kai
2026-02-12 14:35 ` [PATCH v4 04/24] x86/virt/seamldr: Introduce a wrapper for P-SEAMLDR SEAMCALLs Chao Gao
2026-02-20  1:12   ` Huang, Kai
2026-02-24  2:31     ` Chao Gao
2026-02-24 10:25       ` Huang, Kai
2026-03-12 20:15         ` Dave Hansen
2026-03-05  9:51   ` Binbin Wu
2026-03-12 20:14   ` Dave Hansen
2026-03-13  8:02     ` Chao Gao
2026-02-12 14:35 ` [PATCH v4 05/24] x86/virt/seamldr: Retrieve P-SEAMLDR information Chao Gao
2026-02-20  9:36   ` Huang, Kai
2026-02-24  2:59     ` Chao Gao
2026-02-24 10:30       ` Huang, Kai
2026-02-12 14:35 ` [PATCH v4 06/24] coco/tdx-host: Expose P-SEAMLDR information via sysfs Chao Gao
2026-03-06  9:29   ` Binbin Wu
2026-02-12 14:35 ` [PATCH v4 07/24] coco/tdx-host: Implement firmware upload sysfs ABI for TDX Module updates Chao Gao
2026-02-27  3:30   ` Xu Yilun
2026-02-27  4:36   ` Xu Yilun
2026-03-10  2:31   ` Yan Zhao
2026-03-12 20:20   ` Dave Hansen
2026-03-13  8:28     ` Chao Gao
2026-02-12 14:35 ` [PATCH v4 08/24] x86/virt/seamldr: Block TDX Module updates if any CPU is offline Chao Gao
2026-03-05  7:02   ` Huang, Kai
2026-03-12 20:20   ` Dave Hansen
2026-03-13  8:17     ` Chao Gao
2026-02-12 14:35 ` [PATCH v4 09/24] x86/virt/seamldr: Check update limit before TDX Module updates Chao Gao
2026-03-05  4:09   ` Xu Yilun
2026-03-05  7:04   ` Huang, Kai
2026-03-12  2:35   ` Yan Zhao
2026-03-12 14:13     ` Chao Gao
2026-03-12 19:21   ` Edgecombe, Rick P
2026-03-12 20:23   ` Dave Hansen
2026-03-13  8:32     ` Chao Gao
2026-02-12 14:35 ` Chao Gao [this message]
2026-02-19 22:31   ` [PATCH v4 10/24] x86/virt/seamldr: Allocate and populate a module update request Huang, Kai
2026-02-24  5:15     ` Chao Gao
2026-02-24 10:46       ` Huang, Kai
2026-03-05  4:12   ` Xu Yilun
2026-03-12  2:32   ` Yan Zhao
2026-03-12 14:36     ` Chao Gao
2026-03-12 16:56       ` Edgecombe, Rick P
2026-03-13 12:16         ` Chao Gao
2026-02-12 14:35 ` [PATCH v4 11/24] x86/virt/seamldr: Introduce skeleton for TDX Module updates Chao Gao
2026-02-23  9:25   ` Huang, Kai
2026-02-24  6:00     ` Chao Gao
2026-02-24 10:49       ` Huang, Kai
2026-03-12  2:00   ` Edgecombe, Rick P
2026-03-12 14:09     ` Chao Gao
2026-03-12 18:05       ` Edgecombe, Rick P
2026-03-13 13:54         ` Chao Gao
2026-03-13 17:43           ` Edgecombe, Rick P
2026-03-12 20:40   ` Dave Hansen
2026-03-13 12:15     ` Chao Gao
2026-02-12 14:35 ` [PATCH v4 12/24] x86/virt/seamldr: Abort updates if errors occurred midway Chao Gao
2026-03-04 22:38   ` Huang, Kai
2026-02-12 14:35 ` [PATCH v4 13/24] x86/virt/seamldr: Shut down the current TDX module Chao Gao
2026-03-04 22:59   ` Huang, Kai
2026-03-06  8:14     ` Chao Gao
2026-03-12  2:34       ` Edgecombe, Rick P
2026-03-05  4:14   ` Xu Yilun
2026-03-12  2:17   ` Edgecombe, Rick P
2026-03-12  2:57     ` Chao Gao
2026-02-12 14:35 ` [PATCH v4 14/24] x86/virt/tdx: Reset software states during TDX Module shutdown Chao Gao
2026-03-04 23:06   ` Huang, Kai
2026-02-12 14:35 ` [PATCH v4 15/24] x86/virt/seamldr: Log TDX Module update failures Chao Gao
2026-03-04 23:08   ` Huang, Kai
2026-03-05  4:18   ` Xu Yilun
2026-02-12 14:35 ` [PATCH v4 16/24] x86/virt/seamldr: Install a new TDX Module Chao Gao
2026-03-04 23:17   ` Huang, Kai
2026-03-05  4:22     ` Xu Yilun
2026-02-12 14:35 ` [PATCH v4 17/24] x86/virt/seamldr: Do TDX per-CPU initialization after updates Chao Gao
2026-03-04 23:18   ` Huang, Kai
2026-02-12 14:35 ` [PATCH v4 18/24] x86/virt/tdx: Restore TDX Module state Chao Gao
2026-03-04 23:24   ` Huang, Kai
2026-02-12 14:35 ` [PATCH v4 19/24] x86/virt/tdx: Update tdx_sysinfo and check features post-update Chao Gao
2026-03-04 23:40   ` Huang, Kai
2026-03-06  8:32     ` Chao Gao
2026-03-06  9:35       ` Huang, Kai
2026-03-12 18:48   ` Edgecombe, Rick P
2026-02-12 14:35 ` [PATCH v4 20/24] x86/virt/tdx: Enable TDX Module runtime updates Chao Gao
2026-02-23  5:09   ` Huang, Kai
2026-02-24  6:02     ` Chao Gao
2026-02-12 14:35 ` [PATCH v4 21/24] x86/virt/tdx: Avoid updates during update-sensitive operations Chao Gao
2026-02-23  4:58   ` Huang, Kai
2026-02-26  3:02     ` Chao Gao
2026-02-26  6:34       ` dan.j.williams
2026-02-26 15:32         ` Chao Gao
2026-02-26 22:06           ` dan.j.williams
2026-02-12 14:35 ` [PATCH v4 22/24] coco/tdx-host: Document TDX Module update expectations Chao Gao
2026-02-12 21:59   ` dan.j.williams
2026-02-12 14:35 ` [PATCH v4 23/24] x86/virt/tdx: Document TDX Module updates Chao Gao
2026-03-04 23:49   ` Huang, Kai
2026-03-12  2:42   ` Edgecombe, Rick P
2026-02-12 14:35 ` [PATCH v4 24/24] [NOT-FOR-REVIEW] x86/virt/seamldr: Save and restore current VMCS Chao Gao
2026-03-11 12:50   ` Chao Gao
2026-03-11 22:06     ` Huang, Kai
2026-03-12  8:48       ` Chao Gao
2026-03-12  9:59         ` Huang, Kai
2026-03-12 15:26         ` Vishal Annapurve
2026-03-12 15:31           ` Dave Hansen
2026-02-12 14:46 ` [PATCH v4 00/24] Runtime TDX Module update support Chao Gao

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=20260212143606.534586-11-chao.gao@intel.com \
    --to=chao.gao@intel.com \
    --cc=binbin.wu@linux.intel.com \
    --cc=bp@alien8.de \
    --cc=dan.j.williams@intel.com \
    --cc=dave.hansen@linux.intel.com \
    --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=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=yilun.xu@linux.intel.com \
    --cc=zhenzhong.duan@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

all inboxes | Powered by JetHome®