[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 1/2] Use batched hypercalls for mapping foreign pages


  • To: win-pv-devel@xxxxxxxxxxxxxxxxxxxx
  • From: Rafał Wojdyła <omeg@xxxxxxxxxxxxxxxxxxxxxx>
  • Date: Fri, 5 Jun 2026 23:18:01 +0200
  • Authentication-results: eu.smtp.expurgate.cloud; dkim=pass header.s=fm3 header.d=invisiblethingslab.com header.i="@invisiblethingslab.com" header.h="Cc:Content-Transfer-Encoding:Content-Type:Date:From:In-Reply-To:Message-ID:MIME-Version:References:Subject:To"; dkim=pass header.s=fm1 header.d=messagingengine.com header.i="@messagingengine.com" header.h="Cc:Content-Transfer-Encoding:Content-Type:Date:Feedback-ID:From:In-Reply-To:Message-ID:MIME-Version:References:Subject:To:X-ME-Proxy:X-ME-Sender"
  • Cc: Rafał Wojdyła <omeg@xxxxxxxxxxxxxxxxxxxxxx>
  • Delivery-date: Fri, 05 Jun 2026 21:18:51 +0000
  • Feedback-id: i409c4082:Fastmail
  • List-id: Developer list for the Windows PV Drivers subproject <win-pv-devel.lists.xenproject.org>

Use one hypercall op with multiple pages instead of
separate hypercalls for each page.

Signed-off-by: Rafał Wojdyła <omeg@xxxxxxxxxxxxxxxxxxxxxx>
---
 include/xen.h         |  20 +++--
 src/xen/grant_table.c | 187 +++++++++++++++++++++++++++++++++---------
 src/xenbus/gnttab.c   |  47 ++++-------
 3 files changed, 177 insertions(+), 77 deletions(-)

