Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,10 @@ patches:
- 0008-xen-netfront-place-per-queue-rings-on-per-queue-node.patch
- 0009-xen-blkfront-place-per-ring-buffers-on-per-hctx-node.patch
lower: '6.18'
- patches:
- 0001-xen-xlate_mmu-relocate-remap_pfn-utils.patch
- 0002-xen-xlate_mmu-batch-gfn-mappings.patch
lower: '6.10'
images:
- target: kernelsrc
name: kernel-src
Expand Down
70 changes: 70 additions & 0 deletions patches/0001-xen-xlate_mmu-relocate-remap_pfn-utils.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
From 5bc298c60601161ec0f012d38e4cc021347b9831 Mon Sep 17 00:00:00 2001
Message-ID: <5bc298c60601161ec0f012d38e4cc021347b9831.1779978695.git.alexander@edera.dev>
From: "Alexander M. Merritt" <alexander@edera.dev>
Date: Wed, 27 May 2026 13:21:23 -0500
Subject: [PATCH 1/2] xen: xlate_mmu: relocate remap_pfn utils

Signed-off-by: Alexander M. Merritt <alexander@edera.dev>
---
drivers/xen/xlate_mmu.c | 38 +++++++++++++++++++-------------------
1 file changed, 19 insertions(+), 19 deletions(-)

diff --git a/drivers/xen/xlate_mmu.c b/drivers/xen/xlate_mmu.c
index f17c4c03db30..6a15396b08aa 100644
--- a/drivers/xen/xlate_mmu.c
+++ b/drivers/xen/xlate_mmu.c
@@ -61,6 +61,25 @@ static void xen_for_each_gfn(struct page **pages, unsigned nr_gfn,
}
}

