[prev in list] [next in list] [prev in thread] [next in thread]
List: win-pv-devel
Subject: Re: [win-pv-devel] [PATCH 5/6] Implement new IOCTL handlers
From: Paul Durrant <Paul.Durrant () citrix ! com>
Date: 2015-10-23 14:36:11
Message-ID: 9AAE0902D5BC7E449B7C8E4E778ABCD02F623232 () AMSPEX01CL01 ! citrite ! net
[Download RAW message or body]
> -----Original Message-----
> From: win-pv-devel-bounces@lists.xenproject.org [mailto:win-pv-devel-
> bounces@lists.xenproject.org] On Behalf Of Rafal Wojdyla
> Sent: 21 October 2015 06:27
> To: win-pv-devel@lists.xenproject.org
> Subject: [win-pv-devel] [PATCH 5/6] 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@invisiblethingslab.com>
Acked-by: Paul Durrant <paul.durrant@citrix.com>
> ---
> include/xeniface_ioctls.h | 1 +
> src/xeniface/fdo.c | 179 +++++++++-
> src/xeniface/fdo.h | 44 ++-
> src/xeniface/ioctl_evtchn.c | 492 ++++++++++++++++++++++++++
> src/xeniface/ioctl_gnttab.c | 747
> +++++++++++++++++++++++++++++++++++++++
> src/xeniface/ioctl_store.c | 608 +++++++++++++++++++++++++++++++
> src/xeniface/ioctls.c | 396 ++++++++-------------
> src/xeniface/ioctls.h | 330 ++++++++++++++++-
> src/xeniface/irp_queue.c | 162 +++++++++
> src/xeniface/irp_queue.h | 81 +++++
> vs2012/xeniface/xeniface.vcxproj | 30 +-
> vs2013/xeniface/xeniface.vcxproj | 30 +-
> 12 files changed, 2807 insertions(+), 293 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/include/xeniface_ioctls.h b/include/xeniface_ioctls.h
> index 6ad98d6..a842d4f 100644
> --- a/include/xeniface_ioctls.h
> +++ b/include/xeniface_ioctls.h
> @@ -1,4 +1,5 @@
> /* Copyright (c) Citrix Systems Inc.
> + * Copyright (c) Rafal Wojdyla <omeg@invisiblethingslab.com>
> * All rights reserved.
> *
> * Redistribution and use in source and binary forms,
> diff --git a/src/xeniface/fdo.c b/src/xeniface/fdo.c
> index b73dee1..71ffbe2 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, "FO %p, Process %p\n", Stack->FileObject,
> PsGetCurrentProcess());
>
> - XenIfaceDebugPrint(TRACE, "Create \n");
> -
> - 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;
> }
> @@ -2081,7 +2117,7 @@ FdoDispatch(
> break;
>
> case IRP_MJ_DEVICE_CONTROL:
> - status = XenIFaceIoctl(Fdo, Irp);
> + status = XenIfaceIoctl(Fdo, Irp);
> break;
>
> case IRP_MJ_SYSTEM_CONTROL:
> @@ -2206,6 +2242,8 @@ FdoCreate(
> WCHAR Name[MAXNAMELEN * sizeof (WCHAR)];
> ULONG Size;
> NTSTATUS status;
> + ULONG ProcessorCount;
> + ULONG Index;
>
> #pragma prefast(suppress:28197) // Possibly leaking memory
> 'FunctionDeviceObject'
> status = IoCreateDevice(DriverObject,
> @@ -2296,6 +2334,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;
> @@ -2306,7 +2362,46 @@ FdoCreate(
>
> status = ThreadCreate(FdoRegistryThreadHandler, Fdo, &Fdo-
> >registryThread);
> if (!NT_SUCCESS(status))
> - goto fail11;
> + 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 =
> KeQueryMaximumProcessorCountEx(ALL_PROCESSOR_GROUPS);
> +
> + status = STATUS_NO_MEMORY;
> + Fdo->EvtchnDpc = __FdoAllocate(sizeof (KDPC) * ProcessorCount);
> + if (Fdo->EvtchnDpc == NULL)
> + goto fail15;
> +
> + for (Index = 0; Index < ProcessorCount; Index++) {
> + PROCESSOR_NUMBER ProcNumber;
> +
> + status = KeGetProcessorNumberFromIndex(Index, &ProcNumber);
> + ASSERT(NT_SUCCESS(status));
> +
> + KeInitializeDpc(&Fdo->EvtchnDpc[Index], EvtchnNotificationDpc,
> NULL);
> + status = KeSetTargetProcessorDpcEx(&Fdo->EvtchnDpc[Index],
> &ProcNumber);
> + ASSERT(NT_SUCCESS(status));
> + }
>
> Info("%p (%s)\n",
> FunctionDeviceObject,
> @@ -2317,6 +2412,27 @@ 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");
> @@ -2394,7 +2510,8 @@ FdoDestroy(
> )
> {
> PXENIFACE_DX Dx = Fdo->Dx;
> - PDEVICE_OBJECT FunctionDeviceObject = Dx->DeviceObject;
> + PDEVICE_OBJECT FunctionDeviceObject = Dx->DeviceObject;
> + ULONG ProcessorCount;
>
> ASSERT(IsListEmpty(&Dx->ListEntry));
> ASSERT3U(Fdo->References, ==, 0);
> @@ -2408,10 +2525,34 @@ FdoDestroy(
>
> Dx->Fdo = NULL;
>
> + ProcessorCount =
> KeQueryMaximumProcessorCountEx(ALL_PROCESSOR_GROUPS);
> + RtlZeroMemory(Fdo->EvtchnDpc, sizeof (KDPC) * ProcessorCount);
> + __FdoFree(Fdo->EvtchnDpc);
> +
> + 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 c859338..781b1cc 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,32 +75,44 @@ typedef struct _XENIFACE_FDO {
>
> FDO_RESOURCE Resource[RESOURCE_COUNT];
>
> -
> XENBUS_STORE_INTERFACE StoreInterface;
> -
> XENBUS_SUSPEND_INTERFACE SuspendInterface;
> -
> XENBUS_SHARED_INFO_INTERFACE SharedInfoInterface;
> -
> + XENBUS_EVTCHN_INTERFACE EvtchnInterface;
> + XENBUS_GNTTAB_INTERFACE GnttabInterface;
> PXENBUS_SUSPEND_CALLBACK SuspendCallbackLate;
>
> - BOOLEAN InterfacesAcquired;
> + BOOLEAN InterfacesAcquired;
> +
> + 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;
> + int WmiReady;
>
> - USHORT Sessions;
> - FAST_MUTEX SessionLock;
> - LIST_ENTRY SessionHead;
> + USHORT Sessions;
> + FAST_MUTEX SessionLock;
> + LIST_ENTRY SessionHead;
>
> - PXENIFACE_THREAD registryThread;
> - KEVENT registryWriteEvent;
> + PXENIFACE_THREAD registryThread;
> + KEVENT registryWriteEvent;
>
> + UNICODE_STRING SuggestedInstanceName;
>
> - UNICODE_STRING SuggestedInstanceName;
> -
> - UNICODE_STRING InterfaceName;
> + UNICODE_STRING InterfaceName;
>
> } XENIFACE_FDO, *PXENIFACE_FDO;
>
> @@ -163,6 +177,4 @@ FdoDispatch(
> IN PIRP Irp
> );
>
> -
> -
> #endif // _XENIFACE_FDO_H
> diff --git a/src/xeniface/ioctl_evtchn.c b/src/xeniface/ioctl_evtchn.c
> new file mode 100644
> index 0000000..93f1931
> --- /dev/null
> +++ b/src/xeniface/ioctl_evtchn.c
> @@ -0,0 +1,492 @@
> +/* Copyright (c) Rafal Wojdyla <omeg@invisiblethingslab.com>
> + * 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 "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 = Argument1;
> +
> + UNREFERENCED_PARAMETER(Dpc);
> + UNREFERENCED_PARAMETER(_Context);
> + UNREFERENCED_PARAMETER(Argument2);
> +
> + ASSERT(Context);
> +
> +#if DBG
> + XenIfaceDebugPrint(INFO, "Channel %p, LocalPort %d, Cpu %lu\n",
> + Context->Channel, Context->LocalPort,
> KeGetCurrentProcessorNumber());
> +#endif
> + 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 = Argument;
> + PROCESSOR_NUMBER ProcNumber;
> + ULONG ProcIndex;
> +
> + UNREFERENCED_PARAMETER(Interrupt);
> + ASSERT(Context);
> +
> + KeGetCurrentProcessorNumberEx(&ProcNumber);
> + ProcIndex = KeGetProcessorIndexFromNumber(&ProcNumber);
> + if (!KeInsertQueueDpc(&Context->Fdo->EvtchnDpc[ProcIndex], Context,
> NULL)) {
> + XenIfaceDebugPrint(TRACE, "NOT INSERTED: Context %p, Port %lu, FO
> %p, Cpu %lu\n",
> + Context, Context->LocalPort, Context->FileObject,
> ProcIndex);
> + }
> +
> + 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);
> +
> + 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));
> + 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 &&
> + FileObject != Context->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)) {
> + 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);
> +
> + 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);
> +
> + 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;
> + 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);
> + status = STATUS_NOT_FOUND;
> + Context = EvtchnFindChannel(Fdo, In->LocalPort, FileObject);
> + if (Context == NULL)
> + goto fail2;
> +
> + RemoveEntryList(&Context->Entry);
> + KeReleaseSpinLock(&Fdo->EvtchnLock, Irql);
> + EvtchnFree(Fdo, Context);
> +
> + return STATUS_SUCCESS;
> +
> +fail2:
> + XenIfaceDebugPrint(ERROR, "Fail2\n");
> + KeReleaseSpinLock(&Fdo->EvtchnLock, Irql);
> +
> +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;
> + 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:
> + XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
> + KeReleaseSpinLock(&Fdo->EvtchnLock, Irql);
> + 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;
> + 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:
> + XenIfaceDebugPrint(ERROR, "Fail2\n");
> + KeReleaseSpinLock(&Fdo->EvtchnLock, Irql);
> +
> +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..a24a5ee
> --- /dev/null
> +++ b/src/xeniface/ioctl_gnttab.c
> @@ -0,0 +1,747 @@
> +/* Copyright (c) Rafal Wojdyla <omeg@invisiblethingslab.com>
> + * 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 "xeniface_ioctls.h"
> +#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;
> + PXENIFACE_GNTTAB_PERMIT_FOREIGN_ACCESS_OUT Out = Irp-
> >UserBuffer;
> + PXENIFACE_GRANT_CONTEXT Context;
> + ULONG Page;
> +
> + status = STATUS_INVALID_BUFFER_SIZE;
> + if (InLen != sizeof(XENIFACE_GNTTAB_PERMIT_FOREIGN_ACCESS_IN))
> + goto fail1;
> +
> + // This IOCTL uses METHOD_NEITHER so we directly access user memory.
> + status = __CaptureUserBuffer(Buffer, InLen, &In);
> + if (!NT_SUCCESS(status))
> + goto fail2;
> +
> + status = STATUS_INVALID_PARAMETER;
> + if (In->NumberPages == 0 ||
> + In->NumberPages > 1024 * 1024) {
> + goto fail3;
> + }
> +
> + if ((In->Flags & XENIFACE_GNTTAB_USE_NOTIFY_OFFSET) &&
> + (In->NotifyOffset >= In->NumberPages * PAGE_SIZE)) {
> + goto fail4;
> + }
> +
> + status = STATUS_INVALID_BUFFER_SIZE;
> + if (OutLen !=
> (ULONG)FIELD_OFFSET(XENIFACE_GNTTAB_PERMIT_FOREIGN_ACCESS_OU
> T, References[In->NumberPages]))
> + goto fail5;
> +
> + status = STATUS_NO_MEMORY;
> + Context = ExAllocatePoolWithTag(NonPagedPool,
> sizeof(XENIFACE_GRANT_CONTEXT), XENIFACE_POOL_TAG);
> + if (Context == NULL)
> + goto fail6;
> +
> + RtlZeroMemory(Context, sizeof(XENIFACE_GRANT_CONTEXT));
> + Context->Id.Type = XENIFACE_CONTEXT_GRANT;
> + 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);
> +
> + // Check if the request ID is unique for this process.
> + // 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 fail7;
> +
> + status = STATUS_NO_MEMORY;
> + Context->Grants = ExAllocatePoolWithTag(NonPagedPool, Context-
> >NumberPages * sizeof(PXENBUS_GNTTAB_ENTRY),
> XENIFACE_POOL_TAG);
> + if (Context->Grants == NULL)
> + goto fail8;
> +
> + 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 fail9;
> +
> + RtlZeroMemory(Context->KernelVa, Context->NumberPages *
> PAGE_SIZE);
> + Context->Mdl = IoAllocateMdl(Context->KernelVa, Context-
> >NumberPages * PAGE_SIZE, FALSE, FALSE, NULL);
> + if (Context->Mdl == NULL)
> + goto fail10;
> +
> + 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 fail11;
> + }
> +
> + // 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 fail12;
> + }
> +
> + status = STATUS_UNSUCCESSFUL;
> + if (Context->UserVa == NULL)
> + goto fail13;
> +
> + XenIfaceDebugPrint(TRACE, "< Context %p, Irp %p, KernelVa %p, UserVa
> %p\n",
> + Context, Irp, Context->KernelVa, Context->UserVa);
> +
> + // Pass the result to user mode.
> +#pragma prefast(suppress: 6320) // we want to catch all exceptions
> + try {
> + ProbeForWrite(Out, OutLen, 1);
> + Out->Address = Context->UserVa;
> +
> + for (Page = 0; Page < Context->NumberPages; Page++) {
> + Out->References[Page] = XENBUS_GNTTAB(GetReference,
> + &Fdo->GnttabInterface,
> + Context->Grants[Page]);
> + }
> + } except(EXCEPTION_EXECUTE_HANDLER) {
> + status = GetExceptionCode();
> + XenIfaceDebugPrint(ERROR, "Exception 0x%lx while probing/writing
> output buffer at %p, size 0x%lx\n", status, Out, OutLen);
> + goto fail14;
> + }
> +
> + // Insert the IRP/context into the pending queue.
> + // This also checks (again) if the request ID is unique for the calling
> process.
> + Irp->Tail.Overlay.DriverContext[0] = &Context->Id;
> + status = IoCsqInsertIrpEx(&Fdo->IrpQueue, Irp, NULL, &Context->Id);
> + if (!NT_SUCCESS(status))
> + goto fail15;
> +
> + __FreeCapturedBuffer(In);
> +
> + return STATUS_PENDING;
> +
> +fail15:
> + XenIfaceDebugPrint(ERROR, "Fail15\n");
> +
> +fail14:
> + XenIfaceDebugPrint(ERROR, "Fail14\n");
> + MmUnmapLockedPages(Context->UserVa, Context->Mdl);
> +
> +fail13:
> + XenIfaceDebugPrint(ERROR, "Fail13\n");
> +
> +fail12:
> + XenIfaceDebugPrint(ERROR, "Fail12\n");
> +
> +fail11:
> + XenIfaceDebugPrint(ERROR, "Fail11: 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);
> +
> +fail10:
> + XenIfaceDebugPrint(ERROR, "Fail10\n");
> + ExFreePoolWithTag(Context->KernelVa, XENIFACE_POOL_TAG);
> +
> +fail9:
> + XenIfaceDebugPrint(ERROR, "Fail9\n");
> + ExFreePoolWithTag(Context->Grants, XENIFACE_POOL_TAG);
> +
> +fail8:
> + XenIfaceDebugPrint(ERROR, "Fail8\n");
> +
> +fail7:
> + XenIfaceDebugPrint(ERROR, "Fail7\n");
> + RtlZeroMemory(Context, sizeof(XENIFACE_GRANT_CONTEXT));
> + ExFreePoolWithTag(Context, XENIFACE_POOL_TAG);
> +
> +fail6:
> + XenIfaceDebugPrint(ERROR, "Fail6\n");
> +
> +fail5:
> + XenIfaceDebugPrint(ERROR, "Fail5\n");
> +
> +fail4:
> + XenIfaceDebugPrint(ERROR, "Fail4\n");
> +
> +fail3:
> + XenIfaceDebugPrint(ERROR, "Fail3\n");
> + __FreeCapturedBuffer(In);
> +
> +fail2:
> + XenIfaceDebugPrint(ERROR, "Fail2\n");
> +
> +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_GNTTAB_MAP_FOREIGN_PAGES_OUT Out = Irp-
> >UserBuffer;
> + ULONG NumberPages;
> + ULONG PageIndex;
> + PXENIFACE_MAP_CONTEXT Context;
> +
> + status = STATUS_INVALID_BUFFER_SIZE;
> + if (InLen < sizeof(XENIFACE_GNTTAB_MAP_FOREIGN_PAGES_IN) ||
> + OutLen != sizeof(XENIFACE_GNTTAB_MAP_FOREIGN_PAGES_OUT)) {
> + goto fail1;
> + }
> +
> + // This IOCTL uses METHOD_NEITHER so we directly access user memory.
> +
> + // Calculate the expected number of pages based on input buffer size.
> + NumberPages = (InLen -
> (ULONG)FIELD_OFFSET(XENIFACE_GNTTAB_MAP_FOREIGN_PAGES_IN,
> References)) / sizeof(In->References[0]);
> +
> + status = __CaptureUserBuffer(Buffer, InLen, &In);
> + if (!NT_SUCCESS(status))
> + goto fail2;
> +
> + status = STATUS_INVALID_PARAMETER;
> + if (In->NumberPages == 0 ||
> + In->NumberPages > 1024 * 1024 ||
> + In->NumberPages != NumberPages) {
> + goto fail3;
> + }
> +
> + if ((In->Flags & XENIFACE_GNTTAB_USE_NOTIFY_OFFSET) &&
> + (In->NotifyOffset >= In->NumberPages * PAGE_SIZE)) {
> + goto fail4;
> + }
> +
> + status = STATUS_INVALID_BUFFER_SIZE;
> + if (InLen !=
> (ULONG)FIELD_OFFSET(XENIFACE_GNTTAB_MAP_FOREIGN_PAGES_IN,
> References[In->NumberPages]))
> + goto fail5;
> +
> + status = STATUS_NO_MEMORY;
> + Context = ExAllocatePoolWithTag(NonPagedPool,
> sizeof(XENIFACE_MAP_CONTEXT), XENIFACE_POOL_TAG);
> + if (Context == NULL)
> + goto fail6;
> +
> + 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 (PageIndex = 0; PageIndex < In->NumberPages; PageIndex++)
> + XenIfaceDebugPrint(INFO, "> Ref %d\n", In->References[PageIndex]);
> +
> + status = STATUS_INVALID_PARAMETER;
> + if (FindGnttabIrp(Fdo, &Context->Id) != NULL)
> + goto fail7;
> +
> + status = XENBUS_GNTTAB(MapForeignPages,
> + &Fdo->GnttabInterface,
> + Context->RemoteDomain,
> + Context->NumberPages,
> + In->References,
> + Context->Flags & XENIFACE_GNTTAB_READONLY,
> + &Context->Address);
> +
> + if (!NT_SUCCESS(status))
> + goto fail8;
> +
> + status = STATUS_NO_MEMORY;
> + Context->KernelVa = MmMapIoSpace(Context->Address, Context-
> >NumberPages * PAGE_SIZE, MmCached);
> + if (Context->KernelVa == NULL)
> + goto fail9;
> +
> + status = STATUS_NO_MEMORY;
> + Context->Mdl = IoAllocateMdl(Context->KernelVa, Context-
> >NumberPages * PAGE_SIZE, FALSE, FALSE, NULL);
> + if (Context->Mdl == NULL)
> + goto fail10;
> +
> + 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 fail11;
> + }
> +
> + status = STATUS_UNSUCCESSFUL;
> + if (Context->UserVa == NULL)
> + goto fail12;
> +
> + XenIfaceDebugPrint(TRACE, "< Context %p, Irp %p, Address %p, KernelVa
> %p, UserVa %p\n",
> + Context, Irp, Context->Address, Context->KernelVa, Context-
> >UserVa);
> +
> + // Pass the result to user mode.
> +#pragma prefast(suppress: 6320) // we want to catch all exceptions
> + try {
> + ProbeForWrite(Out, OutLen, 1);
> + Out->Address = Context->UserVa;
> + } except(EXCEPTION_EXECUTE_HANDLER) {
> + status = GetExceptionCode();
> + XenIfaceDebugPrint(ERROR, "Exception 0x%lx while probing/writing
> output buffer at %p, size 0x%lx\n", status, Out, OutLen);
> + goto fail13;
> + }
> +
> + // Insert the IRP/context into the pending queue.
> + // This also checks (again) if the request ID is unique for the calling
> process.
> + Irp->Tail.Overlay.DriverContext[0] = &Context->Id;
> + status = IoCsqInsertIrpEx(&Fdo->IrpQueue, Irp, NULL, &Context->Id);
> + if (!NT_SUCCESS(status))
> + goto fail14;
> +
> + __FreeCapturedBuffer(In);
> +
> + return STATUS_PENDING;
> +
> +fail14:
> + XenIfaceDebugPrint(ERROR, "Fail14\n");
> +
> +fail13:
> + XenIfaceDebugPrint(ERROR, "Fail13\n");
> + MmUnmapLockedPages(Context->UserVa, Context->Mdl);
> +
> +fail12:
> + XenIfaceDebugPrint(ERROR, "Fail12\n");
> +
> +fail11:
> + XenIfaceDebugPrint(ERROR, "Fail11\n");
> + IoFreeMdl(Context->Mdl);
> +
> +fail10:
> + XenIfaceDebugPrint(ERROR, "Fail10\n");
> + MmUnmapIoSpace(Context->KernelVa, Context->NumberPages *
> PAGE_SIZE);
> +
> +fail9:
> + XenIfaceDebugPrint(ERROR, "Fail9\n");
> + ASSERT(NT_SUCCESS(XENBUS_GNTTAB(UnmapForeignPages,
> + &Fdo->GnttabInterface,
> + Context->Address
> + )));
> +
> +fail8:
> + XenIfaceDebugPrint(ERROR, "Fail8\n");
> +
> +fail7:
> + XenIfaceDebugPrint(ERROR, "Fail7\n");
> + RtlZeroMemory(Context, sizeof(XENIFACE_MAP_CONTEXT));
> + ExFreePoolWithTag(Context, XENIFACE_POOL_TAG);
> +
> +fail6:
> + XenIfaceDebugPrint(ERROR, "Fail6\n");
> +
> +fail5:
> + XenIfaceDebugPrint(ERROR, "Fail5\n");
> +
> +fail4:
> + XenIfaceDebugPrint(ERROR, "Fail4\n");
> +
> +fail3:
> + XenIfaceDebugPrint(ERROR, "Fail3\n");
> + __FreeCapturedBuffer(In);
> +
> +fail2:
> + XenIfaceDebugPrint(ERROR, "Fail2\n");
> +
> +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..5bd4649
> --- /dev/null
> +++ b/src/xeniface/ioctl_store.c
> @@ -0,0 +1,608 @@
> +/* Copyright (c) Citrix Systems Inc.
> + * Copyright (c) Rafal Wojdyla <omeg@invisiblethingslab.com>
> + * 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 "xeniface_ioctls.h"
> +#include "log.h"
> +
> +#define XENSTORE_ABS_PATH_MAX 3072
> +#define XENSTORE_REL_PATH_MAX 2048
> +
> +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;
> +}
> +
> +static
> +PXENBUS_STORE_PERMISSION
> +__ConvertPermissions(
> + __in ULONG NumberPermissions,
> + __in PXENIFACE_STORE_PERMISSION XenifacePermissions
> +)
> +{
> + PXENBUS_STORE_PERMISSION XenbusPermissions;
> + ULONG Index;
> +
> + if (NumberPermissions > 255)
> + goto fail1;
> +
> + XenbusPermissions = ExAllocatePoolWithTag(NonPagedPool,
> NumberPermissions * sizeof(XENBUS_STORE_PERMISSION),
> XENIFACE_POOL_TAG);
> + if (XenbusPermissions == NULL)
> + goto fail2;
> +
> + // Currently XENIFACE_STORE_PERMISSION is the same as
> XENBUS_STORE_PERMISSION,
> + // but we convert them here in case something changes in the future.
> + for (Index = 0; Index < NumberPermissions; Index++) {
> + if ((XenifacePermissions[Index].Mask &
> ~XENIFACE_STORE_ALLOWED_PERMISSIONS) != 0)
> + goto fail3;
> +
> + XenbusPermissions[Index].Domain =
> XenifacePermissions[Index].Domain;
> + XenbusPermissions[Index].Mask =
> (XENBUS_STORE_PERMISSION_MASK)XenifacePermissions[Index].Mask;
> + }
> +
> + return XenbusPermissions;
> +
> +fail3:
> + XenIfaceDebugPrint(ERROR, "Fail3\n");
> + ExFreePoolWithTag(XenbusPermissions, XENIFACE_POOL_TAG);
> +
> +fail2:
> + XenIfaceDebugPrint(ERROR, "Fail2\n");
> +
> +fail1:
> + XenIfaceDebugPrint(ERROR, "Fail1\n");
> + return NULL;
> +}
> +
> +static
> +VOID
> +__FreePermissions(
> + __in PXENBUS_STORE_PERMISSION Permissions
> + )
> +{
> + ExFreePoolWithTag(Permissions, XENIFACE_POOL_TAG);
> +}
> +
> +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;
> + PXENBUS_STORE_PERMISSION Permissions;
> + ULONG Index;
> + PCHAR Path;
> +
> + status = STATUS_INVALID_BUFFER_SIZE;
> + if (InLen < sizeof(XENIFACE_STORE_SET_PERMISSIONS_IN) ||
> + OutLen != 0) {
> + goto fail1;
> + }
> +
> + if (InLen !=
> (ULONG)FIELD_OFFSET(XENIFACE_STORE_SET_PERMISSIONS_IN,
> Permissions[In->NumberPermissions]))
> + goto fail2;
> +
> + status = STATUS_INVALID_PARAMETER;
> + if (In->PathLength == 0 ||
> + In->PathLength > XENSTORE_ABS_PATH_MAX) {
> + goto fail3;
> + }
> +
> + Permissions = __ConvertPermissions(In->NumberPermissions, In-
> >Permissions);
> + if (Permissions == NULL)
> + goto fail4;
> +
> + status = __CaptureUserBuffer(In->Path, In->PathLength, &Path);
> + if (!NT_SUCCESS(status))
> + goto fail5;
> +
> + 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, Permissions[Index].Domain,
> Permissions[Index].Mask);
> + }
> +
> + status = XENBUS_STORE(PermissionsSet,
> + &Fdo->StoreInterface,
> + NULL, // transaction
> + NULL, // prefix
> + Path,
> + Permissions,
> + In->NumberPermissions);
> +
> + if (!NT_SUCCESS(status))
> + goto fail6;
> +
> + __FreeCapturedBuffer(Path);
> + return status;
> +
> +fail6:
> + XenIfaceDebugPrint(ERROR, "Fail6\n");
> + __FreeCapturedBuffer(Path);
> +
> +fail5:
> + XenIfaceDebugPrint(ERROR, "Fail5\n");
> + __FreePermissions(Permissions);
> +
> +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 ead7f9b..b306a45 100644
> --- a/src/xeniface/ioctls.c
> +++ b/src/xeniface/ioctls.c
> @@ -1,4 +1,5 @@
> /* Copyright (c) Citrix Systems Inc.
> + * Copyright (c) Rafal Wojdyla <omeg@invisiblethingslab.com>
> * All rights reserved.
> *
> * Redistribution and use in source and binary forms,
> @@ -29,266 +30,123 @@
> * SUCH DAMAGE.
> */
>
> -
> #include "driver.h"
> #include "ioctls.h"
> -#include "..\..\include\xeniface_ioctls.h"
> +#include "xeniface_ioctls.h"
> #include "log.h"
>
> -static FORCEINLINE BOOLEAN
> -__IsValidStr(
> - __in PCHAR Str,
> - __in ULONG Len
> +NTSTATUS
> +__CaptureUserBuffer(
> + __in PVOID Buffer,
> + __in ULONG Length,
> + __out PVOID *CapturedBuffer
> )
> {
> - for ( ; Len--; ++Str) {
> - if (*Str == '\0')
> - return TRUE;
> - if (!isprint((unsigned char)*Str))
> - break;
> + NTSTATUS Status;
> + PVOID TempBuffer = NULL;
> +
> + if (Length == 0) {
> + *CapturedBuffer = NULL;
> + return STATUS_SUCCESS;
> }
> - 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);
> +
> + 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;
>
> -static DECLSPEC_NOINLINE NTSTATUS
> -IoctlRead(
> - __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(INFO, "|%s: (\"%s\")=(%d)\n", __FUNCTION__,
> Buffer, Length);
> - goto done;
> - }
> -
> - 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;
> -
> -done:
> - *Info = (ULONG_PTR)Length;
> - XENBUS_STORE(Free, &Fdo->StoreInterface, Value);
> - return status;
> -
> -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;
> + return Status;
> }
>
> -static DECLSPEC_NOINLINE NTSTATUS
> -IoctlWrite(
> - __in PXENIFACE_FDO Fdo,
> - __in PCHAR Buffer,
> - __in ULONG InLen,
> - __in ULONG OutLen
> +VOID
> +__FreeCapturedBuffer(
> + __in PVOID CapturedBuffer
> )
> {
> - 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;
> + if (CapturedBuffer != NULL) {
> + ExFreePoolWithTag(CapturedBuffer, XENIFACE_POOL_TAG);
> + }
> }
>
> -static DECLSPEC_NOINLINE NTSTATUS
> -IoctlDirectory(
> - __in PXENIFACE_FDO Fdo,
> - __in PCHAR Buffer,
> - __in ULONG InLen,
> - __in ULONG OutLen,
> - __out PULONG_PTR Info
> +// 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 PFILE_OBJECT FileObject
> )
> {
> - 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(INFO, "|%s: (\"%s\")=(%d)(%d)\n",
> __FUNCTION__, Buffer, Length, Count);
> - goto done;
> - }
> -
> - status = STATUS_INVALID_PARAMETER;
> - if (OutLen < Length)
> - goto fail4;
> -
> - XenIfaceDebugPrint(INFO, "|%s: (\"%s\")=(%d)(%d)\n", __FUNCTION__,
> 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, "|%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;
> -}
> + 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);
> +
> + // 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);
>
> -static DECLSPEC_NOINLINE NTSTATUS
> -IoctlRemove(
> - __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(INFO, "|%s: (\"%s\")\n", __FUNCTION__, Buffer);
> - return status;
> -
> -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;
> + Node = ToFree.Flink;
> + while (Node->Flink != ToFree.Flink) {
> + EvtchnContext = CONTAINING_RECORD(Node,
> XENIFACE_EVTCHN_CONTEXT, Entry);
> + Node = Node->Flink;
> +
> + RemoveEntryList(&EvtchnContext->Entry);
> + EvtchnFree(Fdo, EvtchnContext);
> + }
> }
>
> NTSTATUS
> -XenIFaceIoctl(
> - __in PXENIFACE_FDO Fdo,
> - __in PIRP Irp
> +XenIfaceIoctl(
> + __in PXENIFACE_FDO Fdo,
> + __inout PIRP Irp
> )
> {
> NTSTATUS status;
> @@ -302,20 +160,71 @@ XenIFaceIoctl(
> goto done;
>
> switch (Stack->Parameters.DeviceIoControl.IoControlCode) {
> + // store
> case IOCTL_XENIFACE_STORE_READ:
> - status = IoctlRead(Fdo, (PCHAR)Buffer, InLen, OutLen, &Irp-
> >IoStatus.Information);
> + status = IoctlStoreRead(Fdo, (PCHAR)Buffer, InLen, OutLen, &Irp-
> >IoStatus.Information);
> break;
>
> case IOCTL_XENIFACE_STORE_WRITE:
> - status = IoctlWrite(Fdo, (PCHAR)Buffer, InLen, OutLen);
> + status = IoctlStoreWrite(Fdo, (PCHAR)Buffer, InLen, OutLen);
> break;
>
> case IOCTL_XENIFACE_STORE_DIRECTORY:
> - status = IoctlDirectory(Fdo, (PCHAR)Buffer, InLen, OutLen, &Irp-
> >IoStatus.Information);
> + status = IoctlStoreDirectory(Fdo, (PCHAR)Buffer, InLen, OutLen, &Irp-
> >IoStatus.Information);
> break;
>
> case IOCTL_XENIFACE_STORE_REMOVE:
> - status = IoctlRemove(Fdo, (PCHAR)Buffer, InLen, OutLen);
> + status = IoctlStoreRemove(Fdo, (PCHAR)Buffer, InLen, OutLen);
> + break;
> +
> + case IOCTL_XENIFACE_STORE_SET_PERMISSIONS:
> + status = IoctlStoreSetPermissions(Fdo, Buffer, InLen, OutLen);
> + break;
> +
> + case IOCTL_XENIFACE_STORE_ADD_WATCH:
> + status = IoctlStoreAddWatch(Fdo, Buffer, InLen, OutLen, Stack-
> >FileObject, &Irp->IoStatus.Information);
> + break;
> +
> + case IOCTL_XENIFACE_STORE_REMOVE_WATCH:
> + status = IoctlStoreRemoveWatch(Fdo, Buffer, InLen, OutLen, Stack-
> >FileObject);
> + break;
> +
> + // evtchn
> + case IOCTL_XENIFACE_EVTCHN_BIND_UNBOUND:
> + status = IoctlEvtchnBindUnbound(Fdo, Buffer, InLen, OutLen, Stack-
> >FileObject, &Irp->IoStatus.Information);
> + break;
> +
> + case IOCTL_XENIFACE_EVTCHN_BIND_INTERDOMAIN:
> + status = IoctlEvtchnBindInterdomain(Fdo, Buffer, InLen, OutLen, Stack-
> >FileObject, &Irp->IoStatus.Information);
> + break;
> +
> + case IOCTL_XENIFACE_EVTCHN_CLOSE:
> + status = IoctlEvtchnClose(Fdo, Buffer, InLen, OutLen, Stack-
> >FileObject);
> + break;
> +
> + case IOCTL_XENIFACE_EVTCHN_NOTIFY:
> + status = IoctlEvtchnNotify(Fdo, Buffer, InLen, OutLen, Stack-
> >FileObject);
> + break;
> +
> + case IOCTL_XENIFACE_EVTCHN_UNMASK:
> + status = IoctlEvtchnUnmask(Fdo, Buffer, InLen, OutLen, Stack-
> >FileObject);
> + break;
> +
> + // gnttab
> + case IOCTL_XENIFACE_GNTTAB_PERMIT_FOREIGN_ACCESS: // this is a
> METHOD_NEITHER IOCTL
> + status = IoctlGnttabPermitForeignAccess(Fdo, Stack-
> >Parameters.DeviceIoControl.Type3InputBuffer, InLen, OutLen, Irp);
> + break;
> +
> + case IOCTL_XENIFACE_GNTTAB_REVOKE_FOREIGN_ACCESS:
> + status = IoctlGnttabRevokeForeignAccess(Fdo, Buffer, InLen, OutLen);
> + break;
> +
> + case IOCTL_XENIFACE_GNTTAB_MAP_FOREIGN_PAGES: // this is a
> METHOD_NEITHER IOCTL
> + status = IoctlGnttabMapForeignPages(Fdo, Stack-
> >Parameters.DeviceIoControl.Type3InputBuffer, InLen, OutLen, Irp);
> + break;
> +
> + case IOCTL_XENIFACE_GNTTAB_UNMAP_FOREIGN_PAGES:
> + status = IoctlGnttabUnmapForeignPages(Fdo, Buffer, InLen, OutLen);
> break;
>
> default:
> @@ -327,7 +236,8 @@ done:
>
> Irp->IoStatus.Status = status;
>
> - IoCompleteRequest(Irp, IO_NO_INCREMENT);
> + if (status != STATUS_PENDING)
> + IoCompleteRequest(Irp, IO_NO_INCREMENT);
>
> return status;
> }
> diff --git a/src/xeniface/ioctls.h b/src/xeniface/ioctls.h
> index 63de9eb..225ed7f 100644
> --- a/src/xeniface/ioctls.h
> +++ b/src/xeniface/ioctls.h
> @@ -1,4 +1,5 @@
> /* Copyright (c) Citrix Systems Inc.
> + * Copyright (c) Rafal Wojdyla <omeg@invisiblethingslab.com>
> * All rights reserved.
> *
> * Redistribution and use in source and binary forms,
> @@ -32,10 +33,333 @@
> #ifndef _IOCTLS_H_
> #define _IOCTLS_H_
>
> +#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;
> + 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,
> - __in PIRP Irp
> +__CaptureUserBuffer(
> + __in PVOID Buffer,
> + __in ULONG Length,
> + __out PVOID *CapturedBuffer
> + );
> +
> +VOID
> +__FreeCapturedBuffer(
> + __in PVOID CapturedBuffer
> + );
> +
> +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
> +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 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..5184726
> --- /dev/null
> +++ b/src/xeniface/irp_queue.c
> @@ -0,0 +1,162 @@
> +/* Copyright (c) Rafal Wojdyla <omeg@invisiblethingslab.com>
> + * 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 "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..47c36dc
> --- /dev/null
> +++ b/src/xeniface/irp_queue.h
> @@ -0,0 +1,81 @@
> +/* Copyright (c) Rafal Wojdyla <omeg@invisiblethingslab.com>
> + * 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.
> + */
> +
> +#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/vs2012/xeniface/xeniface.vcxproj
> b/vs2012/xeniface/xeniface.vcxproj
> index a3472ba..fadc1d1 100644
> --- a/vs2012/xeniface/xeniface.vcxproj
> +++ b/vs2012/xeniface/xeniface.vcxproj
> @@ -73,12 +73,16 @@
> <FilesToPackage Include="@(Inf->'%(CopyOutput)')"
> Condition="'@(Inf)'!=''" />
> </ItemGroup>
> <ItemGroup>
> - <ClCompile Include="../../src/xeniface/ioctls.c" />
> - <ClCompile Include="../../src/xeniface/wmi.c" />
> - <ClCompile Include="../../src/xeniface/driver.c" />
> - <ClCompile Include="../../src/xeniface/fdo.c" />
> - <ClCompile Include="../../src/xeniface/registry.c" />
> - <ClCompile Include="../../src\xeniface/thread.c" />
> + <ClCompile Include="..\..\src\xeniface\ioctls.c" />
> + <ClCompile Include="..\..\src\xeniface\wmi.c" />
> + <ClCompile Include="..\..\src\xeniface\driver.c" />
> + <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">
> @@ -96,5 +100,19 @@
> <ItemGroup>
> <Inf Include="..\xeniface.inf" />
> </ItemGroup>
> + <ItemGroup>
> + <ClInclude Include="..\..\src\xeniface\assert.h" />
> + <ClInclude Include="..\..\src\xeniface\driver.h" />
> + <ClInclude Include="..\..\src\xeniface\fdo.h" />
> + <ClInclude Include="..\..\src\xeniface\ioctls.h" />
> + <ClInclude Include="..\..\src\xeniface\irp_queue.h" />
> + <ClInclude Include="..\..\src\xeniface\log.h" />
> + <ClInclude Include="..\..\src\xeniface\mutex.h" />
> + <ClInclude Include="..\..\src\xeniface\names.h" />
> + <ClInclude Include="..\..\src\xeniface\registry.h" />
> + <ClInclude Include="..\..\src\xeniface\thread.h" />
> + <ClInclude Include="..\..\src\xeniface\types.h" />
> + <ClInclude Include="..\..\src\xeniface\wmi.h" />
> + </ItemGroup>
> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
> </Project>
> diff --git a/vs2013/xeniface/xeniface.vcxproj
> b/vs2013/xeniface/xeniface.vcxproj
> index fea2ad1..44a1cdf 100644
> --- a/vs2013/xeniface/xeniface.vcxproj
> +++ b/vs2013/xeniface/xeniface.vcxproj
> @@ -125,12 +125,16 @@
> <FilesToPackage Include="@(Inf->'%(CopyOutput)')"
> Condition="'@(Inf)'!=''" />
> </ItemGroup>
> <ItemGroup>
> - <ClCompile Include="../../src/xeniface/ioctls.c" />
> - <ClCompile Include="../../src/xeniface/wmi.c" />
> - <ClCompile Include="../../src/xeniface/driver.c" />
> - <ClCompile Include="../../src/xeniface/fdo.c" />
> - <ClCompile Include="../../src/xeniface/registry.c" />
> - <ClCompile Include="../../src\xeniface/thread.c" />
> + <ClCompile Include="..\..\src\xeniface\ioctls.c" />
> + <ClCompile Include="..\..\src\xeniface\wmi.c" />
> + <ClCompile Include="..\..\src\xeniface\driver.c" />
> + <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">
> @@ -148,5 +152,19 @@
> <ItemGroup>
> <Inf Include="..\xeniface.inf" />
> </ItemGroup>
> + <ItemGroup>
> + <ClInclude Include="..\..\src\xeniface\assert.h" />
> + <ClInclude Include="..\..\src\xeniface\driver.h" />
> + <ClInclude Include="..\..\src\xeniface\fdo.h" />
> + <ClInclude Include="..\..\src\xeniface\ioctls.h" />
> + <ClInclude Include="..\..\src\xeniface\irp_queue.h" />
> + <ClInclude Include="..\..\src\xeniface\log.h" />
> + <ClInclude Include="..\..\src\xeniface\mutex.h" />
> + <ClInclude Include="..\..\src\xeniface\names.h" />
> + <ClInclude Include="..\..\src\xeniface\registry.h" />
> + <ClInclude Include="..\..\src\xeniface\thread.h" />
> + <ClInclude Include="..\..\src\xeniface\types.h" />
> + <ClInclude Include="..\..\src\xeniface\wmi.h" />
> + </ItemGroup>
> <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
> </Project>
> --
> 1.8.1.msysgit.1
>
> _______________________________________________
> win-pv-devel mailing list
> win-pv-devel@lists.xenproject.org
> http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel
_______________________________________________
win-pv-devel mailing list
win-pv-devel@lists.xenproject.org
http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel
[prev in list] [next in list] [prev in thread] [next in thread]
Configure |
About |
News |
Add a list |
Sponsored by KoreLogic