[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_UNMAP SRBs. 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 | 1863 ++++++++++++++++++++++++++++++ src/xendisk/fdo.h | 78 ++ src/xendisk/mutex.h | 113 ++ src/xendisk/pdo.c | 2126 +++++++++++++++++++++++++++++++++++ src/xendisk/pdo.h | 90 ++ src/xendisk/thread.c | 225 ++++ src/xendisk/thread.h | 74 ++ src/xendisk/types.h | 53 + src/xendisk/util.h | 222 ++++ src/xendisk/xendisk.rc | 56 + src/xenvbd.inf | 18 + vs2012/package/package.vcxproj | 5 +- vs2012/xendisk/xendisk.vcxproj | 84 ++ vs2012/xendisk/xendisk.vcxproj.user | 8 + vs2012/xenvbd.sln | 30 +- vs2013/package/package.vcxproj | 5 +- vs2013/xendisk/xendisk.user | 8 + vs2013/xendisk/xendisk.vcxproj | 112 ++ vs2013/xenvbd.sln | 27 + 24 files changed, 5780 insertions(+), 3 deletions(-) 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.user create mode 100644 vs2013/xendisk/xendisk.vcxproj 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..5209ca6 --- /dev/null +++ b/src/xendisk/fdo.c @@ -0,0 +1,1863 @@ +/* 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..c815a1e --- /dev/null +++ b/src/xendisk/pdo.c @@ -0,0 +1,2126 @@ +/* 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 FORCEINLINE VOID +__Set8Bytes( + IN PUCHAR Bytes, + IN ULONGLONG Value + ) +{ + Bytes[0] = (UCHAR)(Value >> 56); + Bytes[1] = (UCHAR)(Value >> 48); + Bytes[2] = (UCHAR)(Value >> 40); + Bytes[3] = (UCHAR)(Value >> 32); + Bytes[4] = (UCHAR)(Value >> 24); + Bytes[5] = (UCHAR)(Value >> 16); + Bytes[6] = (UCHAR)(Value >> 8); + Bytes[7] = (UCHAR)(Value); +} + +static FORCEINLINE VOID +__Set4Bytes( + IN PUCHAR Bytes, + IN ULONG Value + ) +{ + Bytes[0] = (UCHAR)(Value >> 24); + Bytes[1] = (UCHAR)(Value >> 16); + Bytes[2] = (UCHAR)(Value >> 8); + Bytes[3] = (UCHAR)(Value); +} + +static FORCEINLINE VOID +__Set2Bytes( + IN PUCHAR Bytes, + IN USHORT Value + ) +{ + Bytes[0] = (UCHAR)(Value << 8); + Bytes[1] = (UCHAR)(Value); +} + +static FORCEINLINE VOID +__SetUnmap( + IN PUNMAP_LIST_HEADER Unmap, + IN ULONG Length, + IN PDEVICE_DATA_SET_RANGE Ranges, + IN ULONG Count, + IN ULONG SectorSize + ) +{ + ULONG Index; + + __Set2Bytes(Unmap->DataLength, (USHORT)Length); + __Set2Bytes(Unmap->BlockDescrDataLength, (USHORT)sizeof(UNMAP_BLOCK_DESCRIPTOR)); + + for (Index = 0; Index < Count; ++Index) { + Trace("TRIM[%x] %x @ %llx\n", + Index, + (ULONG)(Ranges[Index].LengthInBytes / SectorSize), + (ULONG64)(Ranges[Index].StartingOffset / SectorSize)); + + __Set8Bytes(Unmap->Descriptors[Index].StartingLba, + (ULONG64)(Ranges[Index].StartingOffset / SectorSize)); + __Set4Bytes(Unmap->Descriptors[Index].LbaCount, + (ULONG)(Ranges[Index].LengthInBytes / SectorSize)); + } +} + +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; + 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 = SRB_FLAGS_BYPASS_FROZEN_QUEUE | SRB_FLAGS_NO_QUEUE_FREEZE; + 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; + __Set2Bytes(Cdb->UNMAP.AllocationLength, (USHORT)Length); + + __SetUnmap(Unmap, Length, Ranges, Count, Pdo->SectorSize); + + 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..63b4979 --- /dev/null +++ b/src/xendisk/thread.h @@ -0,0 +1,74 @@ +/* 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..7ca8f60 --- /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> \ No newline at end of file diff --git a/src/xenvbd.inf b/src/xenvbd.inf index bc8627b..20bd38a 100644 --- a/src/xenvbd.inf +++ b/src/xenvbd.inf @@ -45,6 +45,7 @@ CoInst_CopyFiles=11 [SourceDisksFiles] xenvbd.sys=0,, +xendisk.sys=0,, xencrsh.sys=0,, xenvbd_coinst.dll=0,, @@ -59,12 +60,20 @@ xenvbd_coinst.dll=0,, [XenVbd_Inst] CopyFiles=XenVbd_Copyfiles +[XenVbd_Inst.HW] +AddReg=XenVbd_AddReg + +[XenVbd_AddReg] +HKR,,"UpperFilters",0x00010000,"xendisk" + [XenVbd_Copyfiles] xenvbd.sys +xendisk.sys xencrsh.sys [XenVbd_Inst.Services] AddService=xenvbd,2,XenVbd_Service, +AddService=xendisk,,XenDisk_Service, [XenVbd_Service] DisplayName=%XenVbdDesc% @@ -75,6 +84,14 @@ ServiceBinary=%12%\xenvbd.sys LoadOrderGroup="Scsi Miniport" AddReg=XenVbd_Parameters +[XenDisk_Service] +DisplayName=%XenDiskDesc% +ServiceType=%SERVICE_KERNEL_DRIVER% +StartType=%SERVICE_BOOT_START% +ErrorControl=%SERVICE_ERROR_NORMAL% +ServiceBinary=%12%\xendisk.sys +LoadOrderGroup="Scsi Miniport" + [XenVbd_Parameters] HKR,"Parameters",,0x00000010 HKR,"Parameters","BusType",0x00010001,0x00000001 @@ -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..e029d13 100644 --- a/vs2012/package/package.vcxproj +++ b/vs2012/package/package.vcxproj @@ -48,6 +48,9 @@ <ProjectReference Include="..\xencrsh\xencrsh.vcxproj"> <Project>{58f5bc43-b92e-4a2b-975d-0066eab29092}</Project> </ProjectReference> + <ProjectReference Include="..\xendisk\xendisk.vcxproj"> + <Project>{d7411b2c-2c43-434d-9f56-e10a3d2f5bad}</Project> + </ProjectReference> <ProjectReference Include="..\xenvbd\xenvbd.vcxproj"> <Project>{ef236371-3145-41b1-99c9-82b33e353f17}</Project> </ProjectReference> @@ -59,4 +62,4 @@ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> -</Project> \ No newline at end of file +</Project> diff --git a/vs2012/xendisk/xendisk.vcxproj b/vs2012/xendisk/xendisk.vcxproj new file mode 100644 index 0000000..67a6ad7 --- /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> \ No newline at end of file diff --git a/vs2012/xendisk/xendisk.vcxproj.user b/vs2012/xendisk/xendisk.vcxproj.user new file mode 100644 index 0000000..4ecdd46 --- /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..71c2780 100644 --- a/vs2012/xenvbd.sln +++ b/vs2012/xenvbd.sln @@ -8,7 +8,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xenvbd", "xenvbd\xenvbd.vcx 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}" +EndProject ProjectSection(ProjectDependencies) = postProject {58F5BC43-B92E-4A2B-975D-0066EAB29092} = {58F5BC43-B92E-4A2B-975D-0066EAB29092} EndProjectSection @@ -16,6 +19,7 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "package\package.vcxproj", "{AB8DAED3-9D70-4907-99A3-C643F1FC1972}" ProjectSection(ProjectDependencies) = postProject {50C08437-C1F3-4349-BF6A-7B55A06BF999} = {50C08437-C1F3-4349-BF6A-7B55A06BF999} + {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD} = {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD} {58F5BC43-B92E-4A2B-975D-0066EAB29092} = {58F5BC43-B92E-4A2B-975D-0066EAB29092} {EF236371-3145-41B1-99C9-82B33E353F17} = {EF236371-3145-41B1-99C9-82B33E353F17} EndProjectSection @@ -36,8 +40,32 @@ 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.Build.0 = Windows 7 Debug|Win32 {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 {EF236371-3145-41B1-99C9-82B33E353F17}.Windows 7 Debug|x64.Build.0 = Windows 7 Debug|x64 {EF236371-3145-41B1-99C9-82B33E353F17}.Windows 7 Release|Win32.ActiveCfg = Windows 7 Release|Win32 diff --git a/vs2013/package/package.vcxproj b/vs2013/package/package.vcxproj index 5d0de4d..5001c61 100644 --- a/vs2013/package/package.vcxproj +++ b/vs2013/package/package.vcxproj @@ -77,6 +77,9 @@ <ProjectReference Include="..\xencrsh\xencrsh.vcxproj"> <Project>{58f5bc43-b92e-4a2b-975d-0066eab29092}</Project> </ProjectReference> + <ProjectReference Include="..\xendisk\xendisk.vcxproj"> + <Project>{d7411b2c-2c43-434d-9f56-e10a3d2f5bad}</Project> + </ProjectReference> <ProjectReference Include="..\xenvbd\xenvbd.vcxproj"> <Project>{ef236371-3145-41b1-99c9-82b33e353f17}</Project> </ProjectReference> @@ -88,4 +91,4 @@ <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> <ImportGroup Label="ExtensionTargets"> </ImportGroup> -</Project> \ No newline at end of file +</Project> diff --git a/vs2013/xendisk/xendisk.user b/vs2013/xendisk/xendisk.user new file mode 100644 index 0000000..c4b84e8 --- /dev/null +++ b/vs2013/xendisk/xendisk.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/xendisk/xendisk.vcxproj b/vs2013/xendisk/xendisk.vcxproj new file mode 100644 index 0000000..cdf3ad8 --- /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> \ No newline at end of file diff --git a/vs2013/xenvbd.sln b/vs2013/xenvbd.sln index 13128c5..60d9513 100644 --- a/vs2013/xenvbd.sln +++ b/vs2013/xenvbd.sln @@ -8,6 +8,8 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xenvbd", "xenvbd\xenvbd.vcx 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} @@ -16,6 +18,7 @@ EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "package", "package\package.vcxproj", "{AB8DAED3-9D70-4907-99A3-C643F1FC1972}" ProjectSection(ProjectDependencies) = postProject {50C08437-C1F3-4349-BF6A-7B55A06BF999} = {50C08437-C1F3-4349-BF6A-7B55A06BF999} + {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD} = {D7411B2C-2C43-434D-9F56-E10A3D2F5BAD} {58F5BC43-B92E-4A2B-975D-0066EAB29092} = {58F5BC43-B92E-4A2B-975D-0066EAB29092} {EF236371-3145-41B1-99C9-82B33E353F17} = {EF236371-3145-41B1-99C9-82B33E353F17} EndProjectSection @@ -36,6 +39,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 -- 2.1.0 _______________________________________________ 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 |