+struct remap_pfn {
+ struct mm_struct *mm;
+ struct page **pages;
+ pgprot_t prot;
+ unsigned long i;
+};
+
+static int remap_pfn_fn(pte_t *ptep, unsigned long addr, void *data)
+{
+ struct remap_pfn *r = data;
+ struct page *page = r->pages[r->i];
+ pte_t pte = pte_mkspecial(pfn_pte(page_to_pfn(page), r->prot));
+
+ set_pte_at(r->mm, addr, ptep, pte);
+ r->i++;
+
+ return 0;
+}
+
struct remap_data {
xen_pfn_t *fgfn; /* foreign domain's gfn */
int nr_fgfn; /* Number of foreign gfn left to map */
@@ -262,25 +281,6 @@ int __init xen_xlate_map_ballooned_pages(xen_pfn_t **gfns, void **virt,
return 0;
}

-struct remap_pfn {
- struct mm_struct *mm;
- struct page **pages;
- pgprot_t prot;
- unsigned long i;
-};
-
-static int remap_pfn_fn(pte_t *ptep, unsigned long addr, void *data)
-{
- struct remap_pfn *r = data;
- struct page *page = r->pages[r->i];
- pte_t pte = pte_mkspecial(pfn_pte(page_to_pfn(page), r->prot));
-
- set_pte_at(r->mm, addr, ptep, pte);
- r->i++;
-
- return 0;
-}
-
/* Used by the privcmd module, but has to be built-in on ARM */
int xen_remap_vma_range(struct vm_area_struct *vma, unsigned long addr, unsigned long len)
{
--
2.48.1

197 changes: 197 additions & 0 deletions patches/0002-xen-xlate_mmu-batch-gfn-mappings.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,197 @@
From 0b3410862d1c9a6be6973314f6979cf309b13e13 Mon Sep 17 00:00:00 2001
Message-ID: <0b3410862d1c9a6be6973314f6979cf309b13e13.1779978695.git.alexander@edera.dev>
In-Reply-To: <5bc298c60601161ec0f012d38e4cc021347b9831.1779978695.git.alexander@edera.dev>
References: <5bc298c60601161ec0f012d38e4cc021347b9831.1779978695.git.alexander@edera.dev>
From: "Alexander M. Merritt" <alexander@edera.dev>
Date: Wed, 27 May 2026 13:47:13 -0500
Subject: [PATCH 2/2] xen: xlate_mmu: batch gfn mappings

PVH dom0 wanting to map in guest memory would iterate over each page
individually invoking hypercall add_to_physmap_range, leading to high
mapping latencies.

Refactor xen_xlate_remap_gfn_array to separately batch GFN mappings to
the hypervisor to amortize hypercall overhead.

Signed-off-by: Alexander M. Merritt <alexander@edera.dev>
---
drivers/xen/xlate_mmu.c | 133 +++++++++++++++++++++++-----------------
1 file changed, 76 insertions(+), 57 deletions(-)

diff --git a/drivers/xen/xlate_mmu.c b/drivers/xen/xlate_mmu.c
index 6a15396b08aa..f8dd332b7f46 100644
--- a/drivers/xen/xlate_mmu.c
+++ b/drivers/xen/xlate_mmu.c
@@ -42,6 +42,9 @@
#include <xen/interface/memory.h>
#include <xen/balloon.h>

+/* Issue up to this many GFN mapping requests in a batch at a time. */
+#define XLATE_BATCH_SIZE 16
+
typedef void (*xen_gfn_fn_t)(unsigned long gfn, void *data);

/* Break down the pages in 4KB chunk and call fn for each gfn */
@@ -92,12 +95,19 @@ struct remap_data {
int *err_ptr;
int mapped;

- /* Hypercall parameters */
- int h_errs[XEN_PFN_PER_PAGE];
- xen_ulong_t h_idxs[XEN_PFN_PER_PAGE];
- xen_pfn_t h_gpfns[XEN_PFN_PER_PAGE];
+ /* Hypercall parameters.
+ *
+ * idxs: source GFNs in foreign domain P2M (combined with XENMAPSPACE_gmfn_foreign)
+ * gpfns: destination GFNs in dom0's P2M. Extracted from pages[]
+ *
+ * h_idxs and h_gpfns exist as pairs: we map into dom0's GFN
+ * the same MFN for the GFN in the foreign domain.
+ */
+ int h_errs[XLATE_BATCH_SIZE];
+ xen_ulong_t h_idxs[XLATE_BATCH_SIZE];
+ xen_pfn_t h_gpfns[XLATE_BATCH_SIZE];

- int h_iter; /* Iterator */
+ int h_iter;
};

static void setup_hparams(unsigned long gfn, void *data)
@@ -112,53 +122,6 @@ static void setup_hparams(unsigned long gfn, void *data)
info->fgfn++;
}

-static int remap_pte_fn(pte_t *ptep, unsigned long addr, void *data)
-{
- struct remap_data *info = data;
- struct page *page = info->pages[info->index++];
- pte_t pte = pte_mkspecial(pfn_pte(page_to_pfn(page), info->prot));
- int rc, nr_gfn;
- uint32_t i;
- struct xen_add_to_physmap_range xatp = {
- .domid = DOMID_SELF,
- .foreign_domid = info->domid,
- .space = XENMAPSPACE_gmfn_foreign,
- };
-
- nr_gfn = min_t(typeof(info->nr_fgfn), XEN_PFN_PER_PAGE, info->nr_fgfn);
- info->nr_fgfn -= nr_gfn;
-
- info->h_iter = 0;
- xen_for_each_gfn(&page, nr_gfn, setup_hparams, info);
- BUG_ON(info->h_iter != nr_gfn);
-
- set_xen_guest_handle(xatp.idxs, info->h_idxs);
- set_xen_guest_handle(xatp.gpfns, info->h_gpfns);
- set_xen_guest_handle(xatp.errs, info->h_errs);
- xatp.size = nr_gfn;
-
- rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp);
-
- /* info->err_ptr expect to have one error status per Xen PFN */
- for (i = 0; i < nr_gfn; i++) {
- int err = (rc < 0) ? rc : info->h_errs[i];
-
- *(info->err_ptr++) = err;
- if (!err)
- info->mapped++;
- }
-
- /*
- * Note: The hypercall will return 0 in most of the case if even if
- * all the fgmfn are not mapped. We still have to update the pte
- * as the userspace may decide to continue.
- */
- if (!rc)
- set_pte_at(info->vma->vm_mm, addr, ptep, pte);
-
- return 0;
-}
-
int xen_xlate_remap_gfn_array(struct vm_area_struct *vma,
unsigned long addr,
xen_pfn_t *gfn, int nr,
@@ -166,9 +129,10 @@ int xen_xlate_remap_gfn_array(struct vm_area_struct *vma,
unsigned domid,
struct page **pages)
{
- int err;
struct remap_data data;
- unsigned long range = DIV_ROUND_UP(nr, XEN_PFN_PER_PAGE) << PAGE_SHIFT;
+ int page_off = 0;
+
+ BUILD_BUG_ON(XLATE_BATCH_SIZE % XEN_PFN_PER_PAGE != 0);

/* Kept here for the purpose of making sure code doesn't break
x86 PVOPS */
@@ -184,9 +148,64 @@ int xen_xlate_remap_gfn_array(struct vm_area_struct *vma,
data.err_ptr = err_ptr;
data.mapped = 0;

- err = apply_to_page_range(vma->vm_mm, addr, range,
- remap_pte_fn, &data);
- return err < 0 ? err : data.mapped;
+ while (data.nr_fgfn > 0) {
+ int batch = min_t(int, XLATE_BATCH_SIZE, data.nr_fgfn); /* xen GFN units */
+ /* NOTE: on ARM, page size may be larger than in Xen */
+ int batch_pages = DIV_ROUND_UP(batch, XEN_PFN_PER_PAGE);
+ unsigned long batch_range = (unsigned long)batch_pages << PAGE_SHIFT;
+
+ struct xen_add_to_physmap_range xatp = {
+ .domid = DOMID_SELF,
+ .foreign_domid = domid,
+ .space = XENMAPSPACE_gmfn_foreign,
+ .size = batch,
+ };
+
+ int rc, i;
+
+ data.h_iter = 0;
+ xen_for_each_gfn(&pages[page_off], batch, setup_hparams, &data);
+ data.nr_fgfn -= batch;
+
+ set_xen_guest_handle(xatp.idxs, data.h_idxs);
+ set_xen_guest_handle(xatp.gpfns, data.h_gpfns);
+ set_xen_guest_handle(xatp.errs, data.h_errs);
+
+ rc = HYPERVISOR_memory_op(XENMEM_add_to_physmap_range, &xatp);
+
+ /*
+ * Note: The hypercall will return 0 in most of the case if even if
+ * all the fgmfn are not mapped. We still have to update the pte
+ * as the userspace may decide to continue.
+ */
+ if (rc == 0) {
+ struct remap_pfn r = {
+ .mm = vma->vm_mm,
+ .pages = &pages[page_off],
+ .prot = prot,
+ .i = 0,
+ };
+ int walk_err = apply_to_page_range(vma->vm_mm, addr,
+ batch_range,
+ remap_pfn_fn, &r);
+ if (walk_err < 0)
+ return walk_err;
+ }
+
+ /* err_ptr expected to have one error status per Xen PFN */
+ for (i = 0; i < batch; i++) {
+ int err = (rc < 0) ? rc : data.h_errs[i];
+ *(data.err_ptr++) = err;
+ if (!err)
+ data.mapped++;
+ }
+
+ addr += batch_range;
+ page_off += batch_pages;
+ cond_resched();
+ }
+
+ return data.mapped;
}
EXPORT_SYMBOL_GPL(xen_xlate_remap_gfn_array);

--
2.48.1

Loading