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

Re: [win-pv-devel] [PATCH 4/5] Implement new IOCTL handlers




> -----Original Message-----
> From: win-pv-devel-bounces@xxxxxxxxxxxxxxxxxxxx [mailto:win-pv-devel-
> bounces@xxxxxxxxxxxxxxxxxxxx] On Behalf Of Rafal Wojdyla
> Sent: 07 October 2015 05:49
> To: win-pv-devel@xxxxxxxxxxxxxxxxxxxx
> Subject: [win-pv-devel] [PATCH 4/5] Implement new IOCTL handlers
> 
> This patch implements new store, evtchn and gnttab IOCTLs.
> Handlers are split into separate files for readability.
> 
> Signed-off-by: Rafal Wojdyla <omeg@xxxxxxxxxxxxxxxxxxxxxx>
> ---
>  src/xeniface/fdo.c               | 188 ++++++++--
>  src/xeniface/fdo.h               |  25 +-
>  src/xeniface/ioctl_evtchn.c      | 467 ++++++++++++++++++++++++
>  src/xeniface/ioctl_gnttab.c      | 765
> +++++++++++++++++++++++++++++++++++++++
>  src/xeniface/ioctl_store.c       | 574 +++++++++++++++++++++++++++++
>  src/xeniface/ioctls.c            | 360 ++++++------------
>  src/xeniface/ioctls.h            | 315 +++++++++++++++-
>  src/xeniface/irp_queue.c         | 131 +++++++
>  src/xeniface/irp_queue.h         |  50 +++
>  vs2013/xeniface/xeniface.vcxproj |   4 +
>  10 files changed, 2602 insertions(+), 277 deletions(-)
>  create mode 100644 src/xeniface/ioctl_evtchn.c
>  create mode 100644 src/xeniface/ioctl_gnttab.c
>  create mode 100644 src/xeniface/ioctl_store.c
>  create mode 100644 src/xeniface/irp_queue.c
>  create mode 100644 src/xeniface/irp_queue.h
> 
> diff --git a/src/xeniface/fdo.c b/src/xeniface/fdo.c
> index 51bda24..338c8da 100644
> --- a/src/xeniface/fdo.c
> +++ b/src/xeniface/fdo.c
> @@ -36,7 +36,8 @@
>  #include <stdlib.h>
> 
>  #include <store_interface.h>
> -
> +#include <evtchn_interface.h>
> +#include <gnttab_interface.h>
>  #include <suspend_interface.h>
> 
> 
> @@ -52,6 +53,7 @@
>  #include "ioctls.h"
>  #include "wmi.h"
>  #include "xeniface_ioctls.h"
> +#include "irp_queue.h"
> 
>  #define FDO_POOL 'ODF'
> 
> @@ -664,6 +666,25 @@ __FdoD3ToD0(
>      if (!NT_SUCCESS(status))
>          goto fail1;
> 
> +    status = XENBUS_EVTCHN(Acquire, &Fdo->EvtchnInterface);
> +    if (!NT_SUCCESS(status))
> +        goto fail2;
> +
> +    status = XENBUS_GNTTAB(Acquire, &Fdo->GnttabInterface);
> +    if (!NT_SUCCESS(status))
> +        goto fail3;
> +
> +    status = XENBUS_GNTTAB(CreateCache,
> +                           &Fdo->GnttabInterface,
> +                           "xeniface-gnttab",
> +                           0,
> +                           GnttabAcquireLock,
> +                           GnttabReleaseLock,
> +                           Fdo,
> +                           &Fdo->GnttabCache);
> +    if (!NT_SUCCESS(status))
> +        goto fail4;
> +
>      __FdoSetDevicePowerState(Fdo, PowerDeviceD0);
> 
>      PowerState.DeviceState = PowerDeviceD0;
> @@ -675,6 +696,18 @@ __FdoD3ToD0(
> 
>      return STATUS_SUCCESS;
> 
> +fail4:
> +    Error("fail4\n");
> +    XENBUS_GNTTAB(Release, &Fdo->GnttabInterface);
> +
> +fail3:
> +    Error("fail3\n");
> +    XENBUS_EVTCHN(Release, &Fdo->EvtchnInterface);
> +
> +fail2:
> +    Error("fail2\n");
> +    XENBUS_STORE(Release, &Fdo->StoreInterface);
> +
>  fail1:
>      Error("fail1 (%08x)\n", status);
> 
> @@ -700,6 +733,9 @@ __FdoD0ToD3(
> 
>      __FdoSetDevicePowerState(Fdo, PowerDeviceD3);
> 
> +    XENBUS_GNTTAB(DestroyCache, &Fdo->GnttabInterface, Fdo-
> >GnttabCache);
> +    XENBUS_GNTTAB(Release, &Fdo->GnttabInterface);
> +    XENBUS_EVTCHN(Release, &Fdo->EvtchnInterface);
>      XENBUS_STORE(Release, &Fdo->StoreInterface);
> 
>      Trace("<====\n");
> @@ -1991,27 +2027,25 @@ FdoDispatchDefault(
> 
>  NTSTATUS
>  FdoCreateFile (
> -    __in PXENIFACE_FDO fdoData,
> -    __inout PIRP Irp
> +    __in PXENIFACE_FDO  Fdo,
> +    __inout PIRP        Irp
>      )
>  {
> -    NTSTATUS     status;
> -
> +    PIO_STACK_LOCATION  Stack = IoGetCurrentIrpStackLocation(Irp);
> +    NTSTATUS            status;
> 
> -    XenIfaceDebugPrint(TRACE, "Create \n");
> +    XenIfaceDebugPrint(TRACE, "FO %p, Process %p\n", Stack->FileObject,
> PsGetCurrentProcess());
> 
> -    if (Deleted == fdoData->Dx->DevicePnpState)
> -    {
> +    if (Deleted == Fdo->Dx->DevicePnpState) {
>          Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE;
> -        IoCompleteRequest (Irp, IO_NO_INCREMENT);
> +        IoCompleteRequest(Irp, IO_NO_INCREMENT);
>          return STATUS_NO_SUCH_DEVICE;
>      }
> 
> -
>      status = STATUS_SUCCESS;
>      Irp->IoStatus.Information = 0;
>      Irp->IoStatus.Status = status;
> -    IoCompleteRequest (Irp, IO_NO_INCREMENT);
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> 
>      return status;
>  }
> @@ -2019,20 +2053,22 @@ FdoCreateFile (
> 
>  NTSTATUS
>  FdoClose (
> -    __in PXENIFACE_FDO fdoData,
> -    __inout PIRP Irp
> +    __in PXENIFACE_FDO  Fdo,
> +    __inout PIRP        Irp
>      )
> 
>  {
> +    PIO_STACK_LOCATION  Stack = IoGetCurrentIrpStackLocation(Irp);
> +    NTSTATUS            status;
> 
> -    NTSTATUS     status;
> +    XenIfaceDebugPrint(TRACE, "FO %p, Process %p\n", Stack->FileObject,
> PsGetCurrentProcess());
> 
> -    XenIfaceDebugPrint(TRACE, "Close \n");
> +    XenIfaceCleanup(Fdo, Stack->FileObject);
> 
>      status = STATUS_SUCCESS;
>      Irp->IoStatus.Information = 0;
>      Irp->IoStatus.Status = status;
> -    IoCompleteRequest (Irp, IO_NO_INCREMENT);
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> 
>      return status;
>  }
> @@ -2080,9 +2116,9 @@ FdoDispatch(
>          status = FdoDispatchPower(Fdo, Irp);
>          break;
> 
> -     case IRP_MJ_DEVICE_CONTROL:
> -             status = XenIFaceIoctl(Fdo, Irp);
> -             break;
> +    case IRP_MJ_DEVICE_CONTROL:
> +        status = XenIfaceIoctl(Fdo, Irp);
> +        break;
> 
>       case IRP_MJ_SYSTEM_CONTROL:
>               status = XenIfaceSystemControl(Fdo, Irp);
> @@ -2206,6 +2242,7 @@ FdoCreate(
>      WCHAR               Name[MAXNAMELEN * sizeof (WCHAR)];
>      ULONG               Size;
>      NTSTATUS            status;
> +    ULONG               ProcessorCount;
> 
>  #pragma prefast(suppress:28197) // Possibly leaking memory
> 'FunctionDeviceObject'
>      status = IoCreateDevice(DriverObject,
> @@ -2296,6 +2333,24 @@ FdoCreate(
>      if (!NT_SUCCESS(status))
>          goto fail10;
> 
> +    status = FDO_QUERY_INTERFACE(Fdo,
> +                                 XENBUS,
> +                                 EVTCHN,
> +                                 (PINTERFACE)&Fdo->EvtchnInterface,
> +                                 sizeof(Fdo->EvtchnInterface),
> +                                 FALSE);
> +    if (!NT_SUCCESS(status))
> +        goto fail11;
> +
> +    status = FDO_QUERY_INTERFACE(Fdo,
> +                                 XENBUS,
> +                                 GNTTAB,
> +                                 (PINTERFACE)&Fdo->GnttabInterface,
> +                                 sizeof(Fdo->GnttabInterface),
> +                                 FALSE);
> +    if (!NT_SUCCESS(status))
> +        goto fail12;
> +
>      InitializeMutex(&Fdo->Mutex);
>      InitializeListHead(&Dx->ListEntry);
>      Fdo->References = 1;
> @@ -2304,9 +2359,46 @@ FdoCreate(
> 
>       KeInitializeEvent(&Fdo->registryWriteEvent, NotificationEvent,
> FALSE);
> 
> -     status = ThreadCreate(FdoRegistryThreadHandler, Fdo, &Fdo-
> >registryThread);
> -     if (!NT_SUCCESS(status))
> -             goto fail11;
> +    status = ThreadCreate(FdoRegistryThreadHandler, Fdo, &Fdo-
> >registryThread);
> +    if (!NT_SUCCESS(status))
> +        goto fail13;
> +
> +    KeInitializeSpinLock(&Fdo->StoreWatchLock);
> +    InitializeListHead(&Fdo->StoreWatchList);
> +
> +    KeInitializeSpinLock(&Fdo->EvtchnLock);
> +    InitializeListHead(&Fdo->EvtchnList);
> +
> +    KeInitializeSpinLock(&Fdo->IrpQueueLock);
> +    InitializeListHead(&Fdo->IrpList);
> +
> +    KeInitializeSpinLock(&Fdo->GnttabCacheLock);
> +
> +    status = IoCsqInitializeEx(&Fdo->IrpQueue,
> +                               CsqInsertIrpEx,
> +                               CsqRemoveIrp,
> +                               CsqPeekNextIrp,
> +                               CsqAcquireLock,
> +                               CsqReleaseLock,
> +                               CsqCompleteCanceledIrp);
> +    if (!NT_SUCCESS(status))
> +        goto fail14;
> +
> +    ProcessorCount =
> KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
> +    status = STATUS_NO_MEMORY;

Need a blank line here, I think.

> +    Fdo->EvtchnDpc = __FdoAllocate(sizeof(KDPC) * ProcessorCount);
> +    if (Fdo->EvtchnDpc == NULL)
> +        goto fail15;
> +
> +    for (ULONG i = 0; i < ProcessorCount; i++) {

Let's not use C++-isms where we don't have to. Also use 'Index' or somesuch 
rather than 'i'.

> +        PROCESSOR_NUMBER ProcNumber;
> +
> +        status = KeGetProcessorNumberFromIndex(i, &ProcNumber);
> +        ASSERT(NT_SUCCESS(status));

Blank line here.

> +        KeInitializeDpc(&Fdo->EvtchnDpc[i], EvtchnNotificationDpc, NULL);
> +        status = KeSetTargetProcessorDpcEx(&Fdo->EvtchnDpc[i],
> &ProcNumber);
> +        ASSERT(NT_SUCCESS(status));
> +    }
> 
>      Info("%p (%s)\n",
>           FunctionDeviceObject,
> @@ -2317,7 +2409,28 @@ FdoCreate(
> 
>      return STATUS_SUCCESS;
> 
> -
> +fail15:
> +    Error("fail15\n");
> +
> +fail14:
> +    Error("fail14\n");
> +
> +    ThreadAlert(Fdo->registryThread);
> +    ThreadJoin(Fdo->registryThread);
> +    Fdo->registryThread = NULL;
> +
> +fail13:
> +    Error("fail13\n");
> +
> +    RtlZeroMemory(&Fdo->GnttabInterface,
> +                  sizeof (XENBUS_GNTTAB_INTERFACE));
> +
> +fail12:
> +    Error("fail12\n");
> +
> +    RtlZeroMemory(&Fdo->EvtchnInterface,
> +                  sizeof(XENBUS_EVTCHN_INTERFACE));
> +
>  fail11:
>       Error("fail11\n");
> 
> @@ -2395,6 +2508,7 @@ FdoDestroy(
>  {
>      PXENIFACE_DX          Dx = Fdo->Dx;
>      PDEVICE_OBJECT      FunctionDeviceObject = Dx->DeviceObject;
> +    ULONG               ProcessorCount;
> 
>      ASSERT(IsListEmpty(&Dx->ListEntry));
>      ASSERT3U(Fdo->References, ==, 0);
> @@ -2408,9 +2522,33 @@ FdoDestroy(
> 
>      Dx->Fdo = NULL;
> 
> -    RtlZeroMemory(&Fdo->Mutex, sizeof (XENIFACE_MUTEX));
> +    ProcessorCount =
> KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
> +    RtlZeroMemory(Fdo->EvtchnDpc, sizeof(KDPC)*ProcessorCount);

Spaces around '*'. Also I don't think it's safe to use the active processor 
count. What if a processor came online since the FDO was created?

> +    __FdoFree(Fdo->EvtchnDpc);
> 
> -     Fdo->InterfacesAcquired = FALSE;
> +    RtlZeroMemory(&Fdo->GnttabCacheLock, sizeof(KSPIN_LOCK));
> +    ASSERT(IsListEmpty(&Fdo->IrpList));
> +    RtlZeroMemory(&Fdo->IrpList, sizeof(LIST_ENTRY));
> +    RtlZeroMemory(&Fdo->IrpQueueLock, sizeof(KSPIN_LOCK));
> +    RtlZeroMemory(&Fdo->IrpQueue, sizeof(IO_CSQ));
> +
> +    ASSERT(IsListEmpty(&Fdo->EvtchnList));
> +    RtlZeroMemory(&Fdo->EvtchnList, sizeof(LIST_ENTRY));
> +    RtlZeroMemory(&Fdo->EvtchnLock, sizeof(KSPIN_LOCK));
> +
> +    ASSERT(IsListEmpty(&Fdo->StoreWatchList));
> +    RtlZeroMemory(&Fdo->StoreWatchList, sizeof(LIST_ENTRY));
> +    RtlZeroMemory(&Fdo->StoreWatchLock, sizeof(KSPIN_LOCK));
> +
> +    RtlZeroMemory(&Fdo->Mutex, sizeof(XENIFACE_MUTEX));
> +
> +    Fdo->InterfacesAcquired = FALSE;
> +
> +    RtlZeroMemory(&Fdo->GnttabInterface,
> +                  sizeof(XENBUS_GNTTAB_INTERFACE));
> +
> +    RtlZeroMemory(&Fdo->EvtchnInterface,
> +                  sizeof(XENBUS_EVTCHN_INTERFACE));
> 
>      RtlZeroMemory(&Fdo->StoreInterface,
>                    sizeof (XENBUS_STORE_INTERFACE));
> diff --git a/src/xeniface/fdo.h b/src/xeniface/fdo.h
> index 4416064..cbe5de3 100644
> --- a/src/xeniface/fdo.h
> +++ b/src/xeniface/fdo.h
> @@ -34,6 +34,8 @@
> 
>  #include <ntifs.h>
>  #include <store_interface.h>
> +#include <evtchn_interface.h>
> +#include <gnttab_interface.h>
>  #include <suspend_interface.h>
>  #include <shared_info_interface.h>
> 
> @@ -73,17 +75,30 @@ typedef struct _XENIFACE_FDO {
> 
>      FDO_RESOURCE                    Resource[RESOURCE_COUNT];
> 
> -
>      XENBUS_STORE_INTERFACE          StoreInterface;
> -
>      XENBUS_SUSPEND_INTERFACE        SuspendInterface;
> -
> -     XENBUS_SHARED_INFO_INTERFACE    SharedInfoInterface;
> -
> +    XENBUS_SHARED_INFO_INTERFACE    SharedInfoInterface;
> +    XENBUS_EVTCHN_INTERFACE         EvtchnInterface;
> +    XENBUS_GNTTAB_INTERFACE         GnttabInterface;
>      PXENBUS_SUSPEND_CALLBACK        SuspendCallbackLate;
> 
>       BOOLEAN
> InterfacesAcquired;
> 

Since you're fixing whitespace, could you fix the above to have sane tabbing?

> +    KSPIN_LOCK                      StoreWatchLock;
> +    LIST_ENTRY                      StoreWatchList;
> +
> +    KSPIN_LOCK                      EvtchnLock;
> +    LIST_ENTRY                      EvtchnList;
> +    PKDPC                           EvtchnDpc;
> +
> +    KSPIN_LOCK                      GnttabCacheLock;
> +
> +    IO_CSQ                          IrpQueue;
> +    KSPIN_LOCK                      IrpQueueLock;
> +    LIST_ENTRY                      IrpList;
> +
> +    PXENBUS_GNTTAB_CACHE            GnttabCache;
> +
>       #define MAX_SESSIONS    (65536)
> 
>      int                                                          WmiReady;
> diff --git a/src/xeniface/ioctl_evtchn.c b/src/xeniface/ioctl_evtchn.c
> new file mode 100644
> index 0000000..d46894f
> --- /dev/null
> +++ b/src/xeniface/ioctl_evtchn.c
> @@ -0,0 +1,467 @@
> +/* Copyright (c) Citrix Systems Inc.
> + * All rights reserved.

You're not obliged to give Citrix copyright AFAIK. As long as it's BSD licensed 
I think we're all happy.

> + *
> + * Redistribution and use in source and binary forms,
> + * with or without modification, are permitted provided
> + * that the following conditions are met:
> + *
> + * *   Redistributions of source code must retain the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer.
> + * *   Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer in the documentation and/or other
> + *     materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#include "driver.h"
> +#include "ioctls.h"
> +#include "..\..\include\xeniface_ioctls.h"

Hmm. I think you should really use

#include <xeniface_ioctls.h>

> +#include "log.h"
> +
> +_Function_class_(KDEFERRED_ROUTINE)
> +_IRQL_requires_(DISPATCH_LEVEL)
> +_IRQL_requires_same_
> +VOID
> +EvtchnNotificationDpc(
> +    __in      PKDPC Dpc,
> +    __in_opt  PVOID _Context,
> +    __in_opt  PVOID Argument1,
> +    __in_opt  PVOID Argument2
> +    )
> +{
> +    PXENIFACE_EVTCHN_CONTEXT Context =
> (PXENIFACE_EVTCHN_CONTEXT)Argument1;
> +
> +    UNREFERENCED_PARAMETER(Dpc);
> +    UNREFERENCED_PARAMETER(_Context);
> +    UNREFERENCED_PARAMETER(Argument2);
> +
> +    ASSERT(Context);
> +
> +#if DBG
> +    XenIfaceDebugPrint(INFO, "Channel %p, LocalPort %d, Active %d, Cpu
> %lu\n",
> +                       Context->Channel, Context->LocalPort, Context->Active,
> KeGetCurrentProcessorNumber());
> +#endif
> +    if (Context->Active) {
> +        KeSetEvent(Context->Event, 0, FALSE);
> +
> +        XENBUS_EVTCHN(Unmask,
> +                      &Context->Fdo->EvtchnInterface,
> +                      Context->Channel,
> +                      FALSE);
> +    }
> +}
> +
> +_Function_class_(KSERVICE_ROUTINE)
> +_IRQL_requires_(HIGH_LEVEL)
> +_IRQL_requires_same_
> +static DECLSPEC_NOINLINE
> +BOOLEAN
> +EvtchnInterruptHandler(
> +    __in      PKINTERRUPT Interrupt,
> +    __in_opt  PVOID Argument
> +    )
> +{
> +    PXENIFACE_EVTCHN_CONTEXT Context =
> (PXENIFACE_EVTCHN_CONTEXT)Argument;
> +    PROCESSOR_NUMBER ProcNumber;
> +    ULONG ProcIndex;
> +
> +    UNREFERENCED_PARAMETER(Interrupt);
> +    ASSERT(Context);
> +
> +    KeGetCurrentProcessorNumberEx(&ProcNumber);
> +    ProcIndex = KeGetProcessorIndexFromNumber(&ProcNumber);
> +    if (Context->Active)
> +        KeInsertQueueDpc(&Context->Fdo->EvtchnDpc[ProcIndex], Context,
> NULL);
> +
> +    return TRUE;
> +}
> +
> +_IRQL_requires_(PASSIVE_LEVEL) // needed for KeFlushQueuedDpcs
> +VOID
> +EvtchnFree(
> +    __in     PXENIFACE_FDO Fdo,
> +    __inout  PXENIFACE_EVTCHN_CONTEXT Context
> +    )
> +{
> +    ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL);
> +
> +    XenIfaceDebugPrint(TRACE, "Context %p, LocalPort %d, FO %p\n",
> +                       Context, Context->LocalPort, Context->FileObject);
> +
> +    InterlockedExchange8(&Context->Active, 0);
> +
> +    XENBUS_EVTCHN(Close,
> +                  &Fdo->EvtchnInterface,
> +                  Context->Channel);
> +
> +    // There may still be a pending event at this time.
> +    // Wait for our DPCs to complete.
> +    KeFlushQueuedDpcs();
> +
> +    ObDereferenceObject(Context->Event);
> +    RtlZeroMemory(Context, sizeof(XENIFACE_EVTCHN_CONTEXT));

'sizeof' is a keyword so it really should be sizeof (), similar to if () or for 
().

> +    ExFreePoolWithTag(Context, XENIFACE_POOL_TAG);
> +}
> +
> +_Requires_exclusive_lock_held_(Fdo->EvtchnLock)
> +static
> +PXENIFACE_EVTCHN_CONTEXT
> +EvtchnFindChannel(
> +    __in      PXENIFACE_FDO Fdo,
> +    __in      ULONG         LocalPort,
> +    __in_opt  PFILE_OBJECT  FileObject
> +    )
> +{
> +    PXENIFACE_EVTCHN_CONTEXT Context, Found = NULL;
> +    PLIST_ENTRY Node;
> +
> +    Node = Fdo->EvtchnList.Flink;
> +    while (Node->Flink != Fdo->EvtchnList.Flink) {
> +        Context = CONTAINING_RECORD(Node, XENIFACE_EVTCHN_CONTEXT,
> Entry);
> +
> +        Node = Node->Flink;
> +        if (Context->LocalPort != LocalPort)
> +            continue;
> +
> +        if (FileObject != NULL && Context->FileObject != FileObject)
> +            continue;
> +
> +        Found = Context;
> +        break;
> +    }
> +
> +    return Found;
> +}
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlEvtchnBindUnbound(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __in  PFILE_OBJECT      FileObject,
> +    __out PULONG_PTR        Info
> +    )
> +{
> +    NTSTATUS status;
> +    PXENIFACE_EVTCHN_BIND_UNBOUND_IN In = Buffer;
> +    PXENIFACE_EVTCHN_BIND_UNBOUND_OUT Out = Buffer;
> +    PXENIFACE_EVTCHN_CONTEXT Context;
> +
> +    status = STATUS_INVALID_BUFFER_SIZE;
> +    if (InLen != sizeof(XENIFACE_EVTCHN_BIND_UNBOUND_IN) || OutLen !=
> sizeof(XENIFACE_EVTCHN_BIND_UNBOUND_OUT))

Break this line at the '||'.

> +        goto fail1;
> +
> +    status = STATUS_NO_MEMORY;
> +    Context = ExAllocatePoolWithTag(NonPagedPool,
> sizeof(XENIFACE_EVTCHN_CONTEXT), XENIFACE_POOL_TAG);
> +    if (Context == NULL)
> +        goto fail2;
> +
> +    RtlZeroMemory(Context, sizeof(XENIFACE_EVTCHN_CONTEXT));
> +    Context->FileObject = FileObject;
> +
> +    XenIfaceDebugPrint(TRACE, "> RemoteDomain %d, Mask %d, FO %p\n",
> +                       In->RemoteDomain, In->Mask, FileObject);
> +
> +    status = ObReferenceObjectByHandle(In->Event,
> EVENT_MODIFY_STATE, *ExEventObjectType, UserMode, &Context->Event,
> NULL);
> +    if (!NT_SUCCESS(status))
> +        goto fail3;
> +
> +    status = STATUS_UNSUCCESSFUL;
> +    Context->Channel = XENBUS_EVTCHN(Open,
> +                                     &Fdo->EvtchnInterface,
> +                                     XENBUS_EVTCHN_TYPE_UNBOUND,
> +                                     EvtchnInterruptHandler,
> +                                     Context,
> +                                     In->RemoteDomain,
> +                                     TRUE);
> +    if (Context->Channel == NULL)
> +        goto fail4;
> +
> +    Context->LocalPort = XENBUS_EVTCHN(GetPort,
> +                                       &Fdo->EvtchnInterface,
> +                                       Context->Channel);
> +
> +    Context->Fdo = Fdo;
> +
> +    ExInterlockedInsertTailList(&Fdo->EvtchnList, &Context->Entry, &Fdo-
> >EvtchnLock);
> +
> +    InterlockedExchange8(&Context->Active, 1);
> +    Out->LocalPort = Context->LocalPort;
> +    *Info = sizeof(XENIFACE_EVTCHN_BIND_UNBOUND_OUT);
> +
> +    if (!In->Mask) {
> +        XENBUS_EVTCHN(Unmask,
> +                      &Fdo->EvtchnInterface,
> +                      Context->Channel,
> +                      FALSE);
> +    }
> +
> +    XenIfaceDebugPrint(TRACE, "< LocalPort %lu, Context %p\n", Context-
> >LocalPort, Context);
> +    return STATUS_SUCCESS;
> +
> +fail4:
> +    XenIfaceDebugPrint(ERROR, "Fail4\n");
> +    ObDereferenceObject(Context->Event);
> +fail3:
> +    XenIfaceDebugPrint(ERROR, "Fail3\n");
> +    RtlZeroMemory(Context, sizeof(XENIFACE_EVTCHN_CONTEXT));
> +    ExFreePoolWithTag(Context, XENIFACE_POOL_TAG);
> +fail2:
> +    XenIfaceDebugPrint(ERROR, "Fail2\n");
> +fail1:
> +    XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
> +    return status;
> +}
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlEvtchnBindInterdomain(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __in  PFILE_OBJECT      FileObject,
> +    __out PULONG_PTR        Info
> +    )
> +{
> +    NTSTATUS status;
> +    PXENIFACE_EVTCHN_BIND_INTERDOMAIN_IN In = Buffer;
> +    PXENIFACE_EVTCHN_BIND_INTERDOMAIN_OUT Out = Buffer;
> +    PXENIFACE_EVTCHN_CONTEXT Context;
> +
> +    status = STATUS_INVALID_BUFFER_SIZE;
> +    if (InLen != sizeof(XENIFACE_EVTCHN_BIND_INTERDOMAIN_IN) ||
> OutLen != sizeof(XENIFACE_EVTCHN_BIND_INTERDOMAIN_OUT))
> +        goto fail1;
> +
> +    status = STATUS_NO_MEMORY;
> +    Context = ExAllocatePoolWithTag(NonPagedPool,
> sizeof(XENIFACE_EVTCHN_CONTEXT), XENIFACE_POOL_TAG);
> +    if (Context == NULL)
> +        goto fail2;
> +
> +    RtlZeroMemory(Context, sizeof(XENIFACE_EVTCHN_CONTEXT));
> +    Context->FileObject = FileObject;
> +
> +    XenIfaceDebugPrint(TRACE, "> RemoteDomain %d, RemotePort %lu,
> Mask %d, FO %p\n",
> +                       In->RemoteDomain, In->RemotePort, In->Mask, 
> FileObject);
> +
> +    status = ObReferenceObjectByHandle(In->Event,
> EVENT_MODIFY_STATE, *ExEventObjectType, UserMode, &Context->Event,
> NULL);
> +    if (!NT_SUCCESS(status))
> +        goto fail3;
> +
> +    status = STATUS_UNSUCCESSFUL;
> +    Context->Channel = XENBUS_EVTCHN(Open,
> +                                     &Fdo->EvtchnInterface,
> +                                     XENBUS_EVTCHN_TYPE_INTER_DOMAIN,
> +                                     EvtchnInterruptHandler,
> +                                     Context,
> +                                     In->RemoteDomain,
> +                                     In->RemotePort,
> +                                     TRUE);
> +    if (Context->Channel == NULL)
> +        goto fail4;
> +
> +    Context->LocalPort = XENBUS_EVTCHN(GetPort,
> +                                       &Fdo->EvtchnInterface,
> +                                       Context->Channel);
> +
> +    Context->Fdo = Fdo;
> +
> +    ExInterlockedInsertTailList(&Fdo->EvtchnList, &Context->Entry, &Fdo-
> >EvtchnLock);
> +
> +    InterlockedExchange8(&Context->Active, 1);
> +    Out->LocalPort = Context->LocalPort;
> +    *Info = sizeof(XENIFACE_EVTCHN_BIND_INTERDOMAIN_OUT);
> +
> +    if (!In->Mask) {
> +        XENBUS_EVTCHN(Unmask,
> +                      &Fdo->EvtchnInterface,
> +                      Context->Channel,
> +                      FALSE);
> +    }
> +
> +    XenIfaceDebugPrint(TRACE, "< LocalPort %lu, Context %p\n", Context-
> >LocalPort, Context);
> +
> +    return STATUS_SUCCESS;
> +
> +fail4:
> +    XenIfaceDebugPrint(ERROR, "Fail4\n");
> +    ObDereferenceObject(Context->Event);
> +fail3:
> +    XenIfaceDebugPrint(ERROR, "Fail3\n");
> +    RtlZeroMemory(Context, sizeof(XENIFACE_EVTCHN_CONTEXT));
> +    ExFreePoolWithTag(Context, XENIFACE_POOL_TAG);
> +fail2:
> +    XenIfaceDebugPrint(ERROR, "Fail2\n");
> +fail1:
> +    XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
> +    return status;
> +}
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlEvtchnClose(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __in  PFILE_OBJECT      FileObject
> +    )
> +{
> +    NTSTATUS status;
> +    PXENIFACE_EVTCHN_CLOSE_IN In = Buffer;
> +    PXENIFACE_EVTCHN_CONTEXT Context = NULL;
> +    KIRQL Irql;
> +
> +    status = STATUS_INVALID_BUFFER_SIZE;
> +    if (InLen != sizeof(XENIFACE_EVTCHN_CLOSE_IN) || OutLen != 0)
> +        goto fail1;
> +
> +    XenIfaceDebugPrint(TRACE, "> LocalPort %lu, FO %p\n", In->LocalPort,
> FileObject);
> +
> +    KeAcquireSpinLock(&Fdo->EvtchnLock, &Irql);
> +    Context = EvtchnFindChannel(Fdo, In->LocalPort, FileObject);
> +    if (Context != NULL)

Could you not go straight to fail2 here (and drop the lock there) and thus get 
rid of the tests for Context == or != NULL below?

> +        RemoveEntryList(&Context->Entry);
> +    KeReleaseSpinLock(&Fdo->EvtchnLock, Irql);
> +    if (Context != NULL)
> +        EvtchnFree(Fdo, Context);
> +
> +    status = STATUS_NOT_FOUND;
> +    if (Context == NULL)
> +        goto fail2;
> +
> +    return STATUS_SUCCESS;
> +
> +fail2:
> +    XenIfaceDebugPrint(ERROR, "Fail2\n");
> +fail1:
> +    XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
> +    return status;
> +}
> +
> +_Requires_lock_not_held_(Fdo->EvtchnLock)
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +EvtchnNotify(
> +    __in      PXENIFACE_FDO Fdo,
> +    __in      ULONG         LocalPort,
> +    __in_opt  PFILE_OBJECT  FileObject
> +    )
> +{
> +    NTSTATUS status;
> +    PXENIFACE_EVTCHN_CONTEXT Context = NULL;
> +    KIRQL Irql;
> +
> +    KeAcquireSpinLock(&Fdo->EvtchnLock, &Irql);
> +
> +    Context = EvtchnFindChannel(Fdo, LocalPort, FileObject);
> +
> +    status = STATUS_NOT_FOUND;
> +    if (Context == NULL)
> +        goto fail1;
> +
> +    XENBUS_EVTCHN(Send,
> +                  &Fdo->EvtchnInterface,
> +                  Context->Channel);
> +
> +    KeReleaseSpinLock(&Fdo->EvtchnLock, Irql);
> +
> +    return STATUS_SUCCESS;
> +
> +fail1:
> +    KeReleaseSpinLock(&Fdo->EvtchnLock, Irql);
> +    XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
> +    return status;
> +}
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlEvtchnNotify(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __in  PFILE_OBJECT      FileObject
> +    )
> +{
> +    NTSTATUS status;
> +    PXENIFACE_EVTCHN_NOTIFY_IN In = Buffer;
> +
> +    status = STATUS_INVALID_BUFFER_SIZE;
> +    if (InLen != sizeof(XENIFACE_EVTCHN_NOTIFY_IN) || OutLen != 0)
> +        goto fail1;
> +#if DBG
> +    XenIfaceDebugPrint(INFO, "> LocalPort %d, FO %p\n", In->LocalPort,
> FileObject);
> +#endif
> +
> +    return EvtchnNotify(Fdo, In->LocalPort, FileObject);
> +
> +fail1:
> +    XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
> +    return status;
> +}
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlEvtchnUnmask(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __in  PFILE_OBJECT      FileObject
> +    )
> +{
> +    NTSTATUS status;
> +    PXENIFACE_EVTCHN_UNMASK_IN In = Buffer;
> +    PXENIFACE_EVTCHN_CONTEXT Context = NULL;
> +    KIRQL Irql;
> +
> +    status = STATUS_INVALID_BUFFER_SIZE;
> +    if (InLen != sizeof(XENIFACE_EVTCHN_UNMASK_IN) || OutLen != 0)
> +        goto fail1;
> +
> +    XenIfaceDebugPrint(TRACE, "> LocalPort %d, FO %p\n", In->LocalPort,
> FileObject);
> +
> +    KeAcquireSpinLock(&Fdo->EvtchnLock, &Irql);
> +
> +    Context = EvtchnFindChannel(Fdo, In->LocalPort, FileObject);
> +
> +    status = STATUS_INVALID_PARAMETER;
> +    if (Context == NULL)
> +        goto fail2;
> +
> +    XENBUS_EVTCHN(Unmask,
> +                  &Fdo->EvtchnInterface,
> +                  Context->Channel,
> +                  FALSE);
> +
> +    KeReleaseSpinLock(&Fdo->EvtchnLock, Irql);
> +
> +    return STATUS_SUCCESS;
> +
> +fail2:
> +    KeReleaseSpinLock(&Fdo->EvtchnLock, Irql);
> +    XenIfaceDebugPrint(ERROR, "Fail2\n");
> +
> +fail1:
> +    XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
> +    return status;
> +}
> diff --git a/src/xeniface/ioctl_gnttab.c b/src/xeniface/ioctl_gnttab.c
> new file mode 100644
> index 0000000..a279b77
> --- /dev/null
> +++ b/src/xeniface/ioctl_gnttab.c
> @@ -0,0 +1,765 @@
> +/* Copyright (c) Citrix Systems Inc.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms,
> + * with or without modification, are permitted provided
> + * that the following conditions are met:
> + *
> + * *   Redistributions of source code must retain the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer.
> + * *   Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer in the documentation and/or other
> + *     materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#include "driver.h"
> +#include "ioctls.h"
> +#include "..\..\include\xeniface_ioctls.h"

Use <> too.

> +#include "log.h"
> +#include "irp_queue.h"
> +
> +// Complete a canceled gnttab IRP, cleanup associated grant/map.
> +_Function_class_(IO_WORKITEM_ROUTINE)
> +VOID
> +CompleteGnttabIrp(
> +    __in      PDEVICE_OBJECT DeviceObject,
> +    __in_opt  PVOID          Context
> +    )
> +{
> +    PXENIFACE_DX Dx = (PXENIFACE_DX)DeviceObject->DeviceExtension;
> +    PXENIFACE_FDO Fdo = Dx->Fdo;
> +    PIRP Irp = Context;
> +    PXENIFACE_CONTEXT_ID Id;
> +    PIO_WORKITEM WorkItem;
> +    KAPC_STATE ApcState;
> +    BOOLEAN ChangeProcess;
> +
> +    ASSERT(Context != NULL);
> +
> +    Id = Irp->Tail.Overlay.DriverContext[0];
> +    WorkItem = Irp->Tail.Overlay.DriverContext[1];
> +
> +    // We are not guaranteed to be in the context of the process that
> initiated the IRP,
> +    // but we need to be there to unmap memory.
> +    ChangeProcess = PsGetCurrentProcess() != Id->Process;
> +    if (ChangeProcess) {
> +        XenIfaceDebugPrint(TRACE, "Changing process from %p to %p\n",
> PsGetCurrentProcess(), Id->Process);
> +        KeStackAttachProcess(Id->Process, &ApcState);
> +    }
> +
> +    XenIfaceDebugPrint(TRACE, "Irp %p, Process %p, Id %lu, Type %d, IRQL
> %d\n",
> +                       Irp, Id->Process, Id->RequestId, Id->Type, 
> KeGetCurrentIrql());
> +
> +    switch (Id->Type) {
> +
> +    case XENIFACE_CONTEXT_GRANT:
> +        GnttabFreeGrant(Fdo, CONTAINING_RECORD(Id,
> XENIFACE_GRANT_CONTEXT, Id));
> +        break;
> +
> +    case XENIFACE_CONTEXT_MAP:
> +        GnttabFreeMap(Fdo, CONTAINING_RECORD(Id,
> XENIFACE_MAP_CONTEXT, Id));
> +        break;
> +
> +    default:
> +        ASSERT(FALSE);
> +    }
> +
> +    if (ChangeProcess)
> +        KeUnstackDetachProcess(&ApcState);
> +
> +    IoFreeWorkItem(WorkItem);
> +
> +    Irp->IoStatus.Status = STATUS_CANCELLED;
> +    Irp->IoStatus.Information = 0;
> +    IoCompleteRequest(Irp, IO_NO_INCREMENT);
> +}
> +
> +_Acquires_exclusive_lock_(((PXENIFACE_FDO)Argument)-
> >GnttabCacheLock)
> +_IRQL_requires_(DISPATCH_LEVEL)
> +VOID
> +GnttabAcquireLock(
> +    __in  PVOID Argument
> +    )
> +{
> +    PXENIFACE_FDO Fdo = Argument;
> +
> +    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
> +
> +    KeAcquireSpinLockAtDpcLevel(&Fdo->GnttabCacheLock);
> +}
> +
> +_Releases_exclusive_lock_(((PXENIFACE_FDO)Argument)-
> >GnttabCacheLock)
> +_IRQL_requires_(DISPATCH_LEVEL)
> +VOID
> +GnttabReleaseLock(
> +    __in  PVOID Argument
> +    )
> +{
> +    PXENIFACE_FDO Fdo = Argument;
> +
> +    ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL);
> +
> +    KeReleaseSpinLockFromDpcLevel(&Fdo->GnttabCacheLock);
> +}
> +
> +_Requires_lock_not_held_(Fdo->IrpQueueLock)
> +static
> +PIRP
> +FindGnttabIrp(
> +    __in  PXENIFACE_FDO Fdo,
> +    __in  PXENIFACE_CONTEXT_ID Id
> +    )
> +{
> +    KIRQL Irql;
> +    PIRP Irp;
> +
> +    CsqAcquireLock(&Fdo->IrpQueue, &Irql);
> +    Irp = CsqPeekNextIrp(&Fdo->IrpQueue, NULL, Id);
> +    CsqReleaseLock(&Fdo->IrpQueue, Irql);
> +    return Irp;
> +}
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlGnttabPermitForeignAccess(
> +    __in     PXENIFACE_FDO  Fdo,
> +    __in     PVOID          Buffer,
> +    __in     ULONG          InLen,
> +    __in     ULONG          OutLen,
> +    __inout  PIRP           Irp
> +    )
> +{
> +    NTSTATUS status;
> +    PXENIFACE_GNTTAB_PERMIT_FOREIGN_ACCESS_IN In = Buffer;
> +    PXENIFACE_GRANT_CONTEXT Context;
> +    ULONG Page;
> +
> +    status = STATUS_INVALID_BUFFER_SIZE;
> +    if (InLen != sizeof(XENIFACE_GNTTAB_PERMIT_FOREIGN_ACCESS_IN) ||
> OutLen != 0)
> +        goto fail1;
> +
> +    status = STATUS_INVALID_PARAMETER;
> +    if ((In->NumberPages == 0) || (In->NumberPages > 1024 * 1024) ||
> +        ((In->Flags & XENIFACE_GNTTAB_USE_NOTIFY_OFFSET) && (In-
> >NotifyOffset >= In->NumberPages * PAGE_SIZE))
> +        )
> +        goto fail2;
> +
> +    status = STATUS_NO_MEMORY;
> +    Context = ExAllocatePoolWithTag(NonPagedPool,
> sizeof(XENIFACE_GRANT_CONTEXT), XENIFACE_POOL_TAG);
> +    if (Context == NULL)
> +        goto fail3;
> +
> +    RtlZeroMemory(Context, sizeof(XENIFACE_GRANT_CONTEXT));
> +    Context->Id.Type = XENIFACE_CONTEXT_GRANT;
> +    Context->Id.Process = PsGetCurrentProcess();

Careful. I don't think Wndows guarantees that METHOD_BUFFERED ioctls will be 
handled in the issuers process context. See the sentence:

" After the I/O manager has created a system-space buffer for the driver, the 
requesting user-mode thread can be swapped out and its physical memory can be 
reused by another thread, possibly by a thread belonging to another process."

at 
https://msdn.microsoft.com/en-us/library/windows/hardware/ff565356%28v=vs.85%29.aspx.

You should probably consider using METHOD_NEITHER. That may also allow you to 
play tricks like injecting the results of the operation into the user-space 
buffer without completing the ioctl possibly negating the need for a 'get 
results' ioctl.

  Paul

> +    Context->Id.RequestId = In->RequestId;
> +    Context->RemoteDomain = In->RemoteDomain;
> +    Context->NumberPages = In->NumberPages;
> +    Context->Flags = In->Flags;
> +    Context->NotifyOffset = In->NotifyOffset;
> +    Context->NotifyPort = In->NotifyPort;
> +
> +    XenIfaceDebugPrint(TRACE, "> RemoteDomain %d, NumberPages %lu,
> Flags 0x%x, Offset 0x%x, Port %d, Process %p, Id %lu\n",
> +                       Context->RemoteDomain, Context->NumberPages, Context-
> >Flags, Context->NotifyOffset, Context->NotifyPort,
> +                       Context->Id.Process, Context->Id.RequestId);
> +
> +    // Check if the request ID is unique.
> +    // This doesn't protect us from simultaneous requests with the same ID
> arriving here
> +    // but another check for duplicate ID is performed when the context/IRP
> is queued at the end.
> +    // Ideally we would lock the whole section but that's not really an 
> option
> since we touch user memory.
> +    status = STATUS_INVALID_PARAMETER;
> +    if (FindGnttabIrp(Fdo, &Context->Id) != NULL)
> +        goto fail4;
> +
> +    status = STATUS_NO_MEMORY;
> +    Context->Grants = ExAllocatePoolWithTag(NonPagedPool, Context-
> >NumberPages * sizeof(PXENBUS_GNTTAB_ENTRY),
> XENIFACE_POOL_TAG);
> +    if (Context->Grants == NULL)
> +        goto fail5;
> +
> +    RtlZeroMemory(Context->Grants, Context->NumberPages *
> sizeof(PXENBUS_GNTTAB_ENTRY));
> +
> +    // allocate memory to share
> +    status = STATUS_NO_MEMORY;
> +    Context->KernelVa = ExAllocatePoolWithTag(NonPagedPool, Context-
> >NumberPages * PAGE_SIZE, XENIFACE_POOL_TAG);
> +    if (Context->KernelVa == NULL)
> +        goto fail6;
> +
> +    RtlZeroMemory(Context->KernelVa, Context->NumberPages *
> PAGE_SIZE);
> +    Context->Mdl = IoAllocateMdl(Context->KernelVa, Context-
> >NumberPages * PAGE_SIZE, FALSE, FALSE, NULL);
> +    if (Context->Mdl == NULL)
> +        goto fail7;
> +
> +    MmBuildMdlForNonPagedPool(Context->Mdl);
> +    ASSERT(MmGetMdlByteCount(Context->Mdl) == Context-
> >NumberPages * PAGE_SIZE);
> +
> +    // perform sharing
> +    for (Page = 0; Page < Context->NumberPages; Page++) {
> +        status = XENBUS_GNTTAB(PermitForeignAccess,
> +                               &Fdo->GnttabInterface,
> +                               Fdo->GnttabCache,
> +                               FALSE,
> +                               Context->RemoteDomain,
> +                               MmGetMdlPfnArray(Context->Mdl)[Page],
> +                               (Context->Flags & XENIFACE_GNTTAB_READONLY) 
> != 0,
> +                               &(Context->Grants[Page]));
> +
> +// prefast somehow thinks that this call can modify Page...
> +#pragma prefast(suppress:6385)
> +        XenIfaceDebugPrint(INFO, "Grants[%lu] = %p\n", Page, Context-
> >Grants[Page]);
> +        if (!NT_SUCCESS(status))
> +            goto fail8;
> +    }
> +
> +    // map into user mode
> +#pragma prefast(suppress:6320) // we want to catch all exceptions
> +    __try {
> +        Context->UserVa = MmMapLockedPagesSpecifyCache(Context->Mdl,
> UserMode, MmCached, NULL, FALSE, NormalPagePriority);
> +    }
> +    __except (EXCEPTION_EXECUTE_HANDLER) {
> +        status = GetExceptionCode();
> +        goto fail9;
> +    }
> +
> +    status = STATUS_UNSUCCESSFUL;
> +    if (Context->UserVa == NULL)
> +        goto fail10;
> +
> +    XenIfaceDebugPrint(TRACE, "< Context %p, Irp %p, KernelVa %p, UserVa
> %p\n", Context, Irp, Context->KernelVa, Context->UserVa);
> +
> +    // Insert the IRP/context into the pending queue.
> +    // This also checks (again) if the request ID is unique.
> +    Irp->Tail.Overlay.DriverContext[0] = &Context->Id;
> +    status = IoCsqInsertIrpEx(&Fdo->IrpQueue, Irp, NULL, &Context->Id);
> +    if (!NT_SUCCESS(status))
> +        goto fail11;
> +
> +    return STATUS_PENDING;
> +
> +fail11:
> +    XenIfaceDebugPrint(ERROR, "Fail11\n");
> +    MmUnmapLockedPages(Context->UserVa, Context->Mdl);
> +
> +fail10:
> +    XenIfaceDebugPrint(ERROR, "Fail10\n");
> +
> +fail9:
> +    XenIfaceDebugPrint(ERROR, "Fail9\n");
> +
> +fail8:
> +    XenIfaceDebugPrint(ERROR, "Fail8: Page = %lu\n", Page);
> +
> +    while (Page > 0) {
> +        ASSERT(NT_SUCCESS(XENBUS_GNTTAB(RevokeForeignAccess,
> +                                        &Fdo->GnttabInterface,
> +                                        Fdo->GnttabCache,
> +                                        FALSE,
> +                                        Context->Grants[Page - 1])));
> +
> +        --Page;
> +    }
> +    IoFreeMdl(Context->Mdl);
> +
> +fail7:
> +    XenIfaceDebugPrint(ERROR, "Fail7\n");
> +    ExFreePoolWithTag(Context->KernelVa, XENIFACE_POOL_TAG);
> +
> +fail6:
> +    XenIfaceDebugPrint(ERROR, "Fail6\n");
> +    ExFreePoolWithTag(Context->Grants, XENIFACE_POOL_TAG);
> +
> +fail5:
> +    XenIfaceDebugPrint(ERROR, "Fail5\n");
> +
> +fail4:
> +    XenIfaceDebugPrint(ERROR, "Fail4\n");
> +    RtlZeroMemory(Context, sizeof(XENIFACE_GRANT_CONTEXT));
> +    ExFreePoolWithTag(Context, XENIFACE_POOL_TAG);
> +
> +fail3:
> +    XenIfaceDebugPrint(ERROR, "Fail3\n");
> +
> +fail2:
> +    XenIfaceDebugPrint(ERROR, "Fail2\n");
> +
> +fail1:
> +    XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
> +    return status;
> +}
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlGnttabGetGrantResult(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __out PULONG_PTR        Info
> +    )
> +{
> +    NTSTATUS status;
> +    PXENIFACE_GNTTAB_GET_GRANT_RESULT_IN In = Buffer;
> +    PXENIFACE_GNTTAB_GET_GRANT_RESULT_OUT Out = Buffer;
> +    XENIFACE_CONTEXT_ID Id;
> +    KIRQL Irql;
> +    PIRP Irp;
> +    PXENIFACE_CONTEXT_ID ContextId;
> +    PXENIFACE_GRANT_CONTEXT Context;
> +
> +    status = STATUS_INVALID_BUFFER_SIZE;
> +    if (InLen != sizeof(XENIFACE_GNTTAB_GET_GRANT_RESULT_IN))
> +        goto fail1;
> +
> +    Id.Process = PsGetCurrentProcess();
> +    Id.RequestId = In->RequestId;
> +    Id.Type = XENIFACE_CONTEXT_GRANT;
> +
> +    XenIfaceDebugPrint(TRACE, "> Process %p, Id %lu\n", Id.Process,
> Id.RequestId);
> +
> +    CsqAcquireLock(&Fdo->IrpQueue, &Irql);
> +    Irp = CsqPeekNextIrp(&Fdo->IrpQueue, NULL, &Id);
> +
> +    status = STATUS_NOT_FOUND;
> +    if (Irp == NULL)
> +        goto fail2;
> +
> +    ContextId = Irp->Tail.Overlay.DriverContext[0];
> +    Context = CONTAINING_RECORD(ContextId,
> XENIFACE_GRANT_CONTEXT, Id);
> +
> +    status = STATUS_INVALID_BUFFER_SIZE;
> +    if (OutLen != (sizeof(XENIFACE_GNTTAB_GET_GRANT_RESULT_OUT) +
> sizeof(ULONG) * Context->NumberPages))
> +        goto fail3;
> +
> +    Out->Address = Context->UserVa;
> +    XenIfaceDebugPrint(TRACE, "< Address %p, Irp %p\n", Context->UserVa,
> Irp);
> +
> +    for (ULONG Page = 0; Page < Context->NumberPages; Page++) {
> +        Out->References[Page] = XENBUS_GNTTAB(GetReference,
> +                                              &Fdo->GnttabInterface,
> +                                              Context->Grants[Page]);
> +        XenIfaceDebugPrint(INFO, "Ref[%lu] = %lu\n", Page, Out-
> >References[Page]);
> +    }
> +
> +    CsqReleaseLock(&Fdo->IrpQueue, Irql);
> +    *Info = OutLen;
> +
> +    return STATUS_SUCCESS;
> +
> +fail3:
> +    XenIfaceDebugPrint(ERROR, "Fail3\n");
> +fail2:
> +    XenIfaceDebugPrint(ERROR, "Fail2\n");
> +    CsqReleaseLock(&Fdo->IrpQueue, Irql);
> +fail1:
> +    XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
> +    return status;
> +}
> +
> +_IRQL_requires_max_(APC_LEVEL)
> +VOID
> +GnttabFreeGrant(
> +    __in     PXENIFACE_FDO Fdo,
> +    __inout  PXENIFACE_GRANT_CONTEXT Context
> +)
> +{
> +    NTSTATUS status;
> +    ULONG Page;
> +
> +    ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
> +
> +    XenIfaceDebugPrint(TRACE, "Context %p\n", Context);
> +
> +    if (Context->Flags & XENIFACE_GNTTAB_USE_NOTIFY_OFFSET) {
> +        ((PCHAR)Context->KernelVa)[Context->NotifyOffset] = 0;
> +    }
> +
> +    if (Context->Flags & XENIFACE_GNTTAB_USE_NOTIFY_PORT) {
> +        status = EvtchnNotify(Fdo, Context->NotifyPort, NULL);
> +
> +        if (!NT_SUCCESS(status)) // non-fatal, we must free memory
> +            XenIfaceDebugPrint(ERROR, "failed to notify port %lu: 0x%x\n",
> Context->NotifyPort, status);
> +    }
> +
> +    // unmap from user address space
> +    MmUnmapLockedPages(Context->UserVa, Context->Mdl);
> +
> +    // stop sharing
> +    for (Page = 0; Page < Context->NumberPages; Page++) {
> +        status = XENBUS_GNTTAB(RevokeForeignAccess,
> +                               &Fdo->GnttabInterface,
> +                               Fdo->GnttabCache,
> +                               FALSE,
> +                               Context->Grants[Page]);
> +
> +        ASSERT(NT_SUCCESS(status)); // failure here is fatal, something
> must've gone catastrophically wrong
> +    }
> +
> +    IoFreeMdl(Context->Mdl);
> +
> +    RtlZeroMemory(Context->KernelVa, Context->NumberPages *
> PAGE_SIZE);
> +    ExFreePoolWithTag(Context->KernelVa, XENIFACE_POOL_TAG);
> +
> +    RtlZeroMemory(Context->Grants, Context->NumberPages *
> sizeof(PXENBUS_GNTTAB_ENTRY));
> +    ExFreePoolWithTag(Context->Grants, XENIFACE_POOL_TAG);
> +
> +    RtlZeroMemory(Context, sizeof(XENIFACE_GRANT_CONTEXT));
> +    ExFreePoolWithTag(Context, XENIFACE_POOL_TAG);
> +}
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlGnttabRevokeForeignAccess(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen
> +    )
> +{
> +    NTSTATUS status;
> +    PXENIFACE_GNTTAB_REVOKE_FOREIGN_ACCESS_IN In = Buffer;
> +    PXENIFACE_GRANT_CONTEXT Context = NULL;
> +    XENIFACE_CONTEXT_ID Id;
> +    PIRP PendingIrp;
> +    PXENIFACE_CONTEXT_ID ContextId;
> +
> +    status = STATUS_INVALID_BUFFER_SIZE;
> +    if (InLen != sizeof(XENIFACE_GNTTAB_REVOKE_FOREIGN_ACCESS_IN))
> +        goto fail1;
> +
> +    Id.Type = XENIFACE_CONTEXT_GRANT;
> +    Id.Process = PsGetCurrentProcess();
> +    Id.RequestId = In->RequestId;
> +
> +    XenIfaceDebugPrint(TRACE, "> Process %p, Id %lu\n", Id.Process,
> Id.RequestId);
> +
> +    status = STATUS_NOT_FOUND;
> +    PendingIrp = IoCsqRemoveNextIrp(&Fdo->IrpQueue, &Id);
> +    if (PendingIrp == NULL)
> +        goto fail2;
> +
> +    ContextId = PendingIrp->Tail.Overlay.DriverContext[0];
> +    Context = CONTAINING_RECORD(ContextId,
> XENIFACE_GRANT_CONTEXT, Id);
> +    GnttabFreeGrant(Fdo, Context);
> +
> +    PendingIrp->IoStatus.Status = STATUS_SUCCESS;
> +    PendingIrp->IoStatus.Information = 0;
> +    IoCompleteRequest(PendingIrp, IO_NO_INCREMENT);
> +
> +    return STATUS_SUCCESS;
> +
> +fail2:
> +    XenIfaceDebugPrint(ERROR, "Fail2\n");
> +fail1:
> +    XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
> +    return status;
> +}
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlGnttabMapForeignPages(
> +    __in     PXENIFACE_FDO     Fdo,
> +    __in     PVOID             Buffer,
> +    __in     ULONG             InLen,
> +    __in     ULONG             OutLen,
> +    __inout  PIRP           Irp
> +    )
> +{
> +    NTSTATUS status;
> +    PXENIFACE_GNTTAB_MAP_FOREIGN_PAGES_IN In = Buffer;
> +    PXENIFACE_MAP_CONTEXT Context;
> +
> +    status = STATUS_INVALID_BUFFER_SIZE;
> +    if (InLen < sizeof(XENIFACE_GNTTAB_MAP_FOREIGN_PAGES_IN) ||
> OutLen != 0)
> +        goto fail1;
> +
> +    status = STATUS_INVALID_PARAMETER;
> +    if ((In->NumberPages == 0) || (In->NumberPages > 1024 * 1024) ||
> +        ((In->Flags & XENIFACE_GNTTAB_USE_NOTIFY_OFFSET) && (In-
> >NotifyOffset >= In->NumberPages * PAGE_SIZE))
> +        )
> +        goto fail2;
> +
> +    status = STATUS_INVALID_BUFFER_SIZE;
> +    if (InLen != sizeof(XENIFACE_GNTTAB_MAP_FOREIGN_PAGES_IN) +
> sizeof(ULONG) * In->NumberPages)
> +        goto fail3;
> +
> +    status = STATUS_NO_MEMORY;
> +    Context = ExAllocatePoolWithTag(NonPagedPool,
> sizeof(XENIFACE_MAP_CONTEXT), XENIFACE_POOL_TAG);
> +    if (Context == NULL)
> +        goto fail4;
> +
> +    RtlZeroMemory(Context, sizeof(XENIFACE_MAP_CONTEXT));
> +    Context->Id.Type = XENIFACE_CONTEXT_MAP;
> +    Context->Id.Process = PsGetCurrentProcess();
> +    Context->Id.RequestId = In->RequestId;
> +    Context->RemoteDomain = In->RemoteDomain;
> +    Context->NumberPages = In->NumberPages;
> +    Context->Flags = In->Flags;
> +    Context->NotifyOffset = In->NotifyOffset;
> +    Context->NotifyPort = In->NotifyPort;
> +
> +    XenIfaceDebugPrint(TRACE, "> RemoteDomain %d, NumberPages %lu,
> Flags 0x%x, Offset 0x%x, Port %d, Process %p, Id %lu\n",
> +                       Context->RemoteDomain, Context->NumberPages, Context-
> >Flags, Context->NotifyOffset, Context->NotifyPort,
> +                       Context->Id.Process, Context->Id.RequestId);
> +
> +    for (ULONG i = 0; i < In->NumberPages; i++)
> +        XenIfaceDebugPrint(INFO, "> Ref %d\n", In->References[i]);
> +
> +    status = STATUS_INVALID_PARAMETER;
> +    if (FindGnttabIrp(Fdo, &Context->Id) != NULL)
> +        goto fail5;
> +
> +    status = XENBUS_GNTTAB(MapForeignPages,
> +                           &Fdo->GnttabInterface,
> +                           Context->RemoteDomain,
> +                           Context->NumberPages,
> +                           In->References,
> +                           Context->Flags & XENIFACE_GNTTAB_READONLY,
> +                           &Context->Address);
> +
> +    if (!NT_SUCCESS(status))
> +        goto fail6;
> +
> +    status = STATUS_NO_MEMORY;
> +    Context->KernelVa = MmMapIoSpace(Context->Address, Context-
> >NumberPages * PAGE_SIZE, MmCached);
> +    if (Context->KernelVa == NULL)
> +        goto fail7;
> +
> +    status = STATUS_NO_MEMORY;
> +    Context->Mdl = IoAllocateMdl(Context->KernelVa, Context-
> >NumberPages * PAGE_SIZE, FALSE, FALSE, NULL);
> +    if (Context->Mdl == NULL)
> +        goto fail8;
> +
> +    MmBuildMdlForNonPagedPool(Context->Mdl);
> +
> +    // map into user mode
> +#pragma prefast(suppress: 6320) // we want to catch all exceptions
> +    __try {
> +        Context->UserVa = MmMapLockedPagesSpecifyCache(Context->Mdl,
> UserMode, MmCached, NULL, FALSE, NormalPagePriority);
> +    }
> +    __except (EXCEPTION_EXECUTE_HANDLER) {
> +        status = GetExceptionCode();
> +        goto fail9;
> +    }
> +
> +    status = STATUS_UNSUCCESSFUL;
> +    if (Context->UserVa == NULL)
> +        goto fail10;
> +
> +    XenIfaceDebugPrint(TRACE, "< Context %p, Irp %p, Address %p, KernelVa
> %p, UserVa %p\n",
> +                       Context, Irp, Context->Address, Context->KernelVa, 
> Context-
> >UserVa);
> +
> +    // Insert the IRP/context into the pending queue.
> +    // This also checks (again) if the request ID is unique.
> +    Irp->Tail.Overlay.DriverContext[0] = &Context->Id;
> +    status = IoCsqInsertIrpEx(&Fdo->IrpQueue, Irp, NULL, &Context->Id);
> +    if (!NT_SUCCESS(status))
> +        goto fail11;
> +
> +    return STATUS_PENDING;
> +
> +fail11:
> +    XenIfaceDebugPrint(ERROR, "Fail11\n");
> +    MmUnmapLockedPages(Context->UserVa, Context->Mdl);
> +
> +fail10:
> +    XenIfaceDebugPrint(ERROR, "Fail10\n");
> +
> +fail9:
> +    XenIfaceDebugPrint(ERROR, "Fail9\n");
> +    IoFreeMdl(Context->Mdl);
> +
> +fail8:
> +    XenIfaceDebugPrint(ERROR, "Fail8\n");
> +    MmUnmapIoSpace(Context->KernelVa, Context->NumberPages *
> PAGE_SIZE);
> +
> +fail7:
> +    XenIfaceDebugPrint(ERROR, "Fail7\n");
> +    ASSERT(NT_SUCCESS(XENBUS_GNTTAB(UnmapForeignPages,
> +                                    &Fdo->GnttabInterface,
> +                                    Context->Address
> +                                    )));
> +
> +fail6:
> +    XenIfaceDebugPrint(ERROR, "Fail6\n");
> +
> +fail5:
> +    XenIfaceDebugPrint(ERROR, "Fail5\n");
> +    RtlZeroMemory(Context, sizeof(XENIFACE_MAP_CONTEXT));
> +    ExFreePoolWithTag(Context, XENIFACE_POOL_TAG);
> +
> +fail4:
> +    XenIfaceDebugPrint(ERROR, "Fail4\n");
> +
> +fail3:
> +    XenIfaceDebugPrint(ERROR, "Fail3\n");
> +
> +fail2:
> +    XenIfaceDebugPrint(ERROR, "Fail2\n");
> +
> +fail1:
> +    XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
> +    return status;
> +}
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlGnttabGetMapResult(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __out PULONG_PTR        Info
> +    )
> +{
> +    NTSTATUS status;
> +    PXENIFACE_GNTTAB_GET_MAP_RESULT_IN In = Buffer;
> +    PXENIFACE_GNTTAB_GET_MAP_RESULT_OUT Out = Buffer;
> +    XENIFACE_CONTEXT_ID Id;
> +    KIRQL Irql;
> +    PIRP Irp;
> +    PXENIFACE_MAP_CONTEXT Context;
> +    PXENIFACE_CONTEXT_ID ContextId;
> +
> +    status = STATUS_INVALID_BUFFER_SIZE;
> +    if (InLen != sizeof(XENIFACE_GNTTAB_GET_MAP_RESULT_IN) || OutLen
> != sizeof(XENIFACE_GNTTAB_GET_MAP_RESULT_OUT))
> +        goto fail1;
> +
> +    Id.Type = XENIFACE_CONTEXT_MAP;
> +    Id.Process = PsGetCurrentProcess();
> +    Id.RequestId = In->RequestId;
> +
> +    XenIfaceDebugPrint(TRACE, "> Process %p, Id %lu\n", Id.Process,
> Id.RequestId);
> +
> +    CsqAcquireLock(&Fdo->IrpQueue, &Irql);
> +    Irp = CsqPeekNextIrp(&Fdo->IrpQueue, NULL, &Id);
> +
> +    status = STATUS_NOT_FOUND;
> +    if (Irp == NULL)
> +        goto fail2;
> +
> +    ContextId = Irp->Tail.Overlay.DriverContext[0];
> +    Context = CONTAINING_RECORD(ContextId, XENIFACE_MAP_CONTEXT,
> Id);
> +
> +    Out->Address = Context->UserVa;
> +    XenIfaceDebugPrint(TRACE, "< Address %p, Irp %p\n", Context->UserVa,
> Irp);
> +
> +    CsqReleaseLock(&Fdo->IrpQueue, Irql);
> +    *Info = OutLen;
> +
> +    return STATUS_SUCCESS;
> +
> +fail2:
> +    XenIfaceDebugPrint(ERROR, "Fail2\n");
> +    CsqReleaseLock(&Fdo->IrpQueue, Irql);
> +fail1:
> +    XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
> +    return status;
> +}
> +
> +_IRQL_requires_max_(APC_LEVEL)
> +DECLSPEC_NOINLINE
> +VOID
> +GnttabFreeMap(
> +    __in     PXENIFACE_FDO Fdo,
> +    __inout  PXENIFACE_MAP_CONTEXT Context
> +    )
> +{
> +    NTSTATUS status;
> +
> +    ASSERT(KeGetCurrentIrql() <= APC_LEVEL);
> +
> +    XenIfaceDebugPrint(TRACE, "Context %p\n", Context);
> +
> +    if (Context->Flags & XENIFACE_GNTTAB_USE_NOTIFY_OFFSET) {
> +        ((PCHAR)Context->KernelVa)[Context->NotifyOffset] = 0;
> +    }
> +
> +    if (Context->Flags & XENIFACE_GNTTAB_USE_NOTIFY_PORT) {
> +        status = EvtchnNotify(Fdo, Context->NotifyPort, NULL);
> +
> +        if (!NT_SUCCESS(status)) // non-fatal, we must free memory
> +            XenIfaceDebugPrint(ERROR, "failed to notify port %lu: 0x%x\n",
> Context->NotifyPort, status);
> +    }
> +
> +    // unmap from user address space
> +    MmUnmapLockedPages(Context->UserVa, Context->Mdl);
> +
> +    IoFreeMdl(Context->Mdl);
> +
> +    // unmap from system space
> +    MmUnmapIoSpace(Context->KernelVa, Context->NumberPages *
> PAGE_SIZE);
> +
> +    // undo mapping
> +    status = XENBUS_GNTTAB(UnmapForeignPages,
> +                           &Fdo->GnttabInterface,
> +                           Context->Address);
> +
> +    ASSERT(NT_SUCCESS(status));
> +
> +    RtlZeroMemory(Context, sizeof(XENIFACE_MAP_CONTEXT));
> +    ExFreePoolWithTag(Context, XENIFACE_POOL_TAG);
> +}
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlGnttabUnmapForeignPages(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen
> +    )
> +{
> +    NTSTATUS status;
> +    PXENIFACE_GNTTAB_UNMAP_FOREIGN_PAGES_IN In = Buffer;
> +    PXENIFACE_MAP_CONTEXT Context = NULL;
> +    XENIFACE_CONTEXT_ID Id;
> +    PIRP PendingIrp;
> +    PXENIFACE_CONTEXT_ID ContextId;
> +
> +    status = STATUS_INVALID_BUFFER_SIZE;
> +    if (InLen != sizeof(XENIFACE_GNTTAB_UNMAP_FOREIGN_PAGES_IN) &&
> OutLen != 0)
> +        goto fail1;
> +
> +    Id.Type = XENIFACE_CONTEXT_MAP;
> +    Id.Process = PsGetCurrentProcess();
> +    Id.RequestId = In->RequestId;
> +
> +    XenIfaceDebugPrint(TRACE, "> Process %p, Id %lu\n", Id.Process,
> Id.RequestId);
> +
> +    status = STATUS_NOT_FOUND;
> +    PendingIrp = IoCsqRemoveNextIrp(&Fdo->IrpQueue, &Id);
> +    if (PendingIrp == NULL)
> +        goto fail2;
> +
> +    ContextId = PendingIrp->Tail.Overlay.DriverContext[0];
> +    Context = CONTAINING_RECORD(ContextId, XENIFACE_MAP_CONTEXT,
> Id);
> +    GnttabFreeMap(Fdo, Context);
> +
> +    PendingIrp->IoStatus.Status = STATUS_SUCCESS;
> +    PendingIrp->IoStatus.Information = 0;
> +    IoCompleteRequest(PendingIrp, IO_NO_INCREMENT);
> +
> +    return STATUS_SUCCESS;
> +
> +fail2:
> +    XenIfaceDebugPrint(ERROR, "Fail2\n");
> +fail1:
> +    XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
> +    return status;
> +}
> diff --git a/src/xeniface/ioctl_store.c b/src/xeniface/ioctl_store.c
> new file mode 100644
> index 0000000..181c706
> --- /dev/null
> +++ b/src/xeniface/ioctl_store.c
> @@ -0,0 +1,574 @@
> +/* Copyright (c) Citrix Systems Inc.
> + * All rights reserved.
> + *
> + * Redistribution and use in source and binary forms,
> + * with or without modification, are permitted provided
> + * that the following conditions are met:
> + *
> + * *   Redistributions of source code must retain the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer.
> + * *   Redistributions in binary form must reproduce the above
> + *     copyright notice, this list of conditions and the
> + *     following disclaimer in the documentation and/or other
> + *     materials provided with the distribution.
> + *
> + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
> + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
> + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
> + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
> + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
> + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
> + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
> + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
> + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
> + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
> + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
> + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
> + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
> + * SUCH DAMAGE.
> + */
> +
> +#include "driver.h"
> +#include "ioctls.h"
> +#include "..\..\include\xeniface_ioctls.h"
> +#include "log.h"
> +
> +#define XENSTORE_ABS_PATH_MAX 3072
> +#define XENSTORE_REL_PATH_MAX 2048
> +
> +static
> +NTSTATUS
> +__CaptureUserBuffer(
> +    __in  PVOID Buffer,
> +    __in  ULONG Length,
> +    __out PVOID *CapturedBuffer
> +    )
> +{
> +    NTSTATUS Status;
> +    PVOID TempBuffer = NULL;
> +
> +    if (Length == 0) {
> +        *CapturedBuffer = NULL;
> +        return STATUS_SUCCESS;
> +    }
> +
> +    Status = STATUS_NO_MEMORY;
> +    TempBuffer = ExAllocatePoolWithTag(NonPagedPool, Length,
> XENIFACE_POOL_TAG);
> +    if (TempBuffer == NULL)
> +        return STATUS_INSUFFICIENT_RESOURCES;
> +
> +    Status = STATUS_SUCCESS;
> +
> +#pragma prefast(suppress: 6320) // we want to catch all exceptions
> +    try {
> +        ProbeForRead(Buffer, Length, 1);
> +        RtlCopyMemory(TempBuffer, Buffer, Length);
> +    } except(EXCEPTION_EXECUTE_HANDLER) {
> +        XenIfaceDebugPrint(ERROR, "Exception while probing/reading buffer at
> %p, size 0x%lx\n", Buffer, Length);
> +        ExFreePoolWithTag(TempBuffer, XENIFACE_POOL_TAG);
> +        TempBuffer = NULL;
> +        Status = GetExceptionCode();
> +    }
> +
> +    *CapturedBuffer = TempBuffer;
> +
> +    return Status;
> + }
> +
> +static
> +VOID
> +__FreeCapturedBuffer(
> +    __in  PVOID CapturedBuffer
> +    )
> +{
> +    if (CapturedBuffer != NULL) {
> +        ExFreePoolWithTag(CapturedBuffer, XENIFACE_POOL_TAG);
> +    }
> +}
> +
> +static FORCEINLINE
> +BOOLEAN
> +__IsValidStr(
> +    __in  PCHAR             Str,
> +    __in  ULONG             Len
> +    )
> +{
> +    for ( ; Len--; ++Str) {
> +        if (*Str == '\0')
> +            return TRUE;
> +        if (!isprint((unsigned char)*Str))
> +            break;
> +    }
> +    return FALSE;
> +}
> +
> +static FORCEINLINE
> +ULONG
> +__MultiSzLen(
> +    __in  PCHAR             Str,
> +    __out PULONG            Count
> +    )
> +{
> +    ULONG Length = 0;
> +    if (Count)  *Count = 0;
> +    do {
> +        for ( ; *Str; ++Str, ++Length) ;
> +        ++Str; ++Length;
> +        if (*Count) ++(*Count);
> +    } while (*Str);
> +    return Length;
> +}
> +
> +static FORCEINLINE
> +VOID
> +__DisplayMultiSz(
> +    __in PCHAR              Caller,
> +    __in PCHAR              Str
> +    )
> +{
> +    PCHAR   Ptr;
> +    ULONG   Idx;
> +    ULONG   Len;
> +
> +    for (Ptr = Str, Idx = 0; *Ptr; ++Idx) {
> +        Len = (ULONG)strlen(Ptr);
> +        XenIfaceDebugPrint(TRACE, "|%s: [%d]=(%d)->\"%s\"\n", Caller, Idx,
> Len, Ptr);
> +        Ptr += (Len + 1);
> +    }
> +}
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlStoreRead(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PCHAR             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __out PULONG_PTR        Info
> +    )
> +{
> +    NTSTATUS    status;
> +    PCHAR       Value;
> +    ULONG       Length;
> +
> +    status = STATUS_INVALID_BUFFER_SIZE;
> +    if (InLen == 0)
> +        goto fail1;
> +
> +    status = STATUS_INVALID_PARAMETER;
> +    if (!__IsValidStr(Buffer, InLen))
> +        goto fail2;
> +
> +    status = XENBUS_STORE(Read, &Fdo->StoreInterface, NULL, NULL,
> Buffer, &Value);
> +    if (!NT_SUCCESS(status))
> +        goto fail3;
> +
> +    Length = (ULONG)strlen(Value) + 1;
> +
> +    status = STATUS_BUFFER_OVERFLOW;
> +    if (OutLen == 0) {
> +        XenIfaceDebugPrint(TRACE, "(\"%s\")=(%d)\n", Buffer, Length);
> +        goto done;
> +    }
> +
> +    status = STATUS_INVALID_PARAMETER;
> +    if (OutLen < Length)
> +        goto fail4;
> +
> +    XenIfaceDebugPrint(TRACE, "(\"%s\")=(%d)->\"%s\"\n", Buffer, Length,
> Value);
> +
> +    RtlCopyMemory(Buffer, Value, Length);
> +    Buffer[Length - 1] = 0;
> +    status = STATUS_SUCCESS;
> +
> +done:
> +    *Info = (ULONG_PTR)Length;
> +    XENBUS_STORE(Free, &Fdo->StoreInterface, Value);
> +    return status;
> +
> +fail4:
> +    XenIfaceDebugPrint(ERROR, "Fail4 (\"%s\")=(%d < %d)\n", Buffer,
> OutLen, Length);
> +    XENBUS_STORE(Free, &Fdo->StoreInterface, Value);
> +fail3:
> +    XenIfaceDebugPrint(ERROR, "Fail3 (\"%s\")\n", Buffer);
> +fail2:
> +    XenIfaceDebugPrint(ERROR, "Fail2\n");
> +fail1:
> +    XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
> +    return status;
> +}
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlStoreWrite(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PCHAR             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen
> +    )
> +{
> +    NTSTATUS    status;
> +    PCHAR       Value;
> +    ULONG       Length;
> +
> +    status = STATUS_INVALID_BUFFER_SIZE;
> +    if (InLen == 0 || OutLen != 0)
> +        goto fail1;
> +
> +    status = STATUS_INVALID_PARAMETER;
> +    if (!__IsValidStr(Buffer, InLen))
> +        goto fail2;
> +
> +    Length = (ULONG)strlen(Buffer) + 1;
> +    Value = Buffer + Length;
> +
> +    if (!__IsValidStr(Value, InLen - Length))
> +        goto fail3;
> +
> +    status = XENBUS_STORE(Printf, &Fdo->StoreInterface, NULL, NULL,
> Buffer, Value);
> +    if (!NT_SUCCESS(status))
> +        goto fail4;
> +
> +    XenIfaceDebugPrint(TRACE, "(\"%s\"=\"%s\")\n", Buffer, Value);
> +    return status;
> +
> +fail4:
> +    XenIfaceDebugPrint(ERROR, "Fail4 (\"%s\")\n", Value);
> +fail3:
> +    XenIfaceDebugPrint(ERROR, "Fail3 (\"%s\")\n", Buffer);
> +fail2:
> +    XenIfaceDebugPrint(ERROR, "Fail2\n");
> +fail1:
> +    XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
> +    return status;
> +}
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlStoreDirectory(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PCHAR             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __out PULONG_PTR        Info
> +    )
> +{
> +    NTSTATUS    status;
> +    PCHAR       Value;
> +    ULONG       Length;
> +    ULONG       Count;
> +
> +    status = STATUS_INVALID_BUFFER_SIZE;
> +    if (InLen == 0)
> +        goto fail1;
> +
> +    status = STATUS_INVALID_PARAMETER;
> +    if (!__IsValidStr(Buffer, InLen))
> +        goto fail2;
> +
> +    status = XENBUS_STORE(Directory, &Fdo->StoreInterface, NULL, NULL,
> Buffer, &Value);
> +    if (!NT_SUCCESS(status))
> +        goto fail3;
> +
> +    Length = __MultiSzLen(Value, &Count) + 1;
> +
> +    status = STATUS_BUFFER_OVERFLOW;
> +    if (OutLen == 0) {
> +        XenIfaceDebugPrint(TRACE, "(\"%s\")=(%d)(%d)\n", Buffer, Length,
> Count);
> +        goto done;
> +    }
> +
> +    status = STATUS_INVALID_PARAMETER;
> +    if (OutLen < Length)
> +        goto fail4;
> +
> +    XenIfaceDebugPrint(INFO, "(\"%s\")=(%d)(%d)\n", Buffer, Length,
> Count);
> +#if DBG
> +    __DisplayMultiSz(__FUNCTION__, Value);
> +#endif
> +
> +    RtlCopyMemory(Buffer, Value, Length);
> +    Buffer[Length - 2] = 0;
> +    Buffer[Length - 1] = 0;
> +    status = STATUS_SUCCESS;
> +
> +done:
> +    *Info = (ULONG_PTR)Length;
> +    XENBUS_STORE(Free, &Fdo->StoreInterface, Value);
> +    return status;
> +
> +fail4:
> +    XenIfaceDebugPrint(ERROR, "Fail4 (\"%s\")=(%d < %d)\n", Buffer,
> OutLen, Length);
> +    XENBUS_STORE(Free, &Fdo->StoreInterface, Value);
> +fail3:
> +    XenIfaceDebugPrint(ERROR, "Fail3 (\"%s\")\n", Buffer);
> +fail2:
> +    XenIfaceDebugPrint(ERROR, "Fail2\n");
> +fail1:
> +    XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
> +    return status;
> +}
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlStoreRemove(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PCHAR             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen
> +    )
> +{
> +    NTSTATUS    status;
> +
> +    status = STATUS_INVALID_BUFFER_SIZE;
> +    if (InLen == 0 || OutLen != 0)
> +        goto fail1;
> +
> +    status = STATUS_INVALID_PARAMETER;
> +    if (!__IsValidStr(Buffer, InLen))
> +        goto fail2;
> +
> +    status = XENBUS_STORE(Remove, &Fdo->StoreInterface, NULL, NULL,
> Buffer);
> +    if (!NT_SUCCESS(status))
> +        goto fail3;
> +
> +    XenIfaceDebugPrint(TRACE, "(\"%s\")\n", Buffer);
> +    return status;
> +
> +fail3:
> +    XenIfaceDebugPrint(ERROR, "Fail3 (\"%s\")\n", Buffer);
> +fail2:
> +    XenIfaceDebugPrint(ERROR, "Fail2\n");
> +fail1:
> +    XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
> +    return status;
> +}
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlStoreSetPermissions(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen
> +    )
> +{
> +    NTSTATUS status;
> +    PXENIFACE_STORE_SET_PERMISSIONS_IN In = Buffer;
> +    ULONG Index;
> +    PCHAR Path;
> +
> +    status = STATUS_INVALID_BUFFER_SIZE;
> +    if (InLen < sizeof(XENIFACE_STORE_SET_PERMISSIONS_IN) || OutLen !=
> 0)
> +        goto fail1;
> +
> +    if (InLen < sizeof(XENIFACE_STORE_SET_PERMISSIONS_IN) + In-
> >NumberPermissions * sizeof(XENBUS_STORE_PERMISSION))
> +        goto fail2;
> +
> +    status = STATUS_INVALID_PARAMETER;
> +    if (In->PathLength == 0 || In->PathLength > XENSTORE_ABS_PATH_MAX)
> +        goto fail3;
> +
> +    status = __CaptureUserBuffer(In->Path, In->PathLength, &Path);
> +    if (!NT_SUCCESS(status))
> +        goto fail4;
> +
> +    Path[In->PathLength - 1] = 0;
> +    XenIfaceDebugPrint(TRACE, "> Path '%s', NumberPermissions %lu\n",
> Path, In->NumberPermissions);
> +
> +    for (Index = 0; Index < In->NumberPermissions; Index++) {
> +        XenIfaceDebugPrint(TRACE, "> %lu: Domain %d, Mask 0x%x\n", Index,
> In->Permissions[Index].Domain, In->Permissions[Index].Mask);
> +        if ((In->Permissions[Index].Mask &
> ~XENIFACE_STORE_ALLOWED_PERMISSIONS) != 0)
> +            goto fail5;
> +    }
> +
> +    status = XENBUS_STORE(PermissionsSet,
> +                          &Fdo->StoreInterface,
> +                          NULL, // transaction
> +                          NULL, // prefix
> +                          Path,
> +                          In->Permissions,
> +                          In->NumberPermissions);
> +
> +    if (!NT_SUCCESS(status))
> +        goto fail6;
> +
> +    __FreeCapturedBuffer(Path);
> +    return status;
> +
> +fail6:
> +    XenIfaceDebugPrint(ERROR, "Fail6\n");
> +fail5:
> +    XenIfaceDebugPrint(ERROR, "Fail5\n");
> +    __FreeCapturedBuffer(Path);
> +fail4:
> +    XenIfaceDebugPrint(ERROR, "Fail4\n");
> +fail3:
> +    XenIfaceDebugPrint(ERROR, "Fail3\n");
> +fail2:
> +    XenIfaceDebugPrint(ERROR, "Fail2\n");
> +fail1:
> +    XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
> +    return status;
> +}
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlStoreAddWatch(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __in  PFILE_OBJECT      FileObject,
> +    __out PULONG_PTR        Info
> +    )
> +{
> +    NTSTATUS status;
> +    PXENIFACE_STORE_ADD_WATCH_IN In = Buffer;
> +    PXENIFACE_STORE_ADD_WATCH_OUT Out = Buffer;
> +    PCHAR Path;
> +    PXENIFACE_STORE_CONTEXT Context;
> +
> +    status = STATUS_INVALID_BUFFER_SIZE;
> +    if (InLen != sizeof(XENIFACE_STORE_ADD_WATCH_IN) || OutLen !=
> sizeof(XENIFACE_STORE_ADD_WATCH_OUT))
> +        goto fail1;
> +
> +    status = STATUS_INVALID_PARAMETER;
> +    if (In->PathLength == 0 || In->PathLength > XENSTORE_ABS_PATH_MAX)
> +        goto fail2;
> +
> +    status = __CaptureUserBuffer(In->Path, In->PathLength, &Path);
> +    if (!NT_SUCCESS(status))
> +        goto fail3;
> +
> +    Path[In->PathLength - 1] = 0;
> +
> +    status = STATUS_NO_MEMORY;
> +    Context = ExAllocatePoolWithTag(NonPagedPool,
> sizeof(XENIFACE_STORE_CONTEXT), XENIFACE_POOL_TAG);
> +    if (Context == NULL)
> +        goto fail4;
> +
> +    RtlZeroMemory(Context, sizeof(XENIFACE_STORE_CONTEXT));
> +
> +    Context->FileObject = FileObject;
> +
> +    status = ObReferenceObjectByHandle(In->Event,
> EVENT_MODIFY_STATE, *ExEventObjectType, UserMode, &Context->Event,
> NULL);
> +    if (!NT_SUCCESS(status))
> +        goto fail5;
> +
> +    XenIfaceDebugPrint(TRACE, "> Path '%s', Event %p, FO %p\n", Path, In-
> >Event, FileObject);
> +
> +    status = XENBUS_STORE(WatchAdd,
> +                          &Fdo->StoreInterface,
> +                          NULL, // prefix
> +                          Path,
> +                          Context->Event,
> +                          &Context->Watch);
> +
> +    if (!NT_SUCCESS(status))
> +        goto fail6;
> +
> +    __FreeCapturedBuffer(Path);
> +
> +    ExInterlockedInsertTailList(&Fdo->StoreWatchList, &Context->Entry,
> &Fdo->StoreWatchLock);
> +
> +    XenIfaceDebugPrint(TRACE, "< Context %p, Watch %p\n", Context,
> Context->Watch);
> +
> +    Out->Context = Context;
> +    *Info = sizeof(XENIFACE_STORE_ADD_WATCH_OUT);
> +
> +    return status;
> +
> +fail6:
> +    XenIfaceDebugPrint(ERROR, "Fail6\n");
> +    ObDereferenceObject(Context->Event);
> +fail5:
> +    XenIfaceDebugPrint(ERROR, "Fail5\n");
> +    RtlZeroMemory(Context, sizeof(XENIFACE_STORE_CONTEXT));
> +    ExFreePoolWithTag(Context, XENIFACE_POOL_TAG);
> +fail4:
> +    XenIfaceDebugPrint(ERROR, "Fail4\n");
> +    __FreeCapturedBuffer(Path);
> +fail3:
> +    XenIfaceDebugPrint(ERROR, "Fail3\n");
> +fail2:
> +    XenIfaceDebugPrint(ERROR, "Fail2\n");
> +fail1:
> +    XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
> +    return status;
> +}
> +
> +_IRQL_requires_max_(DISPATCH_LEVEL)
> +VOID
> +StoreFreeWatch(
> +    __in     PXENIFACE_FDO Fdo,
> +    __inout  PXENIFACE_STORE_CONTEXT Context
> +    )
> +{
> +    NTSTATUS status;
> +
> +    XenIfaceDebugPrint(TRACE, "Context %p, Watch %p, FO %p\n",
> +                       Context, Context->Watch, Context->FileObject);
> +
> +    status = XENBUS_STORE(WatchRemove,
> +                          &Fdo->StoreInterface,
> +                          Context->Watch);
> +
> +    ASSERT(NT_SUCCESS(status)); // this is fatal since we'd leave an active
> watch without cleaning it up
> +
> +    ObDereferenceObject(Context->Event);
> +    RtlZeroMemory(Context, sizeof(XENIFACE_STORE_CONTEXT));
> +    ExFreePoolWithTag(Context, XENIFACE_POOL_TAG);
> +}
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlStoreRemoveWatch(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __in  PFILE_OBJECT      FileObject
> +    )
> +{
> +    NTSTATUS status;
> +    PXENIFACE_STORE_REMOVE_WATCH_IN In = Buffer;
> +    PXENIFACE_STORE_CONTEXT Context = NULL;
> +    KIRQL Irql;
> +    PLIST_ENTRY Node;
> +
> +    status = STATUS_INVALID_BUFFER_SIZE;
> +    if (InLen != sizeof(XENIFACE_STORE_REMOVE_WATCH_IN) || OutLen !=
> 0)
> +        goto fail1;
> +
> +    XenIfaceDebugPrint(TRACE, "> Context %p, FO %p\n", In->Context,
> FileObject);
> +
> +    KeAcquireSpinLock(&Fdo->StoreWatchLock, &Irql);
> +    Node = Fdo->StoreWatchList.Flink;
> +    while (Node->Flink != Fdo->StoreWatchList.Flink) {
> +        Context = CONTAINING_RECORD(Node, XENIFACE_STORE_CONTEXT,
> Entry);
> +
> +        Node = Node->Flink;
> +        if (Context != In->Context || Context->FileObject != FileObject)
> +            continue;
> +
> +        RemoveEntryList(&Context->Entry);
> +        break;
> +    }
> +    KeReleaseSpinLock(&Fdo->StoreWatchLock, Irql);
> +
> +    status = STATUS_NOT_FOUND;
> +    if (Context == NULL || Context != In->Context)
> +        goto fail2;
> +
> +    StoreFreeWatch(Fdo, Context);
> +
> +    return STATUS_SUCCESS;
> +
> +fail2:
> +    XenIfaceDebugPrint(ERROR, "Fail2\n");
> +fail1:
> +    XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
> +    return status;
> +}
> diff --git a/src/xeniface/ioctls.c b/src/xeniface/ioctls.c
> index 3bef9ea..e20b7dc 100644
> --- a/src/xeniface/ioctls.c
> +++ b/src/xeniface/ioctls.c
> @@ -35,287 +35,156 @@
>  #include "..\..\include\xeniface_ioctls.h"
>  #include "log.h"
> 
> -static FORCEINLINE BOOLEAN
> -__IsValidStr(
> -    __in  PCHAR             Str,
> -    __in  ULONG             Len
> -    )
> -{
> -    for ( ; Len--; ++Str) {
> -        if (*Str == '\0')
> -            return TRUE;
> -        if (!isprint((unsigned char)*Str))
> -            break;
> -    }
> -    return FALSE;
> -}
> -static FORCEINLINE ULONG
> -__MultiSzLen(
> -    __in  PCHAR             Str,
> -    __out PULONG            Count
> -    )
> -{
> -    ULONG Length = 0;
> -    if (Count)  *Count = 0;
> -    do {
> -        for ( ; *Str; ++Str, ++Length) ;
> -        ++Str; ++Length;
> -        if (*Count) ++(*Count);
> -    } while (*Str);
> -    return Length;
> -}
> -static FORCEINLINE VOID
> -__DisplayMultiSz(
> -    __in PCHAR              Caller,
> -    __in PCHAR              Str
> -    )
> -{
> -    PCHAR   Ptr;
> -    ULONG   Idx;
> -    ULONG   Len;
> -
> -    for (Ptr = Str, Idx = 0; *Ptr; ++Idx) {
> -        Len = (ULONG)strlen(Ptr);
> -        XenIfaceDebugPrint(INFO, "|%s: [%d]=(%d)->\"%s\"\n", Caller, Idx,
> Len, Ptr);
> -        Ptr += (Len + 1);
> -    }
> -}
> -
> -
> -static DECLSPEC_NOINLINE NTSTATUS
> -IoctlRead(
> +// Cleanup store watches and event channels, called on file object close.
> +_IRQL_requires_(PASSIVE_LEVEL) // EvtchnFree calls KeFlushQueuedDpcs
> +VOID
> +XenIfaceCleanup(
>      __in  PXENIFACE_FDO         Fdo,
> -    __in  PCHAR             Buffer,
> -    __in  ULONG             InLen,
> -    __in  ULONG             OutLen,
> -    __out PULONG_PTR        Info
> +    __in  PFILE_OBJECT  FileObject
>      )
>  {
> -    NTSTATUS    status;
> -    PCHAR       Value;
> -    ULONG       Length;
> -
> -    status = STATUS_INVALID_BUFFER_SIZE;
> -    if (InLen == 0)
> -        goto fail1;
> -
> -    status = STATUS_INVALID_PARAMETER;
> -    if (!__IsValidStr(Buffer, InLen))
> -        goto fail2;
> -
> -    status = XENBUS_STORE(Read, &Fdo->StoreInterface, NULL, NULL,
> Buffer, &Value);
> -    if (!NT_SUCCESS(status))
> -        goto fail3;
> -
> -    Length = (ULONG)strlen(Value) + 1;
> -
> -    status = STATUS_BUFFER_OVERFLOW;
> -    if (OutLen == 0) {
> -        XenIfaceDebugPrint(INFO, "|%s: (\"%s\")=(%d)\n", __FUNCTION__,
> Buffer, Length);
> -        goto done;
> +    PLIST_ENTRY Node;
> +    PXENIFACE_STORE_CONTEXT StoreContext;
> +    PXENIFACE_EVTCHN_CONTEXT EvtchnContext;
> +    KIRQL Irql;
> +    LIST_ENTRY ToFree;
> +
> +    XenIfaceDebugPrint(TRACE, "FO %p, IRQL %d, Cpu %lu\n", FileObject,
> KeGetCurrentIrql(), KeGetCurrentProcessorNumber());
> +
> +    // store watches
> +    KeAcquireSpinLock(&Fdo->StoreWatchLock, &Irql);
> +    Node = Fdo->StoreWatchList.Flink;
> +    while (Node->Flink != Fdo->StoreWatchList.Flink) {
> +        StoreContext = CONTAINING_RECORD(Node,
> XENIFACE_STORE_CONTEXT, Entry);
> +
> +        Node = Node->Flink;
> +        if (StoreContext->FileObject != FileObject)
> +            continue;
> +
> +        XenIfaceDebugPrint(TRACE, "Store context %p\n", StoreContext);
> +        RemoveEntryList(&StoreContext->Entry);
> +        StoreFreeWatch(Fdo, StoreContext);
>      }
> +    KeReleaseSpinLock(&Fdo->StoreWatchLock, Irql);
> 
> -    status = STATUS_INVALID_PARAMETER;
> -    if (OutLen < Length)
> -        goto fail4;
> -
> -    XenIfaceDebugPrint(INFO, "|%s: (\"%s\")=(%d)->\"%s\"\n",
> __FUNCTION__, Buffer, Length, Value);
> -
> -    RtlCopyMemory(Buffer, Value, Length);
> -    Buffer[Length - 1] = 0;
> -    status = STATUS_SUCCESS;
> +    // event channels
> +    InitializeListHead(&ToFree);
> +    KeAcquireSpinLock(&Fdo->EvtchnLock, &Irql);
> +    Node = Fdo->EvtchnList.Flink;
> +    while (Node->Flink != Fdo->EvtchnList.Flink) {
> +        EvtchnContext = CONTAINING_RECORD(Node,
> XENIFACE_EVTCHN_CONTEXT, Entry);
> +
> +        Node = Node->Flink;
> +        if (EvtchnContext->FileObject != FileObject)
> +            continue;
> +
> +        XenIfaceDebugPrint(TRACE, "Evtchn context %p\n", EvtchnContext);
> +        RemoveEntryList(&EvtchnContext->Entry);
> +        // EvtchnFree requires PASSIVE_LEVEL and we're inside a lock
> +        InsertTailList(&ToFree, &EvtchnContext->Entry);
> +    }
> +    KeReleaseSpinLock(&Fdo->EvtchnLock, Irql);
> 
> -done:
> -    *Info = (ULONG_PTR)Length;
> -    XENBUS_STORE(Free, &Fdo->StoreInterface, Value);
> -    return status;
> +    Node = ToFree.Flink;
> +    while (Node->Flink != ToFree.Flink) {
> +        EvtchnContext = CONTAINING_RECORD(Node,
> XENIFACE_EVTCHN_CONTEXT, Entry);
> +        Node = Node->Flink;
> 
> -fail4:
> -    XenIfaceDebugPrint(ERROR, "|%s: Fail4 (\"%s\")=(%d < %d)\n",
> __FUNCTION__, Buffer, OutLen, Length);
> -    XENBUS_STORE(Free, &Fdo->StoreInterface, Value);
> -fail3:
> -    XenIfaceDebugPrint(ERROR, "|%s: Fail3 (\"%s\")\n", __FUNCTION__,
> Buffer);
> -fail2:
> -    XenIfaceDebugPrint(ERROR, "|%s: Fail2\n", __FUNCTION__);
> -fail1:
> -    XenIfaceDebugPrint(ERROR, "|%s: Fail1 (%08x)\n", __FUNCTION__,
> status);
> -    return status;
> +        RemoveEntryList(&EvtchnContext->Entry);
> +        EvtchnFree(Fdo, EvtchnContext);
>  }
> -
> -static DECLSPEC_NOINLINE NTSTATUS
> -IoctlWrite(
> -    __in  PXENIFACE_FDO         Fdo,
> -    __in  PCHAR             Buffer,
> -    __in  ULONG             InLen,
> -    __in  ULONG             OutLen
> -    )
> -{
> -    NTSTATUS    status;
> -    PCHAR       Value;
> -    ULONG       Length;
> -
> -    status = STATUS_INVALID_BUFFER_SIZE;
> -    if (InLen == 0 || OutLen != 0)
> -        goto fail1;
> -
> -    status = STATUS_INVALID_PARAMETER;
> -    if (!__IsValidStr(Buffer, InLen))
> -        goto fail2;
> -
> -    Length = (ULONG)strlen(Buffer) + 1;
> -    Value = Buffer + Length;
> -
> -    if (!__IsValidStr(Value, InLen - Length))
> -        goto fail3;
> -
> -    status = XENBUS_STORE(Printf, &Fdo->StoreInterface, NULL, NULL,
> Buffer, Value);
> -    if (!NT_SUCCESS(status))
> -        goto fail4;
> -
> -    XenIfaceDebugPrint(INFO, "|%s: (\"%s\"=\"%s\")\n", __FUNCTION__,
> Buffer, Value);
> -    return status;
> -
> -fail4:
> -    XenIfaceDebugPrint(ERROR, "|%s: Fail4 (\"%s\")\n", __FUNCTION__,
> Value);
> -fail3:
> -    XenIfaceDebugPrint(ERROR, "|%s: Fail3 (\"%s\")\n", __FUNCTION__,
> Buffer);
> -fail2:
> -    XenIfaceDebugPrint(ERROR, "|%s: Fail2\n", __FUNCTION__);
> -fail1:
> -    XenIfaceDebugPrint(ERROR, "|%s: Fail1 (%08x)\n", __FUNCTION__,
> status);
> -    return status;
>  }
> 
> -static DECLSPEC_NOINLINE NTSTATUS
> -IoctlDirectory(
> +NTSTATUS
> +XenIfaceIoctl(
>      __in  PXENIFACE_FDO         Fdo,
> -    __in  PCHAR             Buffer,
> -    __in  ULONG             InLen,
> -    __in  ULONG             OutLen,
> -    __out PULONG_PTR        Info
> +    __inout  PIRP              Irp
>      )
>  {
>      NTSTATUS    status;
> -    PCHAR       Value;
> -    ULONG       Length;
> -    ULONG       Count;
> -
> -    status = STATUS_INVALID_BUFFER_SIZE;
> -    if (InLen == 0)
> -        goto fail1;
> -
> -    status = STATUS_INVALID_PARAMETER;
> -    if (!__IsValidStr(Buffer, InLen))
> -        goto fail2;
> -
> -    status = XENBUS_STORE(Directory, &Fdo->StoreInterface, NULL, NULL,
> Buffer, &Value);
> -    if (!NT_SUCCESS(status))
> -        goto fail3;
> -
> -    Length = __MultiSzLen(Value, &Count) + 1;
> +    PIO_STACK_LOCATION  Stack = IoGetCurrentIrpStackLocation(Irp);
> +    PVOID               Buffer = Irp->AssociatedIrp.SystemBuffer;
> +    ULONG               InLen = Stack-
> >Parameters.DeviceIoControl.InputBufferLength;
> +    ULONG               OutLen = Stack-
> >Parameters.DeviceIoControl.OutputBufferLength;
> 
> -    status = STATUS_BUFFER_OVERFLOW;
> -    if (OutLen == 0) {
> -        XenIfaceDebugPrint(INFO, "|%s: (\"%s\")=(%d)(%d)\n",
> __FUNCTION__, Buffer, Length, Count);
> +    status = STATUS_DEVICE_NOT_READY;
> +    if (Fdo->InterfacesAcquired == FALSE)
>          goto done;
> -    }
> 
> -    status = STATUS_INVALID_PARAMETER;
> -    if (OutLen < Length)
> -        goto fail4;
> +    switch (Stack->Parameters.DeviceIoControl.IoControlCode) {
> +        // store
> +    case IOCTL_XENIFACE_STORE_READ:
> +        status = IoctlStoreRead(Fdo, (PCHAR)Buffer, InLen, OutLen, &Irp-
> >IoStatus.Information);
> +        break;
> 
> -    XenIfaceDebugPrint(INFO, "|%s: (\"%s\")=(%d)(%d)\n", __FUNCTION__,
> Buffer, Length, Count);
> -#if DBG
> -    __DisplayMultiSz(__FUNCTION__, Value);
> -#endif
> +    case IOCTL_XENIFACE_STORE_WRITE:
> +        status = IoctlStoreWrite(Fdo, (PCHAR)Buffer, InLen, OutLen);
> +        break;
> 
> -    RtlCopyMemory(Buffer, Value, Length);
> -    Buffer[Length - 2] = 0;
> -    Buffer[Length - 1] = 0;
> -    status = STATUS_SUCCESS;
> +    case IOCTL_XENIFACE_STORE_DIRECTORY:
> +        status = IoctlStoreDirectory(Fdo, (PCHAR)Buffer, InLen, OutLen, &Irp-
> >IoStatus.Information);
> +        break;
> 
> -done:
> -    *Info = (ULONG_PTR)Length;
> -    XENBUS_STORE(Free, &Fdo->StoreInterface, Value);
> -    return status;
> +    case IOCTL_XENIFACE_STORE_REMOVE:
> +        status = IoctlStoreRemove(Fdo, (PCHAR)Buffer, InLen, OutLen);
> +        break;
> 
> -fail4:
> -    XenIfaceDebugPrint(ERROR, "|%s: Fail4 (\"%s\")=(%d < %d)\n",
> __FUNCTION__, Buffer, OutLen, Length);
> -    XENBUS_STORE(Free, &Fdo->StoreInterface, Value);
> -fail3:
> -    XenIfaceDebugPrint(ERROR, "|%s: Fail3 (\"%s\")\n", __FUNCTION__,
> Buffer);
> -fail2:
> -    XenIfaceDebugPrint(ERROR, "|%s: Fail2\n", __FUNCTION__);
> -fail1:
> -    XenIfaceDebugPrint(ERROR, "|%s: Fail1 (%08x)\n", __FUNCTION__,
> status);
> -    return status;
> -}
> +    case IOCTL_XENIFACE_STORE_SET_PERMISSIONS:
> +        status = IoctlStoreSetPermissions(Fdo, Buffer, InLen, OutLen);
> +        break;
> 
> -static DECLSPEC_NOINLINE NTSTATUS
> -IoctlRemove(
> -    __in  PXENIFACE_FDO         Fdo,
> -    __in  PCHAR             Buffer,
> -    __in  ULONG             InLen,
> -    __in  ULONG             OutLen
> -    )
> -{
> -    NTSTATUS    status;
> +    case IOCTL_XENIFACE_STORE_ADD_WATCH:
> +        status = IoctlStoreAddWatch(Fdo, Buffer, InLen, OutLen, Stack-
> >FileObject, &Irp->IoStatus.Information);
> +        break;
> 
> -    status = STATUS_INVALID_BUFFER_SIZE;
> -    if (InLen == 0 || OutLen != 0)
> -        goto fail1;
> +    case IOCTL_XENIFACE_STORE_REMOVE_WATCH:
> +        status = IoctlStoreRemoveWatch(Fdo, Buffer, InLen, OutLen, Stack-
> >FileObject);
> +        break;
> 
> -    status = STATUS_INVALID_PARAMETER;
> -    if (!__IsValidStr(Buffer, InLen))
> -        goto fail2;
> +        // evtchn
> +    case IOCTL_XENIFACE_EVTCHN_BIND_UNBOUND:
> +        status = IoctlEvtchnBindUnbound(Fdo, Buffer, InLen, OutLen, Stack-
> >FileObject, &Irp->IoStatus.Information);
> +        break;
> 
> -    status = XENBUS_STORE(Remove, &Fdo->StoreInterface, NULL, NULL,
> Buffer);
> -    if (!NT_SUCCESS(status))
> -        goto fail3;
> +    case IOCTL_XENIFACE_EVTCHN_BIND_INTERDOMAIN:
> +        status = IoctlEvtchnBindInterdomain(Fdo, Buffer, InLen, OutLen, 
> Stack-
> >FileObject, &Irp->IoStatus.Information);
> +        break;
> 
> -    XenIfaceDebugPrint(INFO, "|%s: (\"%s\")\n", __FUNCTION__, Buffer);
> -    return status;
> +    case IOCTL_XENIFACE_EVTCHN_CLOSE:
> +        status = IoctlEvtchnClose(Fdo, Buffer, InLen, OutLen, Stack-
> >FileObject);
> +        break;
> 
> -fail3:
> -    XenIfaceDebugPrint(ERROR, "|%s: Fail3 (\"%s\")\n", __FUNCTION__,
> Buffer);
> -fail2:
> -    XenIfaceDebugPrint(ERROR, "|%s: Fail2\n", __FUNCTION__);
> -fail1:
> -    XenIfaceDebugPrint(ERROR, "|%s: Fail1 (%08x)\n", __FUNCTION__,
> status);
> -    return status;
> -}
> +    case IOCTL_XENIFACE_EVTCHN_NOTIFY:
> +        status = IoctlEvtchnNotify(Fdo, Buffer, InLen, OutLen, Stack-
> >FileObject);
> +        break;
> 
> -NTSTATUS
> -XenIFaceIoctl(
> -    __in  PXENIFACE_FDO         Fdo,
> -    __in  PIRP              Irp
> -    )
> -{
> -    NTSTATUS            status;
> -    PIO_STACK_LOCATION  Stack = IoGetCurrentIrpStackLocation(Irp);
> -    PVOID               Buffer = Irp->AssociatedIrp.SystemBuffer;
> -    ULONG               InLen = Stack-
> >Parameters.DeviceIoControl.InputBufferLength;
> -    ULONG               OutLen = Stack-
> >Parameters.DeviceIoControl.OutputBufferLength;
> +    case IOCTL_XENIFACE_EVTCHN_UNMASK:
> +        status = IoctlEvtchnUnmask(Fdo, Buffer, InLen, OutLen, Stack-
> >FileObject);
> +        break;
> 
> -    status = STATUS_DEVICE_NOT_READY;
> -    if (Fdo->InterfacesAcquired == FALSE)
> -        goto done;
> +        // gnttab
> +    case IOCTL_XENIFACE_GNTTAB_PERMIT_FOREIGN_ACCESS:
> +        status = IoctlGnttabPermitForeignAccess(Fdo, Buffer, InLen, OutLen,
> Irp);
> +        break;
> 
> -    switch (Stack->Parameters.DeviceIoControl.IoControlCode) {
> -    case IOCTL_XENIFACE_STORE_READ:
> -        status = IoctlRead(Fdo, (PCHAR)Buffer, InLen, OutLen, &Irp-
> >IoStatus.Information);
> +    case IOCTL_XENIFACE_GNTTAB_GET_GRANT_RESULT:
> +        status = IoctlGnttabGetGrantResult(Fdo, Buffer, InLen, OutLen, &Irp-
> >IoStatus.Information);
>          break;
> 
> -    case IOCTL_XENIFACE_STORE_WRITE:
> -        status = IoctlWrite(Fdo, (PCHAR)Buffer, InLen, OutLen);
> +    case IOCTL_XENIFACE_GNTTAB_REVOKE_FOREIGN_ACCESS:
> +        status = IoctlGnttabRevokeForeignAccess(Fdo, Buffer, InLen, OutLen);
>          break;
> 
> -    case IOCTL_XENIFACE_STORE_DIRECTORY:
> -        status = IoctlDirectory(Fdo, (PCHAR)Buffer, InLen, OutLen, &Irp-
> >IoStatus.Information);
> +    case IOCTL_XENIFACE_GNTTAB_MAP_FOREIGN_PAGES:
> +        status = IoctlGnttabMapForeignPages(Fdo, Buffer, InLen, OutLen, Irp);
>          break;
> 
> -    case IOCTL_XENIFACE_STORE_REMOVE:
> -        status = IoctlRemove(Fdo, (PCHAR)Buffer, InLen, OutLen);
> +    case IOCTL_XENIFACE_GNTTAB_GET_MAP_RESULT:
> +        status = IoctlGnttabGetMapResult(Fdo, Buffer, InLen, OutLen, &Irp-
> >IoStatus.Information);
> +        break;
> +
> +    case IOCTL_XENIFACE_GNTTAB_UNMAP_FOREIGN_PAGES:
> +        status = IoctlGnttabUnmapForeignPages(Fdo, Buffer, InLen, OutLen);
>          break;
> 
>      default:
> @@ -327,6 +196,7 @@ done:
> 
>       Irp->IoStatus.Status = status;
> 
> +    if (status != STATUS_PENDING)
>       IoCompleteRequest(Irp, IO_NO_INCREMENT);
> 
>      return status;
> diff --git a/src/xeniface/ioctls.h b/src/xeniface/ioctls.h
> index 7ee7801..00e11e4 100644
> --- a/src/xeniface/ioctls.h
> +++ b/src/xeniface/ioctls.h
> @@ -33,11 +33,322 @@
>  #define _IOCTLS_H_
> 
>  #define XENIFACE_KERNEL_MODE
> +#include "xeniface_ioctls.h"
> 
> +typedef enum _XENIFACE_CONTEXT_TYPE {
> +    XENIFACE_CONTEXT_GRANT = 1,
> +    XENIFACE_CONTEXT_MAP
> +} XENIFACE_CONTEXT_TYPE;
> +
> +typedef struct _XENIFACE_CONTEXT_ID {
> +    XENIFACE_CONTEXT_TYPE  Type;
> +    ULONG                  RequestId;
> +    PEPROCESS              Process;
> +} XENIFACE_CONTEXT_ID, *PXENIFACE_CONTEXT_ID;
> +
> +typedef struct _XENIFACE_STORE_CONTEXT {
> +    LIST_ENTRY             Entry;
> +    PXENBUS_STORE_WATCH    Watch;
> +    PKEVENT                Event;
> +    PVOID                  FileObject;
> +} XENIFACE_STORE_CONTEXT, *PXENIFACE_STORE_CONTEXT;
> +
> +typedef struct _XENIFACE_EVTCHN_CONTEXT {
> +    LIST_ENTRY             Entry;
> +    PXENBUS_EVTCHN_CHANNEL Channel;
> +    ULONG                  LocalPort;
> +    PKEVENT                Event;
> +    PXENIFACE_FDO          Fdo;
> +    BOOLEAN                Active;
> +    PVOID                  FileObject;
> +} XENIFACE_EVTCHN_CONTEXT, *PXENIFACE_EVTCHN_CONTEXT;
> +
> +typedef struct _XENIFACE_GRANT_CONTEXT {
> +    XENIFACE_CONTEXT_ID        Id;
> +    LIST_ENTRY                 Entry;
> +    PXENBUS_GNTTAB_ENTRY       *Grants;
> +    USHORT                     RemoteDomain;
> +    ULONG                      NumberPages;
> +    XENIFACE_GNTTAB_PAGE_FLAGS Flags;
> +    ULONG                      NotifyOffset;
> +    ULONG                      NotifyPort;
> +    PVOID                      KernelVa;
> +    PVOID                      UserVa;
> +    PMDL                       Mdl;
> +} XENIFACE_GRANT_CONTEXT, *PXENIFACE_GRANT_CONTEXT;
> +
> +typedef struct _XENIFACE_MAP_CONTEXT {
> +    XENIFACE_CONTEXT_ID        Id;
> +    LIST_ENTRY                 Entry;
> +    USHORT                     RemoteDomain;
> +    ULONG                      NumberPages;
> +    XENIFACE_GNTTAB_PAGE_FLAGS Flags;
> +    ULONG                      NotifyOffset;
> +    ULONG                      NotifyPort;
> +    PHYSICAL_ADDRESS           Address;
> +    PVOID                      KernelVa;
> +    PVOID                      UserVa;
> +    PMDL                       Mdl;
> +} XENIFACE_MAP_CONTEXT, *PXENIFACE_MAP_CONTEXT;
> +
> +NTSTATUS
> +XenIfaceIoctl(
> +    __in     PXENIFACE_FDO     Fdo,
> +    __inout  PIRP              Irp
> +    );
> +
> +_IRQL_requires_(PASSIVE_LEVEL)
> +VOID
> +XenIfaceCleanup(
> +    __in  PXENIFACE_FDO Fdo,
> +    __in  PFILE_OBJECT  FileObject
> +    );
> +
> +DECLSPEC_NOINLINE
>  NTSTATUS
> -XenIFaceIoctl(
> +IoctlStoreRead(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PCHAR             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __out PULONG_PTR        Info
> +    );
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlStoreWrite(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PCHAR             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen
> +    );
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlStoreDirectory(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PCHAR             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __out PULONG_PTR        Info
> +    );
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlStoreRemove(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PCHAR             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen
> +    );
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlStoreSetPermissions(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen
> +    );
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlStoreAddWatch(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __in  PFILE_OBJECT      FileObject,
> +    __out PULONG_PTR        Info
> +    );
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlStoreRemoveWatch(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __in  PFILE_OBJECT      FileObject
> +    );
> +
> +_IRQL_requires_max_(DISPATCH_LEVEL)
> +VOID
> +StoreFreeWatch(
> +    __in     PXENIFACE_FDO Fdo,
> +    __inout  PXENIFACE_STORE_CONTEXT Context
> +    );
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlEvtchnBindUnbound(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __in  PFILE_OBJECT      FileObject,
> +    __out PULONG_PTR        Info
> +    );
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlEvtchnBindInterdomain(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __in  PFILE_OBJECT      FileObject,
> +    __out PULONG_PTR        Info
> +    );
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlEvtchnClose(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __in  PFILE_OBJECT      FileObject
> +    );
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlEvtchnNotify(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __in  PFILE_OBJECT      FileObject
> +    );
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlEvtchnUnmask(
>      __in  PXENIFACE_FDO         Fdo,
> -    __in  PIRP              Irp
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __in  PFILE_OBJECT      FileObject
> +    );
> +
> +_Requires_lock_not_held_(Fdo->EvtchnLock)
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +EvtchnNotify(
> +    __in      PXENIFACE_FDO Fdo,
> +    __in      ULONG         LocalPort,
> +    __in_opt  PFILE_OBJECT  FileObject
> +    );
> +
> +_Function_class_(KDEFERRED_ROUTINE)
> +_IRQL_requires_(DISPATCH_LEVEL)
> +_IRQL_requires_same_
> +VOID
> +EvtchnNotificationDpc(
> +    __in      PKDPC Dpc,
> +    __in_opt  PVOID Context,
> +    __in_opt  PVOID Argument1,
> +    __in_opt  PVOID Argument2
> +    );
> +
> +_IRQL_requires_(PASSIVE_LEVEL)
> +VOID
> +EvtchnFree(
> +    __in     PXENIFACE_FDO Fdo,
> +    __inout  PXENIFACE_EVTCHN_CONTEXT Context
> +    );
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlGnttabPermitForeignAccess(
> +    __in     PXENIFACE_FDO  Fdo,
> +    __in     PVOID          Buffer,
> +    __in     ULONG          InLen,
> +    __in     ULONG          OutLen,
> +    __inout  PIRP           Irp
> +    );
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlGnttabGetGrantResult(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __out PULONG_PTR        Info
> +    );
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlGnttabRevokeForeignAccess(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen
> +    );
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlGnttabMapForeignPages(
> +    __in     PXENIFACE_FDO     Fdo,
> +    __in     PVOID             Buffer,
> +    __in     ULONG             InLen,
> +    __in     ULONG             OutLen,
> +    __inout  PIRP              Irp
> +    );
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlGnttabGetMapResult(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen,
> +    __out PULONG_PTR        Info
> +    );
> +
> +DECLSPEC_NOINLINE
> +NTSTATUS
> +IoctlGnttabUnmapForeignPages(
> +    __in  PXENIFACE_FDO     Fdo,
> +    __in  PVOID             Buffer,
> +    __in  ULONG             InLen,
> +    __in  ULONG             OutLen
> +    );
> +
> +_Acquires_exclusive_lock_(((PXENIFACE_FDO)Argument)-
> >GnttabCacheLock)
> +_IRQL_requires_(DISPATCH_LEVEL)
> +VOID
> +GnttabAcquireLock(
> +    __in  PVOID Argument
> +    );
> +
> +_Releases_exclusive_lock_(((PXENIFACE_FDO)Argument)-
> >GnttabCacheLock)
> +_IRQL_requires_(DISPATCH_LEVEL)
> +VOID
> +GnttabReleaseLock(
> +    __in  PVOID Argument
> +    );
> +
> +_Function_class_(IO_WORKITEM_ROUTINE)
> +VOID
> +CompleteGnttabIrp(
> +    __in      PDEVICE_OBJECT DeviceObject,
> +    __in_opt  PVOID          Context
> +    );
> +
> +_IRQL_requires_max_(APC_LEVEL)
> +VOID
> +GnttabFreeGrant(
> +    __in     PXENIFACE_FDO Fdo,
> +    __inout  PXENIFACE_GRANT_CONTEXT Context
> +    );
> +
> +_IRQL_requires_max_(APC_LEVEL)
> +VOID
> +GnttabFreeMap(
> +    __in     PXENIFACE_FDO Fdo,
> +    __inout  PXENIFACE_MAP_CONTEXT Context
>      );
> 
>  #endif // _IOCTLS_H_
> diff --git a/src/xeniface/irp_queue.c b/src/xeniface/irp_queue.c
> new file mode 100644
> index 0000000..c3bf86c
> --- /dev/null
> +++ b/src/xeniface/irp_queue.c
> @@ -0,0 +1,131 @@
> +#include "driver.h"
> +#include "irp_queue.h"
> +#include "log.h"
> +#include "ioctls.h"
> +
> +// Cancel-safe IRP queue implementation
> +
> +NTSTATUS
> +CsqInsertIrpEx(
> +    _In_  PIO_CSQ Csq,
> +    _In_  PIRP    Irp,
> +    _In_  PVOID   InsertContext // PXENIFACE_CONTEXT_ID
> +    )
> +{
> +    PXENIFACE_FDO Fdo;
> +
> +    Fdo = CONTAINING_RECORD(Csq, XENIFACE_FDO, IrpQueue);
> +
> +    // Fail if a request with the same ID already exists.
> +    if (CsqPeekNextIrp(Csq, NULL, InsertContext) != NULL)
> +        return STATUS_INVALID_PARAMETER;
> +
> +    InsertTailList(&Fdo->IrpList, &Irp->Tail.Overlay.ListEntry);
> +    return STATUS_SUCCESS;
> +}
> +
> +VOID
> +CsqRemoveIrp(
> +    _In_  PIO_CSQ Csq,
> +    _In_  PIRP    Irp
> +    )
> +{
> +    UNREFERENCED_PARAMETER(Csq);
> +
> +    RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
> +}
> +
> +PIRP
> +CsqPeekNextIrp(
> +    _In_      PIO_CSQ Csq,
> +    _In_opt_  PIRP    Irp,
> +    _In_opt_  PVOID   PeekContext // PXENIFACE_CONTEXT_ID
> +    )
> +{
> +    PXENIFACE_FDO        Fdo;
> +    PIRP                 NextIrp = NULL;
> +    PLIST_ENTRY          Head, NextEntry;
> +    PXENIFACE_CONTEXT_ID Id, TargetId;
> +
> +    Fdo = CONTAINING_RECORD(Csq, XENIFACE_FDO, IrpQueue);
> +    TargetId = PeekContext;
> +    Head = &Fdo->IrpList;
> +
> +    // If the IRP is NULL, we will start peeking from the list head,
> +    // else we will start from that IRP onwards. This is done under the
> +    // assumption that new IRPs are always inserted at the tail.
> +
> +    if (Irp == NULL) {
> +        NextEntry = Head->Flink;
> +    } else {
> +        NextEntry = Irp->Tail.Overlay.ListEntry.Flink;
> +    }
> +
> +    while (NextEntry != Head) {
> +        NextIrp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry);
> +
> +        if (PeekContext) {
> +            Id = NextIrp->Tail.Overlay.DriverContext[0];
> +            if (Id->RequestId == TargetId->RequestId && Id->Process ==
> TargetId->Process)
> +                break;
> +        } else {
> +            break;
> +        }
> +        NextIrp = NULL;
> +        NextEntry = NextEntry->Flink;
> +    }
> +
> +    return NextIrp;
> +}
> +
> +_IRQL_raises_(DISPATCH_LEVEL)
> +_IRQL_requires_max_(DISPATCH_LEVEL)
> +_Acquires_lock_(CONTAINING_RECORD(Csq, XENIFACE_FDO, IrpQueue)-
> >IrpQueueLock)
> +VOID
> +CsqAcquireLock(
> +    _In_                                       PIO_CSQ Csq,
> +    _Out_ _At_(*Irql, _Post_ _IRQL_saves_)     PKIRQL  Irql
> +    )
> +{
> +    PXENIFACE_FDO Fdo;
> +
> +    Fdo = CONTAINING_RECORD(Csq, XENIFACE_FDO, IrpQueue);
> +
> +    KeAcquireSpinLock(&Fdo->IrpQueueLock, Irql);
> +}
> +
> +_IRQL_requires_(DISPATCH_LEVEL)
> +_Releases_lock_(CONTAINING_RECORD(Csq, XENIFACE_FDO, IrpQueue)-
> >IrpQueueLock)
> +VOID
> +CsqReleaseLock(
> +    _In_                    PIO_CSQ Csq,
> +    _In_ _IRQL_restores_    KIRQL   Irql
> +    )
> +{
> +    PXENIFACE_FDO Fdo;
> +
> +    Fdo = CONTAINING_RECORD(Csq, XENIFACE_FDO, IrpQueue);
> +
> +    KeReleaseSpinLock(&Fdo->IrpQueueLock, Irql);
> +}
> +
> +_IRQL_requires_max_(DISPATCH_LEVEL)
> +VOID
> +CsqCompleteCanceledIrp(
> +    _In_  PIO_CSQ Csq,
> +    _In_  PIRP    Irp
> +    )
> +{
> +    PXENIFACE_FDO Fdo = CONTAINING_RECORD(Csq, XENIFACE_FDO,
> IrpQueue);
> +    PIO_WORKITEM WorkItem;
> +
> +    XenIfaceDebugPrint(TRACE, "Irp %p, IRQL %d\n",
> +                       Irp, KeGetCurrentIrql());
> +
> +    // This is not guaranteed to run at PASSIVE_LEVEL, so queue a work item
> +    // to perform actual cleanup/IRP completion.
> +
> +    WorkItem = IoAllocateWorkItem(Fdo->Dx->DeviceObject);
> +    Irp->Tail.Overlay.DriverContext[1] = WorkItem; // store so the work item
> can free it
> +    IoQueueWorkItem(WorkItem, CompleteGnttabIrp, DelayedWorkQueue,
> Irp);
> +}
> diff --git a/src/xeniface/irp_queue.h b/src/xeniface/irp_queue.h
> new file mode 100644
> index 0000000..746ee19
> --- /dev/null
> +++ b/src/xeniface/irp_queue.h
> @@ -0,0 +1,50 @@
> +#ifndef _IRP_QUEUE_H_
> +#define _IRP_QUEUE_H_
> +
> +#include <ntddk.h>
> +
> +NTSTATUS
> +CsqInsertIrpEx(
> +    _In_  PIO_CSQ Csq,
> +    _In_  PIRP    Irp,
> +    _In_  PVOID   InsertContext
> +    );
> +
> +VOID
> +CsqRemoveIrp(
> +    _In_  PIO_CSQ Csq,
> +    _In_  PIRP    Irp
> +    );
> +
> +PIRP
> +CsqPeekNextIrp(
> +    _In_      PIO_CSQ Csq,
> +    _In_opt_  PIRP    Irp,
> +    _In_opt_  PVOID   PeekContext // PXENIFACE_CONTEXT_ID
> +    );
> +
> +_IRQL_raises_(DISPATCH_LEVEL)
> +_IRQL_requires_max_(DISPATCH_LEVEL)
> +_Acquires_lock_(CONTAINING_RECORD(Csq, XENIFACE_FDO, IrpQueue)-
> >IrpQueueLock)
> +VOID
> +CsqAcquireLock(
> +    _In_                                       PIO_CSQ Csq,
> +    _Out_ _At_(*Irql, _Post_ _IRQL_saves_)     PKIRQL  Irql
> +    );
> +
> +_IRQL_requires_(DISPATCH_LEVEL)
> +_Releases_lock_(CONTAINING_RECORD(Csq, XENIFACE_FDO, IrpQueue)-
> >IrpQueueLock)
> +VOID
> +CsqReleaseLock(
> +    _In_                    PIO_CSQ Csq,
> +    _In_ _IRQL_restores_    KIRQL   Irql
> +    );
> +
> +_IRQL_requires_max_(DISPATCH_LEVEL)
> +VOID
> +CsqCompleteCanceledIrp(
> +    _In_  PIO_CSQ             Csq,
> +    _In_  PIRP                Irp
> +    );
> +
> +#endif
> diff --git a/vs2013/xeniface/xeniface.vcxproj
> b/vs2013/xeniface/xeniface.vcxproj
> index fea2ad1..14f1338 100644
> --- a/vs2013/xeniface/xeniface.vcxproj
> +++ b/vs2013/xeniface/xeniface.vcxproj
> @@ -131,6 +131,10 @@
>      <ClCompile Include="../../src/xeniface/fdo.c" />
>      <ClCompile Include="../../src/xeniface/registry.c" />
>      <ClCompile Include="../../src\xeniface/thread.c" />
> +    <ClCompile Include="..\..\src\xeniface\ioctl_evtchn.c" />
> +    <ClCompile Include="..\..\src\xeniface\ioctl_gnttab.c" />
> +    <ClCompile Include="..\..\src\xeniface\ioctl_store.c" />
> +    <ClCompile Include="..\..\src\xeniface\irp_queue.c" />
>    </ItemGroup>
>    <ItemGroup>
>      <Mofcomp Include="../../src/xeniface/wmi.mof">
> --
> 1.8.1.msysgit.1
> 
> _______________________________________________
> win-pv-devel mailing list
> win-pv-devel@xxxxxxxxxxxxxxxxxxxx
> http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel

_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel


 


Rackspace

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