ULONG RequestId; /*! Request ID used in the corresponding IOCTL_XENIFACE_GNTTAB_MAP_FOREIGN_PAGES call */
} XENIFACE_GNTTAB_UNMAP_FOREIGN_PAGES_IN, *PXENIFACE_GNTTAB_UNMAP_FOREIGN_PAGES_IN;
+/*! \brief Gets the current suspend count.
+
+ Input: None
+
+ Output: ULONG
+*/
+#define IOCTL_XENIFACE_SUSPEND_GET_COUNT \
+ CTL_CODE(FILE_DEVICE_UNKNOWN, 0x830, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+/*! \brief Input for IOCTL_XENIFACE_SUSPEND_REGISTER */
+typedef struct _XENIFACE_SUSPEND_REGISTER_IN {
+ HANDLE Event; /*!< Handle to an event object that will receive suspend notifications */
+} XENIFACE_SUSPEND_REGISTER_IN, *PXENIFACE_SUSPEND_REGISTER_IN;
+
+/*! \brief Input for IOCTL_XENIFACE_SUSPEND_DEREGISTER */
+typedef struct _XENIFACE_SUSPEND_REGISTER_OUT {
+ PVOID Context; /*!< Handle to the suspend event */
+} XENIFACE_SUSPEND_REGISTER_OUT, *PXENIFACE_SUSPEND_REGISTER_OUT;
+
+/*! \brief Registers an event which is signalled on resume-from-suspend
+
+ Input: XENIFACE_SUSPEND_REGISTER_IN
+
+ Output: XENIFACE_SUSPEND_REGISTER_OUT
+*/
+#define IOCTL_XENIFACE_SUSPEND_REGISTER \
+ CTL_CODE(FILE_DEVICE_UNKNOWN, 0x831, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
+/*! \brief Deregisters an event which is signalled on resume-from-suspend
+
+ Input: XENIFACE_SUSPEND_REGISTER_OUT
+
+ Output: None
+*/
+#define IOCTL_XENIFACE_SUSPEND_DEREGISTER \
+ CTL_CODE(FILE_DEVICE_UNKNOWN, 0x832, METHOD_BUFFERED, FILE_ANY_ACCESS)
+
#endif // _XENIFACE_IOCTLS_H_
ASSERT(NT_SUCCESS(status));
WmiFireSuspendEvent(Fdo);
+ SuspendEventFire(Fdo);
}
static DECLSPEC_NOINLINE NTSTATUS
KeInitializeSpinLock(&Fdo->EvtchnLock);
InitializeListHead(&Fdo->EvtchnList);
+ KeInitializeSpinLock(&Fdo->SuspendLock);
+ InitializeListHead(&Fdo->SuspendList);
+
KeInitializeSpinLock(&Fdo->IrpQueueLock);
InitializeListHead(&Fdo->IrpList);
RtlZeroMemory(&Fdo->IrpList, sizeof (LIST_ENTRY));
RtlZeroMemory(&Fdo->IrpQueueLock, sizeof (KSPIN_LOCK));
+ ASSERT(IsListEmpty(&Fdo->SuspendList));
+ RtlZeroMemory(&Fdo->SuspendList, sizeof (LIST_ENTRY));
+ RtlZeroMemory(&Fdo->SuspendLock, sizeof (KSPIN_LOCK));
+
ASSERT(IsListEmpty(&Fdo->EvtchnList));
RtlZeroMemory(&Fdo->EvtchnList, sizeof (LIST_ENTRY));
RtlZeroMemory(&Fdo->EvtchnLock, sizeof (KSPIN_LOCK));
RtlZeroMemory(&Fdo->IrpQueueLock, sizeof (KSPIN_LOCK));
RtlZeroMemory(&Fdo->IrpQueue, sizeof (IO_CSQ));
+ ASSERT(IsListEmpty(&Fdo->SuspendList));
+ RtlZeroMemory(&Fdo->SuspendList, sizeof (LIST_ENTRY));
+ RtlZeroMemory(&Fdo->SuspendLock, sizeof (KSPIN_LOCK));
+
ASSERT(IsListEmpty(&Fdo->EvtchnList));
RtlZeroMemory(&Fdo->EvtchnList, sizeof (LIST_ENTRY));
RtlZeroMemory(&Fdo->EvtchnLock, sizeof (KSPIN_LOCK));
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "driver.h"
+#include "ioctls.h"
+#include "xeniface_ioctls.h"
+#include "log.h"
+
+DECLSPEC_NOINLINE
+NTSTATUS
+IoctlSuspendGetCount(
+ __in PXENIFACE_FDO Fdo,
+ __in PCHAR Buffer,
+ __in ULONG InLen,
+ __in ULONG OutLen,
+ __out PULONG_PTR Info
+ )
+{
+ NTSTATUS status;
+ PULONG Value;
+
+ status = STATUS_INVALID_BUFFER_SIZE;
+ if (InLen != 0)
+ goto fail1;
+
+ if (OutLen != sizeof(ULONG))
+ goto fail2;
+
+ Value = (PULONG)Buffer;
+ *Value = XENBUS_SUSPEND(GetCount, &Fdo->SuspendInterface);
+ *Info = (ULONG_PTR)sizeof(ULONG);
+ status = STATUS_SUCCESS;
+
+ return status;
+
+fail2:
+ XenIfaceDebugPrint(ERROR, "Fail2\n");
+fail1:
+ XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
+ return status;
+}
+
+DECLSPEC_NOINLINE
+NTSTATUS
+IoctlSuspendRegister(
+ __in PXENIFACE_FDO Fdo,
+ __in PVOID Buffer,
+ __in ULONG InLen,
+ __in ULONG OutLen,
+ __in PFILE_OBJECT FileObject,
+ __out PULONG_PTR Info
+ )
+{
+ NTSTATUS status;
+ PXENIFACE_SUSPEND_REGISTER_IN In = Buffer;
+ PXENIFACE_SUSPEND_REGISTER_OUT Out = Buffer;
+ PXENIFACE_SUSPEND_CONTEXT Context;
+
+ status = STATUS_INVALID_BUFFER_SIZE;
+ if (InLen != sizeof(XENIFACE_SUSPEND_REGISTER_IN) ||
+ OutLen != sizeof(XENIFACE_SUSPEND_REGISTER_OUT)) {
+ goto fail1;
+ }
+
+ status = STATUS_NO_MEMORY;
+ Context = ExAllocatePoolWithTag(NonPagedPool, sizeof(XENIFACE_SUSPEND_CONTEXT), XENIFACE_POOL_TAG);
+ if (Context == NULL)
+ goto fail2;
+
+ RtlZeroMemory(Context, sizeof(XENIFACE_SUSPEND_CONTEXT));
+
+ Context->FileObject = FileObject;
+
+ status = ObReferenceObjectByHandle(In->Event,
+ EVENT_MODIFY_STATE,
+ *ExEventObjectType,
+ UserMode,
+ &Context->Event,
+ NULL);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ XenIfaceDebugPrint(TRACE, "> Suspend Event %p, FO %p\n", In->Event, FileObject);
+ ExInterlockedInsertTailList(&Fdo->SuspendList, &Context->Entry, &Fdo->SuspendLock);
+
+ Out->Context = Context;
+ *Info = sizeof(XENIFACE_SUSPEND_REGISTER_OUT);
+
+ return status;
+
+fail3:
+ XenIfaceDebugPrint(ERROR, "Fail3\n");
+ RtlZeroMemory(Context, sizeof(XENIFACE_SUSPEND_CONTEXT));
+ ExFreePoolWithTag(Context, XENIFACE_POOL_TAG);
+
+fail2:
+ XenIfaceDebugPrint(ERROR, "Fail2\n");
+
+fail1:
+ XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
+ return status;
+}
+
+_IRQL_requires_max_(DISPATCH_LEVEL)
+VOID
+SuspendFreeEvent(
+ __in PXENIFACE_FDO Fdo,
+ __inout PXENIFACE_SUSPEND_CONTEXT Context
+ )
+{
+ XenIfaceDebugPrint(TRACE, "Context %p, FO %p\n",
+ Context, Context->FileObject);
+
+ ObDereferenceObject(Context->Event);
+ RtlZeroMemory(Context, sizeof(XENIFACE_SUSPEND_CONTEXT));
+ ExFreePoolWithTag(Context, XENIFACE_POOL_TAG);
+}
+
+DECLSPEC_NOINLINE
+NTSTATUS
+IoctlSuspendDeregister(
+ __in PXENIFACE_FDO Fdo,
+ __in PVOID Buffer,
+ __in ULONG InLen,
+ __in ULONG OutLen,
+ __in PFILE_OBJECT FileObject
+ )
+{
+ NTSTATUS status;
+ PXENIFACE_SUSPEND_REGISTER_OUT In = Buffer;
+ PXENIFACE_SUSPEND_CONTEXT Context = NULL;
+ KIRQL Irql;
+ PLIST_ENTRY Node;
+
+ status = STATUS_INVALID_BUFFER_SIZE;
+ if (InLen != sizeof(XENIFACE_SUSPEND_REGISTER_OUT) ||
+ OutLen != 0) {
+ goto fail1;
+ }
+
+ XenIfaceDebugPrint(TRACE, "> Context %p, FO %p\n", In->Context, FileObject);
+
+ KeAcquireSpinLock(&Fdo->SuspendLock, &Irql);
+ Node = Fdo->SuspendList.Flink;
+ while (Node->Flink != Fdo->SuspendList.Flink) {
+ Context = CONTAINING_RECORD(Node, XENIFACE_SUSPEND_CONTEXT, Entry);
+
+ Node = Node->Flink;
+ if (Context != In->Context ||
+ Context->FileObject != FileObject) {
+ continue;
+ }
+
+ RemoveEntryList(&Context->Entry);
+ break;
+ }
+ KeReleaseSpinLock(&Fdo->SuspendLock, Irql);
+
+ status = STATUS_NOT_FOUND;
+ if (Context == NULL || Context != In->Context)
+ goto fail2;
+
+ SuspendFreeEvent(Fdo, Context);
+
+ return STATUS_SUCCESS;
+
+fail2:
+ XenIfaceDebugPrint(ERROR, "Fail2\n");
+
+fail1:
+ XenIfaceDebugPrint(ERROR, "Fail1 (%08x)\n", status);
+ return status;
+}
+
+VOID
+SuspendEventFire(
+ __in PXENIFACE_FDO Fdo
+ )
+{
+ KIRQL Irql;
+ PLIST_ENTRY Node;
+ PXENIFACE_SUSPEND_CONTEXT Context;
+
+ KeAcquireSpinLock(&Fdo->SuspendLock, &Irql);
+ Node = Fdo->SuspendList.Flink;
+ while (Node->Flink != Fdo->SuspendList.Flink) {
+ Context = CONTAINING_RECORD(Node, XENIFACE_SUSPEND_CONTEXT, Entry);
+
+ KeSetEvent(Context->Event, IO_NO_INCREMENT, FALSE);
+
+ Node = Node->Flink;
+ }
+ KeReleaseSpinLock(&Fdo->SuspendLock, Irql);
+}
PLIST_ENTRY Node;
PXENIFACE_STORE_CONTEXT StoreContext;
PXENIFACE_EVTCHN_CONTEXT EvtchnContext;
+ PXENIFACE_SUSPEND_CONTEXT SuspendContext;
KIRQL Irql;
LIST_ENTRY ToFree;
RemoveEntryList(&EvtchnContext->Entry);
EvtchnFree(Fdo, EvtchnContext);
}
+
+ // suspend events
+ KeAcquireSpinLock(&Fdo->SuspendLock, &Irql);
+ Node = Fdo->SuspendList.Flink;
+ while (Node->Flink != Fdo->SuspendList.Flink) {
+ SuspendContext = CONTAINING_RECORD(Node, XENIFACE_SUSPEND_CONTEXT, Entry);
+
+ Node = Node->Flink;
+ if (SuspendContext->FileObject != FileObject)
+ continue;
+
+ XenIfaceDebugPrint(TRACE, "Suspend context %p\n", SuspendContext);
+ RemoveEntryList(&SuspendContext->Entry);
+ SuspendFreeEvent(Fdo, SuspendContext);
+ }
+ KeReleaseSpinLock(&Fdo->SuspendLock, Irql);
}
NTSTATUS
status = IoctlGnttabUnmapForeignPages(Fdo, Buffer, InLen, OutLen);
break;
+ // suspend
+ case IOCTL_XENIFACE_SUSPEND_GET_COUNT:
+ status = IoctlSuspendGetCount(Fdo, Buffer, InLen, OutLen, &Irp->IoStatus.Information);
+ break;
+
+ case IOCTL_XENIFACE_SUSPEND_REGISTER:
+ status = IoctlSuspendRegister(Fdo, Buffer, InLen, OutLen, Stack->FileObject, &Irp->IoStatus.Information);
+ break;
+
+ case IOCTL_XENIFACE_SUSPEND_DEREGISTER:
+ status = IoctlSuspendDeregister(Fdo, Buffer, InLen, OutLen, Stack->FileObject);
+ break;
+
default:
status = STATUS_INVALID_DEVICE_REQUEST;
break;