diff --git a/include/xen.h b/include/xen.h
index 0c3e8a4..eaab567 100644
--- a/include/xen.h
+++ b/include/xen.h
@@ -265,20 +265,22 @@ GrantTableCopy(
 _Check_return_
 XEN_API
 NTSTATUS
-GrantTableMapForeignPage(
-    _In_ USHORT             Domain,
-    _In_ ULONG              GrantRef,
-    _In_ PHYSICAL_ADDRESS   Address,
-    _In_ BOOLEAN            ReadOnly,
-    _Out_ ULONG             *Handle
+GrantTableMapForeignPages(
+    _In_ USHORT                        Domain,
+    _In_ ULONG                         NumberPages,
+    _In_reads_(NumberPages) PULONG     GrantRefs,
+    _In_ PHYSICAL_ADDRESS              Address,
+    _In_ BOOLEAN                       ReadOnly,
+    _Out_writes_(NumberPages) PULONG   Handles
     );
 
 _Check_return_
 XEN_API
 NTSTATUS
-GrantTableUnmapForeignPage(
-    _In_ ULONG              Handle,
-    _In_ PHYSICAL_ADDRESS   Address
+GrantTableUnmapForeignPages(
+    _In_ ULONG                       NumberPages,
+    _In_reads_(NumberPages) PULONG   Handles,
+    _In_ PHYSICAL_ADDRESS            Address
     );
 
 _Check_return_
diff --git a/src/xen/grant_table.c b/src/xen/grant_table.c
index 96a5a26..a9099c6 100644
--- a/src/xen/grant_table.c
+++ b/src/xen/grant_table.c
@@ -38,10 +38,13 @@
 #include "hypercall.h"
 #include "dbg_print.h"
 #include "assert.h"
+#include "util.h"
 
 #pragma warning(push)
 #pragma warning(disable:4127)   // conditional expression is constant
 
+#define XEN_GNTTAB_TAG  'TNGX'
+
 // Most of the GNTST_* values don't have meaningful NTSTATUS counterparts,
 // this macro translates those that do.
 #define GNTST_TO_STATUS(_gntst, _status)                    \
@@ -168,27 +171,20 @@ fail1:
 _Check_return_
 XEN_API
 NTSTATUS
-GrantTableMapForeignPage(
-    _In_ USHORT                 Domain,
-    _In_ ULONG                  GrantRef,
-    _In_ PHYSICAL_ADDRESS       Address,
-    _In_ BOOLEAN                ReadOnly,
-    _Out_ ULONG                 *Handle
+GrantTableUnmapForeignPage(
+    _In_ ULONG                    Handle,
+    _In_ PHYSICAL_ADDRESS         Address
     )
 {
-    struct gnttab_map_grant_ref op;
-    LONG_PTR                    rc;
-    NTSTATUS                    status;
+    struct gnttab_unmap_grant_ref op;
+    LONG_PTR                      rc;
+    NTSTATUS                      status;
 
     RtlZeroMemory(&op, sizeof(op));
-    op.dom = Domain;
-    op.ref = GrantRef;
-    op.flags = GNTMAP_host_map;
-    if (ReadOnly)
-        op.flags |= GNTMAP_readonly;
+    op.handle = Handle;
     op.host_addr = Address.QuadPart;
 
-    rc = GrantTableOp(GNTTABOP_map_grant_ref, &op, 1);
+    rc = GrantTableOp(GNTTABOP_unmap_grant_ref, &op, 1);
 
     if (rc < 0) {
         ERRNO_TO_STATUS(-rc, status);
@@ -196,9 +192,7 @@ GrantTableMapForeignPage(
     }
 
     if (op.status != GNTST_okay) {
-        Warning("%u:%u -> %u.%u failed (%d)\n",
-                op.dom,
-                op.ref,
+        Warning("%u.%u failed (%d)\n",
                 Address.HighPart,
                 Address.LowPart,
                 op.status);
@@ -207,8 +201,6 @@ GrantTableMapForeignPage(
         goto fail2;
     }
 
-    *Handle = op.handle;
-
     return STATUS_SUCCESS;
 
 fail2:
@@ -223,40 +215,161 @@ fail1:
 _Check_return_
 XEN_API
 NTSTATUS
-GrantTableUnmapForeignPage(
-    _In_ ULONG                    Handle,
-    _In_ PHYSICAL_ADDRESS         Address
+GrantTableMapForeignPages(
+    _In_ USHORT                       Domain,
+    _In_ ULONG                        NumberPages,
+    _In_reads_(NumberPages) PULONG    GrantRefs,
+    _In_ PHYSICAL_ADDRESS             Address,
+    _In_ BOOLEAN                      ReadOnly,
+    _Out_writes_(NumberPages) PULONG  Handles
     )
 {
-    struct gnttab_unmap_grant_ref op;
-    LONG_PTR                      rc;
-    NTSTATUS                      status;
+    struct gnttab_map_grant_ref       *ops;
+    LONG_PTR                          rc;
+    NTSTATUS                          status;
+    ULONG                             i;
+    PHYSICAL_ADDRESS                  page_address;
+
+    status = STATUS_NO_MEMORY;
+    ops = __AllocatePoolWithTag(NonPagedPool,
+                                NumberPages * sizeof(*ops),
+                                XEN_GNTTAB_TAG);
+    if (ops == NULL)
+        goto fail1;
 
-    RtlZeroMemory(&op, sizeof(op));
-    op.handle = Handle;
-    op.host_addr = Address.QuadPart;
+    page_address.QuadPart = Address.QuadPart;
+    for (i = 0; i < NumberPages; i++) {
+        ops[i].dom = Domain;
+        ops[i].ref = GrantRefs[i];
+        ops[i].flags = GNTMAP_host_map;
+        if (ReadOnly)
+            ops[i].flags |= GNTMAP_readonly;
 
-    rc = GrantTableOp(GNTTABOP_unmap_grant_ref, &op, 1);
+        ops[i].host_addr = page_address.QuadPart;
+        page_address.QuadPart += PAGE_SIZE;
+    }
+
+    rc = GrantTableOp(GNTTABOP_map_grant_ref, ops, NumberPages);
 
     if (rc < 0) {
         ERRNO_TO_STATUS(-rc, status);
+        goto fail2;
+    }
+
+    // check every op, they are independently processed
+    status = STATUS_SUCCESS;
+    for (i = 0; i < NumberPages; i++) {
+        if (ops[i].status != GNTST_okay) {
+            Warning("op[%u] %u:%u -> %u.%u failed (%d)\n",
+                    i, ops[i].dom, ops[i].ref,
+                    (ULONG)(ops[i].host_addr >> 32),
+                    (ULONG)ops[i].host_addr,
+                    ops[i].status);
+
+            if (NT_SUCCESS(status))
+                GNTST_TO_STATUS(ops[i].status, status);
+            continue;
+        }
+
+        Handles[i] = ops[i].handle;
+    }
+
+    if (!NT_SUCCESS(status))
+        goto fail3;
+
+    __FreePoolWithTag(ops, XEN_GNTTAB_TAG);
+    return STATUS_SUCCESS;
+
+fail3:
+    Error("fail3 (%08x)\n", status);
+
+    // undo successful ops
+    for (i = 0; i < NumberPages; i++) {
+        PHYSICAL_ADDRESS unmap_address;
+        NTSTATUS         unmap_status;
+
+        if (ops[i].status != GNTST_okay)
+            continue;
+
+        unmap_address.QuadPart = ops[i].host_addr;
+        unmap_status = GrantTableUnmapForeignPage(ops[i].handle,
+                                                  unmap_address);
+        // don't leave the memory in inconsistent state
+        BUG_ON(!NT_SUCCESS(unmap_status));
+    }
+
+fail2:
+    Error("fail2 (%08x)\n", status);
+    __FreePoolWithTag(ops, XEN_GNTTAB_TAG);
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+_Check_return_
+XEN_API
+NTSTATUS
+GrantTableUnmapForeignPages(
+    _In_ ULONG                      NumberPages,
+    _In_reads_(NumberPages) PULONG  Handles,
+    _In_ PHYSICAL_ADDRESS           Address
+    )
+{
+    struct gnttab_unmap_grant_ref   *ops;
+    LONG_PTR                        rc;
+    NTSTATUS                        status;
+    ULONG                           i;
+    PHYSICAL_ADDRESS                page_address;
+
+    status = STATUS_NO_MEMORY;
+    ops = __AllocatePoolWithTag(NonPagedPool,
+                                NumberPages * sizeof(*ops),
+                                XEN_GNTTAB_TAG);
+    if (ops == NULL)
         goto fail1;
+
+    page_address.QuadPart = Address.QuadPart;
+    for (i = 0; i < NumberPages; i++) {
+        ops[i].handle = Handles[i];
+        ops[i].host_addr = page_address.QuadPart;
+        page_address.QuadPart += PAGE_SIZE;
     }
 
-    if (op.status != GNTST_okay) {
-        Warning("%u.%u failed (%d)\n",
-                Address.HighPart,
-                Address.LowPart,
-                op.status);
+    rc = GrantTableOp(GNTTABOP_unmap_grant_ref, ops, NumberPages);
 
-        GNTST_TO_STATUS(op.status, status);
+    if (rc < 0) {
+        ERRNO_TO_STATUS(-rc, status);
         goto fail2;
     }
 
+    status = STATUS_SUCCESS;
+    for (i = 0; i < NumberPages; i++) {
+        if (ops[i].status != GNTST_okay) {
+            Warning("op[%u] %u.%u failed (%d)\n",
+                    i,
+                    (ULONG)(ops[i].host_addr >> 32),
+                    (ULONG)ops[i].host_addr,
+                    ops[i].status);
+
+            if (NT_SUCCESS(status))
+                GNTST_TO_STATUS(ops[i].status, status);
+        }
+    }
+
+    __FreePoolWithTag(ops, XEN_GNTTAB_TAG);
+
+    if (!NT_SUCCESS(status)) {
+        Error("fail3 (%08x)\n", status);
+        return status;
+    }
+
     return STATUS_SUCCESS;
 
 fail2:
-    Error("fail2\n");
+    Error("fail2 (%08x)\n", status);
+    __FreePoolWithTag(ops, XEN_GNTTAB_TAG);
 
 fail1:
     Error("fail1 (%08x)\n", status);
diff --git a/src/xenbus/gnttab.c b/src/xenbus/gnttab.c
index 71f8ec1..f6fcef6 100644
--- a/src/xenbus/gnttab.c
+++ b/src/xenbus/gnttab.c
@@ -667,8 +667,6 @@ GnttabMapForeignPages(
 {
     PXENBUS_GNTTAB_CONTEXT      Context = Interface->Context;
     PMDL                        Mdl;
-    LONG                        PageIndex;
-    PHYSICAL_ADDRESS            PageAddress;
     PXENBUS_GNTTAB_MAP_ENTRY    MapEntry;
     NTSTATUS                    status;
 
@@ -689,19 +687,15 @@ GnttabMapForeignPages(
     MapEntry->Mdl = Mdl;
 
     Address->QuadPart = MmGetMdlPfnArray(Mdl)[0] << PAGE_SHIFT;
-    PageAddress.QuadPart = Address->QuadPart;
-
-    for (PageIndex = 0; PageIndex < (LONG)NumberPages; PageIndex++) {
-        status = GrantTableMapForeignPage(Domain,
-                                          References[PageIndex],
-                                          PageAddress,
-                                          ReadOnly,
-                                          &MapEntry->MapHandles[PageIndex]);
-        if (!NT_SUCCESS(status))
-            goto fail3;
 
-        PageAddress.QuadPart += PAGE_SIZE;
-    }
+    status = GrantTableMapForeignPages(Domain,
+                                       NumberPages,
+                                       References,
+                                       *Address,
+                                       ReadOnly,
+                                       MapEntry->MapHandles);
+    if (!NT_SUCCESS(status))
+        goto fail3;
 
     status = HashTableAdd(Context->MapTable,
                           (ULONG_PTR)Address->QuadPart,
@@ -714,15 +708,13 @@ GnttabMapForeignPages(
 fail4:
     Error("fail4\n");
 
+    (VOID) GrantTableUnmapForeignPages(NumberPages,
+                                       MapEntry->MapHandles,
+                                       *Address);
+
 fail3:
     Error("fail3\n");
 
-    while (--PageIndex >= 0) {
-        PageAddress.QuadPart -= PAGE_SIZE;
-        (VOID) GrantTableUnmapForeignPage(MapEntry->MapHandles[PageIndex],
-                                          PageAddress);
-    }
-
     Address->QuadPart = 0;
 
     __GnttabFree(MapEntry);
@@ -746,8 +738,6 @@ GnttabUnmapForeignPages(
 {
     PXENBUS_GNTTAB_CONTEXT      Context = Interface->Context;
     ULONG                       NumberPages;
-    PHYSICAL_ADDRESS            PageAddress;
-    ULONG                       PageIndex;
     PXENBUS_GNTTAB_MAP_ENTRY    MapEntry;
     PMDL                        Mdl;
     NTSTATUS                    status;
@@ -763,18 +753,13 @@ GnttabUnmapForeignPages(
     if (!NT_SUCCESS(status))
         goto fail2;
 
-    PageAddress.QuadPart = Address.QuadPart;
-
     Mdl = MapEntry->Mdl;
     NumberPages = Mdl->ByteCount >> PAGE_SHIFT;
 
-    for (PageIndex = 0; PageIndex < NumberPages; PageIndex++) {
-        status = GrantTableUnmapForeignPage(MapEntry->MapHandles[PageIndex],
-                                            PageAddress);
-        BUG_ON(!NT_SUCCESS(status));
-
-        PageAddress.QuadPart += PAGE_SIZE;
-    }
+    status = GrantTableUnmapForeignPages(NumberPages,
+                                         MapEntry->MapHandles,
+                                         Address);
+    BUG_ON(!NT_SUCCESS(status));
 
     __GnttabFree(MapEntry);
 
-- 
2.54.0




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.