Re: [PATCH v2 05/31] x86/virt/tdx: Extend tdx_page_array to support IOMMU_MT

Xu Yilun
2026-04-08T04:51:22Z

On Wed, Apr 01, 2026 at 12:17:45AM +0000, Edgecombe, Rick P wrote:
> On Tue, 2026-03-31 at 22:19 +0800, Xu Yilun wrote:
> > > Consider the amount of tricks that are needed to coax the tdx_page_array to
> > > populate the handoff page as needed. It adds 2 pages here, then subtracts
> > > them
> > > later in the callback. Then tweaks the pa in tdx_page_array_populate() to
> > > add
> > > the length...
> >
> > mm.. The tricky part is the specific memory requirement/allocation, the
> > common part is the pa list contained in a root page. Maybe we only model
> > the later, let the specific user does the memory allocation. Is that
> > closer to your "break concepts apart" idea?
>
> I haven't wrapped my head around this enough to suggest anything is definitely
> the right approach.
>
> But yes, the idea would be that the allocation of the list of pages to give to
> the TDX module would be a separate allocation and set of management functions.
> And the the allocation of the pages that are used to communicate the list of
> pages (and in this case other args) with the module would be another set. So
> each type of TDX module arg page format (IOMMU_MT, etc) would be separable, but
> share the page list allocation part only. It looks like Nikolay was probing
> along the same path. Not sure if he had the same solution in mind.
>
> So for this:
> 1. Allocate a list or array of pages using a generic method.
> 2. Allocate these two IOMMU special pages.
> 3. Allocate memory needed for the seamcall (root pages)
>
> Hand all three to the wrapper and have it shove them all through in the special
> way it prefers.
>
> Maybe... Can you write something about the similarities and differences with the
> three types of lists in that series? Like in a compact form?

The common part:

64bit obj type root page
+----------+----------------+ +---------------------+
| ... | ... | | page0 HPA(bit12-51) |--> page0
+----------+----------------+ +---------------------+
|bit 12-51 | root page HPA |--->| page1 HPA |--> page1
+----------+----------------+ +---------------------+
| ... | ... | | pageX HPA |--> pageX
+----------+----------------+ +---------------------+

The specific objects:

HPA_LIST_INFO root page
+----------+----------------+ +---------------------+
|bit 3-11 | first entry | | page0 HPA(bit12-51) |
+----------+----------------+ +---------------------+
|bit 12-51 | root page HPA |--->| page1 HPA |
+----------+----------------+ +---------------------+
|bit 55-63 | last entry | | pageX HPA |
+----------+----------------+ +---------------------+

HPA_ARRAY_T root page HPA_ARRAY_T(singleton mode)
+----------+----------------+ +---------------------+ +----------+----------------+
|bit 3-11 | Reserved 0 | | page0 HPA(bit12-51) | |bit 3-11 | Reserved 0 |
+----------+----------------+ +---------------------+ +----------+----------------+
|bit 12-51 | root page HPA |--->| page1 HPA | |bit 12-51 | page0 HPA |--> page0
+----------+----------------+ +---------------------+ +----------+----------------+
|bit 55-63 | last entry | | pageX HPA | |bit 55-63 | last entry |
+----------+----------------+ +---------------------+ +----------+----------------+

MMIOMT root page
+----------+----------------+ +-----------------------------+-------------------+
|bit 3-11 | Reserved 0 | | 2^order page0 HPA(bit12-51) |num pages(bit 0-11)|
+----------+----------------+ +-----------------------------+-------------------+
|bit 12-51 | root page HPA |--->| 2^order page1 HPA |num pages |
+----------+----------------+ +-----------------------------+-------------------+
|bit 55-63 | Reserved 0 | | page2 HPA |0 |
+----------+----------------+ +-----------------------------+-------------------+
| page3 HPA |0 |
+-----------------------------+-------------------+
| pageX HPA |0 |
+-----------------------------+-------------------+

The same thing is they all have root_page_hpa->root_page->page_hpa_list structure.

The differences:

HPA_LIST_INFO HPA_ARRAY_T IOMMU_MT Note
first entry Y N N start entry in root page
last entry Y Y N last entry in root page
num pages always 0 always 0 Y for multi-order page
singleton N Y N try to save a root page

>
> Also, how much of the earlier code duplication you wanted to avoid was the
> leaking and special error handling stuff?

This is indeed a large part, and now we don't need them anymore.

Others are:
- the root_page allocation/population/free
- Too much parameters (struct page **, num_pages, struct page *root...)
for seamcall wrappers. Or 3 newly defined structures which looks
pretty much the same and need same implementations like
tdx_clflush_page().

Thanks,
Yilun