[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [win-pv-devel] [PATCH 5/6] Implement new IOCTL handlers
> -----Original Message----- > From: win-pv-devel-bounces@xxxxxxxxxxxxxxxxxxxx [mailto:win-pv-devel- > bounces@xxxxxxxxxxxxxxxxxxxx] On Behalf Of Rafal Wojdyla > Sent: 21 October 2015 06:27 > To: win-pv-devel@xxxxxxxxxxxxxxxxxxxx > 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@xxxxxxxxxxxxxxxxxxxxxx> Acked-by: Paul Durrant <paul.durrant@xxxxxxxxxx> > --- > 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@xxxxxxxxxxxxxxxxxxxxxx> > * 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@xxxxxxxxxxxxxxxxxxxxxx> > + * 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@xxxxxxxxxxxxxxxxxxxxxx> > + * 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@xxxxxxxxxxxxxxxxxxxxxx> > + * 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@xxxxxxxxxxxxxxxxxxxxxx> > * 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@xxxxxxxxxxxxxxxxxxxxxx> > * 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@xxxxxxxxxxxxxxxxxxxxxx> > + * 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@xxxxxxxxxxxxxxxxxxxxxx> > + * 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@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 |