From: Chao Gao <chao.gao@intel.com>
To: "Edgecombe, Rick P" <rick.p.edgecombe@intel.com>
Cc: "kvm@vger.kernel.org" <kvm@vger.kernel.org>,
"linux-coco@lists.linux.dev" <linux-coco@lists.linux.dev>,
"linux-kernel@vger.kernel.org" <linux-kernel@vger.kernel.org>,
"Van De Ven, Arjan" <arjan.van.de.ven@intel.com>,
"Xu, Yilun" <yilun.xu@intel.com>,
"dave.hansen@linux.intel.com" <dave.hansen@linux.intel.com>,
"x86@kernel.org" <x86@kernel.org>,
"kas@kernel.org" <kas@kernel.org>,
"hpa@zytor.com" <hpa@zytor.com>,
"mingo@redhat.com" <mingo@redhat.com>,
"bp@alien8.de" <bp@alien8.de>,
"tglx@kernel.org" <tglx@kernel.org>
Subject: Re: [RFC PATCH v1 2/3] x86/virt/seamldr: Support large TDX module binaries
Date: Tue, 3 Nov 2026 16:57:34 +0800 [thread overview]
Message-ID: <aumh_q8olQPwH0pe@intel.com> (raw)
In-Reply-To: <396de152b28fc1be18bfd61fd0ee7501c188e661.camel@intel.com>
>> +/*
>> + * Like populate_pa_list(), but skip entries pointing to the next page.
>> + */
>> +static void populate_module_pa_list(struct seamldr_params *params,
>> + const u8 *vmalloc_addr, u32
>> vmalloc_len_pages)
>> +{
>> + u64 *pa_list = params->module_pages_pa_list;
>> + int i, j;
>> +
>> + for (i = 0, j = 0; i < vmalloc_len_pages; i++, j++) {
>> + unsigned long offset = i * PAGE_SIZE;
>> + unsigned long pfn = vmalloc_to_pfn(&vmalloc_addr[offset]);
>> +
>> + /*
>> + * Skip non-zero entries. They point to the next page and
>> + * are populated during allocation.
>> + */
>> + if (pa_list[j])
>> + j++;
>
>We know what position in the page this should be right? Can we do some modulus
>and skip it that way? Feels less hacky.
Yes, the link is always the last entry of a page.
how about:
/*
* The last entry of each page points to the next chain
* page.
*/
if (PAGE_ALIGNED(&pa_list[j + 1]))
j++;
>
>> +
>> + pa_list[j] = pfn << PAGE_SHIFT;
>> + }
>> +}
>> +
>> +static struct seamldr_params *alloc_seamldr_params(u32 nr_module_pages)
>> +{
>> + struct seamldr_params *params;
>> + u32 nr_chain_pages;
>> + u32 nr_direct;
>> + u64 *link;
>> +
>> + /*
>> + * Number of module pages that fit directly in
>
>"fit directly" feels like adding jargon where there doesn't need to be.
[...]
>
>> + * module_pages_pa_list[]. Minus one as the last entry is
>> + * reserved to point to the first chain page.
>> + */
>> + nr_direct = SEAMLDR_NR_MODULE_PA_ENTRIES - 1;
>> +
>> + /* Calculate the number of extra chain pages needed. */
>> + nr_chain_pages = 0;
>> + if (nr_module_pages > nr_direct) {
>> + u32 nr_left = nr_module_pages - nr_direct;
>> +
>> + nr_chain_pages = DIV_ROUND_UP(nr_left,
>> SEAMLDR_NR_CHAIN_PA_ENTRIES);
>
>Left pages, module pages, direct pages and chain pages. It's a lot...
[...]
>
>> + }
>> +
>> + params = kzalloc_flex(*params, chain_pages, nr_chain_pages);
>> + if (!params)
>> + return NULL;
>> +
>> + /* Link all the chain pages. */
>> + link = ¶ms->module_pages_pa_list[nr_direct];
>> + for (int i = 0; i < nr_chain_pages; i++) {
>> + struct chain_page *page = ¶ms->chain_pages[i];
>> +
>> + *link = __pa(page);
>> + link = &page->next_page_pa;
>> + }
>> +
>> + return params;
>> +}
>
>This all seems like more than should be needed.
Most of the complexity came from sizing the allocation exactly. If we
over-allocate a little instead, the size calculation becomes much
simpler. Making module_pages_pa_list[] a flexible array also removes
the need to treat its entries differently from those in the chain
pages. And linking the pages while filling in the module page addresses
removes the separate linking loop.
We could even fold populate_module_pa_list() into populate_pa_list().
That works because sigstruct_pages_pa_list[] never reaches the end of a
page. It would save a function, but it looks a bit hacky for the
sigstruct pages, because the spec defines links only for the module page
list. I am not sure which is better. Do you have a preference?
diff --git a/arch/x86/virt/vmx/tdx/seamldr.c b/arch/x86/virt/vmx/tdx/seamldr.c
index b1137ca6150d..cd4a00a7b02e 100644
--- a/arch/x86/virt/vmx/tdx/seamldr.c
+++ b/arch/x86/virt/vmx/tdx/seamldr.c
/*
@@ -48,11 +54,9 @@ struct seamldr_params {
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];
+ u64 module_pages_pa_list[];
} __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
@@ -143,6 +147,55 @@ static void populate_pa_list(u64 *pa_list, const u8 *vmalloc_addr, u32 vmalloc_l
}
}
+/*
+ * Like populate_pa_list(), but skip entries pointing to the next page.
+ */
+static void populate_module_pa_list(struct seamldr_params *params,
+ const u8 *vmalloc_addr, u32 vmalloc_len_pages)
+{
+ u64 *pa_list = params->module_pages_pa_list;
+ int i, j;
+
+ for (i = 0, j = 0; i < vmalloc_len_pages; i++, j++) {
+ unsigned long offset = i * PAGE_SIZE;
+ unsigned long pfn = vmalloc_to_pfn(&vmalloc_addr[offset]);
+
+ /*
+ * The last entry of each page points to the next chain
+ * page.
+ */
+ if (PAGE_ALIGNED(&pa_list[j + 1])) {
+ pa_list[j] = __pa(&pa_list[j + 1]);
+ j++;
+ }
+
+ pa_list[j] = pfn << PAGE_SHIFT;
+ }
+}
+
+static struct seamldr_params *alloc_seamldr_params(u32 nr_module_pages)
+{
+ struct seamldr_params *params;
+ u32 nr_pages;
+
+ if (nr_module_pages > SEAMLDR_MAX_NR_MODULE_PAGES)
+ return ERR_PTR(-EINVAL);
+
+ /*
+ * One page for 'struct seamldr_params', plus chain pages that
+ * each hold 511 module page addresses and a link to the next
+ * page. Ignoring the addresses held in the first page
+ * over-allocates a little.
+ */
+ nr_pages = 1 + DIV_ROUND_UP(nr_module_pages, 511);
+
+ params = kzalloc(nr_pages * PAGE_SIZE, GFP_KERNEL);
+ if (!params)
+ return ERR_PTR(-ENOMEM);
+
+ return params;
+}
+
next prev parent reply other threads:[~2026-11-03 8:59 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-30 8:52 [RFC PATCH v1 0/3] TDX: P-SEAMLDR: Support large TDX modules and sigstructs Chao Gao
2026-10-30 8:52 ` [RFC PATCH v1 1/3] x86/virt/seamldr: Allocate 'struct seamldr_params' after image validation Chao Gao
2026-11-02 23:58 ` Edgecombe, Rick P
2026-11-03 6:30 ` Chao Gao
2026-11-03 18:55 ` Edgecombe, Rick P
2026-10-30 8:52 ` [RFC PATCH v1 2/3] x86/virt/seamldr: Support large TDX module binaries Chao Gao
2026-11-03 0:35 ` Edgecombe, Rick P
2026-11-03 8:57 ` Chao Gao [this message]
2026-11-04 13:12 ` Chao Gao
2026-10-30 8:53 ` [RFC PATCH v1 3/3] x86/virt/seamldr: Support multiple sigstruct pages Chao Gao
2026-11-02 23:50 ` [RFC PATCH v1 0/3] TDX: P-SEAMLDR: Support large TDX modules and sigstructs Edgecombe, Rick P
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=aumh_q8olQPwH0pe@intel.com \
--to=chao.gao@intel.com \
--cc=arjan.van.de.ven@intel.com \
--cc=bp@alien8.de \
--cc=dave.hansen@linux.intel.com \
--cc=hpa@zytor.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=rick.p.edgecombe@intel.com \
--cc=tglx@kernel.org \
--cc=x86@kernel.org \
--cc=yilun.xu@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