[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [win-pv-devel] [PATCH 4/5] Implement new IOCTL handlers
> -----Original Message----- > From: win-pv-devel-bounces@xxxxxxxxxxxxxxxxxxxx [mailto:win-pv-devel- > bounces@xxxxxxxxxxxxxxxxxxxx] On Behalf Of Rafal Wojdyla > Sent: 07 October 2015 05:49 > To: win-pv-devel@xxxxxxxxxxxxxxxxxxxx > Subject: [win-pv-devel] [PATCH 4/5] Implement new IOCTL handlers > > This patch implements new store, evtchn and gnttab IOCTLs. > Handlers are split into separate files for readability. > > Signed-off-by: Rafal Wojdyla <omeg@xxxxxxxxxxxxxxxxxxxxxx> > --- > src/xeniface/fdo.c | 188 ++++++++-- > src/xeniface/fdo.h | 25 +- > src/xeniface/ioctl_evtchn.c | 467 ++++++++++++++++++++++++ > src/xeniface/ioctl_gnttab.c | 765 > +++++++++++++++++++++++++++++++++++++++ > src/xeniface/ioctl_store.c | 574 +++++++++++++++++++++++++++++ > src/xeniface/ioctls.c | 360 ++++++------------ > src/xeniface/ioctls.h | 315 +++++++++++++++- > src/xeniface/irp_queue.c | 131 +++++++ > src/xeniface/irp_queue.h | 50 +++ > vs2013/xeniface/xeniface.vcxproj | 4 + > 10 files changed, 2602 insertions(+), 277 deletions(-) > create mode 100644 src/xeniface/ioctl_evtchn.c > create mode 100644 src/xeniface/ioctl_gnttab.c > create mode 100644 src/xeniface/ioctl_store.c > create mode 100644 src/xeniface/irp_queue.c > create mode 100644 src/xeniface/irp_queue.h > > diff --git a/src/xeniface/fdo.c b/src/xeniface/fdo.c > index 51bda24..338c8da 100644 > --- a/src/xeniface/fdo.c > +++ b/src/xeniface/fdo.c > @@ -36,7 +36,8 @@ > #include <stdlib.h> > > #include <store_interface.h> > - > +#include <evtchn_interface.h> > +#include <gnttab_interface.h> > #include <suspend_interface.h> > > > @@ -52,6 +53,7 @@ > #include "ioctls.h" > #include "wmi.h" > #include "xeniface_ioctls.h" > +#include "irp_queue.h" > > #define FDO_POOL 'ODF' > > @@ -664,6 +666,25 @@ __FdoD3ToD0( > if (!NT_SUCCESS(status)) > goto fail1; > > + status = XENBUS_EVTCHN(Acquire, &Fdo->EvtchnInterface); > + if (!NT_SUCCESS(status)) > + goto fail2; > + > + status = XENBUS_GNTTAB(Acquire, &Fdo->GnttabInterface); > + if (!NT_SUCCESS(status)) > + goto fail3; > + > + status = XENBUS_GNTTAB(CreateCache, > + &Fdo->GnttabInterface, > + "xeniface-gnttab", > + 0, > + GnttabAcquireLock, > + GnttabReleaseLock, > + Fdo, > + &Fdo->GnttabCache); > + if (!NT_SUCCESS(status)) > + goto fail4; > + > __FdoSetDevicePowerState(Fdo, PowerDeviceD0); > > PowerState.DeviceState = PowerDeviceD0; > @@ -675,6 +696,18 @@ __FdoD3ToD0( > > return STATUS_SUCCESS; > > +fail4: > + Error("fail4\n"); > + XENBUS_GNTTAB(Release, &Fdo->GnttabInterface); > + > +fail3: > + Error("fail3\n"); > + XENBUS_EVTCHN(Release, &Fdo->EvtchnInterface); > + > +fail2: > + Error("fail2\n"); > + XENBUS_STORE(Release, &Fdo->StoreInterface); > + > fail1: > Error("fail1 (%08x)\n", status); > > @@ -700,6 +733,9 @@ __FdoD0ToD3( > > __FdoSetDevicePowerState(Fdo, PowerDeviceD3); > > + XENBUS_GNTTAB(DestroyCache, &Fdo->GnttabInterface, Fdo- > >GnttabCache); > + XENBUS_GNTTAB(Release, &Fdo->GnttabInterface); > + XENBUS_EVTCHN(Release, &Fdo->EvtchnInterface); > XENBUS_STORE(Release, &Fdo->StoreInterface); > > Trace("<====\n"); > @@ -1991,27 +2027,25 @@ FdoDispatchDefault( > > NTSTATUS > FdoCreateFile ( > - __in PXENIFACE_FDO fdoData, > - __inout PIRP Irp > + __in PXENIFACE_FDO Fdo, > + __inout PIRP Irp > ) > { > - NTSTATUS status; > - > + PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); > + NTSTATUS status; > > - XenIfaceDebugPrint(TRACE, "Create \n"); > + XenIfaceDebugPrint(TRACE, "FO %p, Process %p\n", Stack->FileObject, > PsGetCurrentProcess()); > > - if (Deleted == fdoData->Dx->DevicePnpState) > - { > + if (Deleted == Fdo->Dx->DevicePnpState) { > Irp->IoStatus.Status = STATUS_NO_SUCH_DEVICE; > - IoCompleteRequest (Irp, IO_NO_INCREMENT); > + IoCompleteRequest(Irp, IO_NO_INCREMENT); > return STATUS_NO_SUCH_DEVICE; > } > > - > status = STATUS_SUCCESS; > Irp->IoStatus.Information = 0; > Irp->IoStatus.Status = status; > - IoCompleteRequest (Irp, IO_NO_INCREMENT); > + IoCompleteRequest(Irp, IO_NO_INCREMENT); > > return status; > } > @@ -2019,20 +2053,22 @@ FdoCreateFile ( > > NTSTATUS > FdoClose ( > - __in PXENIFACE_FDO fdoData, > - __inout PIRP Irp > + __in PXENIFACE_FDO Fdo, > + __inout PIRP Irp > ) > > { > + PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); > + NTSTATUS status; > > - NTSTATUS status; > + XenIfaceDebugPrint(TRACE, "FO %p, Process %p\n", Stack->FileObject, > PsGetCurrentProcess()); > > - XenIfaceDebugPrint(TRACE, "Close \n"); > + XenIfaceCleanup(Fdo, Stack->FileObject); > > status = STATUS_SUCCESS; > Irp->IoStatus.Information = 0; > Irp->IoStatus.Status = status; > - IoCompleteRequest (Irp, IO_NO_INCREMENT); > + IoCompleteRequest(Irp, IO_NO_INCREMENT); > > return status; > } > @@ -2080,9 +2116,9 @@ FdoDispatch( > status = FdoDispatchPower(Fdo, Irp); > break; > > - case IRP_MJ_DEVICE_CONTROL: > - status = XenIFaceIoctl(Fdo, Irp); > - break; > + case IRP_MJ_DEVICE_CONTROL: > + status = XenIfaceIoctl(Fdo, Irp); > + break; > > case IRP_MJ_SYSTEM_CONTROL: > status = XenIfaceSystemControl(Fdo, Irp); > @@ -2206,6 +2242,7 @@ FdoCreate( > WCHAR Name[MAXNAMELEN * sizeof (WCHAR)]; > ULONG Size; > NTSTATUS status; > + ULONG ProcessorCount; > > #pragma prefast(suppress:28197) // Possibly leaking memory > 'FunctionDeviceObject' > status = IoCreateDevice(DriverObject, > @@ -2296,6 +2333,24 @@ FdoCreate( > if (!NT_SUCCESS(status)) > goto fail10; > > + status = FDO_QUERY_INTERFACE(Fdo, > + XENBUS, > + EVTCHN, > + (PINTERFACE)&Fdo->EvtchnInterface, > + sizeof(Fdo->EvtchnInterface), > + FALSE); > + if (!NT_SUCCESS(status)) > + goto fail11; > + > + status = FDO_QUERY_INTERFACE(Fdo, > + XENBUS, > + GNTTAB, > + (PINTERFACE)&Fdo->GnttabInterface, > + sizeof(Fdo->GnttabInterface), > + FALSE); > + if (!NT_SUCCESS(status)) > + goto fail12; > + > InitializeMutex(&Fdo->Mutex); > InitializeListHead(&Dx->ListEntry); > Fdo->References = 1; > @@ -2304,9 +2359,46 @@ FdoCreate( > > KeInitializeEvent(&Fdo->registryWriteEvent, NotificationEvent, > FALSE); > > - status = ThreadCreate(FdoRegistryThreadHandler, Fdo, &Fdo- > >registryThread); > - if (!NT_SUCCESS(status)) > - goto fail11; > + status = ThreadCreate(FdoRegistryThreadHandler, Fdo, &Fdo- > >registryThread); > + if (!NT_SUCCESS(status)) > + goto fail13; > + > + KeInitializeSpinLock(&Fdo->StoreWatchLock); > + InitializeListHead(&Fdo->StoreWatchList); > + > + KeInitializeSpinLock(&Fdo->EvtchnLock); > + InitializeListHead(&Fdo->EvtchnList); > + > + KeInitializeSpinLock(&Fdo->IrpQueueLock); > + InitializeListHead(&Fdo->IrpList); > + > + KeInitializeSpinLock(&Fdo->GnttabCacheLock); > + > + status = IoCsqInitializeEx(&Fdo->IrpQueue, > + CsqInsertIrpEx, > + CsqRemoveIrp, > + CsqPeekNextIrp, > + CsqAcquireLock, > + CsqReleaseLock, > + CsqCompleteCanceledIrp); > + if (!NT_SUCCESS(status)) > + goto fail14; > + > + ProcessorCount = > KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS); > + status = STATUS_NO_MEMORY; Need a blank line here, I think. > + Fdo->EvtchnDpc = __FdoAllocate(sizeof(KDPC) * ProcessorCount); > + if (Fdo->EvtchnDpc == NULL) > + goto fail15; > + > + for (ULONG i = 0; i < ProcessorCount; i++) { Let's not use C++-isms where we don't have to. Also use 'Index' or somesuch rather than 'i'. > + PROCESSOR_NUMBER ProcNumber; > + > + status = KeGetProcessorNumberFromIndex(i, &ProcNumber); > + ASSERT(NT_SUCCESS(status)); Blank line here. > + KeInitializeDpc(&Fdo->EvtchnDpc[i], EvtchnNotificationDpc, NULL); > + status = KeSetTargetProcessorDpcEx(&Fdo->EvtchnDpc[i], > &ProcNumber); > + ASSERT(NT_SUCCESS(status)); > + } > > Info("%p (%s)\n", > FunctionDeviceObject, > @@ -2317,7 +2409,28 @@ FdoCreate( > > return STATUS_SUCCESS; > > - > +fail15: > + Error("fail15\n"); > + > +fail14: > + Error("fail14\n"); > + > + ThreadAlert(Fdo->registryThread); > + ThreadJoin(Fdo->registryThread); > + Fdo->registryThread = NULL; > + > +fail13: > + Error("fail13\n"); > + > + RtlZeroMemory(&Fdo->GnttabInterface, > + sizeof (XENBUS_GNTTAB_INTERFACE)); > + > +fail12: > + Error("fail12\n"); > + > + RtlZeroMemory(&Fdo->EvtchnInterface, > + sizeof(XENBUS_EVTCHN_INTERFACE)); > + > fail11: > Error("fail11\n"); > > @@ -2395,6 +2508,7 @@ FdoDestroy( > { > PXENIFACE_DX Dx = Fdo->Dx; > PDEVICE_OBJECT FunctionDeviceObject = Dx->DeviceObject; > + ULONG ProcessorCount; > > ASSERT(IsListEmpty(&Dx->ListEntry)); > ASSERT3U(Fdo->References, ==, 0); > @@ -2408,9 +2522,33 @@ FdoDestroy( > > Dx->Fdo = NULL; > > - RtlZeroMemory(&Fdo->Mutex, sizeof (XENIFACE_MUTEX)); > + ProcessorCount = > KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS); > + RtlZeroMemory(Fdo->EvtchnDpc, sizeof(KDPC)*ProcessorCount); Spaces around '*'. Also I don't think it's safe to use the active processor count. What if a processor came online since the FDO was created? > + __FdoFree(Fdo->EvtchnDpc); > > - Fdo->InterfacesAcquired = FALSE; > + RtlZeroMemory(&Fdo->GnttabCacheLock, sizeof(KSPIN_LOCK)); > + ASSERT(IsListEmpty(&Fdo->IrpList)); > + RtlZeroMemory(&Fdo->IrpList, sizeof(LIST_ENTRY)); > + RtlZeroMemory(&Fdo->IrpQueueLock, sizeof(KSPIN_LOCK)); > + RtlZeroMemory(&Fdo->IrpQueue, sizeof(IO_CSQ)); > + > + ASSERT(IsListEmpty(&Fdo->EvtchnList)); > + RtlZeroMemory(&Fdo->EvtchnList, sizeof(LIST_ENTRY)); > + RtlZeroMemory(&Fdo->EvtchnLock, sizeof(KSPIN_LOCK)); > + > + ASSERT(IsListEmpty(&Fdo->StoreWatchList)); > + RtlZeroMemory(&Fdo->StoreWatchList, sizeof(LIST_ENTRY)); > + RtlZeroMemory(&Fdo->StoreWatchLock, sizeof(KSPIN_LOCK)); > + > + RtlZeroMemory(&Fdo->Mutex, sizeof(XENIFACE_MUTEX)); > + > + Fdo->InterfacesAcquired = FALSE; > + > + RtlZeroMemory(&Fdo->GnttabInterface, > + sizeof(XENBUS_GNTTAB_INTERFACE)); > + > + RtlZeroMemory(&Fdo->EvtchnInterface, > + sizeof(XENBUS_EVTCHN_INTERFACE)); > > RtlZeroMemory(&Fdo->StoreInterface, > sizeof (XENBUS_STORE_INTERFACE)); > diff --git a/src/xeniface/fdo.h b/src/xeniface/fdo.h > index 4416064..cbe5de3 100644 > --- a/src/xeniface/fdo.h > +++ b/src/xeniface/fdo.h > @@ -34,6 +34,8 @@ > > #include <ntifs.h> > #include <store_interface.h> > +#include <evtchn_interface.h> > +#include <gnttab_interface.h> > #include <suspend_interface.h> > #include <shared_info_interface.h> > > @@ -73,17 +75,30 @@ typedef struct _XENIFACE_FDO { > > FDO_RESOURCE Resource[RESOURCE_COUNT]; > > - > XENBUS_STORE_INTERFACE StoreInterface; > - > XENBUS_SUSPEND_INTERFACE SuspendInterface; > - > - XENBUS_SHARED_INFO_INTERFACE SharedInfoInterface; > - > + XENBUS_SHARED_INFO_INTERFACE SharedInfoInterface; > + XENBUS_EVTCHN_INTERFACE EvtchnInterface; > + XENBUS_GNTTAB_INTERFACE GnttabInterface; > PXENBUS_SUSPEND_CALLBACK SuspendCallbackLate; > > BOOLEAN > InterfacesAcquired; > Since you're fixing whitespace, could you fix the above to have sane tabbing? > + KSPIN_LOCK StoreWatchLock; > + LIST_ENTRY StoreWatchList; > + > + KSPIN_LOCK EvtchnLock; > + LIST_ENTRY EvtchnList; > + PKDPC EvtchnDpc; > + > + KSPIN_LOCK GnttabCacheLock; > + > + IO_CSQ IrpQueue; > + KSPIN_LOCK IrpQueueLock; > + LIST_ENTRY IrpList; > + > + PXENBUS_GNTTAB_CACHE GnttabCache; > + > #define MAX_SESSIONS (65536) > > int WmiReady; > diff --git a/src/xeniface/ioctl_evtchn.c b/src/xeniface/ioctl_evtchn.c > new file mode 100644 > index 0000000..d46894f > --- /dev/null > +++ b/src/xeniface/ioctl_evtchn.c > @@ -0,0 +1,467 @@ > +/* Copyright (c) Citrix Systems Inc. > + * All rights reserved. You're not obliged to give Citrix copyright AFAIK. As long as it's BSD licensed I think we're all happy. > + * > + * Redistribution and use in source and binary forms, > + * with or without modification, are permitted provided > + * that the following conditions are met: > + * > + * * Redistributions of source code must retain the above > + * copyright notice, this list of conditions and the > + * following disclaimer. > + * * Redistributions in binary form must reproduce the above > + * copyright notice, this list of conditions and the > + * following disclaimer in the documentation and/or other > + * materials provided with the distribution. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND > + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, > + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE > + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR > + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, > + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR > + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, > + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING > + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE > + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > + * SUCH DAMAGE. > + */ > + > +#include "driver.h" > +#include "ioctls.h" > +#include "..\..\include\xeniface_ioctls.h" Hmm. I think you should really use #include <xeniface_ioctls.h> > +#include "log.h" > + > +_Function_class_(KDEFERRED_ROUTINE) > +_IRQL_requires_(DISPATCH_LEVEL) > +_IRQL_requires_same_ > +VOID > +EvtchnNotificationDpc( > + __in PKDPC Dpc, > + __in_opt PVOID _Context, > + __in_opt PVOID Argument1, > + __in_opt PVOID Argument2 > + ) > +{ > + PXENIFACE_EVTCHN_CONTEXT Context = > (PXENIFACE_EVTCHN_CONTEXT)Argument1; > + > + UNREFERENCED_PARAMETER(Dpc); > + UNREFERENCED_PARAMETER(_Context); > + UNREFERENCED_PARAMETER(Argument2); > + > + ASSERT(Context); > + > +#if DBG > + XenIfaceDebugPrint(INFO, "Channel %p, LocalPort %d, Active %d, Cpu > %lu\n", > + Context->Channel, Context->LocalPort, Context->Active, > KeGetCurrentProcessorNumber()); > +#endif > + if (Context->Active) { > + KeSetEvent(Context->Event, 0, FALSE); > + > + XENBUS_EVTCHN(Unmask, > + &Context->Fdo->EvtchnInterface, > + Context->Channel, > + FALSE); > + } > +} > + > +_Function_class_(KSERVICE_ROUTINE) > +_IRQL_requires_(HIGH_LEVEL) > +_IRQL_requires_same_ > +static DECLSPEC_NOINLINE > +BOOLEAN > +EvtchnInterruptHandler( > + __in PKINTERRUPT Interrupt, > + __in_opt PVOID Argument > + ) > +{ > + PXENIFACE_EVTCHN_CONTEXT Context = > (PXENIFACE_EVTCHN_CONTEXT)Argument; > + PROCESSOR_NUMBER ProcNumber; > + ULONG ProcIndex; > + > + UNREFERENCED_PARAMETER(Interrupt); > + ASSERT(Context); > + > + KeGetCurrentProcessorNumberEx(&ProcNumber); > + ProcIndex = KeGetProcessorIndexFromNumber(&ProcNumber); > + if (Context->Active) > + KeInsertQueueDpc(&Context->Fdo->EvtchnDpc[ProcIndex], Context, > NULL); > + > + return TRUE; > +} > + > +_IRQL_requires_(PASSIVE_LEVEL) // needed for KeFlushQueuedDpcs > +VOID > +EvtchnFree( > + __in PXENIFACE_FDO Fdo, > + __inout PXENIFACE_EVTCHN_CONTEXT Context > + ) > +{ > + ASSERT(KeGetCurrentIrql() == PASSIVE_LEVEL); > + > + XenIfaceDebugPrint(TRACE, "Context %p, LocalPort %d, FO %p\n", > + Context, Context->LocalPort, Context->FileObject); > + > + InterlockedExchange8(&Context->Active, 0); > + > + XENBUS_EVTCHN(Close, > + &Fdo->EvtchnInterface, > + Context->Channel); > + > + // There may still be a pending event at this time. > + // Wait for our DPCs to complete. > + KeFlushQueuedDpcs(); > + > + ObDereferenceObject(Context->Event); > + RtlZeroMemory(Context, sizeof(XENIFACE_EVTCHN_CONTEXT)); 'sizeof' is a keyword so it really should be sizeof (), similar to if () or for (). > + ExFreePoolWithTag(Context, XENIFACE_POOL_TAG); > +} > + > +_Requires_exclusive_lock_held_(Fdo->EvtchnLock) > +static > +PXENIFACE_EVTCHN_CONTEXT > +EvtchnFindChannel( > + __in PXENIFACE_FDO Fdo, > + __in ULONG LocalPort, > + __in_opt PFILE_OBJECT FileObject > + ) > +{ > + PXENIFACE_EVTCHN_CONTEXT Context, Found = NULL; > + PLIST_ENTRY Node; > + > + Node = Fdo->EvtchnList.Flink; > + while (Node->Flink != Fdo->EvtchnList.Flink) { > + Context = CONTAINING_RECORD(Node, XENIFACE_EVTCHN_CONTEXT, > Entry); > + > + Node = Node->Flink; > + if (Context->LocalPort != LocalPort) > + continue; > + > + if (FileObject != NULL && Context->FileObject != FileObject) > + continue; > + > + Found = Context; > + break; > + } > + > + return Found; > +} > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlEvtchnBindUnbound( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __in PFILE_OBJECT FileObject, > + __out PULONG_PTR Info > + ) > +{ > + NTSTATUS status; > + PXENIFACE_EVTCHN_BIND_UNBOUND_IN In = Buffer; > + PXENIFACE_EVTCHN_BIND_UNBOUND_OUT Out = Buffer; > + PXENIFACE_EVTCHN_CONTEXT Context; > + > + status = STATUS_INVALID_BUFFER_SIZE; > + if (InLen != sizeof(XENIFACE_EVTCHN_BIND_UNBOUND_IN) || OutLen != > sizeof(XENIFACE_EVTCHN_BIND_UNBOUND_OUT)) Break this line at the '||'. > + goto fail1; > + > + status = STATUS_NO_MEMORY; > + Context = ExAllocatePoolWithTag(NonPagedPool, > sizeof(XENIFACE_EVTCHN_CONTEXT), XENIFACE_POOL_TAG); > + if (Context == NULL) > + goto fail2; > + > + RtlZeroMemory(Context, sizeof(XENIFACE_EVTCHN_CONTEXT)); > + Context->FileObject = FileObject; > + > + XenIfaceDebugPrint(TRACE, "> RemoteDomain %d, Mask %d, FO %p\n", > + In->RemoteDomain, In->Mask, FileObject); > + > + status = ObReferenceObjectByHandle(In->Event, > EVENT_MODIFY_STATE, *ExEventObjectType, UserMode, &Context->Event, > NULL); > + if (!NT_SUCCESS(status)) > + goto fail3; > + > + status = STATUS_UNSUCCESSFUL; > + Context->Channel = XENBUS_EVTCHN(Open, > + &Fdo->EvtchnInterface, > + XENBUS_EVTCHN_TYPE_UNBOUND, > + EvtchnInterruptHandler, > + Context, > + In->RemoteDomain, > + TRUE); > + if (Context->Channel == NULL) > + goto fail4; > + > + Context->LocalPort = XENBUS_EVTCHN(GetPort, > + &Fdo->EvtchnInterface, > + Context->Channel); > + > + Context->Fdo = Fdo; > + > + ExInterlockedInsertTailList(&Fdo->EvtchnList, &Context->Entry, &Fdo- > >EvtchnLock); > + > + InterlockedExchange8(&Context->Active, 1); > + Out->LocalPort = Context->LocalPort; > + *Info = sizeof(XENIFACE_EVTCHN_BIND_UNBOUND_OUT); > + > + if (!In->Mask) { > + XENBUS_EVTCHN(Unmask, > + &Fdo->EvtchnInterface, > + Context->Channel, > + FALSE); > + } > + > + XenIfaceDebugPrint(TRACE, "< LocalPort %lu, Context %p\n", Context- > >LocalPort, Context); > + return STATUS_SUCCESS; > + > +fail4: > + XenIfaceDebugPrint(ERROR, "Fail4\n"); > + ObDereferenceObject(Context->Event); > +fail3: > + XenIfaceDebugPrint(ERROR, "Fail3\n"); > + RtlZeroMemory(Context, sizeof(XENIFACE_EVTCHN_CONTEXT)); > + ExFreePoolWithTag(Context, XENIFACE_POOL_TAG); > +fail2: > + XenIfaceDebugPrint(ERROR, "Fail2\n"); > +fail1: > + XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status); > + return status; > +} > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlEvtchnBindInterdomain( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __in PFILE_OBJECT FileObject, > + __out PULONG_PTR Info > + ) > +{ > + NTSTATUS status; > + PXENIFACE_EVTCHN_BIND_INTERDOMAIN_IN In = Buffer; > + PXENIFACE_EVTCHN_BIND_INTERDOMAIN_OUT Out = Buffer; > + PXENIFACE_EVTCHN_CONTEXT Context; > + > + status = STATUS_INVALID_BUFFER_SIZE; > + if (InLen != sizeof(XENIFACE_EVTCHN_BIND_INTERDOMAIN_IN) || > OutLen != sizeof(XENIFACE_EVTCHN_BIND_INTERDOMAIN_OUT)) > + goto fail1; > + > + status = STATUS_NO_MEMORY; > + Context = ExAllocatePoolWithTag(NonPagedPool, > sizeof(XENIFACE_EVTCHN_CONTEXT), XENIFACE_POOL_TAG); > + if (Context == NULL) > + goto fail2; > + > + RtlZeroMemory(Context, sizeof(XENIFACE_EVTCHN_CONTEXT)); > + Context->FileObject = FileObject; > + > + XenIfaceDebugPrint(TRACE, "> RemoteDomain %d, RemotePort %lu, > Mask %d, FO %p\n", > + In->RemoteDomain, In->RemotePort, In->Mask, > FileObject); > + > + status = ObReferenceObjectByHandle(In->Event, > EVENT_MODIFY_STATE, *ExEventObjectType, UserMode, &Context->Event, > NULL); > + if (!NT_SUCCESS(status)) > + goto fail3; > + > + status = STATUS_UNSUCCESSFUL; > + Context->Channel = XENBUS_EVTCHN(Open, > + &Fdo->EvtchnInterface, > + XENBUS_EVTCHN_TYPE_INTER_DOMAIN, > + EvtchnInterruptHandler, > + Context, > + In->RemoteDomain, > + In->RemotePort, > + TRUE); > + if (Context->Channel == NULL) > + goto fail4; > + > + Context->LocalPort = XENBUS_EVTCHN(GetPort, > + &Fdo->EvtchnInterface, > + Context->Channel); > + > + Context->Fdo = Fdo; > + > + ExInterlockedInsertTailList(&Fdo->EvtchnList, &Context->Entry, &Fdo- > >EvtchnLock); > + > + InterlockedExchange8(&Context->Active, 1); > + Out->LocalPort = Context->LocalPort; > + *Info = sizeof(XENIFACE_EVTCHN_BIND_INTERDOMAIN_OUT); > + > + if (!In->Mask) { > + XENBUS_EVTCHN(Unmask, > + &Fdo->EvtchnInterface, > + Context->Channel, > + FALSE); > + } > + > + XenIfaceDebugPrint(TRACE, "< LocalPort %lu, Context %p\n", Context- > >LocalPort, Context); > + > + return STATUS_SUCCESS; > + > +fail4: > + XenIfaceDebugPrint(ERROR, "Fail4\n"); > + ObDereferenceObject(Context->Event); > +fail3: > + XenIfaceDebugPrint(ERROR, "Fail3\n"); > + RtlZeroMemory(Context, sizeof(XENIFACE_EVTCHN_CONTEXT)); > + ExFreePoolWithTag(Context, XENIFACE_POOL_TAG); > +fail2: > + XenIfaceDebugPrint(ERROR, "Fail2\n"); > +fail1: > + XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status); > + return status; > +} > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlEvtchnClose( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __in PFILE_OBJECT FileObject > + ) > +{ > + NTSTATUS status; > + PXENIFACE_EVTCHN_CLOSE_IN In = Buffer; > + PXENIFACE_EVTCHN_CONTEXT Context = NULL; > + KIRQL Irql; > + > + status = STATUS_INVALID_BUFFER_SIZE; > + if (InLen != sizeof(XENIFACE_EVTCHN_CLOSE_IN) || OutLen != 0) > + goto fail1; > + > + XenIfaceDebugPrint(TRACE, "> LocalPort %lu, FO %p\n", In->LocalPort, > FileObject); > + > + KeAcquireSpinLock(&Fdo->EvtchnLock, &Irql); > + Context = EvtchnFindChannel(Fdo, In->LocalPort, FileObject); > + if (Context != NULL) Could you not go straight to fail2 here (and drop the lock there) and thus get rid of the tests for Context == or != NULL below? > + RemoveEntryList(&Context->Entry); > + KeReleaseSpinLock(&Fdo->EvtchnLock, Irql); > + if (Context != NULL) > + EvtchnFree(Fdo, Context); > + > + status = STATUS_NOT_FOUND; > + if (Context == NULL) > + goto fail2; > + > + return STATUS_SUCCESS; > + > +fail2: > + XenIfaceDebugPrint(ERROR, "Fail2\n"); > +fail1: > + XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status); > + return status; > +} > + > +_Requires_lock_not_held_(Fdo->EvtchnLock) > +DECLSPEC_NOINLINE > +NTSTATUS > +EvtchnNotify( > + __in PXENIFACE_FDO Fdo, > + __in ULONG LocalPort, > + __in_opt PFILE_OBJECT FileObject > + ) > +{ > + NTSTATUS status; > + PXENIFACE_EVTCHN_CONTEXT Context = NULL; > + KIRQL Irql; > + > + KeAcquireSpinLock(&Fdo->EvtchnLock, &Irql); > + > + Context = EvtchnFindChannel(Fdo, LocalPort, FileObject); > + > + status = STATUS_NOT_FOUND; > + if (Context == NULL) > + goto fail1; > + > + XENBUS_EVTCHN(Send, > + &Fdo->EvtchnInterface, > + Context->Channel); > + > + KeReleaseSpinLock(&Fdo->EvtchnLock, Irql); > + > + return STATUS_SUCCESS; > + > +fail1: > + KeReleaseSpinLock(&Fdo->EvtchnLock, Irql); > + XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status); > + return status; > +} > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlEvtchnNotify( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __in PFILE_OBJECT FileObject > + ) > +{ > + NTSTATUS status; > + PXENIFACE_EVTCHN_NOTIFY_IN In = Buffer; > + > + status = STATUS_INVALID_BUFFER_SIZE; > + if (InLen != sizeof(XENIFACE_EVTCHN_NOTIFY_IN) || OutLen != 0) > + goto fail1; > +#if DBG > + XenIfaceDebugPrint(INFO, "> LocalPort %d, FO %p\n", In->LocalPort, > FileObject); > +#endif > + > + return EvtchnNotify(Fdo, In->LocalPort, FileObject); > + > +fail1: > + XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status); > + return status; > +} > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlEvtchnUnmask( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __in PFILE_OBJECT FileObject > + ) > +{ > + NTSTATUS status; > + PXENIFACE_EVTCHN_UNMASK_IN In = Buffer; > + PXENIFACE_EVTCHN_CONTEXT Context = NULL; > + KIRQL Irql; > + > + status = STATUS_INVALID_BUFFER_SIZE; > + if (InLen != sizeof(XENIFACE_EVTCHN_UNMASK_IN) || OutLen != 0) > + goto fail1; > + > + XenIfaceDebugPrint(TRACE, "> LocalPort %d, FO %p\n", In->LocalPort, > FileObject); > + > + KeAcquireSpinLock(&Fdo->EvtchnLock, &Irql); > + > + Context = EvtchnFindChannel(Fdo, In->LocalPort, FileObject); > + > + status = STATUS_INVALID_PARAMETER; > + if (Context == NULL) > + goto fail2; > + > + XENBUS_EVTCHN(Unmask, > + &Fdo->EvtchnInterface, > + Context->Channel, > + FALSE); > + > + KeReleaseSpinLock(&Fdo->EvtchnLock, Irql); > + > + return STATUS_SUCCESS; > + > +fail2: > + KeReleaseSpinLock(&Fdo->EvtchnLock, Irql); > + XenIfaceDebugPrint(ERROR, "Fail2\n"); > + > +fail1: > + XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status); > + return status; > +} > diff --git a/src/xeniface/ioctl_gnttab.c b/src/xeniface/ioctl_gnttab.c > new file mode 100644 > index 0000000..a279b77 > --- /dev/null > +++ b/src/xeniface/ioctl_gnttab.c > @@ -0,0 +1,765 @@ > +/* Copyright (c) Citrix Systems Inc. > + * All rights reserved. > + * > + * Redistribution and use in source and binary forms, > + * with or without modification, are permitted provided > + * that the following conditions are met: > + * > + * * Redistributions of source code must retain the above > + * copyright notice, this list of conditions and the > + * following disclaimer. > + * * Redistributions in binary form must reproduce the above > + * copyright notice, this list of conditions and the > + * following disclaimer in the documentation and/or other > + * materials provided with the distribution. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND > + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, > + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE > + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR > + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, > + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR > + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, > + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING > + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE > + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > + * SUCH DAMAGE. > + */ > + > +#include "driver.h" > +#include "ioctls.h" > +#include "..\..\include\xeniface_ioctls.h" Use <> too. > +#include "log.h" > +#include "irp_queue.h" > + > +// Complete a canceled gnttab IRP, cleanup associated grant/map. > +_Function_class_(IO_WORKITEM_ROUTINE) > +VOID > +CompleteGnttabIrp( > + __in PDEVICE_OBJECT DeviceObject, > + __in_opt PVOID Context > + ) > +{ > + PXENIFACE_DX Dx = (PXENIFACE_DX)DeviceObject->DeviceExtension; > + PXENIFACE_FDO Fdo = Dx->Fdo; > + PIRP Irp = Context; > + PXENIFACE_CONTEXT_ID Id; > + PIO_WORKITEM WorkItem; > + KAPC_STATE ApcState; > + BOOLEAN ChangeProcess; > + > + ASSERT(Context != NULL); > + > + Id = Irp->Tail.Overlay.DriverContext[0]; > + WorkItem = Irp->Tail.Overlay.DriverContext[1]; > + > + // We are not guaranteed to be in the context of the process that > initiated the IRP, > + // but we need to be there to unmap memory. > + ChangeProcess = PsGetCurrentProcess() != Id->Process; > + if (ChangeProcess) { > + XenIfaceDebugPrint(TRACE, "Changing process from %p to %p\n", > PsGetCurrentProcess(), Id->Process); > + KeStackAttachProcess(Id->Process, &ApcState); > + } > + > + XenIfaceDebugPrint(TRACE, "Irp %p, Process %p, Id %lu, Type %d, IRQL > %d\n", > + Irp, Id->Process, Id->RequestId, Id->Type, > KeGetCurrentIrql()); > + > + switch (Id->Type) { > + > + case XENIFACE_CONTEXT_GRANT: > + GnttabFreeGrant(Fdo, CONTAINING_RECORD(Id, > XENIFACE_GRANT_CONTEXT, Id)); > + break; > + > + case XENIFACE_CONTEXT_MAP: > + GnttabFreeMap(Fdo, CONTAINING_RECORD(Id, > XENIFACE_MAP_CONTEXT, Id)); > + break; > + > + default: > + ASSERT(FALSE); > + } > + > + if (ChangeProcess) > + KeUnstackDetachProcess(&ApcState); > + > + IoFreeWorkItem(WorkItem); > + > + Irp->IoStatus.Status = STATUS_CANCELLED; > + Irp->IoStatus.Information = 0; > + IoCompleteRequest(Irp, IO_NO_INCREMENT); > +} > + > +_Acquires_exclusive_lock_(((PXENIFACE_FDO)Argument)- > >GnttabCacheLock) > +_IRQL_requires_(DISPATCH_LEVEL) > +VOID > +GnttabAcquireLock( > + __in PVOID Argument > + ) > +{ > + PXENIFACE_FDO Fdo = Argument; > + > + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); > + > + KeAcquireSpinLockAtDpcLevel(&Fdo->GnttabCacheLock); > +} > + > +_Releases_exclusive_lock_(((PXENIFACE_FDO)Argument)- > >GnttabCacheLock) > +_IRQL_requires_(DISPATCH_LEVEL) > +VOID > +GnttabReleaseLock( > + __in PVOID Argument > + ) > +{ > + PXENIFACE_FDO Fdo = Argument; > + > + ASSERT(KeGetCurrentIrql() == DISPATCH_LEVEL); > + > + KeReleaseSpinLockFromDpcLevel(&Fdo->GnttabCacheLock); > +} > + > +_Requires_lock_not_held_(Fdo->IrpQueueLock) > +static > +PIRP > +FindGnttabIrp( > + __in PXENIFACE_FDO Fdo, > + __in PXENIFACE_CONTEXT_ID Id > + ) > +{ > + KIRQL Irql; > + PIRP Irp; > + > + CsqAcquireLock(&Fdo->IrpQueue, &Irql); > + Irp = CsqPeekNextIrp(&Fdo->IrpQueue, NULL, Id); > + CsqReleaseLock(&Fdo->IrpQueue, Irql); > + return Irp; > +} > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlGnttabPermitForeignAccess( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __inout PIRP Irp > + ) > +{ > + NTSTATUS status; > + PXENIFACE_GNTTAB_PERMIT_FOREIGN_ACCESS_IN In = Buffer; > + PXENIFACE_GRANT_CONTEXT Context; > + ULONG Page; > + > + status = STATUS_INVALID_BUFFER_SIZE; > + if (InLen != sizeof(XENIFACE_GNTTAB_PERMIT_FOREIGN_ACCESS_IN) || > OutLen != 0) > + goto fail1; > + > + status = STATUS_INVALID_PARAMETER; > + if ((In->NumberPages == 0) || (In->NumberPages > 1024 * 1024) || > + ((In->Flags & XENIFACE_GNTTAB_USE_NOTIFY_OFFSET) && (In- > >NotifyOffset >= In->NumberPages * PAGE_SIZE)) > + ) > + goto fail2; > + > + status = STATUS_NO_MEMORY; > + Context = ExAllocatePoolWithTag(NonPagedPool, > sizeof(XENIFACE_GRANT_CONTEXT), XENIFACE_POOL_TAG); > + if (Context == NULL) > + goto fail3; > + > + RtlZeroMemory(Context, sizeof(XENIFACE_GRANT_CONTEXT)); > + Context->Id.Type = XENIFACE_CONTEXT_GRANT; > + Context->Id.Process = PsGetCurrentProcess(); Careful. I don't think Wndows guarantees that METHOD_BUFFERED ioctls will be handled in the issuers process context. See the sentence: " After the I/O manager has created a system-space buffer for the driver, the requesting user-mode thread can be swapped out and its physical memory can be reused by another thread, possibly by a thread belonging to another process." at https://msdn.microsoft.com/en-us/library/windows/hardware/ff565356%28v=vs.85%29.aspx. You should probably consider using METHOD_NEITHER. That may also allow you to play tricks like injecting the results of the operation into the user-space buffer without completing the ioctl possibly negating the need for a 'get results' ioctl. Paul > + Context->Id.RequestId = In->RequestId; > + Context->RemoteDomain = In->RemoteDomain; > + Context->NumberPages = In->NumberPages; > + Context->Flags = In->Flags; > + Context->NotifyOffset = In->NotifyOffset; > + Context->NotifyPort = In->NotifyPort; > + > + XenIfaceDebugPrint(TRACE, "> RemoteDomain %d, NumberPages %lu, > Flags 0x%x, Offset 0x%x, Port %d, Process %p, Id %lu\n", > + Context->RemoteDomain, Context->NumberPages, Context- > >Flags, Context->NotifyOffset, Context->NotifyPort, > + Context->Id.Process, Context->Id.RequestId); > + > + // Check if the request ID is unique. > + // This doesn't protect us from simultaneous requests with the same ID > arriving here > + // but another check for duplicate ID is performed when the context/IRP > is queued at the end. > + // Ideally we would lock the whole section but that's not really an > option > since we touch user memory. > + status = STATUS_INVALID_PARAMETER; > + if (FindGnttabIrp(Fdo, &Context->Id) != NULL) > + goto fail4; > + > + status = STATUS_NO_MEMORY; > + Context->Grants = ExAllocatePoolWithTag(NonPagedPool, Context- > >NumberPages * sizeof(PXENBUS_GNTTAB_ENTRY), > XENIFACE_POOL_TAG); > + if (Context->Grants == NULL) > + goto fail5; > + > + RtlZeroMemory(Context->Grants, Context->NumberPages * > sizeof(PXENBUS_GNTTAB_ENTRY)); > + > + // allocate memory to share > + status = STATUS_NO_MEMORY; > + Context->KernelVa = ExAllocatePoolWithTag(NonPagedPool, Context- > >NumberPages * PAGE_SIZE, XENIFACE_POOL_TAG); > + if (Context->KernelVa == NULL) > + goto fail6; > + > + RtlZeroMemory(Context->KernelVa, Context->NumberPages * > PAGE_SIZE); > + Context->Mdl = IoAllocateMdl(Context->KernelVa, Context- > >NumberPages * PAGE_SIZE, FALSE, FALSE, NULL); > + if (Context->Mdl == NULL) > + goto fail7; > + > + MmBuildMdlForNonPagedPool(Context->Mdl); > + ASSERT(MmGetMdlByteCount(Context->Mdl) == Context- > >NumberPages * PAGE_SIZE); > + > + // perform sharing > + for (Page = 0; Page < Context->NumberPages; Page++) { > + status = XENBUS_GNTTAB(PermitForeignAccess, > + &Fdo->GnttabInterface, > + Fdo->GnttabCache, > + FALSE, > + Context->RemoteDomain, > + MmGetMdlPfnArray(Context->Mdl)[Page], > + (Context->Flags & XENIFACE_GNTTAB_READONLY) > != 0, > + &(Context->Grants[Page])); > + > +// prefast somehow thinks that this call can modify Page... > +#pragma prefast(suppress:6385) > + XenIfaceDebugPrint(INFO, "Grants[%lu] = %p\n", Page, Context- > >Grants[Page]); > + if (!NT_SUCCESS(status)) > + goto fail8; > + } > + > + // map into user mode > +#pragma prefast(suppress:6320) // we want to catch all exceptions > + __try { > + Context->UserVa = MmMapLockedPagesSpecifyCache(Context->Mdl, > UserMode, MmCached, NULL, FALSE, NormalPagePriority); > + } > + __except (EXCEPTION_EXECUTE_HANDLER) { > + status = GetExceptionCode(); > + goto fail9; > + } > + > + status = STATUS_UNSUCCESSFUL; > + if (Context->UserVa == NULL) > + goto fail10; > + > + XenIfaceDebugPrint(TRACE, "< Context %p, Irp %p, KernelVa %p, UserVa > %p\n", Context, Irp, Context->KernelVa, Context->UserVa); > + > + // Insert the IRP/context into the pending queue. > + // This also checks (again) if the request ID is unique. > + Irp->Tail.Overlay.DriverContext[0] = &Context->Id; > + status = IoCsqInsertIrpEx(&Fdo->IrpQueue, Irp, NULL, &Context->Id); > + if (!NT_SUCCESS(status)) > + goto fail11; > + > + return STATUS_PENDING; > + > +fail11: > + XenIfaceDebugPrint(ERROR, "Fail11\n"); > + MmUnmapLockedPages(Context->UserVa, Context->Mdl); > + > +fail10: > + XenIfaceDebugPrint(ERROR, "Fail10\n"); > + > +fail9: > + XenIfaceDebugPrint(ERROR, "Fail9\n"); > + > +fail8: > + XenIfaceDebugPrint(ERROR, "Fail8: Page = %lu\n", Page); > + > + while (Page > 0) { > + ASSERT(NT_SUCCESS(XENBUS_GNTTAB(RevokeForeignAccess, > + &Fdo->GnttabInterface, > + Fdo->GnttabCache, > + FALSE, > + Context->Grants[Page - 1]))); > + > + --Page; > + } > + IoFreeMdl(Context->Mdl); > + > +fail7: > + XenIfaceDebugPrint(ERROR, "Fail7\n"); > + ExFreePoolWithTag(Context->KernelVa, XENIFACE_POOL_TAG); > + > +fail6: > + XenIfaceDebugPrint(ERROR, "Fail6\n"); > + ExFreePoolWithTag(Context->Grants, XENIFACE_POOL_TAG); > + > +fail5: > + XenIfaceDebugPrint(ERROR, "Fail5\n"); > + > +fail4: > + XenIfaceDebugPrint(ERROR, "Fail4\n"); > + RtlZeroMemory(Context, sizeof(XENIFACE_GRANT_CONTEXT)); > + ExFreePoolWithTag(Context, XENIFACE_POOL_TAG); > + > +fail3: > + XenIfaceDebugPrint(ERROR, "Fail3\n"); > + > +fail2: > + XenIfaceDebugPrint(ERROR, "Fail2\n"); > + > +fail1: > + XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status); > + return status; > +} > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlGnttabGetGrantResult( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __out PULONG_PTR Info > + ) > +{ > + NTSTATUS status; > + PXENIFACE_GNTTAB_GET_GRANT_RESULT_IN In = Buffer; > + PXENIFACE_GNTTAB_GET_GRANT_RESULT_OUT Out = Buffer; > + XENIFACE_CONTEXT_ID Id; > + KIRQL Irql; > + PIRP Irp; > + PXENIFACE_CONTEXT_ID ContextId; > + PXENIFACE_GRANT_CONTEXT Context; > + > + status = STATUS_INVALID_BUFFER_SIZE; > + if (InLen != sizeof(XENIFACE_GNTTAB_GET_GRANT_RESULT_IN)) > + goto fail1; > + > + Id.Process = PsGetCurrentProcess(); > + Id.RequestId = In->RequestId; > + Id.Type = XENIFACE_CONTEXT_GRANT; > + > + XenIfaceDebugPrint(TRACE, "> Process %p, Id %lu\n", Id.Process, > Id.RequestId); > + > + CsqAcquireLock(&Fdo->IrpQueue, &Irql); > + Irp = CsqPeekNextIrp(&Fdo->IrpQueue, NULL, &Id); > + > + status = STATUS_NOT_FOUND; > + if (Irp == NULL) > + goto fail2; > + > + ContextId = Irp->Tail.Overlay.DriverContext[0]; > + Context = CONTAINING_RECORD(ContextId, > XENIFACE_GRANT_CONTEXT, Id); > + > + status = STATUS_INVALID_BUFFER_SIZE; > + if (OutLen != (sizeof(XENIFACE_GNTTAB_GET_GRANT_RESULT_OUT) + > sizeof(ULONG) * Context->NumberPages)) > + goto fail3; > + > + Out->Address = Context->UserVa; > + XenIfaceDebugPrint(TRACE, "< Address %p, Irp %p\n", Context->UserVa, > Irp); > + > + for (ULONG Page = 0; Page < Context->NumberPages; Page++) { > + Out->References[Page] = XENBUS_GNTTAB(GetReference, > + &Fdo->GnttabInterface, > + Context->Grants[Page]); > + XenIfaceDebugPrint(INFO, "Ref[%lu] = %lu\n", Page, Out- > >References[Page]); > + } > + > + CsqReleaseLock(&Fdo->IrpQueue, Irql); > + *Info = OutLen; > + > + return STATUS_SUCCESS; > + > +fail3: > + XenIfaceDebugPrint(ERROR, "Fail3\n"); > +fail2: > + XenIfaceDebugPrint(ERROR, "Fail2\n"); > + CsqReleaseLock(&Fdo->IrpQueue, Irql); > +fail1: > + XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status); > + return status; > +} > + > +_IRQL_requires_max_(APC_LEVEL) > +VOID > +GnttabFreeGrant( > + __in PXENIFACE_FDO Fdo, > + __inout PXENIFACE_GRANT_CONTEXT Context > +) > +{ > + NTSTATUS status; > + ULONG Page; > + > + ASSERT(KeGetCurrentIrql() <= APC_LEVEL); > + > + XenIfaceDebugPrint(TRACE, "Context %p\n", Context); > + > + if (Context->Flags & XENIFACE_GNTTAB_USE_NOTIFY_OFFSET) { > + ((PCHAR)Context->KernelVa)[Context->NotifyOffset] = 0; > + } > + > + if (Context->Flags & XENIFACE_GNTTAB_USE_NOTIFY_PORT) { > + status = EvtchnNotify(Fdo, Context->NotifyPort, NULL); > + > + if (!NT_SUCCESS(status)) // non-fatal, we must free memory > + XenIfaceDebugPrint(ERROR, "failed to notify port %lu: 0x%x\n", > Context->NotifyPort, status); > + } > + > + // unmap from user address space > + MmUnmapLockedPages(Context->UserVa, Context->Mdl); > + > + // stop sharing > + for (Page = 0; Page < Context->NumberPages; Page++) { > + status = XENBUS_GNTTAB(RevokeForeignAccess, > + &Fdo->GnttabInterface, > + Fdo->GnttabCache, > + FALSE, > + Context->Grants[Page]); > + > + ASSERT(NT_SUCCESS(status)); // failure here is fatal, something > must've gone catastrophically wrong > + } > + > + IoFreeMdl(Context->Mdl); > + > + RtlZeroMemory(Context->KernelVa, Context->NumberPages * > PAGE_SIZE); > + ExFreePoolWithTag(Context->KernelVa, XENIFACE_POOL_TAG); > + > + RtlZeroMemory(Context->Grants, Context->NumberPages * > sizeof(PXENBUS_GNTTAB_ENTRY)); > + ExFreePoolWithTag(Context->Grants, XENIFACE_POOL_TAG); > + > + RtlZeroMemory(Context, sizeof(XENIFACE_GRANT_CONTEXT)); > + ExFreePoolWithTag(Context, XENIFACE_POOL_TAG); > +} > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlGnttabRevokeForeignAccess( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen > + ) > +{ > + NTSTATUS status; > + PXENIFACE_GNTTAB_REVOKE_FOREIGN_ACCESS_IN In = Buffer; > + PXENIFACE_GRANT_CONTEXT Context = NULL; > + XENIFACE_CONTEXT_ID Id; > + PIRP PendingIrp; > + PXENIFACE_CONTEXT_ID ContextId; > + > + status = STATUS_INVALID_BUFFER_SIZE; > + if (InLen != sizeof(XENIFACE_GNTTAB_REVOKE_FOREIGN_ACCESS_IN)) > + goto fail1; > + > + Id.Type = XENIFACE_CONTEXT_GRANT; > + Id.Process = PsGetCurrentProcess(); > + Id.RequestId = In->RequestId; > + > + XenIfaceDebugPrint(TRACE, "> Process %p, Id %lu\n", Id.Process, > Id.RequestId); > + > + status = STATUS_NOT_FOUND; > + PendingIrp = IoCsqRemoveNextIrp(&Fdo->IrpQueue, &Id); > + if (PendingIrp == NULL) > + goto fail2; > + > + ContextId = PendingIrp->Tail.Overlay.DriverContext[0]; > + Context = CONTAINING_RECORD(ContextId, > XENIFACE_GRANT_CONTEXT, Id); > + GnttabFreeGrant(Fdo, Context); > + > + PendingIrp->IoStatus.Status = STATUS_SUCCESS; > + PendingIrp->IoStatus.Information = 0; > + IoCompleteRequest(PendingIrp, IO_NO_INCREMENT); > + > + return STATUS_SUCCESS; > + > +fail2: > + XenIfaceDebugPrint(ERROR, "Fail2\n"); > +fail1: > + XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status); > + return status; > +} > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlGnttabMapForeignPages( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __inout PIRP Irp > + ) > +{ > + NTSTATUS status; > + PXENIFACE_GNTTAB_MAP_FOREIGN_PAGES_IN In = Buffer; > + PXENIFACE_MAP_CONTEXT Context; > + > + status = STATUS_INVALID_BUFFER_SIZE; > + if (InLen < sizeof(XENIFACE_GNTTAB_MAP_FOREIGN_PAGES_IN) || > OutLen != 0) > + goto fail1; > + > + status = STATUS_INVALID_PARAMETER; > + if ((In->NumberPages == 0) || (In->NumberPages > 1024 * 1024) || > + ((In->Flags & XENIFACE_GNTTAB_USE_NOTIFY_OFFSET) && (In- > >NotifyOffset >= In->NumberPages * PAGE_SIZE)) > + ) > + goto fail2; > + > + status = STATUS_INVALID_BUFFER_SIZE; > + if (InLen != sizeof(XENIFACE_GNTTAB_MAP_FOREIGN_PAGES_IN) + > sizeof(ULONG) * In->NumberPages) > + goto fail3; > + > + status = STATUS_NO_MEMORY; > + Context = ExAllocatePoolWithTag(NonPagedPool, > sizeof(XENIFACE_MAP_CONTEXT), XENIFACE_POOL_TAG); > + if (Context == NULL) > + goto fail4; > + > + RtlZeroMemory(Context, sizeof(XENIFACE_MAP_CONTEXT)); > + Context->Id.Type = XENIFACE_CONTEXT_MAP; > + Context->Id.Process = PsGetCurrentProcess(); > + Context->Id.RequestId = In->RequestId; > + Context->RemoteDomain = In->RemoteDomain; > + Context->NumberPages = In->NumberPages; > + Context->Flags = In->Flags; > + Context->NotifyOffset = In->NotifyOffset; > + Context->NotifyPort = In->NotifyPort; > + > + XenIfaceDebugPrint(TRACE, "> RemoteDomain %d, NumberPages %lu, > Flags 0x%x, Offset 0x%x, Port %d, Process %p, Id %lu\n", > + Context->RemoteDomain, Context->NumberPages, Context- > >Flags, Context->NotifyOffset, Context->NotifyPort, > + Context->Id.Process, Context->Id.RequestId); > + > + for (ULONG i = 0; i < In->NumberPages; i++) > + XenIfaceDebugPrint(INFO, "> Ref %d\n", In->References[i]); > + > + status = STATUS_INVALID_PARAMETER; > + if (FindGnttabIrp(Fdo, &Context->Id) != NULL) > + goto fail5; > + > + status = XENBUS_GNTTAB(MapForeignPages, > + &Fdo->GnttabInterface, > + Context->RemoteDomain, > + Context->NumberPages, > + In->References, > + Context->Flags & XENIFACE_GNTTAB_READONLY, > + &Context->Address); > + > + if (!NT_SUCCESS(status)) > + goto fail6; > + > + status = STATUS_NO_MEMORY; > + Context->KernelVa = MmMapIoSpace(Context->Address, Context- > >NumberPages * PAGE_SIZE, MmCached); > + if (Context->KernelVa == NULL) > + goto fail7; > + > + status = STATUS_NO_MEMORY; > + Context->Mdl = IoAllocateMdl(Context->KernelVa, Context- > >NumberPages * PAGE_SIZE, FALSE, FALSE, NULL); > + if (Context->Mdl == NULL) > + goto fail8; > + > + MmBuildMdlForNonPagedPool(Context->Mdl); > + > + // map into user mode > +#pragma prefast(suppress: 6320) // we want to catch all exceptions > + __try { > + Context->UserVa = MmMapLockedPagesSpecifyCache(Context->Mdl, > UserMode, MmCached, NULL, FALSE, NormalPagePriority); > + } > + __except (EXCEPTION_EXECUTE_HANDLER) { > + status = GetExceptionCode(); > + goto fail9; > + } > + > + status = STATUS_UNSUCCESSFUL; > + if (Context->UserVa == NULL) > + goto fail10; > + > + XenIfaceDebugPrint(TRACE, "< Context %p, Irp %p, Address %p, KernelVa > %p, UserVa %p\n", > + Context, Irp, Context->Address, Context->KernelVa, > Context- > >UserVa); > + > + // Insert the IRP/context into the pending queue. > + // This also checks (again) if the request ID is unique. > + Irp->Tail.Overlay.DriverContext[0] = &Context->Id; > + status = IoCsqInsertIrpEx(&Fdo->IrpQueue, Irp, NULL, &Context->Id); > + if (!NT_SUCCESS(status)) > + goto fail11; > + > + return STATUS_PENDING; > + > +fail11: > + XenIfaceDebugPrint(ERROR, "Fail11\n"); > + MmUnmapLockedPages(Context->UserVa, Context->Mdl); > + > +fail10: > + XenIfaceDebugPrint(ERROR, "Fail10\n"); > + > +fail9: > + XenIfaceDebugPrint(ERROR, "Fail9\n"); > + IoFreeMdl(Context->Mdl); > + > +fail8: > + XenIfaceDebugPrint(ERROR, "Fail8\n"); > + MmUnmapIoSpace(Context->KernelVa, Context->NumberPages * > PAGE_SIZE); > + > +fail7: > + XenIfaceDebugPrint(ERROR, "Fail7\n"); > + ASSERT(NT_SUCCESS(XENBUS_GNTTAB(UnmapForeignPages, > + &Fdo->GnttabInterface, > + Context->Address > + ))); > + > +fail6: > + XenIfaceDebugPrint(ERROR, "Fail6\n"); > + > +fail5: > + XenIfaceDebugPrint(ERROR, "Fail5\n"); > + RtlZeroMemory(Context, sizeof(XENIFACE_MAP_CONTEXT)); > + ExFreePoolWithTag(Context, XENIFACE_POOL_TAG); > + > +fail4: > + XenIfaceDebugPrint(ERROR, "Fail4\n"); > + > +fail3: > + XenIfaceDebugPrint(ERROR, "Fail3\n"); > + > +fail2: > + XenIfaceDebugPrint(ERROR, "Fail2\n"); > + > +fail1: > + XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status); > + return status; > +} > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlGnttabGetMapResult( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __out PULONG_PTR Info > + ) > +{ > + NTSTATUS status; > + PXENIFACE_GNTTAB_GET_MAP_RESULT_IN In = Buffer; > + PXENIFACE_GNTTAB_GET_MAP_RESULT_OUT Out = Buffer; > + XENIFACE_CONTEXT_ID Id; > + KIRQL Irql; > + PIRP Irp; > + PXENIFACE_MAP_CONTEXT Context; > + PXENIFACE_CONTEXT_ID ContextId; > + > + status = STATUS_INVALID_BUFFER_SIZE; > + if (InLen != sizeof(XENIFACE_GNTTAB_GET_MAP_RESULT_IN) || OutLen > != sizeof(XENIFACE_GNTTAB_GET_MAP_RESULT_OUT)) > + goto fail1; > + > + Id.Type = XENIFACE_CONTEXT_MAP; > + Id.Process = PsGetCurrentProcess(); > + Id.RequestId = In->RequestId; > + > + XenIfaceDebugPrint(TRACE, "> Process %p, Id %lu\n", Id.Process, > Id.RequestId); > + > + CsqAcquireLock(&Fdo->IrpQueue, &Irql); > + Irp = CsqPeekNextIrp(&Fdo->IrpQueue, NULL, &Id); > + > + status = STATUS_NOT_FOUND; > + if (Irp == NULL) > + goto fail2; > + > + ContextId = Irp->Tail.Overlay.DriverContext[0]; > + Context = CONTAINING_RECORD(ContextId, XENIFACE_MAP_CONTEXT, > Id); > + > + Out->Address = Context->UserVa; > + XenIfaceDebugPrint(TRACE, "< Address %p, Irp %p\n", Context->UserVa, > Irp); > + > + CsqReleaseLock(&Fdo->IrpQueue, Irql); > + *Info = OutLen; > + > + return STATUS_SUCCESS; > + > +fail2: > + XenIfaceDebugPrint(ERROR, "Fail2\n"); > + CsqReleaseLock(&Fdo->IrpQueue, Irql); > +fail1: > + XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status); > + return status; > +} > + > +_IRQL_requires_max_(APC_LEVEL) > +DECLSPEC_NOINLINE > +VOID > +GnttabFreeMap( > + __in PXENIFACE_FDO Fdo, > + __inout PXENIFACE_MAP_CONTEXT Context > + ) > +{ > + NTSTATUS status; > + > + ASSERT(KeGetCurrentIrql() <= APC_LEVEL); > + > + XenIfaceDebugPrint(TRACE, "Context %p\n", Context); > + > + if (Context->Flags & XENIFACE_GNTTAB_USE_NOTIFY_OFFSET) { > + ((PCHAR)Context->KernelVa)[Context->NotifyOffset] = 0; > + } > + > + if (Context->Flags & XENIFACE_GNTTAB_USE_NOTIFY_PORT) { > + status = EvtchnNotify(Fdo, Context->NotifyPort, NULL); > + > + if (!NT_SUCCESS(status)) // non-fatal, we must free memory > + XenIfaceDebugPrint(ERROR, "failed to notify port %lu: 0x%x\n", > Context->NotifyPort, status); > + } > + > + // unmap from user address space > + MmUnmapLockedPages(Context->UserVa, Context->Mdl); > + > + IoFreeMdl(Context->Mdl); > + > + // unmap from system space > + MmUnmapIoSpace(Context->KernelVa, Context->NumberPages * > PAGE_SIZE); > + > + // undo mapping > + status = XENBUS_GNTTAB(UnmapForeignPages, > + &Fdo->GnttabInterface, > + Context->Address); > + > + ASSERT(NT_SUCCESS(status)); > + > + RtlZeroMemory(Context, sizeof(XENIFACE_MAP_CONTEXT)); > + ExFreePoolWithTag(Context, XENIFACE_POOL_TAG); > +} > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlGnttabUnmapForeignPages( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen > + ) > +{ > + NTSTATUS status; > + PXENIFACE_GNTTAB_UNMAP_FOREIGN_PAGES_IN In = Buffer; > + PXENIFACE_MAP_CONTEXT Context = NULL; > + XENIFACE_CONTEXT_ID Id; > + PIRP PendingIrp; > + PXENIFACE_CONTEXT_ID ContextId; > + > + status = STATUS_INVALID_BUFFER_SIZE; > + if (InLen != sizeof(XENIFACE_GNTTAB_UNMAP_FOREIGN_PAGES_IN) && > OutLen != 0) > + goto fail1; > + > + Id.Type = XENIFACE_CONTEXT_MAP; > + Id.Process = PsGetCurrentProcess(); > + Id.RequestId = In->RequestId; > + > + XenIfaceDebugPrint(TRACE, "> Process %p, Id %lu\n", Id.Process, > Id.RequestId); > + > + status = STATUS_NOT_FOUND; > + PendingIrp = IoCsqRemoveNextIrp(&Fdo->IrpQueue, &Id); > + if (PendingIrp == NULL) > + goto fail2; > + > + ContextId = PendingIrp->Tail.Overlay.DriverContext[0]; > + Context = CONTAINING_RECORD(ContextId, XENIFACE_MAP_CONTEXT, > Id); > + GnttabFreeMap(Fdo, Context); > + > + PendingIrp->IoStatus.Status = STATUS_SUCCESS; > + PendingIrp->IoStatus.Information = 0; > + IoCompleteRequest(PendingIrp, IO_NO_INCREMENT); > + > + return STATUS_SUCCESS; > + > +fail2: > + XenIfaceDebugPrint(ERROR, "Fail2\n"); > +fail1: > + XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status); > + return status; > +} > diff --git a/src/xeniface/ioctl_store.c b/src/xeniface/ioctl_store.c > new file mode 100644 > index 0000000..181c706 > --- /dev/null > +++ b/src/xeniface/ioctl_store.c > @@ -0,0 +1,574 @@ > +/* Copyright (c) Citrix Systems Inc. > + * All rights reserved. > + * > + * Redistribution and use in source and binary forms, > + * with or without modification, are permitted provided > + * that the following conditions are met: > + * > + * * Redistributions of source code must retain the above > + * copyright notice, this list of conditions and the > + * following disclaimer. > + * * Redistributions in binary form must reproduce the above > + * copyright notice, this list of conditions and the > + * following disclaimer in the documentation and/or other > + * materials provided with the distribution. > + * > + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND > + * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, > + * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF > + * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE > + * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR > + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, > + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, > + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR > + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS > + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, > + * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING > + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE > + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF > + * SUCH DAMAGE. > + */ > + > +#include "driver.h" > +#include "ioctls.h" > +#include "..\..\include\xeniface_ioctls.h" > +#include "log.h" > + > +#define XENSTORE_ABS_PATH_MAX 3072 > +#define XENSTORE_REL_PATH_MAX 2048 > + > +static > +NTSTATUS > +__CaptureUserBuffer( > + __in PVOID Buffer, > + __in ULONG Length, > + __out PVOID *CapturedBuffer > + ) > +{ > + NTSTATUS Status; > + PVOID TempBuffer = NULL; > + > + if (Length == 0) { > + *CapturedBuffer = NULL; > + return STATUS_SUCCESS; > + } > + > + Status = STATUS_NO_MEMORY; > + TempBuffer = ExAllocatePoolWithTag(NonPagedPool, Length, > XENIFACE_POOL_TAG); > + if (TempBuffer == NULL) > + return STATUS_INSUFFICIENT_RESOURCES; > + > + Status = STATUS_SUCCESS; > + > +#pragma prefast(suppress: 6320) // we want to catch all exceptions > + try { > + ProbeForRead(Buffer, Length, 1); > + RtlCopyMemory(TempBuffer, Buffer, Length); > + } except(EXCEPTION_EXECUTE_HANDLER) { > + XenIfaceDebugPrint(ERROR, "Exception while probing/reading buffer at > %p, size 0x%lx\n", Buffer, Length); > + ExFreePoolWithTag(TempBuffer, XENIFACE_POOL_TAG); > + TempBuffer = NULL; > + Status = GetExceptionCode(); > + } > + > + *CapturedBuffer = TempBuffer; > + > + return Status; > + } > + > +static > +VOID > +__FreeCapturedBuffer( > + __in PVOID CapturedBuffer > + ) > +{ > + if (CapturedBuffer != NULL) { > + ExFreePoolWithTag(CapturedBuffer, XENIFACE_POOL_TAG); > + } > +} > + > +static FORCEINLINE > +BOOLEAN > +__IsValidStr( > + __in PCHAR Str, > + __in ULONG Len > + ) > +{ > + for ( ; Len--; ++Str) { > + if (*Str == '\0') > + return TRUE; > + if (!isprint((unsigned char)*Str)) > + break; > + } > + return FALSE; > +} > + > +static FORCEINLINE > +ULONG > +__MultiSzLen( > + __in PCHAR Str, > + __out PULONG Count > + ) > +{ > + ULONG Length = 0; > + if (Count) *Count = 0; > + do { > + for ( ; *Str; ++Str, ++Length) ; > + ++Str; ++Length; > + if (*Count) ++(*Count); > + } while (*Str); > + return Length; > +} > + > +static FORCEINLINE > +VOID > +__DisplayMultiSz( > + __in PCHAR Caller, > + __in PCHAR Str > + ) > +{ > + PCHAR Ptr; > + ULONG Idx; > + ULONG Len; > + > + for (Ptr = Str, Idx = 0; *Ptr; ++Idx) { > + Len = (ULONG)strlen(Ptr); > + XenIfaceDebugPrint(TRACE, "|%s: [%d]=(%d)->\"%s\"\n", Caller, Idx, > Len, Ptr); > + Ptr += (Len + 1); > + } > +} > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlStoreRead( > + __in PXENIFACE_FDO Fdo, > + __in PCHAR Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __out PULONG_PTR Info > + ) > +{ > + NTSTATUS status; > + PCHAR Value; > + ULONG Length; > + > + status = STATUS_INVALID_BUFFER_SIZE; > + if (InLen == 0) > + goto fail1; > + > + status = STATUS_INVALID_PARAMETER; > + if (!__IsValidStr(Buffer, InLen)) > + goto fail2; > + > + status = XENBUS_STORE(Read, &Fdo->StoreInterface, NULL, NULL, > Buffer, &Value); > + if (!NT_SUCCESS(status)) > + goto fail3; > + > + Length = (ULONG)strlen(Value) + 1; > + > + status = STATUS_BUFFER_OVERFLOW; > + if (OutLen == 0) { > + XenIfaceDebugPrint(TRACE, "(\"%s\")=(%d)\n", Buffer, Length); > + goto done; > + } > + > + status = STATUS_INVALID_PARAMETER; > + if (OutLen < Length) > + goto fail4; > + > + XenIfaceDebugPrint(TRACE, "(\"%s\")=(%d)->\"%s\"\n", Buffer, Length, > Value); > + > + RtlCopyMemory(Buffer, Value, Length); > + Buffer[Length - 1] = 0; > + status = STATUS_SUCCESS; > + > +done: > + *Info = (ULONG_PTR)Length; > + XENBUS_STORE(Free, &Fdo->StoreInterface, Value); > + return status; > + > +fail4: > + XenIfaceDebugPrint(ERROR, "Fail4 (\"%s\")=(%d < %d)\n", Buffer, > OutLen, Length); > + XENBUS_STORE(Free, &Fdo->StoreInterface, Value); > +fail3: > + XenIfaceDebugPrint(ERROR, "Fail3 (\"%s\")\n", Buffer); > +fail2: > + XenIfaceDebugPrint(ERROR, "Fail2\n"); > +fail1: > + XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status); > + return status; > +} > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlStoreWrite( > + __in PXENIFACE_FDO Fdo, > + __in PCHAR Buffer, > + __in ULONG InLen, > + __in ULONG OutLen > + ) > +{ > + NTSTATUS status; > + PCHAR Value; > + ULONG Length; > + > + status = STATUS_INVALID_BUFFER_SIZE; > + if (InLen == 0 || OutLen != 0) > + goto fail1; > + > + status = STATUS_INVALID_PARAMETER; > + if (!__IsValidStr(Buffer, InLen)) > + goto fail2; > + > + Length = (ULONG)strlen(Buffer) + 1; > + Value = Buffer + Length; > + > + if (!__IsValidStr(Value, InLen - Length)) > + goto fail3; > + > + status = XENBUS_STORE(Printf, &Fdo->StoreInterface, NULL, NULL, > Buffer, Value); > + if (!NT_SUCCESS(status)) > + goto fail4; > + > + XenIfaceDebugPrint(TRACE, "(\"%s\"=\"%s\")\n", Buffer, Value); > + return status; > + > +fail4: > + XenIfaceDebugPrint(ERROR, "Fail4 (\"%s\")\n", Value); > +fail3: > + XenIfaceDebugPrint(ERROR, "Fail3 (\"%s\")\n", Buffer); > +fail2: > + XenIfaceDebugPrint(ERROR, "Fail2\n"); > +fail1: > + XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status); > + return status; > +} > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlStoreDirectory( > + __in PXENIFACE_FDO Fdo, > + __in PCHAR Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __out PULONG_PTR Info > + ) > +{ > + NTSTATUS status; > + PCHAR Value; > + ULONG Length; > + ULONG Count; > + > + status = STATUS_INVALID_BUFFER_SIZE; > + if (InLen == 0) > + goto fail1; > + > + status = STATUS_INVALID_PARAMETER; > + if (!__IsValidStr(Buffer, InLen)) > + goto fail2; > + > + status = XENBUS_STORE(Directory, &Fdo->StoreInterface, NULL, NULL, > Buffer, &Value); > + if (!NT_SUCCESS(status)) > + goto fail3; > + > + Length = __MultiSzLen(Value, &Count) + 1; > + > + status = STATUS_BUFFER_OVERFLOW; > + if (OutLen == 0) { > + XenIfaceDebugPrint(TRACE, "(\"%s\")=(%d)(%d)\n", Buffer, Length, > Count); > + goto done; > + } > + > + status = STATUS_INVALID_PARAMETER; > + if (OutLen < Length) > + goto fail4; > + > + XenIfaceDebugPrint(INFO, "(\"%s\")=(%d)(%d)\n", Buffer, Length, > Count); > +#if DBG > + __DisplayMultiSz(__FUNCTION__, Value); > +#endif > + > + RtlCopyMemory(Buffer, Value, Length); > + Buffer[Length - 2] = 0; > + Buffer[Length - 1] = 0; > + status = STATUS_SUCCESS; > + > +done: > + *Info = (ULONG_PTR)Length; > + XENBUS_STORE(Free, &Fdo->StoreInterface, Value); > + return status; > + > +fail4: > + XenIfaceDebugPrint(ERROR, "Fail4 (\"%s\")=(%d < %d)\n", Buffer, > OutLen, Length); > + XENBUS_STORE(Free, &Fdo->StoreInterface, Value); > +fail3: > + XenIfaceDebugPrint(ERROR, "Fail3 (\"%s\")\n", Buffer); > +fail2: > + XenIfaceDebugPrint(ERROR, "Fail2\n"); > +fail1: > + XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status); > + return status; > +} > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlStoreRemove( > + __in PXENIFACE_FDO Fdo, > + __in PCHAR Buffer, > + __in ULONG InLen, > + __in ULONG OutLen > + ) > +{ > + NTSTATUS status; > + > + status = STATUS_INVALID_BUFFER_SIZE; > + if (InLen == 0 || OutLen != 0) > + goto fail1; > + > + status = STATUS_INVALID_PARAMETER; > + if (!__IsValidStr(Buffer, InLen)) > + goto fail2; > + > + status = XENBUS_STORE(Remove, &Fdo->StoreInterface, NULL, NULL, > Buffer); > + if (!NT_SUCCESS(status)) > + goto fail3; > + > + XenIfaceDebugPrint(TRACE, "(\"%s\")\n", Buffer); > + return status; > + > +fail3: > + XenIfaceDebugPrint(ERROR, "Fail3 (\"%s\")\n", Buffer); > +fail2: > + XenIfaceDebugPrint(ERROR, "Fail2\n"); > +fail1: > + XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status); > + return status; > +} > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlStoreSetPermissions( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen > + ) > +{ > + NTSTATUS status; > + PXENIFACE_STORE_SET_PERMISSIONS_IN In = Buffer; > + ULONG Index; > + PCHAR Path; > + > + status = STATUS_INVALID_BUFFER_SIZE; > + if (InLen < sizeof(XENIFACE_STORE_SET_PERMISSIONS_IN) || OutLen != > 0) > + goto fail1; > + > + if (InLen < sizeof(XENIFACE_STORE_SET_PERMISSIONS_IN) + In- > >NumberPermissions * sizeof(XENBUS_STORE_PERMISSION)) > + goto fail2; > + > + status = STATUS_INVALID_PARAMETER; > + if (In->PathLength == 0 || In->PathLength > XENSTORE_ABS_PATH_MAX) > + goto fail3; > + > + status = __CaptureUserBuffer(In->Path, In->PathLength, &Path); > + if (!NT_SUCCESS(status)) > + goto fail4; > + > + Path[In->PathLength - 1] = 0; > + XenIfaceDebugPrint(TRACE, "> Path '%s', NumberPermissions %lu\n", > Path, In->NumberPermissions); > + > + for (Index = 0; Index < In->NumberPermissions; Index++) { > + XenIfaceDebugPrint(TRACE, "> %lu: Domain %d, Mask 0x%x\n", Index, > In->Permissions[Index].Domain, In->Permissions[Index].Mask); > + if ((In->Permissions[Index].Mask & > ~XENIFACE_STORE_ALLOWED_PERMISSIONS) != 0) > + goto fail5; > + } > + > + status = XENBUS_STORE(PermissionsSet, > + &Fdo->StoreInterface, > + NULL, // transaction > + NULL, // prefix > + Path, > + In->Permissions, > + In->NumberPermissions); > + > + if (!NT_SUCCESS(status)) > + goto fail6; > + > + __FreeCapturedBuffer(Path); > + return status; > + > +fail6: > + XenIfaceDebugPrint(ERROR, "Fail6\n"); > +fail5: > + XenIfaceDebugPrint(ERROR, "Fail5\n"); > + __FreeCapturedBuffer(Path); > +fail4: > + XenIfaceDebugPrint(ERROR, "Fail4\n"); > +fail3: > + XenIfaceDebugPrint(ERROR, "Fail3\n"); > +fail2: > + XenIfaceDebugPrint(ERROR, "Fail2\n"); > +fail1: > + XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status); > + return status; > +} > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlStoreAddWatch( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __in PFILE_OBJECT FileObject, > + __out PULONG_PTR Info > + ) > +{ > + NTSTATUS status; > + PXENIFACE_STORE_ADD_WATCH_IN In = Buffer; > + PXENIFACE_STORE_ADD_WATCH_OUT Out = Buffer; > + PCHAR Path; > + PXENIFACE_STORE_CONTEXT Context; > + > + status = STATUS_INVALID_BUFFER_SIZE; > + if (InLen != sizeof(XENIFACE_STORE_ADD_WATCH_IN) || OutLen != > sizeof(XENIFACE_STORE_ADD_WATCH_OUT)) > + goto fail1; > + > + status = STATUS_INVALID_PARAMETER; > + if (In->PathLength == 0 || In->PathLength > XENSTORE_ABS_PATH_MAX) > + goto fail2; > + > + status = __CaptureUserBuffer(In->Path, In->PathLength, &Path); > + if (!NT_SUCCESS(status)) > + goto fail3; > + > + Path[In->PathLength - 1] = 0; > + > + status = STATUS_NO_MEMORY; > + Context = ExAllocatePoolWithTag(NonPagedPool, > sizeof(XENIFACE_STORE_CONTEXT), XENIFACE_POOL_TAG); > + if (Context == NULL) > + goto fail4; > + > + RtlZeroMemory(Context, sizeof(XENIFACE_STORE_CONTEXT)); > + > + Context->FileObject = FileObject; > + > + status = ObReferenceObjectByHandle(In->Event, > EVENT_MODIFY_STATE, *ExEventObjectType, UserMode, &Context->Event, > NULL); > + if (!NT_SUCCESS(status)) > + goto fail5; > + > + XenIfaceDebugPrint(TRACE, "> Path '%s', Event %p, FO %p\n", Path, In- > >Event, FileObject); > + > + status = XENBUS_STORE(WatchAdd, > + &Fdo->StoreInterface, > + NULL, // prefix > + Path, > + Context->Event, > + &Context->Watch); > + > + if (!NT_SUCCESS(status)) > + goto fail6; > + > + __FreeCapturedBuffer(Path); > + > + ExInterlockedInsertTailList(&Fdo->StoreWatchList, &Context->Entry, > &Fdo->StoreWatchLock); > + > + XenIfaceDebugPrint(TRACE, "< Context %p, Watch %p\n", Context, > Context->Watch); > + > + Out->Context = Context; > + *Info = sizeof(XENIFACE_STORE_ADD_WATCH_OUT); > + > + return status; > + > +fail6: > + XenIfaceDebugPrint(ERROR, "Fail6\n"); > + ObDereferenceObject(Context->Event); > +fail5: > + XenIfaceDebugPrint(ERROR, "Fail5\n"); > + RtlZeroMemory(Context, sizeof(XENIFACE_STORE_CONTEXT)); > + ExFreePoolWithTag(Context, XENIFACE_POOL_TAG); > +fail4: > + XenIfaceDebugPrint(ERROR, "Fail4\n"); > + __FreeCapturedBuffer(Path); > +fail3: > + XenIfaceDebugPrint(ERROR, "Fail3\n"); > +fail2: > + XenIfaceDebugPrint(ERROR, "Fail2\n"); > +fail1: > + XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status); > + return status; > +} > + > +_IRQL_requires_max_(DISPATCH_LEVEL) > +VOID > +StoreFreeWatch( > + __in PXENIFACE_FDO Fdo, > + __inout PXENIFACE_STORE_CONTEXT Context > + ) > +{ > + NTSTATUS status; > + > + XenIfaceDebugPrint(TRACE, "Context %p, Watch %p, FO %p\n", > + Context, Context->Watch, Context->FileObject); > + > + status = XENBUS_STORE(WatchRemove, > + &Fdo->StoreInterface, > + Context->Watch); > + > + ASSERT(NT_SUCCESS(status)); // this is fatal since we'd leave an active > watch without cleaning it up > + > + ObDereferenceObject(Context->Event); > + RtlZeroMemory(Context, sizeof(XENIFACE_STORE_CONTEXT)); > + ExFreePoolWithTag(Context, XENIFACE_POOL_TAG); > +} > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlStoreRemoveWatch( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __in PFILE_OBJECT FileObject > + ) > +{ > + NTSTATUS status; > + PXENIFACE_STORE_REMOVE_WATCH_IN In = Buffer; > + PXENIFACE_STORE_CONTEXT Context = NULL; > + KIRQL Irql; > + PLIST_ENTRY Node; > + > + status = STATUS_INVALID_BUFFER_SIZE; > + if (InLen != sizeof(XENIFACE_STORE_REMOVE_WATCH_IN) || OutLen != > 0) > + goto fail1; > + > + XenIfaceDebugPrint(TRACE, "> Context %p, FO %p\n", In->Context, > FileObject); > + > + KeAcquireSpinLock(&Fdo->StoreWatchLock, &Irql); > + Node = Fdo->StoreWatchList.Flink; > + while (Node->Flink != Fdo->StoreWatchList.Flink) { > + Context = CONTAINING_RECORD(Node, XENIFACE_STORE_CONTEXT, > Entry); > + > + Node = Node->Flink; > + if (Context != In->Context || Context->FileObject != FileObject) > + continue; > + > + RemoveEntryList(&Context->Entry); > + break; > + } > + KeReleaseSpinLock(&Fdo->StoreWatchLock, Irql); > + > + status = STATUS_NOT_FOUND; > + if (Context == NULL || Context != In->Context) > + goto fail2; > + > + StoreFreeWatch(Fdo, Context); > + > + return STATUS_SUCCESS; > + > +fail2: > + XenIfaceDebugPrint(ERROR, "Fail2\n"); > +fail1: > + XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status); > + return status; > +} > diff --git a/src/xeniface/ioctls.c b/src/xeniface/ioctls.c > index 3bef9ea..e20b7dc 100644 > --- a/src/xeniface/ioctls.c > +++ b/src/xeniface/ioctls.c > @@ -35,287 +35,156 @@ > #include "..\..\include\xeniface_ioctls.h" > #include "log.h" > > -static FORCEINLINE BOOLEAN > -__IsValidStr( > - __in PCHAR Str, > - __in ULONG Len > - ) > -{ > - for ( ; Len--; ++Str) { > - if (*Str == '\0') > - return TRUE; > - if (!isprint((unsigned char)*Str)) > - break; > - } > - return FALSE; > -} > -static FORCEINLINE ULONG > -__MultiSzLen( > - __in PCHAR Str, > - __out PULONG Count > - ) > -{ > - ULONG Length = 0; > - if (Count) *Count = 0; > - do { > - for ( ; *Str; ++Str, ++Length) ; > - ++Str; ++Length; > - if (*Count) ++(*Count); > - } while (*Str); > - return Length; > -} > -static FORCEINLINE VOID > -__DisplayMultiSz( > - __in PCHAR Caller, > - __in PCHAR Str > - ) > -{ > - PCHAR Ptr; > - ULONG Idx; > - ULONG Len; > - > - for (Ptr = Str, Idx = 0; *Ptr; ++Idx) { > - Len = (ULONG)strlen(Ptr); > - XenIfaceDebugPrint(INFO, "|%s: [%d]=(%d)->\"%s\"\n", Caller, Idx, > Len, Ptr); > - Ptr += (Len + 1); > - } > -} > - > - > -static DECLSPEC_NOINLINE NTSTATUS > -IoctlRead( > +// Cleanup store watches and event channels, called on file object close. > +_IRQL_requires_(PASSIVE_LEVEL) // EvtchnFree calls KeFlushQueuedDpcs > +VOID > +XenIfaceCleanup( > __in PXENIFACE_FDO Fdo, > - __in PCHAR Buffer, > - __in ULONG InLen, > - __in ULONG OutLen, > - __out PULONG_PTR Info > + __in PFILE_OBJECT FileObject > ) > { > - NTSTATUS status; > - PCHAR Value; > - ULONG Length; > - > - status = STATUS_INVALID_BUFFER_SIZE; > - if (InLen == 0) > - goto fail1; > - > - status = STATUS_INVALID_PARAMETER; > - if (!__IsValidStr(Buffer, InLen)) > - goto fail2; > - > - status = XENBUS_STORE(Read, &Fdo->StoreInterface, NULL, NULL, > Buffer, &Value); > - if (!NT_SUCCESS(status)) > - goto fail3; > - > - Length = (ULONG)strlen(Value) + 1; > - > - status = STATUS_BUFFER_OVERFLOW; > - if (OutLen == 0) { > - XenIfaceDebugPrint(INFO, "|%s: (\"%s\")=(%d)\n", __FUNCTION__, > Buffer, Length); > - goto done; > + PLIST_ENTRY Node; > + PXENIFACE_STORE_CONTEXT StoreContext; > + PXENIFACE_EVTCHN_CONTEXT EvtchnContext; > + KIRQL Irql; > + LIST_ENTRY ToFree; > + > + XenIfaceDebugPrint(TRACE, "FO %p, IRQL %d, Cpu %lu\n", FileObject, > KeGetCurrentIrql(), KeGetCurrentProcessorNumber()); > + > + // store watches > + KeAcquireSpinLock(&Fdo->StoreWatchLock, &Irql); > + Node = Fdo->StoreWatchList.Flink; > + while (Node->Flink != Fdo->StoreWatchList.Flink) { > + StoreContext = CONTAINING_RECORD(Node, > XENIFACE_STORE_CONTEXT, Entry); > + > + Node = Node->Flink; > + if (StoreContext->FileObject != FileObject) > + continue; > + > + XenIfaceDebugPrint(TRACE, "Store context %p\n", StoreContext); > + RemoveEntryList(&StoreContext->Entry); > + StoreFreeWatch(Fdo, StoreContext); > } > + KeReleaseSpinLock(&Fdo->StoreWatchLock, Irql); > > - status = STATUS_INVALID_PARAMETER; > - if (OutLen < Length) > - goto fail4; > - > - XenIfaceDebugPrint(INFO, "|%s: (\"%s\")=(%d)->\"%s\"\n", > __FUNCTION__, Buffer, Length, Value); > - > - RtlCopyMemory(Buffer, Value, Length); > - Buffer[Length - 1] = 0; > - status = STATUS_SUCCESS; > + // event channels > + InitializeListHead(&ToFree); > + KeAcquireSpinLock(&Fdo->EvtchnLock, &Irql); > + Node = Fdo->EvtchnList.Flink; > + while (Node->Flink != Fdo->EvtchnList.Flink) { > + EvtchnContext = CONTAINING_RECORD(Node, > XENIFACE_EVTCHN_CONTEXT, Entry); > + > + Node = Node->Flink; > + if (EvtchnContext->FileObject != FileObject) > + continue; > + > + XenIfaceDebugPrint(TRACE, "Evtchn context %p\n", EvtchnContext); > + RemoveEntryList(&EvtchnContext->Entry); > + // EvtchnFree requires PASSIVE_LEVEL and we're inside a lock > + InsertTailList(&ToFree, &EvtchnContext->Entry); > + } > + KeReleaseSpinLock(&Fdo->EvtchnLock, Irql); > > -done: > - *Info = (ULONG_PTR)Length; > - XENBUS_STORE(Free, &Fdo->StoreInterface, Value); > - return status; > + Node = ToFree.Flink; > + while (Node->Flink != ToFree.Flink) { > + EvtchnContext = CONTAINING_RECORD(Node, > XENIFACE_EVTCHN_CONTEXT, Entry); > + Node = Node->Flink; > > -fail4: > - XenIfaceDebugPrint(ERROR, "|%s: Fail4 (\"%s\")=(%d < %d)\n", > __FUNCTION__, Buffer, OutLen, Length); > - XENBUS_STORE(Free, &Fdo->StoreInterface, Value); > -fail3: > - XenIfaceDebugPrint(ERROR, "|%s: Fail3 (\"%s\")\n", __FUNCTION__, > Buffer); > -fail2: > - XenIfaceDebugPrint(ERROR, "|%s: Fail2\n", __FUNCTION__); > -fail1: > - XenIfaceDebugPrint(ERROR, "|%s: Fail1 (%08x)\n", __FUNCTION__, > status); > - return status; > + RemoveEntryList(&EvtchnContext->Entry); > + EvtchnFree(Fdo, EvtchnContext); > } > - > -static DECLSPEC_NOINLINE NTSTATUS > -IoctlWrite( > - __in PXENIFACE_FDO Fdo, > - __in PCHAR Buffer, > - __in ULONG InLen, > - __in ULONG OutLen > - ) > -{ > - NTSTATUS status; > - PCHAR Value; > - ULONG Length; > - > - status = STATUS_INVALID_BUFFER_SIZE; > - if (InLen == 0 || OutLen != 0) > - goto fail1; > - > - status = STATUS_INVALID_PARAMETER; > - if (!__IsValidStr(Buffer, InLen)) > - goto fail2; > - > - Length = (ULONG)strlen(Buffer) + 1; > - Value = Buffer + Length; > - > - if (!__IsValidStr(Value, InLen - Length)) > - goto fail3; > - > - status = XENBUS_STORE(Printf, &Fdo->StoreInterface, NULL, NULL, > Buffer, Value); > - if (!NT_SUCCESS(status)) > - goto fail4; > - > - XenIfaceDebugPrint(INFO, "|%s: (\"%s\"=\"%s\")\n", __FUNCTION__, > Buffer, Value); > - return status; > - > -fail4: > - XenIfaceDebugPrint(ERROR, "|%s: Fail4 (\"%s\")\n", __FUNCTION__, > Value); > -fail3: > - XenIfaceDebugPrint(ERROR, "|%s: Fail3 (\"%s\")\n", __FUNCTION__, > Buffer); > -fail2: > - XenIfaceDebugPrint(ERROR, "|%s: Fail2\n", __FUNCTION__); > -fail1: > - XenIfaceDebugPrint(ERROR, "|%s: Fail1 (%08x)\n", __FUNCTION__, > status); > - return status; > } > > -static DECLSPEC_NOINLINE NTSTATUS > -IoctlDirectory( > +NTSTATUS > +XenIfaceIoctl( > __in PXENIFACE_FDO Fdo, > - __in PCHAR Buffer, > - __in ULONG InLen, > - __in ULONG OutLen, > - __out PULONG_PTR Info > + __inout PIRP Irp > ) > { > NTSTATUS status; > - PCHAR Value; > - ULONG Length; > - ULONG Count; > - > - status = STATUS_INVALID_BUFFER_SIZE; > - if (InLen == 0) > - goto fail1; > - > - status = STATUS_INVALID_PARAMETER; > - if (!__IsValidStr(Buffer, InLen)) > - goto fail2; > - > - status = XENBUS_STORE(Directory, &Fdo->StoreInterface, NULL, NULL, > Buffer, &Value); > - if (!NT_SUCCESS(status)) > - goto fail3; > - > - Length = __MultiSzLen(Value, &Count) + 1; > + PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); > + PVOID Buffer = Irp->AssociatedIrp.SystemBuffer; > + ULONG InLen = Stack- > >Parameters.DeviceIoControl.InputBufferLength; > + ULONG OutLen = Stack- > >Parameters.DeviceIoControl.OutputBufferLength; > > - status = STATUS_BUFFER_OVERFLOW; > - if (OutLen == 0) { > - XenIfaceDebugPrint(INFO, "|%s: (\"%s\")=(%d)(%d)\n", > __FUNCTION__, Buffer, Length, Count); > + status = STATUS_DEVICE_NOT_READY; > + if (Fdo->InterfacesAcquired == FALSE) > goto done; > - } > > - status = STATUS_INVALID_PARAMETER; > - if (OutLen < Length) > - goto fail4; > + switch (Stack->Parameters.DeviceIoControl.IoControlCode) { > + // store > + case IOCTL_XENIFACE_STORE_READ: > + status = IoctlStoreRead(Fdo, (PCHAR)Buffer, InLen, OutLen, &Irp- > >IoStatus.Information); > + break; > > - XenIfaceDebugPrint(INFO, "|%s: (\"%s\")=(%d)(%d)\n", __FUNCTION__, > Buffer, Length, Count); > -#if DBG > - __DisplayMultiSz(__FUNCTION__, Value); > -#endif > + case IOCTL_XENIFACE_STORE_WRITE: > + status = IoctlStoreWrite(Fdo, (PCHAR)Buffer, InLen, OutLen); > + break; > > - RtlCopyMemory(Buffer, Value, Length); > - Buffer[Length - 2] = 0; > - Buffer[Length - 1] = 0; > - status = STATUS_SUCCESS; > + case IOCTL_XENIFACE_STORE_DIRECTORY: > + status = IoctlStoreDirectory(Fdo, (PCHAR)Buffer, InLen, OutLen, &Irp- > >IoStatus.Information); > + break; > > -done: > - *Info = (ULONG_PTR)Length; > - XENBUS_STORE(Free, &Fdo->StoreInterface, Value); > - return status; > + case IOCTL_XENIFACE_STORE_REMOVE: > + status = IoctlStoreRemove(Fdo, (PCHAR)Buffer, InLen, OutLen); > + break; > > -fail4: > - XenIfaceDebugPrint(ERROR, "|%s: Fail4 (\"%s\")=(%d < %d)\n", > __FUNCTION__, Buffer, OutLen, Length); > - XENBUS_STORE(Free, &Fdo->StoreInterface, Value); > -fail3: > - XenIfaceDebugPrint(ERROR, "|%s: Fail3 (\"%s\")\n", __FUNCTION__, > Buffer); > -fail2: > - XenIfaceDebugPrint(ERROR, "|%s: Fail2\n", __FUNCTION__); > -fail1: > - XenIfaceDebugPrint(ERROR, "|%s: Fail1 (%08x)\n", __FUNCTION__, > status); > - return status; > -} > + case IOCTL_XENIFACE_STORE_SET_PERMISSIONS: > + status = IoctlStoreSetPermissions(Fdo, Buffer, InLen, OutLen); > + break; > > -static DECLSPEC_NOINLINE NTSTATUS > -IoctlRemove( > - __in PXENIFACE_FDO Fdo, > - __in PCHAR Buffer, > - __in ULONG InLen, > - __in ULONG OutLen > - ) > -{ > - NTSTATUS status; > + case IOCTL_XENIFACE_STORE_ADD_WATCH: > + status = IoctlStoreAddWatch(Fdo, Buffer, InLen, OutLen, Stack- > >FileObject, &Irp->IoStatus.Information); > + break; > > - status = STATUS_INVALID_BUFFER_SIZE; > - if (InLen == 0 || OutLen != 0) > - goto fail1; > + case IOCTL_XENIFACE_STORE_REMOVE_WATCH: > + status = IoctlStoreRemoveWatch(Fdo, Buffer, InLen, OutLen, Stack- > >FileObject); > + break; > > - status = STATUS_INVALID_PARAMETER; > - if (!__IsValidStr(Buffer, InLen)) > - goto fail2; > + // evtchn > + case IOCTL_XENIFACE_EVTCHN_BIND_UNBOUND: > + status = IoctlEvtchnBindUnbound(Fdo, Buffer, InLen, OutLen, Stack- > >FileObject, &Irp->IoStatus.Information); > + break; > > - status = XENBUS_STORE(Remove, &Fdo->StoreInterface, NULL, NULL, > Buffer); > - if (!NT_SUCCESS(status)) > - goto fail3; > + case IOCTL_XENIFACE_EVTCHN_BIND_INTERDOMAIN: > + status = IoctlEvtchnBindInterdomain(Fdo, Buffer, InLen, OutLen, > Stack- > >FileObject, &Irp->IoStatus.Information); > + break; > > - XenIfaceDebugPrint(INFO, "|%s: (\"%s\")\n", __FUNCTION__, Buffer); > - return status; > + case IOCTL_XENIFACE_EVTCHN_CLOSE: > + status = IoctlEvtchnClose(Fdo, Buffer, InLen, OutLen, Stack- > >FileObject); > + break; > > -fail3: > - XenIfaceDebugPrint(ERROR, "|%s: Fail3 (\"%s\")\n", __FUNCTION__, > Buffer); > -fail2: > - XenIfaceDebugPrint(ERROR, "|%s: Fail2\n", __FUNCTION__); > -fail1: > - XenIfaceDebugPrint(ERROR, "|%s: Fail1 (%08x)\n", __FUNCTION__, > status); > - return status; > -} > + case IOCTL_XENIFACE_EVTCHN_NOTIFY: > + status = IoctlEvtchnNotify(Fdo, Buffer, InLen, OutLen, Stack- > >FileObject); > + break; > > -NTSTATUS > -XenIFaceIoctl( > - __in PXENIFACE_FDO Fdo, > - __in PIRP Irp > - ) > -{ > - NTSTATUS status; > - PIO_STACK_LOCATION Stack = IoGetCurrentIrpStackLocation(Irp); > - PVOID Buffer = Irp->AssociatedIrp.SystemBuffer; > - ULONG InLen = Stack- > >Parameters.DeviceIoControl.InputBufferLength; > - ULONG OutLen = Stack- > >Parameters.DeviceIoControl.OutputBufferLength; > + case IOCTL_XENIFACE_EVTCHN_UNMASK: > + status = IoctlEvtchnUnmask(Fdo, Buffer, InLen, OutLen, Stack- > >FileObject); > + break; > > - status = STATUS_DEVICE_NOT_READY; > - if (Fdo->InterfacesAcquired == FALSE) > - goto done; > + // gnttab > + case IOCTL_XENIFACE_GNTTAB_PERMIT_FOREIGN_ACCESS: > + status = IoctlGnttabPermitForeignAccess(Fdo, Buffer, InLen, OutLen, > Irp); > + break; > > - switch (Stack->Parameters.DeviceIoControl.IoControlCode) { > - case IOCTL_XENIFACE_STORE_READ: > - status = IoctlRead(Fdo, (PCHAR)Buffer, InLen, OutLen, &Irp- > >IoStatus.Information); > + case IOCTL_XENIFACE_GNTTAB_GET_GRANT_RESULT: > + status = IoctlGnttabGetGrantResult(Fdo, Buffer, InLen, OutLen, &Irp- > >IoStatus.Information); > break; > > - case IOCTL_XENIFACE_STORE_WRITE: > - status = IoctlWrite(Fdo, (PCHAR)Buffer, InLen, OutLen); > + case IOCTL_XENIFACE_GNTTAB_REVOKE_FOREIGN_ACCESS: > + status = IoctlGnttabRevokeForeignAccess(Fdo, Buffer, InLen, OutLen); > break; > > - case IOCTL_XENIFACE_STORE_DIRECTORY: > - status = IoctlDirectory(Fdo, (PCHAR)Buffer, InLen, OutLen, &Irp- > >IoStatus.Information); > + case IOCTL_XENIFACE_GNTTAB_MAP_FOREIGN_PAGES: > + status = IoctlGnttabMapForeignPages(Fdo, Buffer, InLen, OutLen, Irp); > break; > > - case IOCTL_XENIFACE_STORE_REMOVE: > - status = IoctlRemove(Fdo, (PCHAR)Buffer, InLen, OutLen); > + case IOCTL_XENIFACE_GNTTAB_GET_MAP_RESULT: > + status = IoctlGnttabGetMapResult(Fdo, Buffer, InLen, OutLen, &Irp- > >IoStatus.Information); > + break; > + > + case IOCTL_XENIFACE_GNTTAB_UNMAP_FOREIGN_PAGES: > + status = IoctlGnttabUnmapForeignPages(Fdo, Buffer, InLen, OutLen); > break; > > default: > @@ -327,6 +196,7 @@ done: > > Irp->IoStatus.Status = status; > > + if (status != STATUS_PENDING) > IoCompleteRequest(Irp, IO_NO_INCREMENT); > > return status; > diff --git a/src/xeniface/ioctls.h b/src/xeniface/ioctls.h > index 7ee7801..00e11e4 100644 > --- a/src/xeniface/ioctls.h > +++ b/src/xeniface/ioctls.h > @@ -33,11 +33,322 @@ > #define _IOCTLS_H_ > > #define XENIFACE_KERNEL_MODE > +#include "xeniface_ioctls.h" > > +typedef enum _XENIFACE_CONTEXT_TYPE { > + XENIFACE_CONTEXT_GRANT = 1, > + XENIFACE_CONTEXT_MAP > +} XENIFACE_CONTEXT_TYPE; > + > +typedef struct _XENIFACE_CONTEXT_ID { > + XENIFACE_CONTEXT_TYPE Type; > + ULONG RequestId; > + PEPROCESS Process; > +} XENIFACE_CONTEXT_ID, *PXENIFACE_CONTEXT_ID; > + > +typedef struct _XENIFACE_STORE_CONTEXT { > + LIST_ENTRY Entry; > + PXENBUS_STORE_WATCH Watch; > + PKEVENT Event; > + PVOID FileObject; > +} XENIFACE_STORE_CONTEXT, *PXENIFACE_STORE_CONTEXT; > + > +typedef struct _XENIFACE_EVTCHN_CONTEXT { > + LIST_ENTRY Entry; > + PXENBUS_EVTCHN_CHANNEL Channel; > + ULONG LocalPort; > + PKEVENT Event; > + PXENIFACE_FDO Fdo; > + BOOLEAN Active; > + PVOID FileObject; > +} XENIFACE_EVTCHN_CONTEXT, *PXENIFACE_EVTCHN_CONTEXT; > + > +typedef struct _XENIFACE_GRANT_CONTEXT { > + XENIFACE_CONTEXT_ID Id; > + LIST_ENTRY Entry; > + PXENBUS_GNTTAB_ENTRY *Grants; > + USHORT RemoteDomain; > + ULONG NumberPages; > + XENIFACE_GNTTAB_PAGE_FLAGS Flags; > + ULONG NotifyOffset; > + ULONG NotifyPort; > + PVOID KernelVa; > + PVOID UserVa; > + PMDL Mdl; > +} XENIFACE_GRANT_CONTEXT, *PXENIFACE_GRANT_CONTEXT; > + > +typedef struct _XENIFACE_MAP_CONTEXT { > + XENIFACE_CONTEXT_ID Id; > + LIST_ENTRY Entry; > + USHORT RemoteDomain; > + ULONG NumberPages; > + XENIFACE_GNTTAB_PAGE_FLAGS Flags; > + ULONG NotifyOffset; > + ULONG NotifyPort; > + PHYSICAL_ADDRESS Address; > + PVOID KernelVa; > + PVOID UserVa; > + PMDL Mdl; > +} XENIFACE_MAP_CONTEXT, *PXENIFACE_MAP_CONTEXT; > + > +NTSTATUS > +XenIfaceIoctl( > + __in PXENIFACE_FDO Fdo, > + __inout PIRP Irp > + ); > + > +_IRQL_requires_(PASSIVE_LEVEL) > +VOID > +XenIfaceCleanup( > + __in PXENIFACE_FDO Fdo, > + __in PFILE_OBJECT FileObject > + ); > + > +DECLSPEC_NOINLINE > NTSTATUS > -XenIFaceIoctl( > +IoctlStoreRead( > + __in PXENIFACE_FDO Fdo, > + __in PCHAR Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __out PULONG_PTR Info > + ); > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlStoreWrite( > + __in PXENIFACE_FDO Fdo, > + __in PCHAR Buffer, > + __in ULONG InLen, > + __in ULONG OutLen > + ); > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlStoreDirectory( > + __in PXENIFACE_FDO Fdo, > + __in PCHAR Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __out PULONG_PTR Info > + ); > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlStoreRemove( > + __in PXENIFACE_FDO Fdo, > + __in PCHAR Buffer, > + __in ULONG InLen, > + __in ULONG OutLen > + ); > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlStoreSetPermissions( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen > + ); > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlStoreAddWatch( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __in PFILE_OBJECT FileObject, > + __out PULONG_PTR Info > + ); > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlStoreRemoveWatch( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __in PFILE_OBJECT FileObject > + ); > + > +_IRQL_requires_max_(DISPATCH_LEVEL) > +VOID > +StoreFreeWatch( > + __in PXENIFACE_FDO Fdo, > + __inout PXENIFACE_STORE_CONTEXT Context > + ); > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlEvtchnBindUnbound( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __in PFILE_OBJECT FileObject, > + __out PULONG_PTR Info > + ); > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlEvtchnBindInterdomain( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __in PFILE_OBJECT FileObject, > + __out PULONG_PTR Info > + ); > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlEvtchnClose( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __in PFILE_OBJECT FileObject > + ); > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlEvtchnNotify( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __in PFILE_OBJECT FileObject > + ); > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlEvtchnUnmask( > __in PXENIFACE_FDO Fdo, > - __in PIRP Irp > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __in PFILE_OBJECT FileObject > + ); > + > +_Requires_lock_not_held_(Fdo->EvtchnLock) > +DECLSPEC_NOINLINE > +NTSTATUS > +EvtchnNotify( > + __in PXENIFACE_FDO Fdo, > + __in ULONG LocalPort, > + __in_opt PFILE_OBJECT FileObject > + ); > + > +_Function_class_(KDEFERRED_ROUTINE) > +_IRQL_requires_(DISPATCH_LEVEL) > +_IRQL_requires_same_ > +VOID > +EvtchnNotificationDpc( > + __in PKDPC Dpc, > + __in_opt PVOID Context, > + __in_opt PVOID Argument1, > + __in_opt PVOID Argument2 > + ); > + > +_IRQL_requires_(PASSIVE_LEVEL) > +VOID > +EvtchnFree( > + __in PXENIFACE_FDO Fdo, > + __inout PXENIFACE_EVTCHN_CONTEXT Context > + ); > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlGnttabPermitForeignAccess( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __inout PIRP Irp > + ); > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlGnttabGetGrantResult( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __out PULONG_PTR Info > + ); > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlGnttabRevokeForeignAccess( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen > + ); > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlGnttabMapForeignPages( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __inout PIRP Irp > + ); > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlGnttabGetMapResult( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen, > + __out PULONG_PTR Info > + ); > + > +DECLSPEC_NOINLINE > +NTSTATUS > +IoctlGnttabUnmapForeignPages( > + __in PXENIFACE_FDO Fdo, > + __in PVOID Buffer, > + __in ULONG InLen, > + __in ULONG OutLen > + ); > + > +_Acquires_exclusive_lock_(((PXENIFACE_FDO)Argument)- > >GnttabCacheLock) > +_IRQL_requires_(DISPATCH_LEVEL) > +VOID > +GnttabAcquireLock( > + __in PVOID Argument > + ); > + > +_Releases_exclusive_lock_(((PXENIFACE_FDO)Argument)- > >GnttabCacheLock) > +_IRQL_requires_(DISPATCH_LEVEL) > +VOID > +GnttabReleaseLock( > + __in PVOID Argument > + ); > + > +_Function_class_(IO_WORKITEM_ROUTINE) > +VOID > +CompleteGnttabIrp( > + __in PDEVICE_OBJECT DeviceObject, > + __in_opt PVOID Context > + ); > + > +_IRQL_requires_max_(APC_LEVEL) > +VOID > +GnttabFreeGrant( > + __in PXENIFACE_FDO Fdo, > + __inout PXENIFACE_GRANT_CONTEXT Context > + ); > + > +_IRQL_requires_max_(APC_LEVEL) > +VOID > +GnttabFreeMap( > + __in PXENIFACE_FDO Fdo, > + __inout PXENIFACE_MAP_CONTEXT Context > ); > > #endif // _IOCTLS_H_ > diff --git a/src/xeniface/irp_queue.c b/src/xeniface/irp_queue.c > new file mode 100644 > index 0000000..c3bf86c > --- /dev/null > +++ b/src/xeniface/irp_queue.c > @@ -0,0 +1,131 @@ > +#include "driver.h" > +#include "irp_queue.h" > +#include "log.h" > +#include "ioctls.h" > + > +// Cancel-safe IRP queue implementation > + > +NTSTATUS > +CsqInsertIrpEx( > + _In_ PIO_CSQ Csq, > + _In_ PIRP Irp, > + _In_ PVOID InsertContext // PXENIFACE_CONTEXT_ID > + ) > +{ > + PXENIFACE_FDO Fdo; > + > + Fdo = CONTAINING_RECORD(Csq, XENIFACE_FDO, IrpQueue); > + > + // Fail if a request with the same ID already exists. > + if (CsqPeekNextIrp(Csq, NULL, InsertContext) != NULL) > + return STATUS_INVALID_PARAMETER; > + > + InsertTailList(&Fdo->IrpList, &Irp->Tail.Overlay.ListEntry); > + return STATUS_SUCCESS; > +} > + > +VOID > +CsqRemoveIrp( > + _In_ PIO_CSQ Csq, > + _In_ PIRP Irp > + ) > +{ > + UNREFERENCED_PARAMETER(Csq); > + > + RemoveEntryList(&Irp->Tail.Overlay.ListEntry); > +} > + > +PIRP > +CsqPeekNextIrp( > + _In_ PIO_CSQ Csq, > + _In_opt_ PIRP Irp, > + _In_opt_ PVOID PeekContext // PXENIFACE_CONTEXT_ID > + ) > +{ > + PXENIFACE_FDO Fdo; > + PIRP NextIrp = NULL; > + PLIST_ENTRY Head, NextEntry; > + PXENIFACE_CONTEXT_ID Id, TargetId; > + > + Fdo = CONTAINING_RECORD(Csq, XENIFACE_FDO, IrpQueue); > + TargetId = PeekContext; > + Head = &Fdo->IrpList; > + > + // If the IRP is NULL, we will start peeking from the list head, > + // else we will start from that IRP onwards. This is done under the > + // assumption that new IRPs are always inserted at the tail. > + > + if (Irp == NULL) { > + NextEntry = Head->Flink; > + } else { > + NextEntry = Irp->Tail.Overlay.ListEntry.Flink; > + } > + > + while (NextEntry != Head) { > + NextIrp = CONTAINING_RECORD(NextEntry, IRP, Tail.Overlay.ListEntry); > + > + if (PeekContext) { > + Id = NextIrp->Tail.Overlay.DriverContext[0]; > + if (Id->RequestId == TargetId->RequestId && Id->Process == > TargetId->Process) > + break; > + } else { > + break; > + } > + NextIrp = NULL; > + NextEntry = NextEntry->Flink; > + } > + > + return NextIrp; > +} > + > +_IRQL_raises_(DISPATCH_LEVEL) > +_IRQL_requires_max_(DISPATCH_LEVEL) > +_Acquires_lock_(CONTAINING_RECORD(Csq, XENIFACE_FDO, IrpQueue)- > >IrpQueueLock) > +VOID > +CsqAcquireLock( > + _In_ PIO_CSQ Csq, > + _Out_ _At_(*Irql, _Post_ _IRQL_saves_) PKIRQL Irql > + ) > +{ > + PXENIFACE_FDO Fdo; > + > + Fdo = CONTAINING_RECORD(Csq, XENIFACE_FDO, IrpQueue); > + > + KeAcquireSpinLock(&Fdo->IrpQueueLock, Irql); > +} > + > +_IRQL_requires_(DISPATCH_LEVEL) > +_Releases_lock_(CONTAINING_RECORD(Csq, XENIFACE_FDO, IrpQueue)- > >IrpQueueLock) > +VOID > +CsqReleaseLock( > + _In_ PIO_CSQ Csq, > + _In_ _IRQL_restores_ KIRQL Irql > + ) > +{ > + PXENIFACE_FDO Fdo; > + > + Fdo = CONTAINING_RECORD(Csq, XENIFACE_FDO, IrpQueue); > + > + KeReleaseSpinLock(&Fdo->IrpQueueLock, Irql); > +} > + > +_IRQL_requires_max_(DISPATCH_LEVEL) > +VOID > +CsqCompleteCanceledIrp( > + _In_ PIO_CSQ Csq, > + _In_ PIRP Irp > + ) > +{ > + PXENIFACE_FDO Fdo = CONTAINING_RECORD(Csq, XENIFACE_FDO, > IrpQueue); > + PIO_WORKITEM WorkItem; > + > + XenIfaceDebugPrint(TRACE, "Irp %p, IRQL %d\n", > + Irp, KeGetCurrentIrql()); > + > + // This is not guaranteed to run at PASSIVE_LEVEL, so queue a work item > + // to perform actual cleanup/IRP completion. > + > + WorkItem = IoAllocateWorkItem(Fdo->Dx->DeviceObject); > + Irp->Tail.Overlay.DriverContext[1] = WorkItem; // store so the work item > can free it > + IoQueueWorkItem(WorkItem, CompleteGnttabIrp, DelayedWorkQueue, > Irp); > +} > diff --git a/src/xeniface/irp_queue.h b/src/xeniface/irp_queue.h > new file mode 100644 > index 0000000..746ee19 > --- /dev/null > +++ b/src/xeniface/irp_queue.h > @@ -0,0 +1,50 @@ > +#ifndef _IRP_QUEUE_H_ > +#define _IRP_QUEUE_H_ > + > +#include <ntddk.h> > + > +NTSTATUS > +CsqInsertIrpEx( > + _In_ PIO_CSQ Csq, > + _In_ PIRP Irp, > + _In_ PVOID InsertContext > + ); > + > +VOID > +CsqRemoveIrp( > + _In_ PIO_CSQ Csq, > + _In_ PIRP Irp > + ); > + > +PIRP > +CsqPeekNextIrp( > + _In_ PIO_CSQ Csq, > + _In_opt_ PIRP Irp, > + _In_opt_ PVOID PeekContext // PXENIFACE_CONTEXT_ID > + ); > + > +_IRQL_raises_(DISPATCH_LEVEL) > +_IRQL_requires_max_(DISPATCH_LEVEL) > +_Acquires_lock_(CONTAINING_RECORD(Csq, XENIFACE_FDO, IrpQueue)- > >IrpQueueLock) > +VOID > +CsqAcquireLock( > + _In_ PIO_CSQ Csq, > + _Out_ _At_(*Irql, _Post_ _IRQL_saves_) PKIRQL Irql > + ); > + > +_IRQL_requires_(DISPATCH_LEVEL) > +_Releases_lock_(CONTAINING_RECORD(Csq, XENIFACE_FDO, IrpQueue)- > >IrpQueueLock) > +VOID > +CsqReleaseLock( > + _In_ PIO_CSQ Csq, > + _In_ _IRQL_restores_ KIRQL Irql > + ); > + > +_IRQL_requires_max_(DISPATCH_LEVEL) > +VOID > +CsqCompleteCanceledIrp( > + _In_ PIO_CSQ Csq, > + _In_ PIRP Irp > + ); > + > +#endif > diff --git a/vs2013/xeniface/xeniface.vcxproj > b/vs2013/xeniface/xeniface.vcxproj > index fea2ad1..14f1338 100644 > --- a/vs2013/xeniface/xeniface.vcxproj > +++ b/vs2013/xeniface/xeniface.vcxproj > @@ -131,6 +131,10 @@ > <ClCompile Include="../../src/xeniface/fdo.c" /> > <ClCompile Include="../../src/xeniface/registry.c" /> > <ClCompile Include="../../src\xeniface/thread.c" /> > + <ClCompile Include="..\..\src\xeniface\ioctl_evtchn.c" /> > + <ClCompile Include="..\..\src\xeniface\ioctl_gnttab.c" /> > + <ClCompile Include="..\..\src\xeniface\ioctl_store.c" /> > + <ClCompile Include="..\..\src\xeniface\irp_queue.c" /> > </ItemGroup> > <ItemGroup> > <Mofcomp Include="../../src/xeniface/wmi.mof"> > -- > 1.8.1.msysgit.1 > > _______________________________________________ > win-pv-devel mailing list > win-pv-devel@xxxxxxxxxxxxxxxxxxxx > http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel _______________________________________________ win-pv-devel mailing list win-pv-devel@xxxxxxxxxxxxxxxxxxxx http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |