|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [win-pv-devel] [PATCH 3/3] Add XenDisk device upper filter.
XenDisk intercepts and translates IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES
into SCSIOP_UNMAP SRBs. Storport will pass on these SCSIOP_UNMAP requests
to XenVbd, which will create the appropriate BLKIF_OP_DISCARD requests.
XenDisk is only neccessary because Storport does not do the translation
to SCSIOP_UNMAPs.
Signed-off-by: Owen Smith <owen.smith@xxxxxxxxxx>
---
build.py | 1 +
src/xendisk/assert.h | 220 ++++
src/xendisk/debug.h | 94 ++
src/xendisk/driver.c | 203 ++++
src/xendisk/driver.h | 68 ++
src/xendisk/fdo.c | 1862 +++++++++++++++++++++++++++++++
src/xendisk/fdo.h | 78 ++
src/xendisk/mutex.h | 113 ++
src/xendisk/pdo.c | 2079 +++++++++++++++++++++++++++++++++++
src/xendisk/pdo.h | 90 ++
src/xendisk/thread.c | 225 ++++
src/xendisk/thread.h | 73 ++
src/xendisk/types.h | 53 +
src/xendisk/util.h | 222 ++++
src/xendisk/xendisk.rc | 56 +
src/xenvbd.inf | 18 +
vs2012/package/package.vcxproj | 3 +
vs2012/xendisk/xendisk.vcxproj | 84 ++
vs2012/xendisk/xendisk.vcxproj.user | 8 +
vs2012/xenvbd.sln | 28 +
vs2013/package/package.vcxproj | 3 +
vs2013/xendisk/xendisk.vcxproj | 112 ++
vs2013/xendisk/xendisk.vcxproj.user | 8 +
vs2013/xenvbd.sln | 28 +
24 files changed, 5729 insertions(+)
create mode 100644 src/xendisk/assert.h
create mode 100644 src/xendisk/debug.h
create mode 100644 src/xendisk/driver.c
create mode 100644 src/xendisk/driver.h
create mode 100644 src/xendisk/fdo.c
create mode 100644 src/xendisk/fdo.h
create mode 100644 src/xendisk/mutex.h
create mode 100644 src/xendisk/pdo.c
create mode 100644 src/xendisk/pdo.h
create mode 100644 src/xendisk/thread.c
create mode 100644 src/xendisk/thread.h
create mode 100644 src/xendisk/types.h
create mode 100644 src/xendisk/util.h
create mode 100644 src/xendisk/xendisk.rc
create mode 100644 vs2012/xendisk/xendisk.vcxproj
create mode 100644 vs2012/xendisk/xendisk.vcxproj.user
create mode 100644 vs2013/xendisk/xendisk.vcxproj
create mode 100644 vs2013/xendisk/xendisk.vcxproj.user
diff --git a/build.py b/build.py
index 26261ad..3a71d0c 100644
--- a/build.py
+++ b/build.py
@@ -368,6 +368,7 @@ if __name__ == '__main__':
if len(sys.argv) <= 2 or sdv[sys.argv[2]]:
run_sdv('xencrsh', driver, vs)
+ run_sdv('xendisk', driver, vs)
run_sdv('xenvbd', driver, vs)
archive(driver + '\\source.tgz', manifest().splitlines(), tgz=True)
diff --git a/src/xendisk/assert.h b/src/xendisk/assert.h
new file mode 100644
index 0000000..cd571bd
--- /dev/null
+++ b/src/xendisk/assert.h
@@ -0,0 +1,220 @@
+/* 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.
+ */
+
+#ifndef _XENDISK_ASSERT_H
+#define _XENDISK_ASSERT_H
+
+#include <ntddk.h>
+
+#include "debug.h"
+
+static FORCEINLINE VOID
+__BugCheck(
+ __in ULONG Code,
+ __in_opt ULONG_PTR Parameter1,
+ __in_opt ULONG_PTR Parameter2,
+ __in_opt ULONG_PTR Parameter3,
+ __in_opt ULONG_PTR Parameter4
+ )
+{
+#pragma prefast(suppress:28159)
+ KeBugCheckEx(Code,
+ Parameter1,
+ Parameter2,
+ Parameter3,
+ Parameter4);
+}
+
+#define ASSERTION_FAILURE 0x0000DEAD
+
+
+#define BUG(_TEXT) \
+ do { \
+ const CHAR *_Text = (_TEXT); \
+ const CHAR *_File = __FILE__; \
+ ULONG _Line = __LINE__; \
+ \
+ Error("BUG: " _TEXT "\n"); \
+ __BugCheck(ASSERTION_FAILURE, \
+ (ULONG_PTR)_Text, \
+ (ULONG_PTR)_File, \
+ (ULONG_PTR)_Line, \
+ 0); \
+ } while (FALSE)
+
+#define BUG_MSG(_TEXT1, _TEXT2) \
+ do { \
+ const CHAR *_Text1 = (_TEXT1); \
+ const CHAR *_Text2 = (_TEXT2); \
+ const CHAR *_File = __FILE__; \
+ ULONG _Line = __LINE__; \
+ \
+ Error("BUG: " _TEXT1 " %s\n", _Text2); \
+ __BugCheck(ASSERTION_FAILURE, \
+ (ULONG_PTR)_Text1, \
+ (ULONG_PTR)_File, \
+ (ULONG_PTR)_Line, \
+ (ULONG_PTR)_Text2); \
+ } while (FALSE)
+
+#define BUG_ON(_EXP) \
+ if (_EXP) BUG(#_EXP)
+
+#define BUG_ON_MSG(_EXP, _TEXT) \
+ if (_EXP) BUG_MSG(#_EXP, _TEXT)
+
+#if DBG
+
+#define __NT_ASSERT(_EXP) \
+ ((!(_EXP)) ? \
+ (Error("ASSERTION FAILED: " #_EXP "\n"), \
+ __annotation(L"Debug", L"AssertFail", L#_EXP), \
+ DbgRaiseAssertionFailure(), FALSE) : \
+ TRUE)
+
+#define __NT_ASSERT_MSG(_EXP, _TEXT) \
+ ((!(_EXP)) ? \
+ (Error("ASSERTION FAILED: " #_EXP " " #_TEXT "\n"), \
+ __annotation(L"Debug", L"AssertFail", L#_EXP), \
+ DbgRaiseAssertionFailure(), FALSE) : \
+ TRUE)
+
+#define __ASSERT(_EXP) __NT_ASSERT(_EXP)
+#define __ASSERT_MSG(_EXP, _TEXT) __NT_ASSERT_MSG(_EXP, _TEXT)
+
+#else // DBG
+
+#define __ASSERT(_EXP) BUG_ON(!(_EXP))
+#define __ASSERT_MSG(_EXP, _TEXT) BUG_ON_MSG(!(_EXP), _TEXT)
+
+#endif // DBG
+
+#undef ASSERT
+
+#define ASSERT(_EXP) \
+ do { \
+ __ASSERT(_EXP); \
+ __analysis_assume(_EXP); \
+ } while (FALSE)
+
+#define ASSERT_MSG(_EXP, _TEXT) \
+ do { \
+ __ASSERT_MSG(_EXP, _TEXT); \
+ __analysis_assume(_EXP); \
+ } while (FALSE)
+
+#define ASSERT3U(_X, _OP, _Y) \
+ do { \
+ ULONGLONG _Lval = (ULONGLONG)(_X); \
+ ULONGLONG _Rval = (ULONGLONG)(_Y); \
+ if (!(_Lval _OP _Rval)) { \
+ Error("%s = %llu\n", #_X, _Lval); \
+ Error("%s = %llu\n", #_Y, _Rval); \
+ ASSERT(_X _OP _Y); \
+ } \
+ } while (FALSE)
+
+#define ASSERT3S(_X, _OP, _Y) \
+ do { \
+ LONGLONG _Lval = (LONGLONG)(_X); \
+ LONGLONG _Rval = (LONGLONG)(_Y); \
+ if (!(_Lval _OP _Rval)) { \
+ Error("%s = %lld\n", #_X, _Lval); \
+ Error("%s = %lld\n", #_Y, _Rval); \
+ ASSERT(_X _OP _Y); \
+ } \
+ } while (FALSE)
+
+#define ASSERT3P(_X, _OP, _Y) \
+ do { \
+ PVOID _Lval = (PVOID)(_X); \
+ PVOID _Rval = (PVOID)(_Y); \
+ if (!(_Lval _OP _Rval)) { \
+ Error("%s = %p\n", #_X, _Lval); \
+ Error("%s = %p\n", #_Y, _Rval); \
+ ASSERT(_X _OP _Y); \
+ } \
+ } while (FALSE)
+
+#define ASSERTREFCOUNT(_X, _OP, _Y, _Z) \
+ do { \
+ LONG _L = (LONG)(_X); \
+ LONG _R = (LONG)(_Y); \
+ if (!(_L _OP _R)) { \
+ Error("%s:%s = %d\n", (_Z), #_X, _L); \
+ Error("%s:%s = %d\n", (_Z), #_Y, _R); \
+ ASSERT_MSG(_X _OP _Y, (_Z)); \
+ } \
+ } while (FALSE)
+
+#ifndef TEST_MEMORY
+#define TEST_MEMORY DBG
+#endif
+
+#if TEST_MEMORY
+
+__checkReturn
+static __inline BOOLEAN
+_IsZeroMemory(
+ __in const PCHAR Caller,
+ __in const PCHAR Name,
+ __in PVOID Buffer,
+ __in ULONG Length
+ )
+{
+ ULONG Offset;
+
+ Offset = 0;
+ while (Offset < Length) {
+ if (*((PUCHAR)Buffer + Offset) != 0) {
+ Error("%s: non-zero byte in %s (0x%p+0x%x)\n", Caller, Name,
Buffer, Offset);
+ return FALSE;
+ }
+ Offset++;
+ }
+
+ return TRUE;
+}
+
+#define IsZeroMemory(_Buffer, _Length) \
+ _IsZeroMemory(__FUNCTION__, #_Buffer, (_Buffer), (_Length))
+
+#else // TEST_MEMORY
+
+#define IsZeroMemory(_Buffer, _Length) TRUE
+
+#endif // TEST_MEMORY
+
+#define IMPLY(_X, _Y) (!(_X) || (_Y))
+#define EQUIV(_X, _Y) (IMPLY((_X), (_Y)) && IMPLY((_Y), (_X)))
+
+#endif // _XENDISK_ASSERT_H
+
diff --git a/src/xendisk/debug.h b/src/xendisk/debug.h
new file mode 100644
index 0000000..f592f86
--- /dev/null
+++ b/src/xendisk/debug.h
@@ -0,0 +1,94 @@
+/* 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.
+ */
+
+#ifndef _DEBUG_H
+#define _DEBUG_H
+
+#include <ntddk.h>
+#include <stdarg.h>
+
+#ifdef _SDV_
+#define __MODULE__ ""
+#endif
+
+// DEBUG_FILTER_MASKs
+// Set these to see relevant output
+// ERROR 0x00000001
+// WARNING 0x00000002
+// TRACE 0x00000004
+// INFO 0x00000008
+
+#pragma warning(disable:4127) // conditional expression is constant
+
+//
+// Debug Output and Logging
+//
+static __inline VOID
+__DebugMessage(
+ __in ULONG Level,
+ __in __nullterminated const CHAR *Prefix,
+ __in __nullterminated const CHAR *Format,
+ ...
+ )
+{
+ va_list Arguments;
+
+ va_start(Arguments, Format);
+
+#pragma prefast(suppress:6001) // Using uninitialized memory
+ vDbgPrintExWithPrefix(Prefix,
+ DPFLTR_IHVDRIVER_ID,
+ Level,
+ Format,
+ Arguments);
+ va_end(Arguments);
+}
+
+#define Error(...) \
+ __DebugMessage(DPFLTR_ERROR_LEVEL, __MODULE__ "|" __FUNCTION__ ":",
__VA_ARGS__)
+
+#define Warning(...) \
+ __DebugMessage(DPFLTR_WARNING_LEVEL, __MODULE__ "|" __FUNCTION__ ":",
__VA_ARGS__)
+
+#if DBG
+#define Trace(...) \
+ __DebugMessage(DPFLTR_TRACE_LEVEL, __MODULE__ "|" __FUNCTION__ ":",
__VA_ARGS__)
+#else // DBG
+#define Trace(...) \
+ (VOID)(__VA_ARGS__)
+#endif // DBG
+
+#define Verbose(...) \
+ __DebugMessage(DPFLTR_INFO_LEVEL, __MODULE__ "|" __FUNCTION__ ":",
__VA_ARGS__)
+
+#include "assert.h"
+
+#endif // _DEBUG_H
diff --git a/src/xendisk/driver.c b/src/xendisk/driver.c
new file mode 100644
index 0000000..743fc61
--- /dev/null
+++ b/src/xendisk/driver.c
@@ -0,0 +1,203 @@
+/* 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 <ntddk.h>
+#include "driver.h"
+#include "util.h"
+#include "debug.h"
+#include "assert.h"
+#include <version.h>
+
+extern PULONG InitSafeBootMode;
+
+typedef struct _XENDISK_DRIVER {
+ PDRIVER_OBJECT DriverObject;
+} XENDISK_DRIVER, *PXENDISK_DRIVER;
+
+static XENDISK_DRIVER Driver;
+
+static FORCEINLINE VOID
+__DriverSetDriverObject(
+ IN PDRIVER_OBJECT DriverObject
+ )
+{
+ Driver.DriverObject = DriverObject;
+}
+
+static FORCEINLINE PDRIVER_OBJECT
+__DriverGetDriverObject(
+ VOID
+ )
+{
+ return Driver.DriverObject;
+}
+
+PDRIVER_OBJECT
+DriverGetDriverObject(
+ VOID
+ )
+{
+ return __DriverGetDriverObject();
+}
+
+DRIVER_UNLOAD DriverUnload;
+
+VOID
+DriverUnload(
+ IN PDRIVER_OBJECT DriverObject
+ )
+{
+ ASSERT3P(DriverObject, ==, __DriverGetDriverObject());
+
+ Trace("====>\n");
+
+ __DriverSetDriverObject(NULL);
+
+ ASSERT(IsZeroMemory(&Driver, sizeof (XENDISK_DRIVER)));
+
+ Trace("<====\n");
+}
+
+DRIVER_ADD_DEVICE AddDevice;
+
+NTSTATUS
+#pragma prefast(suppress:28152) // Does not clear DO_DEVICE_INITIALIZING
+AddDevice(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PDEVICE_OBJECT PhysicalDeviceObject
+ )
+{
+ NTSTATUS status;
+
+ ASSERT3P(DriverObject, ==, __DriverGetDriverObject());
+
+ status = FdoCreate(PhysicalDeviceObject);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ return STATUS_SUCCESS;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+DRIVER_DISPATCH Dispatch;
+
+NTSTATUS
+Dispatch(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp
+ )
+{
+ PXENDISK_DX Dx;
+ NTSTATUS status;
+
+ Dx = (PXENDISK_DX)DeviceObject->DeviceExtension;
+ ASSERT3P(Dx->DeviceObject, ==, DeviceObject);
+
+ if (Dx->DevicePnpState == Deleted) {
+ status = STATUS_NO_SUCH_DEVICE;
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ goto done;
+ }
+
+ status = STATUS_NOT_SUPPORTED;
+ switch (Dx->Type) {
+ case PHYSICAL_DEVICE_OBJECT: {
+ PXENDISK_PDO Pdo = Dx->Pdo;
+
+ status = PdoDispatch(Pdo, Irp);
+ break;
+ }
+ case FUNCTION_DEVICE_OBJECT: {
+ PXENDISK_FDO Fdo = Dx->Fdo;
+
+ status = FdoDispatch(Fdo, Irp);
+ break;
+ }
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+done:
+ return status;
+}
+
+DRIVER_INITIALIZE DriverEntry;
+
+NTSTATUS
+DriverEntry(
+ IN PDRIVER_OBJECT DriverObject,
+ IN PUNICODE_STRING RegistryPath
+ )
+{
+ ULONG Index;
+
+ ASSERT3P(__DriverGetDriverObject(), ==, NULL);
+ UNREFERENCED_PARAMETER(RegistryPath);
+
+ ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
+
+ Trace("====>\n");
+
+ __DriverSetDriverObject(DriverObject);
+
+ DriverObject->DriverUnload = DriverUnload;
+
+ if (*InitSafeBootMode > 0)
+ goto done;
+
+ Verbose("XENDISK %d.%d.%d (%d) (%02d.%02d.%04d)\n",
+ MAJOR_VERSION,
+ MINOR_VERSION,
+ MICRO_VERSION,
+ BUILD_NUMBER,
+ DAY,
+ MONTH,
+ YEAR);
+
+ DriverObject->DriverExtension->AddDevice = AddDevice;
+
+ for (Index = 0; Index <= IRP_MJ_MAXIMUM_FUNCTION; Index++) {
+#pragma prefast(suppress:28169) // No __drv_dispatchType annotation
+#pragma prefast(suppress:28168) // No matching __drv_dispatchType annotation
for IRP_MJ_CREATE
+ DriverObject->MajorFunction[Index] = Dispatch;
+ }
+
+done:
+ Trace("<====\n");
+ return STATUS_SUCCESS;
+}
diff --git a/src/xendisk/driver.h b/src/xendisk/driver.h
new file mode 100644
index 0000000..b47e21b
--- /dev/null
+++ b/src/xendisk/driver.h
@@ -0,0 +1,68 @@
+/* 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.
+ */
+
+#ifndef _XENDISK_DRIVER_H
+#define _XENDISK_DRIVER_H
+
+#include "fdo.h"
+#include "pdo.h"
+
+extern PDRIVER_OBJECT
+DriverGetDriverObject(
+ VOID
+ );
+
+#pragma warning(push)
+#pragma warning(disable:4201) // nonstandard extension used : nameless
struct/union
+
+typedef struct _XENDISK_DX {
+ PDEVICE_OBJECT DeviceObject;
+ DEVICE_OBJECT_TYPE Type;
+
+ DEVICE_PNP_STATE DevicePnpState;
+ DEVICE_PNP_STATE PreviousDevicePnpState;
+
+ SYSTEM_POWER_STATE SystemPowerState;
+ DEVICE_POWER_STATE DevicePowerState;
+
+ IO_REMOVE_LOCK RemoveLock;
+
+ LIST_ENTRY ListEntry;
+
+ union {
+ PXENDISK_FDO Fdo;
+ PXENDISK_PDO Pdo;
+ };
+} XENDISK_DX, *PXENDISK_DX;
+
+#pragma warning(pop)
+
+#endif // _XENDISK_DRIVER_H
diff --git a/src/xendisk/fdo.c b/src/xendisk/fdo.c
new file mode 100644
index 0000000..771c82e
--- /dev/null
+++ b/src/xendisk/fdo.c
@@ -0,0 +1,1862 @@
+/* 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.
+ */
+
+#define INITGUID 1
+
+#include <ntddk.h>
+#include <wdmguid.h>
+#include <ntstrsafe.h>
+#include <stdlib.h>
+#include <names.h>
+
+#include "driver.h"
+#include "fdo.h"
+#include "pdo.h"
+#include "thread.h"
+#include "mutex.h"
+#include "debug.h"
+#include "assert.h"
+#include "util.h"
+
+#define FDO_TAG 'ODF'
+
+struct _XENDISK_FDO {
+ PXENDISK_DX Dx;
+ PDEVICE_OBJECT LowerDeviceObject;
+ PDEVICE_OBJECT PhysicalDeviceObject;
+
+ PXENDISK_THREAD SystemPowerThread;
+ PIRP SystemPowerIrp;
+ PXENDISK_THREAD DevicePowerThread;
+ PIRP DevicePowerIrp;
+
+ MUTEX Mutex;
+ ULONG References;
+};
+
+static FORCEINLINE PVOID
+__FdoAllocate(
+ IN ULONG Length
+ )
+{
+ return __AllocateNonPagedPoolWithTag(__FUNCTION__, __LINE__, Length,
FDO_TAG);
+}
+
+static FORCEINLINE VOID
+__FdoFree(
+ IN PVOID Buffer
+ )
+{
+ __FreePoolWithTag(Buffer, FDO_TAG);
+}
+
+static FORCEINLINE VOID
+__FdoSetDevicePnpState(
+ IN PXENDISK_FDO Fdo,
+ IN DEVICE_PNP_STATE State
+ )
+{
+ PXENDISK_DX Dx = Fdo->Dx;
+
+ // We can never transition out of the deleted state
+ ASSERT(Dx->DevicePnpState != Deleted || State == Deleted);
+
+ Dx->PreviousDevicePnpState = Dx->DevicePnpState;
+ Dx->DevicePnpState = State;
+}
+
+static FORCEINLINE VOID
+__FdoRestoreDevicePnpState(
+ IN PXENDISK_FDO Fdo,
+ IN DEVICE_PNP_STATE State
+ )
+{
+ PXENDISK_DX Dx = Fdo->Dx;
+
+ if (Dx->DevicePnpState == State)
+ Dx->DevicePnpState = Dx->PreviousDevicePnpState;
+}
+
+static FORCEINLINE DEVICE_PNP_STATE
+__FdoGetDevicePnpState(
+ IN PXENDISK_FDO Fdo
+ )
+{
+ PXENDISK_DX Dx = Fdo->Dx;
+
+ return Dx->DevicePnpState;
+}
+
+static FORCEINLINE VOID
+__FdoSetDevicePowerState(
+ IN PXENDISK_FDO Fdo,
+ IN DEVICE_POWER_STATE State
+ )
+{
+ PXENDISK_DX Dx = Fdo->Dx;
+
+ Dx->DevicePowerState = State;
+}
+
+static FORCEINLINE DEVICE_POWER_STATE
+__FdoGetDevicePowerState(
+ IN PXENDISK_FDO Fdo
+ )
+{
+ PXENDISK_DX Dx = Fdo->Dx;
+
+ return Dx->DevicePowerState;
+}
+
+static FORCEINLINE VOID
+__FdoSetSystemPowerState(
+ IN PXENDISK_FDO Fdo,
+ IN SYSTEM_POWER_STATE State
+ )
+{
+ PXENDISK_DX Dx = Fdo->Dx;
+
+ Dx->SystemPowerState = State;
+}
+
+static FORCEINLINE SYSTEM_POWER_STATE
+__FdoGetSystemPowerState(
+ IN PXENDISK_FDO Fdo
+ )
+{
+ PXENDISK_DX Dx = Fdo->Dx;
+
+ return Dx->SystemPowerState;
+}
+
+static FORCEINLINE PDEVICE_OBJECT
+__FdoGetPhysicalDeviceObject(
+ IN PXENDISK_FDO Fdo
+ )
+{
+ return Fdo->PhysicalDeviceObject;
+}
+
+VOID
+FdoAddPhysicalDeviceObject(
+ IN PXENDISK_FDO Fdo,
+ IN PDEVICE_OBJECT DeviceObject
+ )
+{
+ PXENDISK_DX Dx;
+
+ Dx = (PXENDISK_DX)DeviceObject->DeviceExtension;
+ ASSERT3U(Dx->Type, ==, PHYSICAL_DEVICE_OBJECT);
+
+ InsertTailList(&Fdo->Dx->ListEntry, &Dx->ListEntry);
+ ASSERT3U(Fdo->References, !=, 0);
+ Fdo->References++;
+}
+
+VOID
+FdoRemovePhysicalDeviceObject(
+ IN PXENDISK_FDO Fdo,
+ IN PDEVICE_OBJECT DeviceObject
+ )
+{
+ PXENDISK_DX Dx;
+
+ Dx = (PXENDISK_DX)DeviceObject->DeviceExtension;
+ ASSERT3U(Dx->Type, ==, PHYSICAL_DEVICE_OBJECT);
+
+ RemoveEntryList(&Dx->ListEntry);
+ ASSERT3U(Fdo->References, !=, 0);
+ --Fdo->References;
+}
+
+static FORCEINLINE VOID
+__FdoAcquireMutex(
+ IN PXENDISK_FDO Fdo
+ )
+{
+ AcquireMutex(&Fdo->Mutex);
+}
+
+VOID
+FdoAcquireMutex(
+ IN PXENDISK_FDO Fdo
+ )
+{
+ __FdoAcquireMutex(Fdo);
+}
+
+static FORCEINLINE VOID
+__FdoReleaseMutex(
+ IN PXENDISK_FDO Fdo
+ )
+{
+ ReleaseMutex(&Fdo->Mutex);
+}
+
+VOID
+FdoReleaseMutex(
+ IN PXENDISK_FDO Fdo
+ )
+{
+ __FdoReleaseMutex(Fdo);
+
+ if (Fdo->References == 0)
+ FdoDestroy(Fdo);
+}
+
+static FORCEINLINE VOID
+__FdoEnumerate(
+ IN PXENDISK_FDO Fdo,
+ IN PDEVICE_RELATIONS Relations
+ )
+{
+ PDEVICE_OBJECT *PhysicalDeviceObject;
+ ULONG Count;
+ PLIST_ENTRY ListEntry;
+ ULONG Index;
+ NTSTATUS status;
+
+ Count = Relations->Count;
+ ASSERT(Count != 0);
+
+ PhysicalDeviceObject = __FdoAllocate(sizeof (PDEVICE_OBJECT) * Count);
+
+ status = STATUS_NO_MEMORY;
+ if (PhysicalDeviceObject == NULL)
+ goto fail1;
+
+ RtlCopyMemory(PhysicalDeviceObject,
+ Relations->Objects,
+ sizeof (PDEVICE_OBJECT) * Count);
+
+ AcquireMutex(&Fdo->Mutex);
+
+ // Remove any PDOs that do not appear in the device list
+ ListEntry = Fdo->Dx->ListEntry.Flink;
+ while (ListEntry != &Fdo->Dx->ListEntry) {
+ PLIST_ENTRY Next = ListEntry->Flink;
+ PXENDISK_DX Dx = CONTAINING_RECORD(ListEntry, XENDISK_DX,
ListEntry);
+ PXENDISK_PDO Pdo = Dx->Pdo;
+ BOOLEAN Missing;
+
+ Missing = TRUE;
+ for (Index = 0; Index < Count; Index++) {
+ if (PdoGetPhysicalDeviceObject(Pdo) ==
PhysicalDeviceObject[Index]) {
+ Missing = FALSE;
+#pragma prefast(suppress:6387) // PhysicalDeviceObject[Index] could be NULL
+ ObDereferenceObject(PhysicalDeviceObject[Index]);
+ PhysicalDeviceObject[Index] = NULL; // avoid duplication
+ break;
+ }
+ }
+
+ if (Missing && !PdoIsMissing(Pdo)) {
+ if (PdoGetDevicePnpState(Pdo) == Present) {
+ PdoSetDevicePnpState(Pdo, Deleted);
+ PdoDestroy(Pdo);
+ } else {
+ PdoSetMissing(Pdo, "device disappeared");
+ }
+ }
+
+ ListEntry = Next;
+ }
+
+ // Walk the list and create PDO filters for any new devices
+ for (Index = 0; Index < Count; Index++) {
+#pragma warning(suppress:6385) // Reading invalid data from
'PhysicalDeviceObject'
+ if (PhysicalDeviceObject[Index] != NULL) {
+ (VOID) PdoCreate(Fdo,
+ PhysicalDeviceObject[Index]);
+ ObDereferenceObject(PhysicalDeviceObject[Index]);
+ }
+ }
+
+ ReleaseMutex(&Fdo->Mutex);
+
+ __FdoFree(PhysicalDeviceObject);
+ return;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__FdoForwardIrpSynchronously(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PKEVENT Event = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+ UNREFERENCED_PARAMETER(Irp);
+
+ KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+static NTSTATUS
+FdoForwardIrpSynchronously(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ KEVENT Event;
+ NTSTATUS status;
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __FdoForwardIrpSynchronously,
+ &Event,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+ if (status == STATUS_PENDING) {
+ (VOID) KeWaitForSingleObject(&Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ status = Irp->IoStatus.Status;
+ } else {
+ ASSERT3U(status, ==, Irp->IoStatus.Status);
+ }
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoStartDevice(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ POWER_STATE PowerState;
+ NTSTATUS status;
+
+ status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ status = FdoForwardIrpSynchronously(Fdo, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ __FdoSetSystemPowerState(Fdo, PowerSystemWorking);
+ __FdoSetDevicePowerState(Fdo, PowerDeviceD0);
+
+ PowerState.DeviceState = PowerDeviceD0;
+ PoSetPowerState(Fdo->Dx->DeviceObject,
+ DevicePowerState,
+ PowerState);
+
+ __FdoSetDevicePnpState(Fdo, Started);
+
+ IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+
+fail2:
+ Error("fail2\n");
+
+ IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__FdoQueryStopDevice(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PXENDISK_FDO Fdo = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ if (Irp->PendingReturned)
+ IoMarkIrpPending(Irp);
+
+ IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+
+ return STATUS_SUCCESS;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoQueryStopDevice(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ __FdoSetDevicePnpState(Fdo, StopPending);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __FdoQueryStopDevice,
+ Fdo,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ return status;
+
+fail1:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__FdoCancelStopDevice(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PXENDISK_FDO Fdo = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ if (Irp->PendingReturned)
+ IoMarkIrpPending(Irp);
+
+ IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+
+ return STATUS_SUCCESS;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoCancelStopDevice(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ __FdoRestoreDevicePnpState(Fdo, StopPending);
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __FdoCancelStopDevice,
+ Fdo,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ return status;
+
+fail1:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__FdoStopDevice(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PXENDISK_FDO Fdo = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ if (Irp->PendingReturned)
+ IoMarkIrpPending(Irp);
+
+ IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+
+ return STATUS_SUCCESS;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoStopDevice(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ POWER_STATE PowerState;
+ NTSTATUS status;
+
+ status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ if (__FdoGetDevicePowerState(Fdo) != PowerDeviceD0)
+ goto done;
+
+ PowerState.DeviceState = PowerDeviceD3;
+ PoSetPowerState(Fdo->Dx->DeviceObject,
+ DevicePowerState,
+ PowerState);
+
+ __FdoSetDevicePowerState(Fdo, PowerDeviceD3);
+ __FdoSetSystemPowerState(Fdo, PowerSystemShutdown);
+
+done:
+ __FdoSetDevicePnpState(Fdo, Stopped);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __FdoStopDevice,
+ Fdo,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ return status;
+
+fail1:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__FdoQueryRemoveDevice(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PXENDISK_FDO Fdo = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ if (Irp->PendingReturned)
+ IoMarkIrpPending(Irp);
+
+ IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+
+ return STATUS_SUCCESS;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoQueryRemoveDevice(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ __FdoSetDevicePnpState(Fdo, RemovePending);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __FdoQueryRemoveDevice,
+ Fdo,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ return status;
+
+fail1:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__FdoCancelRemoveDevice(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PXENDISK_FDO Fdo = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ if (Irp->PendingReturned)
+ IoMarkIrpPending(Irp);
+
+ IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+
+ return STATUS_SUCCESS;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoCancelRemoveDevice(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ __FdoRestoreDevicePnpState(Fdo, RemovePending);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __FdoCancelRemoveDevice,
+ Fdo,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ return status;
+
+fail1:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__FdoSurpriseRemoval(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PXENDISK_FDO Fdo = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ if (Irp->PendingReturned)
+ IoMarkIrpPending(Irp);
+
+ IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+
+ return STATUS_SUCCESS;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoSurpriseRemoval(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ __FdoSetDevicePnpState(Fdo, SurpriseRemovePending);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __FdoSurpriseRemoval,
+ Fdo,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ return status;
+
+fail1:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoRemoveDevice(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ POWER_STATE PowerState;
+ NTSTATUS status;
+
+ status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ if (__FdoGetDevicePowerState(Fdo) != PowerDeviceD0)
+ goto done;
+
+ PowerState.DeviceState = PowerDeviceD3;
+ PoSetPowerState(Fdo->Dx->DeviceObject,
+ DevicePowerState,
+ PowerState);
+
+ __FdoSetDevicePowerState(Fdo, PowerDeviceD3);
+ __FdoSetSystemPowerState(Fdo, PowerSystemShutdown);
+
+done:
+ __FdoSetDevicePnpState(Fdo, Deleted);
+
+ IoReleaseRemoveLockAndWait(&Fdo->Dx->RemoveLock, Irp);
+
+ status = FdoForwardIrpSynchronously(Fdo, Irp);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ AcquireMutex(&Fdo->Mutex);
+ ASSERT3U(Fdo->References, !=, 0);
+ --Fdo->References;
+ ReleaseMutex(&Fdo->Mutex);
+
+ if (Fdo->References == 0)
+ FdoDestroy(Fdo);
+
+ return status;
+
+fail1:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__FdoQueryDeviceRelations(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PKEVENT Event = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+ UNREFERENCED_PARAMETER(Irp);
+
+ KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoQueryDeviceRelations(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ KEVENT Event;
+ PIO_STACK_LOCATION StackLocation;
+ ULONG Size;
+ PDEVICE_RELATIONS Relations;
+ PLIST_ENTRY ListEntry;
+ ULONG Count;
+ NTSTATUS status;
+
+ status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __FdoQueryDeviceRelations,
+ &Event,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+ if (status == STATUS_PENDING) {
+ (VOID) KeWaitForSingleObject(&Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ status = Irp->IoStatus.Status;
+ } else {
+ ASSERT3U(status, ==, Irp->IoStatus.Status);
+ }
+
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ if (StackLocation->Parameters.QueryDeviceRelations.Type != BusRelations)
+ goto done;
+
+ Relations = (PDEVICE_RELATIONS)Irp->IoStatus.Information;
+
+ if (Relations->Count != 0)
+ __FdoEnumerate(Fdo, Relations);
+
+ ExFreePool(Relations);
+
+ AcquireMutex(&Fdo->Mutex);
+
+ Count = 0;
+ for (ListEntry = Fdo->Dx->ListEntry.Flink;
+ ListEntry != &Fdo->Dx->ListEntry;
+ ListEntry = ListEntry->Flink)
+ Count++;
+
+ Size = FIELD_OFFSET(DEVICE_RELATIONS, Objects) + (sizeof (DEVICE_OBJECT) *
__min(Count, 1));
+
+ Relations = ExAllocatePoolWithTag(PagedPool, Size, 'TLIF');
+
+ status = STATUS_NO_MEMORY;
+ if (Relations == NULL)
+ goto fail3;
+
+ RtlZeroMemory(Relations, Size);
+
+ for (ListEntry = Fdo->Dx->ListEntry.Flink;
+ ListEntry != &Fdo->Dx->ListEntry;
+ ListEntry = ListEntry->Flink) {
+ PXENDISK_DX Dx = CONTAINING_RECORD(ListEntry, XENDISK_DX,
ListEntry);
+ PXENDISK_PDO Pdo = Dx->Pdo;
+
+ ASSERT3U(Dx->Type, ==, PHYSICAL_DEVICE_OBJECT);
+
+ if (PdoGetDevicePnpState(Pdo) == Present)
+ PdoSetDevicePnpState(Pdo, Enumerated);
+
+ ObReferenceObject(PdoGetPhysicalDeviceObject(Pdo));
+ Relations->Objects[Relations->Count++] =
PdoGetPhysicalDeviceObject(Pdo);
+ }
+
+ ASSERT3U(Relations->Count, ==, Count);
+
+ Trace("%d PDO(s)\n", Relations->Count);
+
+ ReleaseMutex(&Fdo->Mutex);
+
+ Irp->IoStatus.Information = (ULONG_PTR)Relations;
+ status = STATUS_SUCCESS;
+
+done:
+ IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+
+fail3:
+ ReleaseMutex(&Fdo->Mutex);
+
+fail2:
+ IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+
+fail1:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__FdoDispatchPnp(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PXENDISK_FDO Fdo = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ if (Irp->PendingReturned)
+ IoMarkIrpPending(Irp);
+
+ IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+ return STATUS_SUCCESS;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoDispatchPnp(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ UCHAR MinorFunction;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ MinorFunction = StackLocation->MinorFunction;
+
+ switch (StackLocation->MinorFunction) {
+ case IRP_MN_START_DEVICE:
+ status = FdoStartDevice(Fdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_STOP_DEVICE:
+ status = FdoQueryStopDevice(Fdo, Irp);
+ break;
+
+ case IRP_MN_CANCEL_STOP_DEVICE:
+ status = FdoCancelStopDevice(Fdo, Irp);
+ break;
+
+ case IRP_MN_STOP_DEVICE:
+ status = FdoStopDevice(Fdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_REMOVE_DEVICE:
+ status = FdoQueryRemoveDevice(Fdo, Irp);
+ break;
+
+ case IRP_MN_SURPRISE_REMOVAL:
+ status = FdoSurpriseRemoval(Fdo, Irp);
+ break;
+
+ case IRP_MN_REMOVE_DEVICE:
+ status = FdoRemoveDevice(Fdo, Irp);
+ break;
+
+ case IRP_MN_CANCEL_REMOVE_DEVICE:
+ status = FdoCancelRemoveDevice(Fdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_DEVICE_RELATIONS:
+ status = FdoQueryDeviceRelations(Fdo, Irp);
+ break;
+
+ default:
+ status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __FdoDispatchPnp,
+ Fdo,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+ break;
+ }
+
+ return status;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoSetDevicePowerUp(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ DEVICE_POWER_STATE DeviceState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+
+ ASSERT3U(DeviceState, <, __FdoGetDevicePowerState(Fdo));
+
+ status = FdoForwardIrpSynchronously(Fdo, Irp);
+ if (!NT_SUCCESS(status))
+ goto done;
+
+ Verbose("%p: %s -> %s\n",
+ Fdo->Dx->DeviceObject,
+ PowerDeviceStateName(__FdoGetDevicePowerState(Fdo)),
+ PowerDeviceStateName(DeviceState));
+
+ __FdoSetDevicePowerState(Fdo, DeviceState);
+
+done:
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoSetDevicePowerDown(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ DEVICE_POWER_STATE DeviceState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+
+ ASSERT3U(DeviceState, >, __FdoGetDevicePowerState(Fdo));
+
+ Verbose("%p: %s -> %s\n",
+ Fdo->Dx->DeviceObject,
+ PowerDeviceStateName(__FdoGetDevicePowerState(Fdo)),
+ PowerDeviceStateName(DeviceState));
+
+ __FdoSetDevicePowerState(Fdo, DeviceState);
+
+ status = FdoForwardIrpSynchronously(Fdo, Irp);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoSetDevicePower(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ DEVICE_POWER_STATE DeviceState;
+ POWER_ACTION PowerAction;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+ PowerAction = StackLocation->Parameters.Power.ShutdownType;
+
+ Trace("====> (%s:%s)\n",
+ PowerDeviceStateName(DeviceState),
+ PowerActionName(PowerAction));
+
+ if (DeviceState == __FdoGetDevicePowerState(Fdo)) {
+ status = FdoForwardIrpSynchronously(Fdo, Irp);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ goto done;
+ }
+
+ status = (DeviceState < __FdoGetDevicePowerState(Fdo)) ?
+ __FdoSetDevicePowerUp(Fdo, Irp) :
+ __FdoSetDevicePowerDown(Fdo, Irp);
+
+done:
+ Trace("<==== (%s:%s)(%08x)\n",
+ PowerDeviceStateName(DeviceState),
+ PowerActionName(PowerAction),
+ status);
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoSetSystemPowerUp(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ SYSTEM_POWER_STATE SystemState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ SystemState = StackLocation->Parameters.Power.State.SystemState;
+
+ ASSERT3U(SystemState, <, __FdoGetSystemPowerState(Fdo));
+
+ status = FdoForwardIrpSynchronously(Fdo, Irp);
+ if (!NT_SUCCESS(status))
+ goto done;
+
+ Verbose("%p: %s -> %s\n",
+ Fdo->Dx->DeviceObject,
+ PowerSystemStateName(__FdoGetSystemPowerState(Fdo)),
+ PowerSystemStateName(SystemState));
+
+ __FdoSetSystemPowerState(Fdo, SystemState);
+
+done:
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoSetSystemPowerDown(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ SYSTEM_POWER_STATE SystemState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ SystemState = StackLocation->Parameters.Power.State.SystemState;
+
+ ASSERT3U(SystemState, >, __FdoGetSystemPowerState(Fdo));
+
+ Verbose("%p: %s -> %s\n",
+ Fdo->Dx->DeviceObject,
+ PowerSystemStateName(__FdoGetSystemPowerState(Fdo)),
+ PowerSystemStateName(SystemState));
+
+ __FdoSetSystemPowerState(Fdo, SystemState);
+
+ status = FdoForwardIrpSynchronously(Fdo, Irp);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoSetSystemPower(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ SYSTEM_POWER_STATE SystemState;
+ POWER_ACTION PowerAction;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ SystemState = StackLocation->Parameters.Power.State.SystemState;
+ PowerAction = StackLocation->Parameters.Power.ShutdownType;
+
+ Trace("====> (%s:%s)\n",
+ PowerSystemStateName(SystemState),
+ PowerActionName(PowerAction));
+
+ if (SystemState == __FdoGetSystemPowerState(Fdo)) {
+ status = FdoForwardIrpSynchronously(Fdo, Irp);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ goto done;
+ }
+
+ status = (SystemState < __FdoGetSystemPowerState(Fdo)) ?
+ __FdoSetSystemPowerUp(Fdo, Irp) :
+ __FdoSetSystemPowerDown(Fdo, Irp);
+
+done:
+ Trace("<==== (%s:%s)(%08x)\n",
+ PowerSystemStateName(SystemState),
+ PowerActionName(PowerAction),
+ status);
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoQueryDevicePowerUp(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ DEVICE_POWER_STATE DeviceState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+
+ ASSERT3U(DeviceState, <, __FdoGetDevicePowerState(Fdo));
+
+ status = FdoForwardIrpSynchronously(Fdo, Irp);
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoQueryDevicePowerDown(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ DEVICE_POWER_STATE DeviceState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+
+ ASSERT3U(DeviceState, >, __FdoGetDevicePowerState(Fdo));
+
+ status = FdoForwardIrpSynchronously(Fdo, Irp);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoQueryDevicePower(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ DEVICE_POWER_STATE DeviceState;
+ POWER_ACTION PowerAction;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+ PowerAction = StackLocation->Parameters.Power.ShutdownType;
+
+ Trace("====> (%s:%s)\n",
+ PowerDeviceStateName(DeviceState),
+ PowerActionName(PowerAction));
+
+ if (DeviceState == __FdoGetDevicePowerState(Fdo)) {
+ status = FdoForwardIrpSynchronously(Fdo, Irp);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ goto done;
+ }
+
+ status = (DeviceState < __FdoGetDevicePowerState(Fdo)) ?
+ __FdoQueryDevicePowerUp(Fdo, Irp) :
+ __FdoQueryDevicePowerDown(Fdo, Irp);
+
+done:
+ Trace("<==== (%s:%s)(%08x)\n",
+ PowerDeviceStateName(DeviceState),
+ PowerActionName(PowerAction),
+ status);
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoQuerySystemPowerUp(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ SYSTEM_POWER_STATE SystemState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ SystemState = StackLocation->Parameters.Power.State.SystemState;
+
+ ASSERT3U(SystemState, <, __FdoGetSystemPowerState(Fdo));
+
+ status = FdoForwardIrpSynchronously(Fdo, Irp);
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoQuerySystemPowerDown(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ SYSTEM_POWER_STATE SystemState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ SystemState = StackLocation->Parameters.Power.State.SystemState;
+
+ ASSERT3U(SystemState, >, __FdoGetSystemPowerState(Fdo));
+
+ status = FdoForwardIrpSynchronously(Fdo, Irp);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__FdoQuerySystemPower(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ SYSTEM_POWER_STATE SystemState;
+ POWER_ACTION PowerAction;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ SystemState = StackLocation->Parameters.Power.State.SystemState;
+ PowerAction = StackLocation->Parameters.Power.ShutdownType;
+
+ Trace("====> (%s:%s)\n",
+ PowerSystemStateName(SystemState),
+ PowerActionName(PowerAction));
+
+ if (SystemState == __FdoGetSystemPowerState(Fdo)) {
+ status = FdoForwardIrpSynchronously(Fdo, Irp);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ goto done;
+ }
+
+ status = (SystemState < __FdoGetSystemPowerState(Fdo)) ?
+ __FdoQuerySystemPowerUp(Fdo, Irp) :
+ __FdoQuerySystemPowerDown(Fdo, Irp);
+
+done:
+ Trace("<==== (%s:%s)(%08x)\n",
+ PowerSystemStateName(SystemState),
+ PowerActionName(PowerAction),
+ status);
+
+ return status;
+}
+
+static NTSTATUS
+FdoDevicePower(
+ IN PXENDISK_THREAD Self,
+ IN PVOID Context
+ )
+{
+ PXENDISK_FDO Fdo = Context;
+ PKEVENT Event;
+
+ Event = ThreadGetEvent(Self);
+
+ for (;;) {
+ PIRP Irp;
+ PIO_STACK_LOCATION StackLocation;
+ UCHAR MinorFunction;
+
+ if (Fdo->DevicePowerIrp == NULL) {
+ (VOID) KeWaitForSingleObject(Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ KeClearEvent(Event);
+ }
+
+ if (ThreadIsAlerted(Self))
+ break;
+
+ Irp = Fdo->DevicePowerIrp;
+
+ if (Irp == NULL)
+ continue;
+
+ Fdo->DevicePowerIrp = NULL;
+ KeMemoryBarrier();
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ MinorFunction = StackLocation->MinorFunction;
+
+ switch (StackLocation->MinorFunction) {
+ case IRP_MN_SET_POWER:
+ (VOID) __FdoSetDevicePower(Fdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_POWER:
+ (VOID) __FdoQueryDevicePower(Fdo, Irp);
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+ IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+FdoSystemPower(
+ IN PXENDISK_THREAD Self,
+ IN PVOID Context
+ )
+{
+ PXENDISK_FDO Fdo = Context;
+ PKEVENT Event;
+
+ Event = ThreadGetEvent(Self);
+
+ for (;;) {
+ PIRP Irp;
+ PIO_STACK_LOCATION StackLocation;
+ UCHAR MinorFunction;
+
+ if (Fdo->SystemPowerIrp == NULL) {
+ (VOID) KeWaitForSingleObject(Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ KeClearEvent(Event);
+ }
+
+ if (ThreadIsAlerted(Self))
+ break;
+
+ Irp = Fdo->SystemPowerIrp;
+
+ if (Irp == NULL)
+ continue;
+
+ Fdo->SystemPowerIrp = NULL;
+ KeMemoryBarrier();
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ MinorFunction = StackLocation->MinorFunction;
+
+ switch (StackLocation->MinorFunction) {
+ case IRP_MN_SET_POWER:
+ (VOID) __FdoSetSystemPower(Fdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_POWER:
+ (VOID) __FdoQuerySystemPower(Fdo, Irp);
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+ IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__FdoDispatchPower(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PXENDISK_FDO Fdo = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ if (Irp->PendingReturned)
+ IoMarkIrpPending(Irp);
+
+ IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+ return STATUS_SUCCESS;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoDispatchPower(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ UCHAR MinorFunction;
+ POWER_STATE_TYPE PowerType;
+ NTSTATUS status;
+
+ status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ MinorFunction = StackLocation->MinorFunction;
+
+ if (MinorFunction != IRP_MN_QUERY_POWER &&
+ MinorFunction != IRP_MN_SET_POWER) {
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __FdoDispatchPower,
+ Fdo,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ goto done;
+ }
+
+ PowerType = StackLocation->Parameters.Power.Type;
+
+ Trace("====> (%02x:%s)\n",
+ MinorFunction,
+ PowerMinorFunctionName(MinorFunction));
+
+ switch (PowerType) {
+ case DevicePowerState:
+ IoMarkIrpPending(Irp);
+
+ ASSERT3P(Fdo->DevicePowerIrp, ==, NULL);
+ Fdo->DevicePowerIrp = Irp;
+ KeMemoryBarrier();
+
+ ThreadWake(Fdo->DevicePowerThread);
+
+ status = STATUS_PENDING;
+ break;
+
+ case SystemPowerState:
+ IoMarkIrpPending(Irp);
+
+ ASSERT3P(Fdo->SystemPowerIrp, ==, NULL);
+ Fdo->SystemPowerIrp = Irp;
+ KeMemoryBarrier();
+
+ ThreadWake(Fdo->SystemPowerThread);
+
+ status = STATUS_PENDING;
+ break;
+
+ default:
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __FdoDispatchPower,
+ Fdo,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+ break;
+ }
+
+ Trace("<==== (%02x:%s) (%08x)\n",
+ MinorFunction,
+ PowerMinorFunctionName(MinorFunction),
+ status);
+
+done:
+ return status;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__FdoDispatchDefault(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PXENDISK_FDO Fdo = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ if (Irp->PendingReturned)
+ IoMarkIrpPending(Irp);
+
+ IoReleaseRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+
+ return STATUS_SUCCESS;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoDispatchDefault(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ status = IoAcquireRemoveLock(&Fdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __FdoDispatchDefault,
+ Fdo,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Fdo->LowerDeviceObject, Irp);
+
+ return status;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+NTSTATUS
+FdoDispatch(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+ switch (StackLocation->MajorFunction) {
+ case IRP_MJ_PNP:
+ status = FdoDispatchPnp(Fdo, Irp);
+ break;
+
+ case IRP_MJ_POWER:
+ status = FdoDispatchPower(Fdo, Irp);
+ break;
+
+ default:
+ status = FdoDispatchDefault(Fdo, Irp);
+ break;
+ }
+
+ return status;
+}
+
+NTSTATUS
+FdoCreate(
+ IN PDEVICE_OBJECT PhysicalDeviceObject
+ )
+{
+ PDEVICE_OBJECT LowerDeviceObject;
+ ULONG DeviceType;
+ PDEVICE_OBJECT FilterDeviceObject;
+ PXENDISK_DX Dx;
+ PXENDISK_FDO Fdo;
+ NTSTATUS status;
+
+ LowerDeviceObject = IoGetAttachedDeviceReference(PhysicalDeviceObject);
+ DeviceType = LowerDeviceObject->DeviceType;
+ ObDereferenceObject(LowerDeviceObject);
+
+#pragma prefast(suppress:28197) // Possibly leaking memory 'FilterDeviceObject'
+ status = IoCreateDevice(DriverGetDriverObject(),
+ sizeof (XENDISK_DX),
+ NULL,
+ DeviceType,
+ FILE_DEVICE_SECURE_OPEN,
+ FALSE,
+ &FilterDeviceObject);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ Dx = (PXENDISK_DX)FilterDeviceObject->DeviceExtension;
+ RtlZeroMemory(Dx, sizeof (XENDISK_DX));
+
+ Dx->Type = FUNCTION_DEVICE_OBJECT;
+ Dx->DeviceObject = FilterDeviceObject;
+ Dx->DevicePnpState = Added;
+ Dx->SystemPowerState = PowerSystemShutdown;
+ Dx->DevicePowerState = PowerDeviceD3;
+
+ IoInitializeRemoveLock(&Dx->RemoveLock, FDO_TAG, 0, 0);
+
+ Fdo = __FdoAllocate(sizeof (XENDISK_FDO));
+
+ status = STATUS_NO_MEMORY;
+ if (Fdo == NULL)
+ goto fail2;
+
+ LowerDeviceObject = IoAttachDeviceToDeviceStack(FilterDeviceObject,
+ PhysicalDeviceObject);
+
+ status = STATUS_UNSUCCESSFUL;
+ if (LowerDeviceObject == NULL)
+ goto fail3;
+
+ Fdo->Dx = Dx;
+ Fdo->PhysicalDeviceObject = PhysicalDeviceObject;
+ Fdo->LowerDeviceObject = LowerDeviceObject;
+
+ status = ThreadCreate(FdoSystemPower, Fdo, &Fdo->SystemPowerThread);
+ if (!NT_SUCCESS(status))
+ goto fail4;
+
+ status = ThreadCreate(FdoDevicePower, Fdo, &Fdo->DevicePowerThread);
+ if (!NT_SUCCESS(status))
+ goto fail5;
+
+ InitializeMutex(&Fdo->Mutex);
+ InitializeListHead(&Dx->ListEntry);
+ Fdo->References = 1;
+
+ Verbose("%p\n", FilterDeviceObject);
+
+ Dx->Fdo = Fdo;
+
+#pragma prefast(suppress:28182) // Dereferencing NULL pointer
+ FilterDeviceObject->DeviceType = LowerDeviceObject->DeviceType;
+ FilterDeviceObject->Characteristics = LowerDeviceObject->Characteristics;
+
+ FilterDeviceObject->Flags |= LowerDeviceObject->Flags;
+ FilterDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+
+ return STATUS_SUCCESS;
+
+fail5:
+ Error("fail5\n");
+
+ ThreadAlert(Fdo->SystemPowerThread);
+ ThreadJoin(Fdo->SystemPowerThread);
+ Fdo->SystemPowerThread = NULL;
+
+fail4:
+ Error("fail4\n");
+
+ Fdo->PhysicalDeviceObject = NULL;
+ Fdo->LowerDeviceObject = NULL;
+ Fdo->Dx = NULL;
+
+ IoDetachDevice(LowerDeviceObject);
+
+fail3:
+ Error("fail3\n");
+
+ ASSERT(IsZeroMemory(Fdo, sizeof (XENDISK_FDO)));
+ __FdoFree(Fdo);
+
+fail2:
+ Error("fail2\n");
+
+ IoDeleteDevice(FilterDeviceObject);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+VOID
+FdoDestroy(
+ IN PXENDISK_FDO Fdo
+ )
+{
+ PDEVICE_OBJECT LowerDeviceObject = Fdo->LowerDeviceObject;
+ PXENDISK_DX Dx = Fdo->Dx;
+ PDEVICE_OBJECT FilterDeviceObject = Dx->DeviceObject;
+
+ ASSERT(IsListEmpty(&Dx->ListEntry));
+ ASSERT3U(Fdo->References, ==, 0);
+ ASSERT3U(__FdoGetDevicePnpState(Fdo), ==, Deleted);
+
+ Dx->Fdo = NULL;
+
+ RtlZeroMemory(&Fdo->Mutex, sizeof (MUTEX));
+
+ ThreadAlert(Fdo->DevicePowerThread);
+ ThreadJoin(Fdo->DevicePowerThread);
+ Fdo->DevicePowerThread = NULL;
+
+ ThreadAlert(Fdo->SystemPowerThread);
+ ThreadJoin(Fdo->SystemPowerThread);
+ Fdo->SystemPowerThread = NULL;
+
+ Fdo->LowerDeviceObject = NULL;
+ Fdo->PhysicalDeviceObject = NULL;
+ Fdo->Dx = NULL;
+
+ IoDetachDevice(LowerDeviceObject);
+
+ ASSERT(IsZeroMemory(Fdo, sizeof (XENDISK_FDO)));
+ __FdoFree(Fdo);
+
+ IoDeleteDevice(FilterDeviceObject);
+}
diff --git a/src/xendisk/fdo.h b/src/xendisk/fdo.h
new file mode 100644
index 0000000..8aa0529
--- /dev/null
+++ b/src/xendisk/fdo.h
@@ -0,0 +1,78 @@
+/* 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.
+ */
+
+#ifndef _XENDISK_FDO_H
+#define _XENDISK_FDO_H
+
+#include <ntddk.h>
+#include "types.h"
+
+typedef struct _XENDISK_FDO XENDISK_FDO, *PXENDISK_FDO;
+
+extern VOID
+FdoAddPhysicalDeviceObject(
+ IN PXENDISK_FDO Fdo,
+ IN PDEVICE_OBJECT DeviceObject
+ );
+
+extern VOID
+FdoRemovePhysicalDeviceObject(
+ IN PXENDISK_FDO Fdo,
+ IN PDEVICE_OBJECT DeviceObject
+ );
+
+extern VOID
+FdoAcquireMutex(
+ IN PXENDISK_FDO Fdo
+ );
+
+extern VOID
+FdoReleaseMutex(
+ IN PXENDISK_FDO Fdo
+ );
+
+extern NTSTATUS
+FdoDispatch(
+ IN PXENDISK_FDO Fdo,
+ IN PIRP Irp
+ );
+
+extern NTSTATUS
+FdoCreate(
+ IN PDEVICE_OBJECT PhysicalDeviceObject
+ );
+
+extern VOID
+FdoDestroy(
+ IN PXENDISK_FDO Fdo
+ );
+
+#endif // _XENDISK_FDO_H
diff --git a/src/xendisk/mutex.h b/src/xendisk/mutex.h
new file mode 100644
index 0000000..bcc2414
--- /dev/null
+++ b/src/xendisk/mutex.h
@@ -0,0 +1,113 @@
+/* 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.
+ */
+
+#ifndef _XENDISK_MUTEX_H
+#define _XENDISK_MUTEX_H
+
+#include <ntddk.h>
+
+#include "assert.h"
+
+typedef struct _MUTEX {
+ PKTHREAD Owner;
+ KEVENT Event;
+} MUTEX, *PMUTEX;
+
+static FORCEINLINE VOID
+InitializeMutex(
+ IN PMUTEX Mutex
+ )
+{
+ RtlZeroMemory(Mutex, sizeof (MUTEX));
+
+ KeInitializeEvent(&Mutex->Event, SynchronizationEvent, TRUE);
+}
+
+static FORCEINLINE BOOLEAN
+__drv_maxIRQL(PASSIVE_LEVEL)
+TryAcquireMutex(
+ IN PMUTEX Mutex
+ )
+{
+ LARGE_INTEGER Timeout;
+ NTSTATUS status;
+
+ Timeout.QuadPart = 0;
+
+ status = KeWaitForSingleObject(&Mutex->Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ &Timeout);
+ if (status == STATUS_TIMEOUT)
+ return FALSE;
+
+ ASSERT(NT_SUCCESS(status));
+
+ ASSERT3P(Mutex->Owner, ==, NULL);
+ Mutex->Owner = KeGetCurrentThread();
+
+ return TRUE;
+}
+
+static FORCEINLINE VOID
+__drv_maxIRQL(PASSIVE_LEVEL)
+AcquireMutex(
+ IN PMUTEX Mutex
+ )
+{
+ NTSTATUS status;
+
+ status = KeWaitForSingleObject(&Mutex->Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ ASSERT(NT_SUCCESS(status));
+
+ ASSERT3P(Mutex->Owner, ==, NULL);
+ Mutex->Owner = KeGetCurrentThread();
+}
+
+static FORCEINLINE VOID
+__drv_maxIRQL(PASSIVE_LEVEL)
+ReleaseMutex(
+ IN PMUTEX Mutex
+ )
+{
+ ASSERT3P(Mutex->Owner, ==, KeGetCurrentThread());
+ Mutex->Owner = NULL;
+
+ KeSetEvent(&Mutex->Event, IO_NO_INCREMENT, FALSE);
+}
+
+#endif // _XENDISK_MUTEX_H
diff --git a/src/xendisk/pdo.c b/src/xendisk/pdo.c
new file mode 100644
index 0000000..3de958a
--- /dev/null
+++ b/src/xendisk/pdo.c
@@ -0,0 +1,2079 @@
+/* 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.
+ */
+
+#define INITGUID 1
+
+#include <ntddk.h>
+#include <wdmguid.h>
+#include <ntstrsafe.h>
+#include <stdlib.h>
+#include <storport.h>
+#include <Ntddstor.h>
+#include <Ntddscsi.h>
+#include <names.h>
+
+#include "fdo.h"
+#include "pdo.h"
+#include "driver.h"
+#include "thread.h"
+#include "debug.h"
+#include "assert.h"
+#include "util.h"
+
+#define PDO_TAG 'ODP'
+
+struct _XENDISK_PDO {
+ PXENDISK_DX Dx;
+ PDEVICE_OBJECT LowerDeviceObject;
+ PDEVICE_OBJECT PhysicalDeviceObject;
+
+ PXENDISK_THREAD SystemPowerThread;
+ PIRP SystemPowerIrp;
+ PXENDISK_THREAD DevicePowerThread;
+ PIRP DevicePowerIrp;
+
+ PXENDISK_FDO Fdo;
+ BOOLEAN Missing;
+ const CHAR *Reason;
+
+ ULONG SectorSize;
+};
+
+static FORCEINLINE PVOID
+__PdoAllocate(
+ IN ULONG Length
+ )
+{
+ return __AllocateNonPagedPoolWithTag(__FUNCTION__, __LINE__, Length,
PDO_TAG);
+}
+
+static FORCEINLINE VOID
+__PdoFree(
+ IN PVOID Buffer
+ )
+{
+ __FreePoolWithTag(Buffer, PDO_TAG);
+}
+
+static FORCEINLINE VOID
+__PdoSetDevicePnpState(
+ IN PXENDISK_PDO Pdo,
+ IN DEVICE_PNP_STATE State
+ )
+{
+ PXENDISK_DX Dx = Pdo->Dx;
+
+ // We can never transition out of the deleted state
+ ASSERT(Dx->DevicePnpState != Deleted || State == Deleted);
+
+ Dx->PreviousDevicePnpState = Dx->DevicePnpState;
+ Dx->DevicePnpState = State;
+}
+
+VOID
+PdoSetDevicePnpState(
+ IN PXENDISK_PDO Pdo,
+ IN DEVICE_PNP_STATE State
+ )
+{
+ __PdoSetDevicePnpState(Pdo, State);
+}
+
+static FORCEINLINE VOID
+__PdoRestoreDevicePnpState(
+ IN PXENDISK_PDO Pdo,
+ IN DEVICE_PNP_STATE State
+ )
+{
+ PXENDISK_DX Dx = Pdo->Dx;
+
+ if (Dx->DevicePnpState == State)
+ Dx->DevicePnpState = Dx->PreviousDevicePnpState;
+}
+
+static FORCEINLINE DEVICE_PNP_STATE
+__PdoGetDevicePnpState(
+ IN PXENDISK_PDO Pdo
+ )
+{
+ PXENDISK_DX Dx = Pdo->Dx;
+
+ return Dx->DevicePnpState;
+}
+
+DEVICE_PNP_STATE
+PdoGetDevicePnpState(
+ IN PXENDISK_PDO Pdo
+ )
+{
+ return __PdoGetDevicePnpState(Pdo);
+}
+
+static FORCEINLINE VOID
+__PdoSetDevicePowerState(
+ IN PXENDISK_PDO Pdo,
+ IN DEVICE_POWER_STATE State
+ )
+{
+ PXENDISK_DX Dx = Pdo->Dx;
+
+ Dx->DevicePowerState = State;
+}
+
+static FORCEINLINE DEVICE_POWER_STATE
+__PdoGetDevicePowerState(
+ IN PXENDISK_PDO Pdo
+ )
+{
+ PXENDISK_DX Dx = Pdo->Dx;
+
+ return Dx->DevicePowerState;
+}
+
+static FORCEINLINE VOID
+__PdoSetSystemPowerState(
+ IN PXENDISK_PDO Pdo,
+ IN SYSTEM_POWER_STATE State
+ )
+{
+ PXENDISK_DX Dx = Pdo->Dx;
+
+ Dx->SystemPowerState = State;
+}
+
+static FORCEINLINE SYSTEM_POWER_STATE
+__PdoGetSystemPowerState(
+ IN PXENDISK_PDO Pdo
+ )
+{
+ PXENDISK_DX Dx = Pdo->Dx;
+
+ return Dx->SystemPowerState;
+}
+
+PDEVICE_OBJECT
+PdoGetPhysicalDeviceObject(
+ IN PXENDISK_PDO Pdo
+ )
+{
+ return Pdo->PhysicalDeviceObject;
+}
+
+static FORCEINLINE VOID
+__PdoSetMissing(
+ IN PXENDISK_PDO Pdo,
+ IN const CHAR *Reason
+ )
+{
+ Pdo->Reason = Reason;
+ Pdo->Missing = TRUE;
+}
+
+VOID
+PdoSetMissing(
+ IN PXENDISK_PDO Pdo,
+ IN const CHAR *Reason
+ )
+{
+ __PdoSetMissing(Pdo, Reason);
+}
+
+static FORCEINLINE BOOLEAN
+__PdoIsMissing(
+ IN PXENDISK_PDO Pdo
+ )
+{
+ return Pdo->Missing;
+}
+
+BOOLEAN
+PdoIsMissing(
+ IN PXENDISK_PDO Pdo
+ )
+{
+ return __PdoIsMissing(Pdo);
+}
+
+static FORCEINLINE VOID
+__PdoLink(
+ IN PXENDISK_PDO Pdo,
+ IN PXENDISK_FDO Fdo
+ )
+{
+ Pdo->Fdo = Fdo;
+ FdoAddPhysicalDeviceObject(Fdo, Pdo->Dx->DeviceObject);
+}
+
+static FORCEINLINE VOID
+__PdoUnlink(
+ IN PXENDISK_PDO Pdo
+ )
+{
+ PXENDISK_FDO Fdo = Pdo->Fdo;
+
+ ASSERT(Fdo != NULL);
+
+ FdoRemovePhysicalDeviceObject(Fdo, Pdo->Dx->DeviceObject);
+
+ Pdo->Fdo = NULL;
+}
+
+static FORCEINLINE PXENDISK_FDO
+__PdoGetFdo(
+ IN PXENDISK_PDO Pdo
+ )
+{
+ return Pdo->Fdo;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__PdoForwardIrpSynchronously(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PKEVENT Event = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+ UNREFERENCED_PARAMETER(Irp);
+
+ KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
+
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+static NTSTATUS
+PdoForwardIrpSynchronously(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ KEVENT Event;
+ NTSTATUS status;
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __PdoForwardIrpSynchronously,
+ &Event,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
+ if (status == STATUS_PENDING) {
+ (VOID) KeWaitForSingleObject(&Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ status = Irp->IoStatus.Status;
+ } else {
+ ASSERT3U(status, ==, Irp->IoStatus.Status);
+ }
+
+ return status;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__PdoForwardIrpAndForget(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PXENDISK_PDO Pdo = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ if (Irp->PendingReturned)
+ IoMarkIrpPending(Irp);
+
+ IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+PdoForwardIrpAndForget(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __PdoForwardIrpAndForget,
+ Pdo,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ return IoCallDriver(Pdo->LowerDeviceObject, Irp);
+}
+
+static NTSTATUS
+PdoCompleteIrp(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp,
+ IN NTSTATUS Status
+ )
+{
+ Irp->IoStatus.Status = Status;
+ IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ return Status;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__PdoQueryProperty(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PXENDISK_PDO Pdo = Context;
+ PSTORAGE_ACCESS_ALIGNMENT_DESCRIPTOR Descriptor = Irp->UserBuffer;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ if (Irp->PendingReturned)
+ IoMarkIrpPending(Irp);
+
+ if (!NT_SUCCESS(Irp->IoStatus.Status))
+ goto done;
+
+ Descriptor = Irp->UserBuffer;
+ Pdo->SectorSize = Descriptor->BytesPerLogicalSector;
+ Verbose("%p : %u bytes per sector\n", Pdo->Dx->DeviceObject,
Pdo->SectorSize);
+
+done:
+ IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+
+ return STATUS_SUCCESS;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoQueryProperty(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PSTORAGE_PROPERTY_QUERY Query;
+ PDEVICE_TRIM_DESCRIPTOR Trim;
+ NTSTATUS status;
+
+ Query = Irp->AssociatedIrp.SystemBuffer;
+
+ switch (Query->PropertyId) {
+ case StorageAccessAlignmentProperty:
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __PdoQueryProperty,
+ Pdo,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
+ break;
+
+ case StorageDeviceTrimProperty:
+ Trim = Irp->AssociatedIrp.SystemBuffer;
+
+ Trim->Version = 0;
+ Trim->Size = sizeof(DEVICE_TRIM_DESCRIPTOR);
+ Trim->TrimEnabled = TRUE;
+
+ Irp->IoStatus.Information = (ULONG_PTR)sizeof(DEVICE_TRIM_DESCRIPTOR);
+ status = PdoCompleteIrp(Pdo, Irp, STATUS_SUCCESS);
+ break;
+
+ default:
+ status = PdoForwardIrpAndForget(Pdo, Irp);
+ break;
+ }
+
+ return status;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__PdoSendAwaitSrb(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ UNREFERENCED_PARAMETER(DeviceObject);
+ UNREFERENCED_PARAMETER(Context);
+
+ *(Irp->UserIosb) = Irp->IoStatus;
+
+ if (Irp->MdlAddress) {
+ MmUnlockPages(Irp->MdlAddress);
+ IoFreeMdl(Irp->MdlAddress);
+ }
+
+ KeSetEvent(Irp->UserEvent, IO_NO_INCREMENT, FALSE);
+
+ IoFreeIrp(Irp);
+ return STATUS_MORE_PROCESSING_REQUIRED;
+}
+
+static NTSTATUS
+PdoSendAwaitSrb(
+ IN PXENDISK_PDO Pdo,
+ IN PSCSI_REQUEST_BLOCK Srb
+ )
+{
+ PIRP Irp;
+ IO_STATUS_BLOCK IoStatus;
+ KEVENT Event;
+ PIO_STACK_LOCATION Stack;
+ NTSTATUS status;
+
+ KeInitializeEvent(&Event, NotificationEvent, FALSE);
+
+ status = STATUS_NO_MEMORY;
+ Irp = IoAllocateIrp((CCHAR)(Pdo->LowerDeviceObject->StackSize + 1), FALSE);
+ if (Irp == NULL)
+ goto fail1;
+
+ Stack = IoGetNextIrpStackLocation(Irp);
+ Stack->MajorFunction = IRP_MJ_SCSI;
+ Stack->Parameters.Scsi.Srb = Srb;
+
+ IoSetCompletionRoutine(Irp,
+ __PdoSendAwaitSrb,
+ Srb,
+ TRUE,
+ TRUE,
+ TRUE);
+ Irp->UserIosb = &IoStatus;
+ Irp->UserEvent = &Event;
+
+ Irp->MdlAddress = IoAllocateMdl(Srb->DataBuffer,
+ Srb->DataTransferLength,
+ FALSE,
+ FALSE,
+ Irp);
+ if (Irp->MdlAddress == NULL)
+ goto fail2;
+
+#pragma warning(disable:6320)
+ try {
+ MmProbeAndLockPages(Irp->MdlAddress, KernelMode, IoReadAccess);
+ } except (EXCEPTION_EXECUTE_HANDLER) {
+ status = GetExceptionCode();
+
+ goto fail3;
+ }
+#pragma warning(default:6320)
+
+ Srb->OriginalRequest = Irp;
+
+ status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
+ if (status == STATUS_PENDING) {
+ (VOID) KeWaitForSingleObject(&Event, Executive, KernelMode, FALSE,
NULL);
+ status = IoStatus.Status;
+ }
+
+ return status;
+
+fail3:
+ Error("fail3\n");
+
+ IoFreeMdl(Irp->MdlAddress);
+
+fail2:
+ Error("fail2\n");
+
+ IoFreeIrp(Irp);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+static NTSTATUS
+PdoSendTrimSynchronous(
+ IN PXENDISK_PDO Pdo,
+ IN PDEVICE_DATA_SET_RANGE Ranges,
+ IN ULONG Count
+ )
+{
+ SCSI_REQUEST_BLOCK Srb;
+ PCDB Cdb;
+ PUNMAP_LIST_HEADER Unmap;
+ ULONG Length;
+ ULONG Index;
+ NTSTATUS status;
+
+ Length = sizeof(UNMAP_LIST_HEADER) +
+ (Count * sizeof(UNMAP_BLOCK_DESCRIPTOR));
+
+ status = STATUS_NO_MEMORY;
+ Unmap = __PdoAllocate(Length);
+ if (Unmap == NULL)
+ goto fail1;
+
+ RtlZeroMemory(&Srb, sizeof(SCSI_REQUEST_BLOCK));
+ Srb.Length = sizeof(SCSI_REQUEST_BLOCK);
+ Srb.SrbFlags = 0;
+ Srb.Function = SRB_FUNCTION_EXECUTE_SCSI;
+ Srb.DataBuffer = Unmap;
+ Srb.DataTransferLength = Length;
+ Srb.TimeOutValue = (ULONG)-1;
+ Srb.CdbLength = 10;
+
+ Cdb = (PCDB)&Srb.Cdb[0];
+ Cdb->UNMAP.OperationCode = SCSIOP_UNMAP;
+ *(PUSHORT)Cdb->UNMAP.AllocationLength = _byteswap_ushort((USHORT)Length);
+
+ *(PUSHORT)Unmap->DataLength = _byteswap_ushort((USHORT)Length);
+ *(PUSHORT)Unmap->BlockDescrDataLength =
_byteswap_ushort((USHORT)sizeof(UNMAP_BLOCK_DESCRIPTOR));
+
+ for (Index = 0; Index < Count; ++Index) {
+ PUNMAP_BLOCK_DESCRIPTOR Block = &Unmap->Descriptors[Index];
+ PDEVICE_DATA_SET_RANGE Range = &Ranges[Index];
+
+ ULONG LengthInSectors = (ULONG)(Range->LengthInBytes /
Pdo->SectorSize);
+ ULONG64 OffsetInSectors = (ULONG64)(Range->StartingOffset /
Pdo->SectorSize);
+
+ Trace("TRIM[%x] %x @ %llx\n",
+ Index,
+ LengthInSectors,
+ OffsetInSectors);
+
+ *(PULONG64)Block->StartingLba = _byteswap_uint64(OffsetInSectors);
+ *(PULONG)Block->LbaCount = _byteswap_ulong(LengthInSectors);
+ }
+
+ status = PdoSendAwaitSrb(Pdo, &Srb);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ __PdoFree(Unmap);
+ return status;
+
+fail2:
+ Error("fail2\n");
+
+ __PdoFree(Unmap);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoManageDataSetAttributes(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PDEVICE_MANAGE_DATA_SET_ATTRIBUTES Attributes;
+ PDEVICE_DATA_SET_RANGE Ranges;
+ ULONG NumRanges;
+ NTSTATUS status;
+
+ Attributes = Irp->AssociatedIrp.SystemBuffer;
+
+ switch (Attributes->Action) {
+ case DeviceDsmAction_Trim:
+ Ranges = (PDEVICE_DATA_SET_RANGE)((PUCHAR)Attributes +
Attributes->DataSetRangesOffset);
+ NumRanges = Attributes->DataSetRangesLength /
sizeof(DEVICE_DATA_SET_RANGE);
+
+ status = PdoSendTrimSynchronous(Pdo, Ranges, NumRanges);
+
+ status = PdoCompleteIrp(Pdo, Irp, status);
+ break;
+
+ default:
+ status = PdoForwardIrpAndForget(Pdo, Irp);
+ break;
+ }
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoDispatchControl(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ ULONG ControlCode;
+ NTSTATUS status;
+
+ status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ ControlCode = StackLocation->Parameters.DeviceIoControl.IoControlCode;
+
+ switch (ControlCode) {
+ case IOCTL_STORAGE_QUERY_PROPERTY:
+ status = PdoQueryProperty(Pdo, Irp);
+ break;
+
+ case IOCTL_STORAGE_MANAGE_DATA_SET_ATTRIBUTES:
+ status = PdoManageDataSetAttributes(Pdo, Irp);
+ break;
+
+ default:
+ status = PdoForwardIrpAndForget(Pdo, Irp);
+ break;
+ }
+
+ return status;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoStartDevice(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ POWER_STATE PowerState;
+ NTSTATUS status;
+
+ status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ status = PdoForwardIrpSynchronously(Pdo, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ __PdoSetSystemPowerState(Pdo, PowerSystemWorking);
+ __PdoSetDevicePowerState(Pdo, PowerDeviceD0);
+
+ PowerState.DeviceState = PowerDeviceD0;
+ PoSetPowerState(Pdo->Dx->DeviceObject,
+ DevicePowerState,
+ PowerState);
+
+ __PdoSetDevicePnpState(Pdo, Started);
+
+ IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return STATUS_SUCCESS;
+
+fail2:
+ IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+
+fail1:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__PdoQueryStopDevice(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PXENDISK_PDO Pdo = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ if (Irp->PendingReturned)
+ IoMarkIrpPending(Irp);
+
+ IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+
+ return STATUS_SUCCESS;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoQueryStopDevice(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ __PdoSetDevicePnpState(Pdo, StopPending);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __PdoQueryStopDevice,
+ Pdo,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
+
+ return status;
+
+fail1:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__PdoCancelStopDevice(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PXENDISK_PDO Pdo = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ if (Irp->PendingReturned)
+ IoMarkIrpPending(Irp);
+
+ IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+
+ return STATUS_SUCCESS;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoCancelStopDevice(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ __PdoRestoreDevicePnpState(Pdo, StopPending);
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __PdoCancelStopDevice,
+ Pdo,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
+
+ return status;
+
+fail1:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__PdoStopDevice(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PXENDISK_PDO Pdo = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ if (Irp->PendingReturned)
+ IoMarkIrpPending(Irp);
+
+ IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+
+ return STATUS_SUCCESS;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoStopDevice(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ POWER_STATE PowerState;
+ NTSTATUS status;
+
+ status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ if (__PdoGetDevicePowerState(Pdo) != PowerDeviceD0)
+ goto done;
+
+ __PdoSetDevicePowerState(Pdo, PowerDeviceD3);
+ __PdoSetSystemPowerState(Pdo, PowerSystemShutdown);
+
+ PowerState.DeviceState = PowerDeviceD3;
+ PoSetPowerState(Pdo->Dx->DeviceObject,
+ DevicePowerState,
+ PowerState);
+
+done:
+ __PdoSetDevicePnpState(Pdo, Stopped);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __PdoStopDevice,
+ Pdo,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
+
+ return status;
+
+fail1:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__PdoQueryRemoveDevice(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PXENDISK_PDO Pdo = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ if (Irp->PendingReturned)
+ IoMarkIrpPending(Irp);
+
+ IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+
+ return STATUS_SUCCESS;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoQueryRemoveDevice(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ __PdoSetDevicePnpState(Pdo, RemovePending);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __PdoQueryRemoveDevice,
+ Pdo,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
+
+ return status;
+
+fail1:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__PdoCancelRemoveDevice(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PXENDISK_PDO Pdo = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ if (Irp->PendingReturned)
+ IoMarkIrpPending(Irp);
+
+ IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+
+ return STATUS_SUCCESS;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoCancelRemoveDevice(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ __PdoRestoreDevicePnpState(Pdo, RemovePending);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __PdoCancelRemoveDevice,
+ Pdo,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
+
+ return status;
+
+fail1:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__PdoSurpriseRemoval(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PXENDISK_PDO Pdo = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ if (Irp->PendingReturned)
+ IoMarkIrpPending(Irp);
+
+ IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+
+ return STATUS_SUCCESS;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoSurpriseRemoval(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ __PdoSetDevicePnpState(Pdo, SurpriseRemovePending);
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __PdoSurpriseRemoval,
+ Pdo,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
+
+ return status;
+
+fail1:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoRemoveDevice(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PXENDISK_FDO Fdo = __PdoGetFdo(Pdo);
+ POWER_STATE PowerState;
+ NTSTATUS status;
+
+ status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ if (__PdoGetDevicePowerState(Pdo) != PowerDeviceD0)
+ goto done;
+
+ __PdoSetDevicePowerState(Pdo, PowerDeviceD3);
+ __PdoSetSystemPowerState(Pdo, PowerSystemShutdown);
+
+ PowerState.DeviceState = PowerDeviceD3;
+ PoSetPowerState(Pdo->Dx->DeviceObject,
+ DevicePowerState,
+ PowerState);
+
+done:
+ if (__PdoIsMissing(Pdo)) {
+ __PdoSetDevicePnpState(Pdo, Deleted);
+ IoReleaseRemoveLockAndWait(&Pdo->Dx->RemoveLock, Irp);
+ } else {
+ __PdoSetDevicePnpState(Pdo, Enumerated);
+ IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+ }
+
+ status = PdoForwardIrpSynchronously(Pdo, Irp);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ if (__PdoIsMissing(Pdo)) {
+ FdoAcquireMutex(Fdo);
+ PdoDestroy(Pdo);
+ FdoReleaseMutex(Fdo);
+ }
+
+ return status;
+
+fail1:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoEject(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PXENDISK_FDO Fdo = __PdoGetFdo(Pdo);
+ NTSTATUS status;
+
+ __PdoSetMissing(Pdo, "Ejected");
+ __PdoSetDevicePnpState(Pdo, Deleted);
+
+ status = PdoForwardIrpSynchronously(Pdo, Irp);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ FdoAcquireMutex(Fdo);
+ PdoDestroy(Pdo);
+ FdoReleaseMutex(Fdo);
+
+ return status;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__PdoDispatchPnp(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PXENDISK_PDO Pdo = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ if (Irp->PendingReturned)
+ IoMarkIrpPending(Irp);
+
+ IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+ return STATUS_SUCCESS;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoDispatchPnp(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ UCHAR MinorFunction;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ MinorFunction = StackLocation->MinorFunction;
+
+ switch (StackLocation->MinorFunction) {
+ case IRP_MN_START_DEVICE:
+ status = PdoStartDevice(Pdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_STOP_DEVICE:
+ status = PdoQueryStopDevice(Pdo, Irp);
+ break;
+
+ case IRP_MN_CANCEL_STOP_DEVICE:
+ status = PdoCancelStopDevice(Pdo, Irp);
+ break;
+
+ case IRP_MN_STOP_DEVICE:
+ status = PdoStopDevice(Pdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_REMOVE_DEVICE:
+ status = PdoQueryRemoveDevice(Pdo, Irp);
+ break;
+
+ case IRP_MN_SURPRISE_REMOVAL:
+ status = PdoSurpriseRemoval(Pdo, Irp);
+ break;
+
+ case IRP_MN_REMOVE_DEVICE:
+ status = PdoRemoveDevice(Pdo, Irp);
+ break;
+
+ case IRP_MN_CANCEL_REMOVE_DEVICE:
+ status = PdoCancelRemoveDevice(Pdo, Irp);
+ break;
+
+ case IRP_MN_EJECT:
+ status = PdoEject(Pdo, Irp);
+ break;
+
+ default:
+ status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __PdoDispatchPnp,
+ Pdo,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
+ break;
+ }
+
+ return status;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__PdoSetDevicePowerUp(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ DEVICE_POWER_STATE DeviceState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+
+ ASSERT3U(DeviceState, <, __PdoGetDevicePowerState(Pdo));
+
+ status = PdoForwardIrpSynchronously(Pdo, Irp);
+ if (!NT_SUCCESS(status))
+ goto done;
+
+ Verbose("%p: %s -> %s\n",
+ Pdo->Dx->DeviceObject,
+ PowerDeviceStateName(__PdoGetDevicePowerState(Pdo)),
+ PowerDeviceStateName(DeviceState));
+
+ __PdoSetDevicePowerState(Pdo, DeviceState);
+
+done:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__PdoSetDevicePowerDown(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ DEVICE_POWER_STATE DeviceState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+
+ ASSERT3U(DeviceState, >, __PdoGetDevicePowerState(Pdo));
+
+ Verbose("%p: %s -> %s\n",
+ Pdo->Dx->DeviceObject,
+ PowerDeviceStateName(__PdoGetDevicePowerState(Pdo)),
+ PowerDeviceStateName(DeviceState));
+
+ __PdoSetDevicePowerState(Pdo, DeviceState);
+
+ status = PdoForwardIrpSynchronously(Pdo, Irp);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__PdoSetDevicePower(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ DEVICE_POWER_STATE DeviceState;
+ POWER_ACTION PowerAction;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+ PowerAction = StackLocation->Parameters.Power.ShutdownType;
+
+ Trace("====> (%s:%s)\n",
+ PowerDeviceStateName(DeviceState),
+ PowerActionName(PowerAction));
+
+ if (DeviceState == __PdoGetDevicePowerState(Pdo)) {
+ status = PdoForwardIrpSynchronously(Pdo, Irp);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ goto done;
+ }
+
+ status = (DeviceState < __PdoGetDevicePowerState(Pdo)) ?
+ __PdoSetDevicePowerUp(Pdo, Irp) :
+ __PdoSetDevicePowerDown(Pdo, Irp);
+
+done:
+ Trace("<==== (%s:%s)(%08x)\n",
+ PowerDeviceStateName(DeviceState),
+ PowerActionName(PowerAction),
+ status);
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__PdoSetSystemPowerUp(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ SYSTEM_POWER_STATE SystemState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ SystemState = StackLocation->Parameters.Power.State.SystemState;
+
+ ASSERT3U(SystemState, <, __PdoGetSystemPowerState(Pdo));
+
+ status = PdoForwardIrpSynchronously(Pdo, Irp);
+ if (!NT_SUCCESS(status))
+ goto done;
+
+ Verbose("%p: %s -> %s\n",
+ Pdo->Dx->DeviceObject,
+ PowerSystemStateName(__PdoGetSystemPowerState(Pdo)),
+ PowerSystemStateName(SystemState));
+
+ __PdoSetSystemPowerState(Pdo, SystemState);
+
+done:
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__PdoSetSystemPowerDown(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ SYSTEM_POWER_STATE SystemState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ SystemState = StackLocation->Parameters.Power.State.SystemState;
+
+ ASSERT3U(SystemState, >, __PdoGetSystemPowerState(Pdo));
+
+ Verbose("%p: %s -> %s\n",
+ Pdo->Dx->DeviceObject,
+ PowerSystemStateName(__PdoGetSystemPowerState(Pdo)),
+ PowerSystemStateName(SystemState));
+
+ __PdoSetSystemPowerState(Pdo, SystemState);
+
+ status = PdoForwardIrpSynchronously(Pdo, Irp);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__PdoSetSystemPower(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ SYSTEM_POWER_STATE SystemState;
+ POWER_ACTION PowerAction;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ SystemState = StackLocation->Parameters.Power.State.SystemState;
+ PowerAction = StackLocation->Parameters.Power.ShutdownType;
+
+ Trace("====> (%s:%s)\n",
+ PowerSystemStateName(SystemState),
+ PowerActionName(PowerAction));
+
+ if (SystemState == __PdoGetSystemPowerState(Pdo)) {
+ status = PdoForwardIrpSynchronously(Pdo, Irp);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ goto done;
+ }
+
+ status = (SystemState < __PdoGetSystemPowerState(Pdo)) ?
+ __PdoSetSystemPowerUp(Pdo, Irp) :
+ __PdoSetSystemPowerDown(Pdo, Irp);
+
+done:
+ Trace("<==== (%s:%s)(%08x)\n",
+ PowerSystemStateName(SystemState),
+ PowerActionName(PowerAction),
+ status);
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__PdoQueryDevicePowerUp(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ DEVICE_POWER_STATE DeviceState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+
+ ASSERT3U(DeviceState, <, __PdoGetDevicePowerState(Pdo));
+
+ status = PdoForwardIrpSynchronously(Pdo, Irp);
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__PdoQueryDevicePowerDown(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ DEVICE_POWER_STATE DeviceState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+
+ ASSERT3U(DeviceState, >, __PdoGetDevicePowerState(Pdo));
+
+ status = PdoForwardIrpSynchronously(Pdo, Irp);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__PdoQueryDevicePower(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ DEVICE_POWER_STATE DeviceState;
+ POWER_ACTION PowerAction;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ DeviceState = StackLocation->Parameters.Power.State.DeviceState;
+ PowerAction = StackLocation->Parameters.Power.ShutdownType;
+
+ Trace("====> (%s:%s)\n",
+ PowerDeviceStateName(DeviceState),
+ PowerActionName(PowerAction));
+
+ if (DeviceState == __PdoGetDevicePowerState(Pdo)) {
+ status = PdoForwardIrpSynchronously(Pdo, Irp);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ goto done;
+ }
+
+ status = (DeviceState < __PdoGetDevicePowerState(Pdo)) ?
+ __PdoQueryDevicePowerUp(Pdo, Irp) :
+ __PdoQueryDevicePowerDown(Pdo, Irp);
+
+done:
+ Trace("<==== (%s:%s)(%08x)\n",
+ PowerDeviceStateName(DeviceState),
+ PowerActionName(PowerAction),
+ status);
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__PdoQuerySystemPowerUp(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ SYSTEM_POWER_STATE SystemState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ SystemState = StackLocation->Parameters.Power.State.SystemState;
+
+ ASSERT3U(SystemState, <, __PdoGetSystemPowerState(Pdo));
+
+ status = PdoForwardIrpSynchronously(Pdo, Irp);
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__PdoQuerySystemPowerDown(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ SYSTEM_POWER_STATE SystemState;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ SystemState = StackLocation->Parameters.Power.State.SystemState;
+
+ ASSERT3U(SystemState, >, __PdoGetSystemPowerState(Pdo));
+
+ status = PdoForwardIrpSynchronously(Pdo, Irp);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static FORCEINLINE NTSTATUS
+__PdoQuerySystemPower(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ SYSTEM_POWER_STATE SystemState;
+ POWER_ACTION PowerAction;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ SystemState = StackLocation->Parameters.Power.State.SystemState;
+ PowerAction = StackLocation->Parameters.Power.ShutdownType;
+
+ Trace("====> (%s:%s)\n",
+ PowerSystemStateName(SystemState),
+ PowerActionName(PowerAction));
+
+ if (SystemState == __PdoGetSystemPowerState(Pdo)) {
+ status = PdoForwardIrpSynchronously(Pdo, Irp);
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ goto done;
+ }
+
+ status = (SystemState < __PdoGetSystemPowerState(Pdo)) ?
+ __PdoQuerySystemPowerUp(Pdo, Irp) :
+ __PdoQuerySystemPowerDown(Pdo, Irp);
+
+done:
+ Trace("<==== (%s:%s)(%08x)\n",
+ PowerSystemStateName(SystemState),
+ PowerActionName(PowerAction),
+ status);
+
+ return status;
+}
+
+static NTSTATUS
+PdoDevicePower(
+ IN PXENDISK_THREAD Self,
+ IN PVOID Context
+ )
+{
+ PXENDISK_PDO Pdo = Context;
+ PKEVENT Event;
+
+ Event = ThreadGetEvent(Self);
+
+ for (;;) {
+ PIRP Irp;
+ PIO_STACK_LOCATION StackLocation;
+ UCHAR MinorFunction;
+
+ if (Pdo->DevicePowerIrp == NULL) {
+ (VOID) KeWaitForSingleObject(Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ KeClearEvent(Event);
+ }
+
+ if (ThreadIsAlerted(Self))
+ break;
+
+ Irp = Pdo->DevicePowerIrp;
+
+ if (Irp == NULL)
+ continue;
+
+ Pdo->DevicePowerIrp = NULL;
+ KeMemoryBarrier();
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ MinorFunction = StackLocation->MinorFunction;
+
+ switch (StackLocation->MinorFunction) {
+ case IRP_MN_SET_POWER:
+ (VOID) __PdoSetDevicePower(Pdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_POWER:
+ (VOID) __PdoQueryDevicePower(Pdo, Irp);
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+ IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+PdoSystemPower(
+ IN PXENDISK_THREAD Self,
+ IN PVOID Context
+ )
+{
+ PXENDISK_PDO Pdo = Context;
+ PKEVENT Event;
+
+ Event = ThreadGetEvent(Self);
+
+ for (;;) {
+ PIRP Irp;
+ PIO_STACK_LOCATION StackLocation;
+ UCHAR MinorFunction;
+
+ if (Pdo->SystemPowerIrp == NULL) {
+ (VOID) KeWaitForSingleObject(Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ KeClearEvent(Event);
+ }
+
+ if (ThreadIsAlerted(Self))
+ break;
+
+ Irp = Pdo->SystemPowerIrp;
+
+ if (Irp == NULL)
+ continue;
+
+ Pdo->SystemPowerIrp = NULL;
+ KeMemoryBarrier();
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ MinorFunction = StackLocation->MinorFunction;
+
+ switch (StackLocation->MinorFunction) {
+ case IRP_MN_SET_POWER:
+ (VOID) __PdoSetSystemPower(Pdo, Irp);
+ break;
+
+ case IRP_MN_QUERY_POWER:
+ (VOID) __PdoQuerySystemPower(Pdo, Irp);
+ break;
+
+ default:
+ ASSERT(FALSE);
+ break;
+ }
+
+ IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__PdoDispatchPower(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PXENDISK_PDO Pdo = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ if (Irp->PendingReturned)
+ IoMarkIrpPending(Irp);
+
+ IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+ return STATUS_SUCCESS;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoDispatchPower(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ UCHAR MinorFunction;
+ POWER_STATE_TYPE PowerType;
+ NTSTATUS status;
+
+ status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ MinorFunction = StackLocation->MinorFunction;
+
+ if (MinorFunction != IRP_MN_QUERY_POWER &&
+ MinorFunction != IRP_MN_SET_POWER) {
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __PdoDispatchPower,
+ Pdo,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
+
+ goto done;
+ }
+
+ PowerType = StackLocation->Parameters.Power.Type;
+
+ Trace("====> (%02x:%s)\n",
+ MinorFunction,
+ PowerMinorFunctionName(MinorFunction));
+
+ switch (PowerType) {
+ case DevicePowerState:
+ IoMarkIrpPending(Irp);
+
+ ASSERT3P(Pdo->DevicePowerIrp, ==, NULL);
+ Pdo->DevicePowerIrp = Irp;
+ KeMemoryBarrier();
+
+ ThreadWake(Pdo->DevicePowerThread);
+
+ status = STATUS_PENDING;
+ break;
+
+ case SystemPowerState:
+ IoMarkIrpPending(Irp);
+
+ ASSERT3P(Pdo->SystemPowerIrp, ==, NULL);
+ Pdo->SystemPowerIrp = Irp;
+ KeMemoryBarrier();
+
+ ThreadWake(Pdo->SystemPowerThread);
+
+ status = STATUS_PENDING;
+ break;
+
+ default:
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __PdoDispatchPower,
+ Pdo,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
+ break;
+ }
+
+ Trace("<==== (%02x:%s) (%08x)\n",
+ MinorFunction,
+ PowerMinorFunctionName(MinorFunction),
+ status);
+
+done:
+ return status;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+__drv_functionClass(IO_COMPLETION_ROUTINE)
+__drv_sameIRQL
+static NTSTATUS
+__PdoDispatchDefault(
+ IN PDEVICE_OBJECT DeviceObject,
+ IN PIRP Irp,
+ IN PVOID Context
+ )
+{
+ PXENDISK_PDO Pdo = Context;
+
+ UNREFERENCED_PARAMETER(DeviceObject);
+
+ if (Irp->PendingReturned)
+ IoMarkIrpPending(Irp);
+
+ IoReleaseRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+
+ return STATUS_SUCCESS;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+PdoDispatchDefault(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ status = IoAcquireRemoveLock(&Pdo->Dx->RemoveLock, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ IoCopyCurrentIrpStackLocationToNext(Irp);
+ IoSetCompletionRoutine(Irp,
+ __PdoDispatchDefault,
+ Pdo,
+ TRUE,
+ TRUE,
+ TRUE);
+
+ status = IoCallDriver(Pdo->LowerDeviceObject, Irp);
+
+ return status;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+NTSTATUS
+PdoDispatch(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+ switch (StackLocation->MajorFunction) {
+ case IRP_MJ_DEVICE_CONTROL:
+ status = PdoDispatchControl(Pdo, Irp);
+ break;
+
+ case IRP_MJ_PNP:
+ status = PdoDispatchPnp(Pdo, Irp);
+ break;
+
+ case IRP_MJ_POWER:
+ status = PdoDispatchPower(Pdo, Irp);
+ break;
+
+ default:
+ status = PdoDispatchDefault(Pdo, Irp);
+ break;
+ }
+
+ return status;
+}
+
+NTSTATUS
+PdoCreate(
+ PXENDISK_FDO Fdo,
+ PDEVICE_OBJECT PhysicalDeviceObject
+ )
+{
+ PDEVICE_OBJECT LowerDeviceObject;
+ ULONG DeviceType;
+ PDEVICE_OBJECT FilterDeviceObject;
+ PXENDISK_DX Dx;
+ PXENDISK_PDO Pdo;
+ NTSTATUS status;
+
+ LowerDeviceObject = IoGetAttachedDeviceReference(PhysicalDeviceObject);
+ DeviceType = LowerDeviceObject->DeviceType;
+ ObDereferenceObject(LowerDeviceObject);
+
+#pragma prefast(suppress:28197) // Possibly leaking memory
'PhysicalDeviceObject'
+ status = IoCreateDevice(DriverGetDriverObject(),
+ sizeof(XENDISK_DX),
+ NULL,
+ DeviceType,
+ FILE_DEVICE_SECURE_OPEN,
+ FALSE,
+ &FilterDeviceObject);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ Dx = (PXENDISK_DX)FilterDeviceObject->DeviceExtension;
+ RtlZeroMemory(Dx, sizeof (XENDISK_DX));
+
+ Dx->Type = PHYSICAL_DEVICE_OBJECT;
+ Dx->DeviceObject = FilterDeviceObject;
+ Dx->DevicePnpState = Present;
+ Dx->SystemPowerState = PowerSystemShutdown;
+ Dx->DevicePowerState = PowerDeviceD3;
+
+ IoInitializeRemoveLock(&Dx->RemoveLock, PDO_TAG, 0, 0);
+
+ Pdo = __PdoAllocate(sizeof (XENDISK_PDO));
+
+ status = STATUS_NO_MEMORY;
+ if (Pdo == NULL)
+ goto fail2;
+
+ LowerDeviceObject = IoAttachDeviceToDeviceStack(FilterDeviceObject,
+ PhysicalDeviceObject);
+
+ status = STATUS_UNSUCCESSFUL;
+ if (LowerDeviceObject == NULL)
+ goto fail3;
+
+ Pdo->Dx = Dx;
+ Pdo->PhysicalDeviceObject = PhysicalDeviceObject;
+ Pdo->LowerDeviceObject = LowerDeviceObject;
+ Pdo->SectorSize = 512;
+
+ status = ThreadCreate(PdoSystemPower, Pdo, &Pdo->SystemPowerThread);
+ if (!NT_SUCCESS(status))
+ goto fail4;
+
+ status = ThreadCreate(PdoDevicePower, Pdo, &Pdo->DevicePowerThread);
+ if (!NT_SUCCESS(status))
+ goto fail5;
+
+ Verbose("%p\n", FilterDeviceObject);
+
+ Dx->Pdo = Pdo;
+
+#pragma prefast(suppress:28182) // Dereferencing NULL pointer
+ FilterDeviceObject->DeviceType = LowerDeviceObject->DeviceType;
+ FilterDeviceObject->Characteristics = LowerDeviceObject->Characteristics;
+
+ FilterDeviceObject->Flags |= LowerDeviceObject->Flags;
+ FilterDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
+
+ __PdoLink(Pdo, Fdo);
+
+ return STATUS_SUCCESS;
+
+fail5:
+ Error("fail5\n");
+
+ ThreadAlert(Pdo->SystemPowerThread);
+ ThreadJoin(Pdo->SystemPowerThread);
+ Pdo->SystemPowerThread = NULL;
+
+fail4:
+ Error("fail4\n");
+
+ Pdo->PhysicalDeviceObject = NULL;
+ Pdo->LowerDeviceObject = NULL;
+ Pdo->Dx = NULL;
+
+ IoDetachDevice(LowerDeviceObject);
+
+fail3:
+ Error("fail3\n");
+
+ ASSERT(IsZeroMemory(Pdo, sizeof (XENDISK_PDO)));
+ __PdoFree(Pdo);
+
+fail2:
+ Error("fail2\n");
+
+ IoDeleteDevice(FilterDeviceObject);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+VOID
+PdoDestroy(
+ IN PXENDISK_PDO Pdo
+ )
+{
+ PDEVICE_OBJECT LowerDeviceObject = Pdo->LowerDeviceObject;
+ PXENDISK_DX Dx = Pdo->Dx;
+ PDEVICE_OBJECT FilterDeviceObject = Dx->DeviceObject;
+
+ ASSERT3U(__PdoGetDevicePnpState(Pdo), ==, Deleted);
+
+ ASSERT(__PdoIsMissing(Pdo));
+ Pdo->Missing = FALSE;
+
+ __PdoUnlink(Pdo);
+
+ Verbose("%p (%s)\n",
+ FilterDeviceObject,
+ Pdo->Reason);
+ Pdo->Reason = NULL;
+
+ Dx->Pdo = NULL;
+
+ ThreadAlert(Pdo->DevicePowerThread);
+ ThreadJoin(Pdo->DevicePowerThread);
+ Pdo->DevicePowerThread = NULL;
+
+ ThreadAlert(Pdo->SystemPowerThread);
+ ThreadJoin(Pdo->SystemPowerThread);
+ Pdo->SystemPowerThread = NULL;
+
+ Pdo->SectorSize = 0;
+ Pdo->PhysicalDeviceObject = NULL;
+ Pdo->LowerDeviceObject = NULL;
+ Pdo->Dx = NULL;
+
+ IoDetachDevice(LowerDeviceObject);
+
+ ASSERT(IsZeroMemory(Pdo, sizeof (XENDISK_PDO)));
+ __PdoFree(Pdo);
+
+ IoDeleteDevice(FilterDeviceObject);
+}
diff --git a/src/xendisk/pdo.h b/src/xendisk/pdo.h
new file mode 100644
index 0000000..5e2e5d6
--- /dev/null
+++ b/src/xendisk/pdo.h
@@ -0,0 +1,90 @@
+/* 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.
+ */
+
+#ifndef _XENDISK_PDO_H
+#define _XENDISK_PDO_H
+
+#include <ntddk.h>
+#include "types.h"
+#include "fdo.h"
+
+typedef struct _XENDISK_PDO XENDISK_PDO, *PXENDISK_PDO;
+
+extern VOID
+PdoSetDevicePnpState(
+ IN PXENDISK_PDO Pdo,
+ IN DEVICE_PNP_STATE State
+ );
+
+extern DEVICE_PNP_STATE
+PdoGetDevicePnpState(
+ IN PXENDISK_PDO Pdo
+ );
+
+extern PDEVICE_OBJECT
+PdoGetPhysicalDeviceObject(
+ IN PXENDISK_PDO Pdo
+ );
+
+extern BOOLEAN
+PdoIsMissing(
+ IN PXENDISK_PDO Pdo
+ );
+
+extern VOID
+PdoSetMissing(
+ IN PXENDISK_PDO Pdo,
+ IN const CHAR *Reason
+ );
+
+extern BOOLEAN
+PdoIsMasked(
+ IN PXENDISK_PDO Pdo
+ );
+
+extern NTSTATUS
+PdoCreate(
+ IN PXENDISK_FDO Fdo,
+ IN PDEVICE_OBJECT PhysicalDeviceObject
+ );
+
+extern VOID
+PdoDestroy(
+ IN PXENDISK_PDO Pdo
+ );
+
+extern NTSTATUS
+PdoDispatch(
+ IN PXENDISK_PDO Pdo,
+ IN PIRP Irp
+ );
+
+#endif // _XENDISK_PDO_H
diff --git a/src/xendisk/thread.c b/src/xendisk/thread.c
new file mode 100644
index 0000000..92e2b94
--- /dev/null
+++ b/src/xendisk/thread.c
@@ -0,0 +1,225 @@
+/* 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 <ntddk.h>
+
+#include "thread.h"
+#include "debug.h"
+#include "assert.h"
+#include "util.h"
+
+#define THREAD_POOL 'ERHT'
+
+struct _XENDISK_THREAD {
+ XENDISK_THREAD_FUNCTION Function;
+ PVOID Context;
+ KEVENT Event;
+ BOOLEAN Alerted;
+ LONG References;
+ PKTHREAD Thread;
+};
+
+static FORCEINLINE PVOID
+__ThreadAllocate(
+ IN ULONG Length
+ )
+{
+ return __AllocateNonPagedPoolWithTag(__FUNCTION__, __LINE__, Length,
THREAD_POOL);
+}
+
+static FORCEINLINE VOID
+__ThreadFree(
+ IN PVOID Buffer
+ )
+{
+ __FreePoolWithTag(Buffer, THREAD_POOL);
+}
+
+static FORCEINLINE VOID
+__ThreadWake(
+ IN PXENDISK_THREAD Thread
+ )
+{
+ KeSetEvent(&Thread->Event, IO_NO_INCREMENT, FALSE);
+}
+
+VOID
+ThreadWake(
+ IN PXENDISK_THREAD Thread
+ )
+{
+ __ThreadWake(Thread);
+}
+
+static FORCEINLINE VOID
+__ThreadAlert(
+ IN PXENDISK_THREAD Thread
+ )
+{
+ Thread->Alerted = TRUE;
+ __ThreadWake(Thread);
+}
+
+VOID
+ThreadAlert(
+ IN PXENDISK_THREAD Thread
+ )
+{
+ __ThreadAlert(Thread);
+}
+
+KSTART_ROUTINE ThreadFunction;
+
+VOID
+ThreadFunction(
+ IN PVOID Argument
+ )
+{
+ PXENDISK_THREAD Self = Argument;
+ NTSTATUS status;
+
+ status = Self->Function(Self, Self->Context);
+
+ if (InterlockedDecrement(&Self->References) == 0)
+ __ThreadFree(Self);
+
+ PsTerminateSystemThread(status);
+ // NOT REACHED
+}
+
+NTSTATUS
+ThreadCreate(
+ IN XENDISK_THREAD_FUNCTION Function,
+ IN PVOID Context,
+ OUT PXENDISK_THREAD *Thread
+ )
+{
+ HANDLE Handle;
+ NTSTATUS status;
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+ (*Thread) = __ThreadAllocate(sizeof (XENDISK_THREAD));
+
+ status = STATUS_NO_MEMORY;
+ if (*Thread == NULL)
+ goto fail1;
+
+ (*Thread)->Function = Function;
+ (*Thread)->Context = Context;
+ (*Thread)->Alerted = FALSE;
+ (*Thread)->References = 2; // One for us, one for the thread function
+
+ KeInitializeEvent(&(*Thread)->Event, NotificationEvent, FALSE);
+
+ status = PsCreateSystemThread(&Handle,
+ STANDARD_RIGHTS_ALL | SPECIFIC_RIGHTS_ALL,
+ NULL,
+ NULL,
+ NULL,
+ ThreadFunction,
+ *Thread);
+ if (!NT_SUCCESS(status)) {
+ --(*Thread)->References; // Fake thread function termination
+ goto fail2;
+ }
+
+ status = ObReferenceObjectByHandle(Handle,
+ SYNCHRONIZE,
+ *PsThreadType,
+ KernelMode,
+ &(*Thread)->Thread,
+ NULL);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ ZwClose(Handle);
+
+ return STATUS_SUCCESS;
+
+fail3:
+ Error("fail3\n");
+
+ __ThreadAlert(*Thread);
+ ZwClose(Handle);
+
+fail2:
+ Error("fail2\n");
+
+ if (InterlockedDecrement(&(*Thread)->References) == 0)
+ __ThreadFree(*Thread);
+
+ *Thread = NULL;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+PKEVENT
+ThreadGetEvent(
+ IN PXENDISK_THREAD Thread
+ )
+{
+ return &Thread->Event;
+}
+
+BOOLEAN
+ThreadIsAlerted(
+ IN PXENDISK_THREAD Thread
+ )
+{
+ return Thread->Alerted;
+}
+
+VOID
+ThreadJoin(
+ IN PXENDISK_THREAD Thread
+ )
+{
+ LONG References;
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+ ASSERT3P(KeGetCurrentThread(), !=, Thread->Thread);
+
+ (VOID) KeWaitForSingleObject(Thread->Thread,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+
+ References = InterlockedDecrement(&Thread->References);
+ ASSERT3U(References, ==, 0);
+
+ __ThreadFree(Thread);
+}
+
diff --git a/src/xendisk/thread.h b/src/xendisk/thread.h
new file mode 100644
index 0000000..c197337
--- /dev/null
+++ b/src/xendisk/thread.h
@@ -0,0 +1,73 @@
+/* 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.
+ */
+
+#ifndef _XENDISK_THREAD_H
+#define _XENDISK_THREAD_H
+
+#include <ntddk.h>
+
+typedef struct _XENDISK_THREAD XENDISK_THREAD, *PXENDISK_THREAD;
+
+typedef NTSTATUS (*XENDISK_THREAD_FUNCTION)(PXENDISK_THREAD, PVOID);
+
+extern NTSTATUS
+ThreadCreate(
+ IN XENDISK_THREAD_FUNCTION Function,
+ IN PVOID Context,
+ OUT PXENDISK_THREAD *Thread
+ );
+
+extern PKEVENT
+ThreadGetEvent(
+ IN PXENDISK_THREAD Self
+ );
+
+extern BOOLEAN
+ThreadIsAlerted(
+ IN PXENDISK_THREAD Self
+ );
+
+extern VOID
+ThreadWake(
+ IN PXENDISK_THREAD Thread
+ );
+
+extern VOID
+ThreadAlert(
+ IN PXENDISK_THREAD Thread
+ );
+
+extern VOID
+ThreadJoin(
+ IN PXENDISK_THREAD Thread
+ );
+
+#endif // _XENDISK_THREAD_H
diff --git a/src/xendisk/types.h b/src/xendisk/types.h
new file mode 100644
index 0000000..b2b4218
--- /dev/null
+++ b/src/xendisk/types.h
@@ -0,0 +1,53 @@
+/* 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.
+ */
+
+#ifndef _XENDISK_TYPES_H
+#define _XENDISK_TYPES_H
+
+typedef enum _DEVICE_OBJECT_TYPE {
+ PHYSICAL_DEVICE_OBJECT = 'ODP',
+ FUNCTION_DEVICE_OBJECT = 'ODF'
+} DEVICE_OBJECT_TYPE, *PDEVICE_OBJECT_TYPE;
+
+typedef enum _DEVICE_PNP_STATE {
+ Invalid = 0,
+ Present, // PDO only
+ Enumerated, // PDO only
+ Added, // FDO only
+ Started,
+ StopPending,
+ Stopped,
+ RemovePending,
+ SurpriseRemovePending,
+ Deleted
+} DEVICE_PNP_STATE, *PDEVICE_PNP_STATE;
+
+#endif // _XENDISK_TYPES_H
diff --git a/src/xendisk/util.h b/src/xendisk/util.h
new file mode 100644
index 0000000..e7adc22
--- /dev/null
+++ b/src/xendisk/util.h
@@ -0,0 +1,222 @@
+/* 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.
+ */
+
+#ifndef _UTIL_H
+#define _UTIL_H
+
+#include <ntddk.h>
+
+#include "assert.h"
+
+typedef struct _NON_PAGED_BUFFER_HEADER {
+ SIZE_T Length;
+ ULONG Tag;
+} NON_PAGED_BUFFER_HEADER, *PNON_PAGED_BUFFER_HEADER;
+
+typedef struct _NON_PAGED_BUFFER_TRAILER {
+ ULONG Tag;
+} NON_PAGED_BUFFER_TRAILER, *PNON_PAGED_BUFFER_TRAILER;
+
+static FORCEINLINE PVOID
+__AllocateNonPagedPoolWithTag(
+ IN PCHAR Caller,
+ IN ULONG Line,
+ IN SIZE_T Length,
+ IN ULONG Tag
+ )
+{
+ PUCHAR Buffer;
+ PNON_PAGED_BUFFER_HEADER Header;
+ PNON_PAGED_BUFFER_TRAILER Trailer;
+
+ ASSERT3S(Length, !=, 0);
+
+ Buffer = (PUCHAR)ExAllocatePoolWithTag(NonPagedPool,
+ sizeof (NON_PAGED_BUFFER_HEADER) +
+ Length +
+ sizeof (NON_PAGED_BUFFER_TRAILER),
+ Tag);
+ if (Buffer == NULL) {
+ Warning("%s:%u : AllocFailed %d bytes, %08x tag\n", Caller, Line,
Length, Tag);
+ goto done;
+ }
+
+ RtlZeroMemory(Buffer,
+ sizeof (NON_PAGED_BUFFER_HEADER) +
+ Length +
+ sizeof (NON_PAGED_BUFFER_TRAILER));
+
+ Header = (PNON_PAGED_BUFFER_HEADER)Buffer;
+ Header->Length = Length;
+ Header->Tag = Tag;
+
+ Buffer += sizeof (NON_PAGED_BUFFER_HEADER);
+
+ Trailer = (PNON_PAGED_BUFFER_TRAILER)(Buffer + Length);
+ Trailer->Tag = Tag;
+
+done:
+ return Buffer;
+}
+
+static FORCEINLINE VOID
+__FreePoolWithTag(
+ IN PVOID _Buffer,
+ IN ULONG Tag
+ )
+{
+ PUCHAR Buffer = (PUCHAR)_Buffer;
+ SIZE_T Length;
+ PNON_PAGED_BUFFER_HEADER Header;
+ PNON_PAGED_BUFFER_TRAILER Trailer;
+
+ ASSERT3P(Buffer, !=, NULL);
+
+ Buffer -= sizeof (NON_PAGED_BUFFER_HEADER);
+
+ Header = (PNON_PAGED_BUFFER_HEADER)Buffer;
+ ASSERT3U(Tag, ==, Header->Tag);
+ Length = Header->Length;
+
+ Buffer += sizeof (NON_PAGED_BUFFER_HEADER);
+
+ Trailer = (PNON_PAGED_BUFFER_TRAILER)(Buffer + Length);
+ ASSERT3U(Tag, ==, Trailer->Tag);
+
+ Buffer -= sizeof (NON_PAGED_BUFFER_HEADER);
+
+ RtlFillMemory(Buffer,
+ sizeof (NON_PAGED_BUFFER_HEADER) +
+ Length +
+ sizeof (NON_PAGED_BUFFER_TRAILER),
+ 0xAA);
+
+ ExFreePoolWithTag(Buffer, Tag);
+}
+
+static FORCEINLINE PMDL
+__AllocPagesForMdl(
+ IN SIZE_T Size
+ )
+{
+ PMDL Mdl;
+ PHYSICAL_ADDRESS LowAddr;
+ PHYSICAL_ADDRESS HighAddr;
+ PHYSICAL_ADDRESS SkipBytes;
+
+ SkipBytes.QuadPart = 0ull;
+ HighAddr.QuadPart = ~0ull;
+
+ // try > 4GB
+ LowAddr.QuadPart = 0x100000000ull;
+ Mdl = MmAllocatePagesForMdlEx(LowAddr, HighAddr, SkipBytes, Size,
MmCached, 0);
+ if (Mdl) {
+ if (MmGetMdlByteCount(Mdl) == Size) {
+ goto done;
+ }
+ MmFreePagesFromMdl(Mdl);
+ ExFreePool(Mdl);
+ Mdl = NULL;
+ }
+
+ // try > 2GB
+ LowAddr.QuadPart = 0x80000000ull;
+ Mdl = MmAllocatePagesForMdlEx(LowAddr, HighAddr, SkipBytes, Size,
MmCached, 0);
+ if (Mdl) {
+ if (MmGetMdlByteCount(Mdl) == Size) {
+ goto done;
+ }
+ MmFreePagesFromMdl(Mdl);
+ ExFreePool(Mdl);
+ Mdl = NULL;
+ }
+
+ // try anywhere
+ LowAddr.QuadPart = 0ull;
+ Mdl = MmAllocatePagesForMdlEx(LowAddr, HighAddr, SkipBytes, Size,
MmCached, 0);
+ // Mdl byte count gets checked again after this returns
+
+done:
+ return Mdl;
+}
+static FORCEINLINE PVOID
+___AllocPages(
+ IN PCHAR Caller,
+ IN ULONG Line,
+ IN SIZE_T Size,
+ OUT PMDL* Mdl
+ )
+{
+ PVOID Buffer;
+
+ *Mdl = __AllocPagesForMdl(Size);
+ if (*Mdl == NULL) {
+ Warning("%s:%u : MmAllocatePagesForMdlEx Failed %d bytes\n", Caller,
Line, Size);
+ goto fail1;
+ }
+
+ if (MmGetMdlByteCount(*Mdl) != Size) {
+ Warning("%s:%u : %d bytes != %d bytes requested\n", Caller, Line,
MmGetMdlByteCount(*Mdl), Size);
+ goto fail2;
+ }
+
+ Buffer = MmMapLockedPagesSpecifyCache(*Mdl, KernelMode, MmCached, NULL,
FALSE, NormalPagePriority);
+ if (Buffer == NULL) {
+ Warning("%s:%u : MmMapLockedPagesSpecifyCache Failed %d bytes\n",
Caller, Line, Size);
+ goto fail3;
+ }
+
+ return Buffer;
+
+fail3:
+fail2:
+ MmFreePagesFromMdl(*Mdl);
+ ExFreePool(*Mdl);
+fail1:
+ *Mdl = NULL;
+ return NULL;
+}
+#define __AllocPages(Size, Mdl) ___AllocPages(__FUNCTION__, __LINE__, Size,
Mdl)
+
+static FORCEINLINE VOID
+__FreePages(
+ IN PVOID Buffer,
+ IN PMDL Mdl
+ )
+{
+ if (Buffer && Mdl) {
+ MmUnmapLockedPages(Buffer, Mdl);
+ MmFreePagesFromMdl(Mdl);
+ ExFreePool(Mdl);
+ }
+}
+
+#endif // _UTIL_H
diff --git a/src/xendisk/xendisk.rc b/src/xendisk/xendisk.rc
new file mode 100644
index 0000000..df2e5b6
--- /dev/null
+++ b/src/xendisk/xendisk.rc
@@ -0,0 +1,56 @@
+/* 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 <windows.h>
+#include <ntverp.h>
+
+
+#undef VER_COMPANYNAME_STR
+#undef VER_PRODUCTNAME_STR
+#undef VER_PRODUCTVERSION
+#undef VER_PRODUCTVERSION_STR
+
+#include <version.h>
+
+#define VER_COMPANYNAME_STR COMPANY_NAME_STR
+#define VER_LEGALCOPYRIGHT_STR "Copyright (c) Citrix Systems Inc."
+
+#define VER_PRODUCTNAME_STR "XENDISK"
+#define VER_PRODUCTVERSION
MAJOR_VERSION,MINOR_VERSION,MICRO_VERSION,BUILD_NUMBER
+#define VER_PRODUCTVERSION_STR MAJOR_VERSION_STR "." MINOR_VERSION_STR
"." MICRO_VERSION_STR "." BUILD_NUMBER_STR
+
+#define VER_INTERNALNAME_STR "XENDISK.SYS"
+#define VER_FILEDESCRIPTION_STR "XENDISK"
+
+#define VER_FILETYPE VFT_DRV
+#define VER_FILESUBTYPE VFT2_DRV_SYSTEM
+
+#include <common.ver>
diff --git a/src/xenvbd.inf b/src/xenvbd.inf
index bc8627b..0d58453 100644
--- a/src/xenvbd.inf
+++ b/src/xenvbd.inf
@@ -46,6 +46,7 @@ CoInst_CopyFiles=11
[SourceDisksFiles]
xenvbd.sys=0,,
xencrsh.sys=0,,
+xendisk.sys=0,,
xenvbd_coinst.dll=0,,
[Manufacturer]
@@ -62,9 +63,25 @@ CopyFiles=XenVbd_Copyfiles
[XenVbd_Copyfiles]
xenvbd.sys
xencrsh.sys
+xendisk.sys
+
+[XenVbd_Inst.HW]
+AddReg=XenVbd_AddReg
+
+[XenVbd_AddReg]
+HKR,,"UpperFilters",0x00010000,"xendisk"
[XenVbd_Inst.Services]
AddService=xenvbd,2,XenVbd_Service,
+AddService=xendisk,,XenDisk_Service,
+
+[XenDisk_Service]
+DisplayName=%XenDiskDesc%
+ServiceType=%SERVICE_KERNEL_DRIVER%
+StartType=%SERVICE_BOOT_START%
+ErrorControl=%SERVICE_ERROR_NORMAL%
+ServiceBinary=%12%\xendisk.sys
+LoadOrderGroup="Scsi Miniport"
[XenVbd_Service]
DisplayName=%XenVbdDesc%
@@ -95,6 +112,7 @@
HKR,,CoInstallers32,0x00010000,"xenvbd_coinst_@MAJOR_VERSION@_@MINOR_VERSION@_@M
Company = "@COMPANY_NAME@"
DiskDesc = "@PRODUCT_NAME@ PV Storage Host Adapter Package"
XenVbdDesc= "@PRODUCT_NAME@ PV Storage Host Adapter"
+XenDiskDesc= "@PRODUCT_NAME@ PV Storage Filter"
SERVICE_BOOT_START = 0x0
SERVICE_SYSTEM_START = 0x1
diff --git a/vs2012/package/package.vcxproj b/vs2012/package/package.vcxproj
index 5e5fcbc..9782f19 100644
--- a/vs2012/package/package.vcxproj
+++ b/vs2012/package/package.vcxproj
@@ -51,6 +51,9 @@
<ProjectReference Include="..\xenvbd\xenvbd.vcxproj">
<Project>{ef236371-3145-41b1-99c9-82b33e353f17}</Project>
</ProjectReference>
+ <ProjectReference Include="..\xendisk\xendisk.vcxproj">
+
<Project>{d7411b2c-2c43-434d-9f56-e10a3d2f5bad}</Project>
+ </ProjectReference>
</ItemGroup>
<ItemGroup>
<FilesToPackage
Include="$(KIT)\Redist\DIFx\dpinst\EngMui\x86\dpinst.exe"
Condition="'$(Platform)'=='Win32'" />
diff --git a/vs2012/xendisk/xendisk.vcxproj b/vs2012/xendisk/xendisk.vcxproj
new file mode 100644
index 0000000..333bc40
--- /dev/null
+++ b/vs2012/xendisk/xendisk.vcxproj
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\configs.props" />
+
+ <PropertyGroup Label="Globals">
+ <Configuration>Windows Vista Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <PropertyGroup Label="ProeprtySheets">
+ <PlatformToolset>WindowsKernelModeDriver8.0</PlatformToolset>
+ <ConfigurationType>Driver</ConfigurationType>
+ <DriverType>WDM</DriverType>
+ </PropertyGroup>
+
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+
+ <PropertyGroup Label="Globals">
+
<ProjectGuid>{D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}</ProjectGuid>
+ </PropertyGroup>
+
+ <Import Project="..\targets.props" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+
+ <PropertyGroup>
+
<IncludePath>$(ProjectDir)..\..\include;$(IncludePath)</IncludePath>
+ <RunCodeAnalysis>true</RunCodeAnalysis>
+ <EnableInf2cat>false</EnableInf2cat>
+
<IntDir>..\$(ProjectName)\$(ConfigurationName)\$(Platform)\</IntDir>
+ <OutDir>..\$(ConfigurationName)\$(Platform)\</OutDir>
+ </PropertyGroup>
+
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <BufferSecurityCheck>false</BufferSecurityCheck>
+
<PreprocessorDefinitions>__MODULE__="XENDISK";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <WarningLevel>EnableAllWarnings</WarningLevel>
+
<DisableSpecificWarnings>4548;4711;4820;4668;4255;6001;6054;28196;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+
<MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <EnablePREfast>true</EnablePREfast>
+ </ClCompile>
+ <Link>
+
<AdditionalDependencies>$(DDK_LIB_PATH)/libcntpr.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <Inf>
+ <SpecifyArchitecture>true</SpecifyArchitecture>
+
<SpecifyDriverVerDirectiveVersion>true</SpecifyDriverVerDirectiveVersion>
+
<TimeStamp>$(MAJOR_VERSION).$(MINOR_VERSION).$(MICRO_VERSION).$(BUILD_NUMBER)</TimeStamp>
+ <EnableVerbose>true</EnableVerbose>
+ </Inf>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Platform)'=='Win32'">
+ <ClCompile>
+
<PreprocessorDefinitions>__i386__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Inf>
+ <Architecture>x86</Architecture>
+ </Inf>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Platform)'=='x64'">
+ <ClCompile>
+
<PreprocessorDefinitions>__x86_64__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Inf>
+ <Architecture>amd64</Architecture>
+ </Inf>
+ </ItemDefinitionGroup>
+
+ <ItemGroup>
+ <FilesToPackage Include="$(TargetPath)" />
+ <FilesToPackage Include="$(OutDir)$(TargetName).pdb" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')"
Condition="'@(Inf)'!=''" />
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="../../src/xendisk/driver.c" />
+ <ClCompile Include="../../src/xendisk/fdo.c" />
+ <ClCompile Include="../../src/xendisk/pdo.c" />
+ <ClCompile Include="../../src/xendisk/thread.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="..\..\src\xendisk\xendisk.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project>
diff --git a/vs2012/xendisk/xendisk.vcxproj.user
b/vs2012/xendisk/xendisk.vcxproj.user
new file mode 100644
index 0000000..0b2b210
--- /dev/null
+++ b/vs2012/xendisk/xendisk.vcxproj.user
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <SignMode>TestSign</SignMode>
+ <TestCertificate>..\..\src\xenvbd.pfx</TestCertificate>
+
<TimeStampServer>http://timestamp.verisign.com/scripts/timstamp.dll</TimeStampServer>
+ </PropertyGroup>
+</Project>
diff --git a/vs2012/xenvbd.sln b/vs2012/xenvbd.sln
index 86fb1a5..15113cf 100644
--- a/vs2012/xenvbd.sln
+++ b/vs2012/xenvbd.sln
@@ -4,10 +4,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xenvbd",
"xenvbd\xenvbd.vcx
ProjectSection(ProjectDependencies) = postProject
{50C08437-C1F3-4349-BF6A-7B55A06BF999} =
{50C08437-C1F3-4349-BF6A-7B55A06BF999}
{58F5BC43-B92E-4A2B-975D-0066EAB29092} =
{58F5BC43-B92E-4A2B-975D-0066EAB29092}
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD} =
{D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xencrsh",
"xencrsh\xencrsh.vcxproj", "{58F5BC43-B92E-4A2B-975D-0066EAB29092}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xendisk",
"xendisk\xendisk.vcxproj", "{D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}"
+EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xenvbd_coinst",
"coinst\xenvbd_coinst.vcxproj", "{50C08437-C1F3-4349-BF6A-7B55A06BF999}"
ProjectSection(ProjectDependencies) = postProject
{58F5BC43-B92E-4A2B-975D-0066EAB29092} =
{58F5BC43-B92E-4A2B-975D-0066EAB29092}
@@ -18,6 +21,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") =
"package", "package\package.
{50C08437-C1F3-4349-BF6A-7B55A06BF999} =
{50C08437-C1F3-4349-BF6A-7B55A06BF999}
{58F5BC43-B92E-4A2B-975D-0066EAB29092} =
{58F5BC43-B92E-4A2B-975D-0066EAB29092}
{EF236371-3145-41B1-99C9-82B33E353F17} =
{EF236371-3145-41B1-99C9-82B33E353F17}
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD} =
{D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}
EndProjectSection
EndProject
Global
@@ -36,6 +40,30 @@ Global
Windows Vista Release|x64 = Windows Vista Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
Debug|Win32.ActiveCfg = Windows 7 Debug|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
Debug|Win32.Build.0 = Windows 7 Debug|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
Debug|x64.ActiveCfg = Windows 7 Debug|x64
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
Debug|x64.Build.0 = Windows 7 Debug|x64
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
Release|Win32.ActiveCfg = Windows 7 Release|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
Release|Win32.Build.0 = Windows 7 Release|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
Release|x64.ActiveCfg = Windows 7 Release|x64
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
Release|x64.Build.0 = Windows 7 Release|x64
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
Debug|Win32.ActiveCfg = Windows 8 Debug|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
Debug|Win32.Build.0 = Windows 8 Debug|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
Debug|x64.ActiveCfg = Windows 8 Debug|x64
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
Debug|x64.Build.0 = Windows 8 Debug|x64
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
Release|Win32.ActiveCfg = Windows 8 Release|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
Release|Win32.Build.0 = Windows 8 Release|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
Release|x64.ActiveCfg = Windows 8 Release|x64
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
Release|x64.Build.0 = Windows 8 Release|x64
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
Debug|Win32.ActiveCfg = Windows Vista Debug|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
Debug|Win32.Build.0 = Windows Vista Debug|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
Debug|x64.ActiveCfg = Windows Vista Debug|x64
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
Debug|x64.Build.0 = Windows Vista Debug|x64
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
Release|Win32.ActiveCfg = Windows Vista Release|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
Release|Win32.Build.0 = Windows Vista Release|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
Release|x64.ActiveCfg = Windows Vista Release|x64
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
Release|x64.Build.0 = Windows Vista Release|x64
{EF236371-3145-41B1-99C9-82B33E353F17}.Windows 7
Debug|Win32.ActiveCfg = Windows 7 Debug|Win32
{EF236371-3145-41B1-99C9-82B33E353F17}.Windows 7
Debug|Win32.Build.0 = Windows 7 Debug|Win32
{EF236371-3145-41B1-99C9-82B33E353F17}.Windows 7
Debug|x64.ActiveCfg = Windows 7 Debug|x64
diff --git a/vs2013/package/package.vcxproj b/vs2013/package/package.vcxproj
index 5d0de4d..8b2fa4f 100644
--- a/vs2013/package/package.vcxproj
+++ b/vs2013/package/package.vcxproj
@@ -80,6 +80,9 @@
<ProjectReference Include="..\xenvbd\xenvbd.vcxproj">
<Project>{ef236371-3145-41b1-99c9-82b33e353f17}</Project>
</ProjectReference>
+ <ProjectReference Include="..\xendisk\xendisk.vcxproj">
+ <Project>{d7411b2c-2c43-434d-9f56-e10a3d2f5bad}</Project>
+ </ProjectReference>
</ItemGroup>
<ItemGroup>
<FilesToPackage Include="$(KIT)\Redist\DIFx\dpinst\EngMui\x86\dpinst.exe"
Condition="'$(Platform)'=='Win32'" />
diff --git a/vs2013/xendisk/xendisk.vcxproj b/vs2013/xendisk/xendisk.vcxproj
new file mode 100644
index 0000000..39b9163
--- /dev/null
+++ b/vs2013/xendisk/xendisk.vcxproj
@@ -0,0 +1,112 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project DefaultTargets="Build" ToolsVersion="4.0"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="..\configs.props" />
+ <PropertyGroup Label="Globals">
+ <Configuration>Windows Vista Debug</Configuration>
+ <Platform Condition="'$(Platform)' == ''">Win32</Platform>
+ <DebuggerFlavor>DbgengKernelDebugger</DebuggerFlavor>
+ </PropertyGroup>
+ <PropertyGroup Label="ProeprtySheets">
+ <ConfigurationType>Driver</ConfigurationType>
+ <DriverType>WDM</DriverType>
+ </PropertyGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
+ <PropertyGroup Label="Configuration"
Condition="'$(Configuration)|$(Platform)'=='Windows 8 Release|Win32'">
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration"
Condition="'$(Configuration)|$(Platform)'=='Windows Vista Debug|Win32'">
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration"
Condition="'$(Configuration)|$(Platform)'=='Windows Vista Release|Win32'">
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration"
Condition="'$(Configuration)|$(Platform)'=='Windows 7 Release|Win32'">
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration"
Condition="'$(Configuration)|$(Platform)'=='Windows 7 Debug|Win32'">
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration"
Condition="'$(Configuration)|$(Platform)'=='Windows 8 Debug|Win32'">
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration"
Condition="'$(Configuration)|$(Platform)'=='Windows 8 Release|x64'">
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration"
Condition="'$(Configuration)|$(Platform)'=='Windows Vista Debug|x64'">
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration"
Condition="'$(Configuration)|$(Platform)'=='Windows Vista Release|x64'">
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration"
Condition="'$(Configuration)|$(Platform)'=='Windows 7 Release|x64'">
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration"
Condition="'$(Configuration)|$(Platform)'=='Windows 7 Debug|x64'">
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Label="Configuration"
Condition="'$(Configuration)|$(Platform)'=='Windows 8 Debug|x64'">
+ <PlatformToolset>WindowsKernelModeDriver8.1</PlatformToolset>
+ </PropertyGroup>
+ <PropertyGroup Label="Globals">
+ <ProjectGuid>{D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}</ProjectGuid>
+ </PropertyGroup>
+ <Import Project="..\targets.props" />
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
+ <PropertyGroup>
+ <IncludePath>$(ProjectDir)..\..\include;$(IncludePath)</IncludePath>
+ <RunCodeAnalysis>true</RunCodeAnalysis>
+ <EnableInf2cat>false</EnableInf2cat>
+ <IntDir>..\$(ProjectName)\$(ConfigurationName)\$(Platform)\</IntDir>
+ <OutDir>..\$(ConfigurationName)\$(Platform)\</OutDir>
+ </PropertyGroup>
+ <ItemDefinitionGroup>
+ <ClCompile>
+ <BufferSecurityCheck>false</BufferSecurityCheck>
+
<PreprocessorDefinitions>__MODULE__="XENDISK";%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ <WarningLevel>EnableAllWarnings</WarningLevel>
+
<DisableSpecificWarnings>4548;4711;4820;4668;4255;6001;6054;28196;%(DisableSpecificWarnings)</DisableSpecificWarnings>
+ <MultiProcessorCompilation>true</MultiProcessorCompilation>
+ <EnablePREfast>true</EnablePREfast>
+ </ClCompile>
+ <Link>
+
<AdditionalDependencies>$(DDK_LIB_PATH)/libcntpr.lib;%(AdditionalDependencies)</AdditionalDependencies>
+ </Link>
+ <Inf>
+ <SpecifyArchitecture>true</SpecifyArchitecture>
+ <SpecifyDriverVerDirectiveVersion>true</SpecifyDriverVerDirectiveVersion>
+
<TimeStamp>$(MAJOR_VERSION).$(MINOR_VERSION).$(MICRO_VERSION).$(BUILD_NUMBER)</TimeStamp>
+ <EnableVerbose>true</EnableVerbose>
+ </Inf>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Platform)'=='Win32'">
+ <ClCompile>
+
<PreprocessorDefinitions>__i386__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Inf>
+ <Architecture>x86</Architecture>
+ </Inf>
+ </ItemDefinitionGroup>
+ <ItemDefinitionGroup Condition="'$(Platform)'=='x64'">
+ <ClCompile>
+
<PreprocessorDefinitions>__x86_64__;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+ </ClCompile>
+ <Inf>
+ <Architecture>amd64</Architecture>
+ </Inf>
+ </ItemDefinitionGroup>
+ <ItemGroup>
+ <FilesToPackage Include="$(TargetPath)" />
+ <FilesToPackage Include="$(OutDir)$(TargetName).pdb" />
+ <FilesToPackage Include="@(Inf->'%(CopyOutput)')" Condition="'@(Inf)'!=''"
/>
+ </ItemGroup>
+ <ItemGroup>
+ <ClCompile Include="../../src/xendisk/driver.c" />
+ <ClCompile Include="../../src/xendisk/fdo.c" />
+ <ClCompile Include="../../src/xendisk/pdo.c" />
+ <ClCompile Include="../../src/xendisk/thread.c" />
+ </ItemGroup>
+ <ItemGroup>
+ <ResourceCompile Include="..\..\src\xendisk\xendisk.rc" />
+ </ItemGroup>
+ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
+</Project>
diff --git a/vs2013/xendisk/xendisk.vcxproj.user
b/vs2013/xendisk/xendisk.vcxproj.user
new file mode 100644
index 0000000..1f1f3c0
--- /dev/null
+++ b/vs2013/xendisk/xendisk.vcxproj.user
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0"
xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <PropertyGroup>
+ <SignMode>TestSign</SignMode>
+ <TestCertificate>..\..\src\xenvbd.pfx</TestCertificate>
+
<TimeStampServer>http://timestamp.verisign.com/scripts/timstamp.dll</TimeStampServer>
+ </PropertyGroup>
+</Project>
diff --git a/vs2013/xenvbd.sln b/vs2013/xenvbd.sln
index 13128c5..da798d2 100644
--- a/vs2013/xenvbd.sln
+++ b/vs2013/xenvbd.sln
@@ -4,10 +4,13 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xenvbd",
"xenvbd\xenvbd.vcx
ProjectSection(ProjectDependencies) = postProject
{50C08437-C1F3-4349-BF6A-7B55A06BF999} =
{50C08437-C1F3-4349-BF6A-7B55A06BF999}
{58F5BC43-B92E-4A2B-975D-0066EAB29092} =
{58F5BC43-B92E-4A2B-975D-0066EAB29092}
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD} =
{D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}
EndProjectSection
EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xencrsh",
"xencrsh\xencrsh.vcxproj", "{58F5BC43-B92E-4A2B-975D-0066EAB29092}"
EndProject
+Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xendisk",
"xendisk\xendisk.vcxproj", "{D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}"
+EndProject
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xenvbd_coinst",
"coinst\xenvbd_coinst.vcxproj", "{50C08437-C1F3-4349-BF6A-7B55A06BF999}"
ProjectSection(ProjectDependencies) = postProject
{58F5BC43-B92E-4A2B-975D-0066EAB29092} =
{58F5BC43-B92E-4A2B-975D-0066EAB29092}
@@ -18,6 +21,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") =
"package", "package\package.
{50C08437-C1F3-4349-BF6A-7B55A06BF999} =
{50C08437-C1F3-4349-BF6A-7B55A06BF999}
{58F5BC43-B92E-4A2B-975D-0066EAB29092} =
{58F5BC43-B92E-4A2B-975D-0066EAB29092}
{EF236371-3145-41B1-99C9-82B33E353F17} =
{EF236371-3145-41B1-99C9-82B33E353F17}
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD} =
{D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}
EndProjectSection
EndProject
Global
@@ -36,6 +40,30 @@ Global
Windows Vista Release|x64 = Windows Vista Release|x64
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
Debug|Win32.ActiveCfg = Windows 7 Debug|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
Debug|Win32.Build.0 = Windows 7 Debug|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
Debug|x64.ActiveCfg = Windows 7 Debug|x64
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
Debug|x64.Build.0 = Windows 7 Debug|x64
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
Release|Win32.ActiveCfg = Windows 7 Release|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
Release|Win32.Build.0 = Windows 7 Release|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
Release|x64.ActiveCfg = Windows 7 Release|x64
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 7
Release|x64.Build.0 = Windows 7 Release|x64
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
Debug|Win32.ActiveCfg = Windows 8 Debug|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
Debug|Win32.Build.0 = Windows 8 Debug|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
Debug|x64.ActiveCfg = Windows 8 Debug|x64
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
Debug|x64.Build.0 = Windows 8 Debug|x64
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
Release|Win32.ActiveCfg = Windows 8 Release|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
Release|Win32.Build.0 = Windows 8 Release|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
Release|x64.ActiveCfg = Windows 8 Release|x64
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows 8
Release|x64.Build.0 = Windows 8 Release|x64
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
Debug|Win32.ActiveCfg = Windows Vista Debug|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
Debug|Win32.Build.0 = Windows Vista Debug|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
Debug|x64.ActiveCfg = Windows Vista Debug|x64
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
Debug|x64.Build.0 = Windows Vista Debug|x64
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
Release|Win32.ActiveCfg = Windows Vista Release|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
Release|Win32.Build.0 = Windows Vista Release|Win32
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
Release|x64.ActiveCfg = Windows Vista Release|x64
+ {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD}.Windows Vista
Release|x64.Build.0 = Windows Vista Release|x64
{EF236371-3145-41B1-99C9-82B33E353F17}.Windows 7
Debug|Win32.ActiveCfg = Windows 7 Debug|Win32
{EF236371-3145-41B1-99C9-82B33E353F17}.Windows 7
Debug|Win32.Build.0 = Windows 7 Debug|Win32
{EF236371-3145-41B1-99C9-82B33E353F17}.Windows 7
Debug|x64.ActiveCfg = Windows 7 Debug|x64
--
1.9.4.msysgit.1
_______________________________________________
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 |