IN PXENBUS_GNTTAB_CACHE Cache
);
+/*! \typedef XENBUS_GNTTAB_MAP_FOREIGN_PAGES
+ \brief Map foreign memory pages into the system address space
+
+ \param Interface The interface header
+ \param Domain The domid of the foreign domain that granted the pages
+ \param NumberPages Number of pages to map
+ \param References Array of grant reference numbers shared by the foreign domain
+ \param ReadOnly If TRUE, pages are mapped with read-only access
+ \param Address The physical address that the foreign pages are mapped under
+*/
+
+typedef NTSTATUS
+(*XENBUS_GNTTAB_MAP_FOREIGN_PAGES)(
+ IN PINTERFACE Interface,
+ IN USHORT Domain,
+ IN ULONG NumberPages,
+ IN PULONG References,
+ IN BOOLEAN ReadOnly,
+ OUT PHYSICAL_ADDRESS *Address
+ );
+
+/*! \typedef XENBUS_GNTTAB_UNMAP_FOREIGN_PAGES
+ \brief Unmap foreign memory pages from the system address space
+
+ \param Interface The interface header
+ \param Address The physical address that the foreign pages are mapped under
+*/
+typedef NTSTATUS
+(*XENBUS_GNTTAB_UNMAP_FOREIGN_PAGES)(
+ IN PINTERFACE Interface,
+ IN PHYSICAL_ADDRESS Address
+ );
+
// {763679C5-E5C2-4A6D-8B88-6BB02EC42D8E}
DEFINE_GUID(GUID_XENBUS_GNTTAB_INTERFACE,
0x763679c5, 0xe5c2, 0x4a6d, 0x8b, 0x88, 0x6b, 0xb0, 0x2e, 0xc4, 0x2d, 0x8e);
XENBUS_GNTTAB_DESTROY_CACHE GnttabDestroyCache;
};
-typedef struct _XENBUS_GNTTAB_INTERFACE_V1 XENBUS_GNTTAB_INTERFACE, *PXENBUS_GNTTAB_INTERFACE;
+/*! \struct _XENBUS_GNTTAB_INTERFACE_V2
+ \brief GNTTAB interface version 2
+ \ingroup interfaces
+*/
+struct _XENBUS_GNTTAB_INTERFACE_V2 {
+ INTERFACE Interface;
+ XENBUS_GNTTAB_ACQUIRE GnttabAcquire;
+ XENBUS_GNTTAB_RELEASE GnttabRelease;
+ XENBUS_GNTTAB_CREATE_CACHE GnttabCreateCache;
+ XENBUS_GNTTAB_PERMIT_FOREIGN_ACCESS GnttabPermitForeignAccess;
+ XENBUS_GNTTAB_REVOKE_FOREIGN_ACCESS GnttabRevokeForeignAccess;
+ XENBUS_GNTTAB_GET_REFERENCE GnttabGetReference;
+ XENBUS_GNTTAB_DESTROY_CACHE GnttabDestroyCache;
+ XENBUS_GNTTAB_MAP_FOREIGN_PAGES GnttabMapForeignPages;
+ XENBUS_GNTTAB_UNMAP_FOREIGN_PAGES GnttabUnmapForeignPages;
+};
+
+typedef struct _XENBUS_GNTTAB_INTERFACE_V2 XENBUS_GNTTAB_INTERFACE, *PXENBUS_GNTTAB_INTERFACE;
/*! \def XENBUS_GNTTAB
\brief Macro at assist in method invocation
#endif // _WINDLL
#define XENBUS_GNTTAB_INTERFACE_VERSION_MIN 1
-#define XENBUS_GNTTAB_INTERFACE_VERSION_MAX 1
+#define XENBUS_GNTTAB_INTERFACE_VERSION_MAX 2
#endif // _XENBUS_GNTTAB_INTERFACE_H
#include "dbg_print.h"
#include "assert.h"
+#pragma warning(push)
+#pragma warning(disable:4127) // conditional expression is constant
+
+// Most of the GNTST_* values don't have meaningful NTSTATUS counterparts,
+// this macro translates those that do.
+#define GNTST_TO_STATUS(_gntst, _status) \
+ do { \
+ switch (_gntst) { \
+ case GNTST_okay: \
+ _status = STATUS_SUCCESS; \
+ break; \
+ \
+ case GNTST_bad_handle: \
+ _status = STATUS_INVALID_HANDLE; \
+ break; \
+ \
+ case GNTST_permission_denied: \
+ _status = STATUS_ACCESS_DENIED; \
+ break; \
+ \
+ case GNTST_eagain: \
+ _status = STATUS_RETRY; \
+ break; \
+ \
+ default: \
+ _status = STATUS_UNSUCCESSFUL; \
+ break; \
+ } \
+ } while (FALSE)
+
+#pragma warning(pop)
+
static LONG_PTR
GrantTableOp(
IN ULONG Command,
return status;
}
+
+__checkReturn
+XEN_API
+NTSTATUS
+GrantTableMapForeignPage(
+ IN USHORT Domain,
+ IN ULONG GrantRef,
+ IN PHYSICAL_ADDRESS Address,
+ IN BOOLEAN ReadOnly,
+ OUT ULONG *Handle
+ )
+{
+ struct gnttab_map_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.host_addr = Address.QuadPart;
+
+ rc = GrantTableOp(GNTTABOP_map_grant_ref, &op, 1);
+
+ if (rc < 0) {
+ ERRNO_TO_STATUS(-rc, status);
+ goto fail1;
+ }
+
+ if (op.status != GNTST_okay) {
+ Warning("%u:%u -> %u.%u failed (%d)\n",
+ op.dom,
+ op.ref,
+ Address.HighPart,
+ Address.LowPart,
+ op.status);
+
+ GNTST_TO_STATUS(op.status, status);
+ goto fail2;
+ }
+
+ *Handle = op.handle;
+
+ return STATUS_SUCCESS;
+
+fail2:
+ Error("fail2\n");
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+__checkReturn
+XEN_API
+NTSTATUS
+GrantTableUnmapForeignPage(
+ IN ULONG Handle,
+ IN PHYSICAL_ADDRESS Address
+ )
+{
+ struct gnttab_unmap_grant_ref op;
+ LONG_PTR rc;
+ NTSTATUS status;
+
+ RtlZeroMemory(&op, sizeof(op));
+ op.handle = Handle;
+ op.host_addr = Address.QuadPart;
+
+ rc = GrantTableOp(GNTTABOP_unmap_grant_ref, &op, 1);
+
+ if (rc < 0) {
+ ERRNO_TO_STATUS(-rc, status);
+ goto fail1;
+ }
+
+ if (op.status != GNTST_okay) {
+ Warning("%u.%u failed (%d)\n",
+ Address.HighPart,
+ Address.LowPart,
+ op.status);
+
+ GNTST_TO_STATUS(op.status, status);
+ goto fail2;
+ }
+
+ return STATUS_SUCCESS;
+
+fail2:
+ Error("fail2\n");
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
#include "dbg_print.h"
#include "assert.h"
#include "util.h"
+#include "hash_table.h"
#define XENBUS_GNTTAB_MAXIMUM_FRAME_COUNT 32
#define XENBUS_GNTTAB_ENTRY_PER_FRAME (PAGE_SIZE / sizeof (grant_entry_v1_t))
grant_entry_v1_t Entry;
};
+typedef struct _XENBUS_GNTTAB_MAP_ENTRY {
+ ULONG NumberPages;
+ ULONG MapHandles[1];
+} XENBUS_GNTTAB_MAP_ENTRY, *PXENBUS_GNTTAB_MAP_ENTRY;
+
struct _XENBUS_GNTTAB_CONTEXT {
PXENBUS_FDO Fdo;
KSPIN_LOCK Lock;
PXENBUS_SUSPEND_CALLBACK SuspendCallbackEarly;
XENBUS_DEBUG_INTERFACE DebugInterface;
PXENBUS_DEBUG_CALLBACK DebugCallback;
+ PXENBUS_HASH_TABLE MapTable;
LIST_ENTRY List;
};
return (ULONG)Entry->Reference;
}
+static NTSTATUS
+GnttabMapForeignPages(
+ IN PINTERFACE Interface,
+ IN USHORT Domain,
+ IN ULONG NumberPages,
+ IN PULONG References,
+ IN BOOLEAN ReadOnly,
+ OUT PHYSICAL_ADDRESS *Address
+ )
+{
+ PXENBUS_GNTTAB_CONTEXT Context = Interface->Context;
+ LONG PageIndex;
+ PHYSICAL_ADDRESS PageAddress;
+ PXENBUS_GNTTAB_MAP_ENTRY MapEntry;
+ NTSTATUS status;
+
+ status = FdoAllocateIoSpace(Context->Fdo,
+ NumberPages * PAGE_SIZE,
+ Address);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ MapEntry = __GnttabAllocate(FIELD_OFFSET(XENBUS_GNTTAB_MAP_ENTRY,
+ MapHandles) +
+ (NumberPages * sizeof (ULONG)));
+
+ status = STATUS_NO_MEMORY;
+ if (MapEntry == NULL)
+ goto fail2;
+
+ PageAddress.QuadPart = Address->QuadPart;
+ MapEntry->NumberPages = NumberPages;
+
+ 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 = HashTableAdd(Context->MapTable,
+ (ULONG_PTR)Address->QuadPart,
+ (ULONG_PTR)MapEntry);
+ if (!NT_SUCCESS(status))
+ goto fail4;
+
+ return STATUS_SUCCESS;
+
+fail4:
+ Error("fail4\n");
+
+fail3:
+ Error("fail3\n");
+
+ while (--PageIndex >= 0) {
+ PageAddress.QuadPart -= PAGE_SIZE;
+ (VOID) GrantTableUnmapForeignPage(MapEntry->MapHandles[PageIndex],
+ PageAddress);
+ }
+
+ __GnttabFree(MapEntry);
+
+fail2:
+ Error("fail2\n");
+
+ FdoFreeIoSpace(Context->Fdo, *Address, NumberPages * PAGE_SIZE);
+
+fail1:
+ Error("fail1: (%08x)\n", status);
+
+ return status;
+}
+
+static NTSTATUS
+GnttabUnmapForeignPages(
+ IN PINTERFACE Interface,
+ IN PHYSICAL_ADDRESS Address
+ )
+{
+ PXENBUS_GNTTAB_CONTEXT Context = Interface->Context;
+ ULONG PageIndex;
+ PHYSICAL_ADDRESS PageAddress;
+ PXENBUS_GNTTAB_MAP_ENTRY MapEntry;
+ NTSTATUS status;
+
+ status = HashTableLookup(Context->MapTable,
+ (ULONG_PTR)Address.QuadPart,
+ (PULONG_PTR)&MapEntry);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ status = HashTableRemove(Context->MapTable,
+ (ULONG_PTR)Address.QuadPart);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ PageAddress.QuadPart = Address.QuadPart;
+
+ for (PageIndex = 0; PageIndex < MapEntry->NumberPages; PageIndex++) {
+ status = GrantTableUnmapForeignPage(MapEntry->MapHandles[PageIndex],
+ PageAddress);
+ BUG_ON(!NT_SUCCESS(status));
+
+ PageAddress.QuadPart += PAGE_SIZE;
+ }
+
+ FdoFreeIoSpace(Context->Fdo,
+ Address,
+ MapEntry->NumberPages * PAGE_SIZE);
+
+ __GnttabFree(MapEntry);
+
+ return STATUS_SUCCESS;
+
+fail2:
+ Error("fail2\n");
+
+fail1:
+ Error("fail1: (%08x)\n", status);
+
+ return status;
+}
+
static VOID
GnttabSuspendCallbackEarly(
IN PVOID Argument
GnttabDestroyCache
};
+static struct _XENBUS_GNTTAB_INTERFACE_V2 GnttabInterfaceVersion2 = {
+ { sizeof (struct _XENBUS_GNTTAB_INTERFACE_V2), 2, NULL, NULL, NULL },
+ GnttabAcquire,
+ GnttabRelease,
+ GnttabCreateCache,
+ GnttabPermitForeignAccess,
+ GnttabRevokeForeignAccess,
+ GnttabGetReference,
+ GnttabDestroyCache,
+ GnttabMapForeignPages,
+ GnttabUnmapForeignPages
+};
+
NTSTATUS
GnttabInitialize(
IN PXENBUS_FDO Fdo,
InitializeListHead(&(*Context)->List);
KeInitializeSpinLock(&(*Context)->Lock);
+ status = HashTableCreate(&(*Context)->MapTable);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
(*Context)->Fdo = Fdo;
Trace("<====\n");
return STATUS_SUCCESS;
+fail2:
+ Error("fail2\n");
+
fail1:
Error("fail1 (%08x)\n", status);
status = STATUS_SUCCESS;
break;
}
+ case 2: {
+ struct _XENBUS_GNTTAB_INTERFACE_V2 *GnttabInterface;
+
+ GnttabInterface = (struct _XENBUS_GNTTAB_INTERFACE_V2 *)Interface;
+
+ status = STATUS_BUFFER_OVERFLOW;
+ if (Size < sizeof (struct _XENBUS_GNTTAB_INTERFACE_V2))
+ break;
+
+ *GnttabInterface = GnttabInterfaceVersion2;
+
+ ASSERT3U(Interface->Version, ==, Version);
+ Interface->Context = Context;
+
+ status = STATUS_SUCCESS;
+ break;
+ }
default:
status = STATUS_NOT_SUPPORTED;
break;
Context->Fdo = NULL;
+ HashTableDestroy(Context->MapTable);
+ Context->MapTable = NULL;
+
RtlZeroMemory(&Context->Lock, sizeof (KSPIN_LOCK));
RtlZeroMemory(&Context->List, sizeof (LIST_ENTRY));