[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH v2] Implement device power state transitions.
Implement device power state transition boilerplate so that xenhid can release its interfaces before the system enters S3. Let hidclass handle other power types. Signed-off-by: Troy Crosley <troycrosley@xxxxxxxxx> --- src/xenhid/fdo.c | 290 +++++++++++++++++++++++++++++++++-- src/xenhid/names.h | 278 +++++++++++++++++++++++++++++++++ src/xenhid/thread.c | 228 +++++++++++++++++++++++++++ src/xenhid/thread.h | 75 +++++++++ vs2015/xenhid/xenhid.vcxproj | 1 + vs2017/xenhid/xenhid.vcxproj | 1 + vs2019/xenhid/xenhid.vcxproj | 1 + 7 files changed, 862 insertions(+), 12 deletions(-) create mode 100644 src/xenhid/names.h create mode 100644 src/xenhid/thread.c create mode 100644 src/xenhid/thread.h diff --git a/src/xenhid/fdo.c b/src/xenhid/fdo.c index 860c7bc..706fa33 100644 --- a/src/xenhid/fdo.c +++ b/src/xenhid/fdo.c @@ -41,10 +41,12 @@ #include <suspend_interface.h> #include "fdo.h" +#include "thread.h" #include "driver.h" #include "dbg_print.h" #include "assert.h" #include "util.h" +#include "names.h" #include "string.h" #define MAXNAMELEN 128 @@ -52,6 +54,9 @@ struct _XENHID_FDO { PDEVICE_OBJECT DeviceObject; PDEVICE_OBJECT LowerDeviceObject; + PXENHID_THREAD DevicePowerThread; + PIRP DevicePowerIrp; + DEVICE_POWER_STATE DevicePowerState; BOOLEAN Enabled; XENHID_HID_INTERFACE HidInterface; XENBUS_STORE_INTERFACE StoreInterface; @@ -220,6 +225,23 @@ __FdoFree( ExFreePoolWithTag(Buffer, FDO_POOL_TAG); } +static FORCEINLINE VOID +__FdoSetDevicePowerState( + IN PXENHID_FDO Fdo, + IN DEVICE_POWER_STATE State +) +{ + Fdo->DevicePowerState = State; +} + +static FORCEINLINE DEVICE_POWER_STATE +__FdoGetDevicePowerState( + IN PXENHID_FDO Fdo +) +{ + return Fdo->DevicePowerState; +} + static FORCEINLINE PANSI_STRING __FdoMultiSzToUpcaseAnsi( IN PCHAR Buffer @@ -588,6 +610,8 @@ FdoD3ToD0( { NTSTATUS status; + ASSERT3U(__FdoGetDevicePowerState(Fdo), ==, PowerDeviceD3); + Trace("=====>\n"); if (Fdo->Enabled) @@ -621,6 +645,7 @@ FdoD3ToD0( Fdo->Enabled = TRUE; done: + __FdoSetDevicePowerState(Fdo, PowerDeviceD0); Trace("<=====\n"); return STATUS_SUCCESS; @@ -659,6 +684,8 @@ FdoD0ToD3( { Trace("=====>\n"); + __FdoSetDevicePowerState(Fdo, PowerDeviceD3); + if (!Fdo->Enabled) goto done; @@ -868,6 +895,222 @@ FdoDispatchPnp( return status; } +static FORCEINLINE NTSTATUS +__FdoSetDevicePowerUp( + IN PXENHID_FDO Fdo, + IN PIRP Irp +) +{ + PIO_STACK_LOCATION StackLocation; + DEVICE_POWER_STATE DeviceState; + NTSTATUS status; + + Trace("====>\n"); + + StackLocation = IoGetCurrentIrpStackLocation(Irp); + DeviceState = StackLocation->Parameters.Power.State.DeviceState; + + ASSERT3U(DeviceState, < , __FdoGetDevicePowerState(Fdo)); + + status = FdoForwardIrpSynchronously(Fdo, Irp); + if (!NT_SUCCESS(status)) + goto done; + + Info("%s -> %s\n", + PowerDeviceStateName(__FdoGetDevicePowerState(Fdo)), + PowerDeviceStateName(DeviceState)); + + ASSERT3U(DeviceState, ==, PowerDeviceD0); + status = FdoD3ToD0(Fdo); + ASSERT(NT_SUCCESS(status)); + +done: + Irp->IoStatus.Status = status; + IoCompleteRequest(Irp, IO_NO_INCREMENT); + + Trace("<==== (%08x)\n", status); + return status; +} + +static FORCEINLINE NTSTATUS +__FdoSetDevicePowerDown( + IN PXENHID_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)); + + Info("%s -> %s\n", + PowerDeviceStateName(__FdoGetDevicePowerState(Fdo)), + PowerDeviceStateName(DeviceState)); + + ASSERT3U(DeviceState, ==, PowerDeviceD3); + + if (__FdoGetDevicePowerState(Fdo) == PowerDeviceD0) + FdoD0ToD3(Fdo); + + IoSkipCurrentIrpStackLocation(Irp); + status = IoCallDriver(Fdo->LowerDeviceObject, Irp); + + return status; +} + +static FORCEINLINE NTSTATUS +__FdoSetDevicePower( + IN PXENHID_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)); + + ASSERT3U(PowerAction, < , PowerActionShutdown); + + if (DeviceState == __FdoGetDevicePowerState(Fdo)) { + IoSkipCurrentIrpStackLocation(Irp); + status = IoCallDriver(Fdo->LowerDeviceObject, Irp); + + 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 NTSTATUS +FdoDevicePower( + IN PXENHID_THREAD Self, + IN PVOID Context +) +{ + PXENHID_FDO Fdo = (PXENHID_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; + + default: + ASSERT(FALSE); + break; + } + } + + return STATUS_SUCCESS; +} + +static DECLSPEC_NOINLINE NTSTATUS +FdoDispatchPower( + IN PXENHID_FDO Fdo, + IN PIRP Irp +) +{ + PIO_STACK_LOCATION StackLocation; + UCHAR MinorFunction; + POWER_STATE_TYPE PowerType; + POWER_ACTION PowerAction; + NTSTATUS status; + + StackLocation = IoGetCurrentIrpStackLocation(Irp); + MinorFunction = StackLocation->MinorFunction; + + if (MinorFunction != IRP_MN_SET_POWER) { + IoSkipCurrentIrpStackLocation(Irp); + status = IoCallDriver(Fdo->LowerDeviceObject, Irp); + + goto done; + } + + PowerType = StackLocation->Parameters.Power.Type; + PowerAction = StackLocation->Parameters.Power.ShutdownType; + + if (PowerAction >= PowerActionShutdown) { + IoSkipCurrentIrpStackLocation(Irp); + status = IoCallDriver(Fdo->LowerDeviceObject, Irp); + + goto done; + } + + switch (PowerType) { + case DevicePowerState: + IoMarkIrpPending(Irp); + + ASSERT3P(Fdo->DevicePowerIrp, ==, NULL); + Fdo->DevicePowerIrp = Irp; + KeMemoryBarrier(); + + ThreadWake(Fdo->DevicePowerThread); + + status = STATUS_PENDING; + break; + + case SystemPowerState: + default: + IoSkipCurrentIrpStackLocation(Irp); + status = IoCallDriver(Fdo->LowerDeviceObject, Irp); + break; + } + +done: + return status; +} + static DECLSPEC_NOINLINE NTSTATUS FdoDispatchInternal( IN PXENHID_FDO Fdo, @@ -1031,6 +1274,10 @@ FdoDispatch( status = FdoDispatchPnp(Fdo, Irp); break; + case IRP_MJ_POWER: + status = FdoDispatchPower(Fdo, Irp); + break; + default: status = FdoDispatchDefault(Fdo, Irp); break; @@ -1118,6 +1365,11 @@ FdoCreate( Fdo->DeviceObject = DeviceObject; Fdo->LowerDeviceObject = LowerDeviceObject; + Fdo->DevicePowerState = PowerDeviceD3; + + status = ThreadCreate(FdoDevicePower, Fdo, &Fdo->DevicePowerThread); + if (!NT_SUCCESS(status)) + goto fail1; InitializeListHead(&Fdo->List); KeInitializeSpinLock(&Fdo->Lock); @@ -1130,7 +1382,7 @@ FdoCreate( FdoCsqReleaseLock, FdoCsqCompleteCanceledIrp); if (!NT_SUCCESS(status)) - goto fail1; + goto fail2; status = FdoQueryInterface(Fdo, &GUID_XENBUS_SUSPEND_INTERFACE, @@ -1138,7 +1390,7 @@ FdoCreate( (PINTERFACE)&Fdo->SuspendInterface, sizeof(XENBUS_SUSPEND_INTERFACE)); if (!NT_SUCCESS(status)) - goto fail2; + goto fail3; status = FdoQueryInterface(Fdo, &GUID_XENBUS_STORE_INTERFACE, @@ -1146,7 +1398,7 @@ FdoCreate( (PINTERFACE)&Fdo->StoreInterface, sizeof(XENBUS_STORE_INTERFACE)); if (!NT_SUCCESS(status)) - goto fail3; + goto fail4; status = FdoQueryInterface(Fdo, &GUID_XENHID_HID_INTERFACE, @@ -1154,34 +1406,41 @@ FdoCreate( (PINTERFACE)&Fdo->HidInterface, sizeof(XENHID_HID_INTERFACE)); if (!NT_SUCCESS(status)) - goto fail4; + goto fail5; Trace("<=====\n"); return STATUS_SUCCESS; -fail4: - Error("fail4\n"); +fail5: + Error("fail5\n"); RtlZeroMemory(&Fdo->StoreInterface, sizeof(XENBUS_STORE_INTERFACE)); -fail3: - Error("fail3\n"); +fail4: + Error("fail4\n"); RtlZeroMemory(&Fdo->SuspendInterface, sizeof(XENBUS_SUSPEND_INTERFACE)); -fail2: - Error("fail2\n"); +fail3: + Error("fail3\n"); RtlZeroMemory(&Fdo->Queue, sizeof(IO_CSQ)); -fail1: - Error("fail1 %08x\n", status); +fail2: + Error("fail2 %08x\n", status); + + ThreadAlert(Fdo->DevicePowerThread); + ThreadJoin(Fdo->DevicePowerThread); + Fdo->DevicePowerThread = NULL; RtlZeroMemory(&Fdo->List, sizeof(LIST_ENTRY)); RtlZeroMemory(&Fdo->Lock, sizeof(KSPIN_LOCK)); +fail1: + Error("fail1 %08x\n", status); + Fdo->DeviceObject = NULL; Fdo->LowerDeviceObject = NULL; @@ -1202,6 +1461,13 @@ FdoDestroy( sizeof(XENBUS_SUSPEND_INTERFACE)); RtlZeroMemory(&Fdo->StoreInterface, sizeof(XENBUS_STORE_INTERFACE)); + + ThreadAlert(Fdo->DevicePowerThread); + ThreadJoin(Fdo->DevicePowerThread); + Fdo->DevicePowerThread = NULL; + Fdo->DevicePowerIrp = NULL; + Fdo->DevicePowerState = 0; + RtlZeroMemory(&Fdo->Queue, sizeof(IO_CSQ)); RtlZeroMemory(&Fdo->List, sizeof(LIST_ENTRY)); RtlZeroMemory(&Fdo->Lock, sizeof(KSPIN_LOCK)); diff --git a/src/xenhid/names.h b/src/xenhid/names.h new file mode 100644 index 0000000..39e0716 --- /dev/null +++ b/src/xenhid/names.h @@ -0,0 +1,278 @@ +/* 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 _XENHID_NAMES_H_ +#define _XENHID_NAMES_H_ + +#include <ntddk.h> + +#include "types.h" + +static FORCEINLINE const CHAR * +PowerTypeName( + IN POWER_STATE_TYPE Type + ) +{ +#define _POWER_TYPE_NAME(_Type) \ + case _Type: \ + return #_Type; + + switch (Type) { + _POWER_TYPE_NAME(SystemPowerState); + _POWER_TYPE_NAME(DevicePowerState); + default: + break; + } + + return ("UNKNOWN"); +#undef _POWER_ACTION_NAME +} + +static FORCEINLINE const CHAR * +PowerSystemStateName( + IN SYSTEM_POWER_STATE State + ) +{ +#define _POWER_SYSTEM_STATE_NAME(_State) \ + case PowerSystem ## _State: \ + return #_State; + + switch (State) { + _POWER_SYSTEM_STATE_NAME(Unspecified); + _POWER_SYSTEM_STATE_NAME(Working); + _POWER_SYSTEM_STATE_NAME(Sleeping1); + _POWER_SYSTEM_STATE_NAME(Sleeping2); + _POWER_SYSTEM_STATE_NAME(Sleeping3); + _POWER_SYSTEM_STATE_NAME(Hibernate); + _POWER_SYSTEM_STATE_NAME(Shutdown); + _POWER_SYSTEM_STATE_NAME(Maximum); + default: + break; + } + + return ("UNKNOWN"); +#undef _POWER_SYSTEM_STATE_NAME +} + +static FORCEINLINE const CHAR * +PowerDeviceStateName( + IN DEVICE_POWER_STATE State + ) +{ +#define _POWER_DEVICE_STATE_NAME(_State) \ + case PowerDevice ## _State: \ + return #_State; + + switch (State) { + _POWER_DEVICE_STATE_NAME(Unspecified); + _POWER_DEVICE_STATE_NAME(D0); + _POWER_DEVICE_STATE_NAME(D1); + _POWER_DEVICE_STATE_NAME(D2); + _POWER_DEVICE_STATE_NAME(D3); + _POWER_DEVICE_STATE_NAME(Maximum); + default: + break; + } + + return ("UNKNOWN"); +#undef _POWER_DEVICE_STATE_NAME +} + +static FORCEINLINE const CHAR * +PowerActionName( + IN POWER_ACTION Type + ) +{ +#define _POWER_ACTION_NAME(_Type) \ + case PowerAction ## _Type: \ + return #_Type; + + switch (Type) { + _POWER_ACTION_NAME(None); + _POWER_ACTION_NAME(Reserved); + _POWER_ACTION_NAME(Sleep); + _POWER_ACTION_NAME(Hibernate); + _POWER_ACTION_NAME(Shutdown); + _POWER_ACTION_NAME(ShutdownReset); + _POWER_ACTION_NAME(ShutdownOff); + _POWER_ACTION_NAME(WarmEject); + default: + break; + } + + return ("UNKNOWN"); +#undef _POWER_ACTION_NAME +} + +static FORCEINLINE const CHAR * +PowerMinorFunctionName( + IN ULONG MinorFunction + ) +{ +#define _POWER_MINOR_FUNCTION_NAME(_Function) \ + case IRP_MN_ ## _Function: \ + return #_Function; + + switch (MinorFunction) { + _POWER_MINOR_FUNCTION_NAME(WAIT_WAKE); + _POWER_MINOR_FUNCTION_NAME(POWER_SEQUENCE); + _POWER_MINOR_FUNCTION_NAME(SET_POWER); + _POWER_MINOR_FUNCTION_NAME(QUERY_POWER); + + default: + return "UNKNOWN"; + } + +#undef _POWER_MINOR_FUNCTION_NAME +} + +static FORCEINLINE const CHAR * +PnpDeviceStateName( + IN DEVICE_PNP_STATE State + ) +{ +#define _PNP_DEVICE_STATE_NAME(_State) \ + case _State: \ + return #_State; + + switch (State) { + _PNP_DEVICE_STATE_NAME(Invalid); + _PNP_DEVICE_STATE_NAME(Added); + _PNP_DEVICE_STATE_NAME(Started); + _PNP_DEVICE_STATE_NAME(StopPending); + _PNP_DEVICE_STATE_NAME(Stopped); + _PNP_DEVICE_STATE_NAME(RemovePending); + _PNP_DEVICE_STATE_NAME(SurpriseRemovePending); + _PNP_DEVICE_STATE_NAME(Deleted); + default: + break; + } + + return "UNKNOWN"; + +#undef _STATE_NAME +} + +static FORCEINLINE const CHAR * +PnpMinorFunctionName( + IN ULONG Function + ) +{ +#define _PNP_MINOR_FUNCTION_NAME(_Function) \ + case IRP_MN_ ## _Function: \ + return #_Function; + + switch (Function) { + _PNP_MINOR_FUNCTION_NAME(START_DEVICE); + _PNP_MINOR_FUNCTION_NAME(QUERY_REMOVE_DEVICE); + _PNP_MINOR_FUNCTION_NAME(REMOVE_DEVICE); + _PNP_MINOR_FUNCTION_NAME(CANCEL_REMOVE_DEVICE); + _PNP_MINOR_FUNCTION_NAME(STOP_DEVICE); + _PNP_MINOR_FUNCTION_NAME(QUERY_STOP_DEVICE); + _PNP_MINOR_FUNCTION_NAME(CANCEL_STOP_DEVICE); + _PNP_MINOR_FUNCTION_NAME(QUERY_DEVICE_RELATIONS); + _PNP_MINOR_FUNCTION_NAME(QUERY_INTERFACE); + _PNP_MINOR_FUNCTION_NAME(QUERY_CAPABILITIES); + _PNP_MINOR_FUNCTION_NAME(QUERY_RESOURCES); + _PNP_MINOR_FUNCTION_NAME(QUERY_RESOURCE_REQUIREMENTS); + _PNP_MINOR_FUNCTION_NAME(QUERY_DEVICE_TEXT); + _PNP_MINOR_FUNCTION_NAME(FILTER_RESOURCE_REQUIREMENTS); + _PNP_MINOR_FUNCTION_NAME(READ_CONFIG); + _PNP_MINOR_FUNCTION_NAME(WRITE_CONFIG); + _PNP_MINOR_FUNCTION_NAME(EJECT); + _PNP_MINOR_FUNCTION_NAME(SET_LOCK); + _PNP_MINOR_FUNCTION_NAME(QUERY_ID); + _PNP_MINOR_FUNCTION_NAME(QUERY_PNP_DEVICE_STATE); + _PNP_MINOR_FUNCTION_NAME(QUERY_BUS_INFORMATION); + _PNP_MINOR_FUNCTION_NAME(DEVICE_USAGE_NOTIFICATION); + _PNP_MINOR_FUNCTION_NAME(SURPRISE_REMOVAL); + _PNP_MINOR_FUNCTION_NAME(QUERY_LEGACY_BUS_INFORMATION); + default: + break; + } + + return "UNKNOWN"; + +#undef _PNP_MINOR_FUNCTION_NAME +} + +static FORCEINLINE const CHAR * +PartialResourceDescriptorTypeName( + IN UCHAR Type + ) +{ +#define _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(_Type) \ + case CmResourceType ## _Type: \ + return #_Type; + + switch (Type) { + _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(Null); + _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(Port); + _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(Interrupt); + _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(Memory); + _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(Dma); + _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(DeviceSpecific); + _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(BusNumber); + _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(MemoryLarge); + _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(ConfigData); + _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(DevicePrivate); + default: + break; + } + + return "UNKNOWN"; + +#undef _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME +} + +static FORCEINLINE const CHAR * +DeviceUsageTypeName( + IN DEVICE_USAGE_NOTIFICATION_TYPE Type + ) +{ +#define _DEVICE_USAGE_TYPE_NAME(_Type) \ + case DeviceUsageType ## _Type: \ + return #_Type; + + switch (Type) { + _DEVICE_USAGE_TYPE_NAME(Paging); + _DEVICE_USAGE_TYPE_NAME(Hibernation); + _DEVICE_USAGE_TYPE_NAME(DumpFile); + default: + break; + } + + return "UNKNOWN"; + +#undef _DEVICE_USAGE_TYPE_NAME +} + +#endif // _XENHID_NAMES_H_ diff --git a/src/xenhid/thread.c b/src/xenhid/thread.c new file mode 100644 index 0000000..cdfb976 --- /dev/null +++ b/src/xenhid/thread.c @@ -0,0 +1,228 @@ +/* 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 "util.h" +#include "dbg_print.h" +#include "assert.h" + +#define THREAD_POOL 'ERHT' + +struct _XENHID_THREAD { + XENHID_THREAD_FUNCTION Function; + PVOID Context; + KEVENT Event; + BOOLEAN Alerted; + LONG References; + PKTHREAD Thread; +}; + +static FORCEINLINE PVOID +__ThreadAllocate( + IN ULONG Length + ) +{ + return __AllocatePoolWithTag(NonPagedPool, Length, THREAD_POOL); +} + +static FORCEINLINE VOID +__ThreadFree( + IN PVOID Buffer + ) +{ + __FreePoolWithTag(Buffer, THREAD_POOL); +} + +static FORCEINLINE VOID +__ThreadWake( + IN PXENHID_THREAD Thread + ) +{ + KeSetEvent(&Thread->Event, IO_NO_INCREMENT, FALSE); +} + +VOID +ThreadWake( + IN PXENHID_THREAD Thread + ) +{ + __ThreadWake(Thread); +} + +static FORCEINLINE VOID +__ThreadAlert( + IN PXENHID_THREAD Thread + ) +{ + Thread->Alerted = TRUE; + __ThreadWake(Thread); +} + +VOID +ThreadAlert( + IN PXENHID_THREAD Thread + ) +{ + __ThreadAlert(Thread); +} + +KSTART_ROUTINE ThreadFunction; + +VOID +ThreadFunction( + IN PVOID Argument + ) +{ + PXENHID_THREAD Self = Argument; + NTSTATUS status; + + status = Self->Function(Self, Self->Context); + + if (InterlockedDecrement(&Self->References) == 0) + __ThreadFree(Self); + + PsTerminateSystemThread(status); + // NOT REACHED +} + +__drv_requiresIRQL(PASSIVE_LEVEL) +NTSTATUS +ThreadCreate( + IN XENHID_THREAD_FUNCTION Function, + IN PVOID Context, + OUT PXENHID_THREAD *Thread + ) +{ + HANDLE Handle; + NTSTATUS status; + + ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL); + + (*Thread) = __ThreadAllocate(sizeof (XENHID_THREAD)); + + Warning("Create thread %p %p\n", Function, 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 PXENHID_THREAD Thread + ) +{ + return &Thread->Event; +} + +BOOLEAN +ThreadIsAlerted( + IN PXENHID_THREAD Thread + ) +{ + return Thread->Alerted; +} + +VOID +ThreadJoin( + IN PXENHID_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/xenhid/thread.h b/src/xenhid/thread.h new file mode 100644 index 0000000..30369c0 --- /dev/null +++ b/src/xenhid/thread.h @@ -0,0 +1,75 @@ +/* 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 _XENHID_THREAD_H +#define _XENHID_THREAD_H + +#include <ntddk.h> + +typedef struct _XENHID_THREAD XENHID_THREAD, *PXENHID_THREAD; + +typedef NTSTATUS (*XENHID_THREAD_FUNCTION)(PXENHID_THREAD, PVOID); + +__drv_requiresIRQL(PASSIVE_LEVEL) +extern NTSTATUS +ThreadCreate( + IN XENHID_THREAD_FUNCTION Function, + IN PVOID Context, + OUT PXENHID_THREAD *Thread + ); + +extern PKEVENT +ThreadGetEvent( + IN PXENHID_THREAD Self + ); + +extern BOOLEAN +ThreadIsAlerted( + IN PXENHID_THREAD Self + ); + +extern VOID +ThreadWake( + IN PXENHID_THREAD Thread + ); + +extern VOID +ThreadAlert( + IN PXENHID_THREAD Thread + ); + +extern VOID +ThreadJoin( + IN PXENHID_THREAD Thread + ); + +#endif // _XENHID_THREAD_H + diff --git a/vs2015/xenhid/xenhid.vcxproj b/vs2015/xenhid/xenhid.vcxproj index 35ba30f..e15b581 100644 --- a/vs2015/xenhid/xenhid.vcxproj +++ b/vs2015/xenhid/xenhid.vcxproj @@ -53,6 +53,7 @@ <ItemGroup> <ClCompile Include="../../src/xenhid/driver.c" /> <ClCompile Include="../../src/xenhid/fdo.c" /> + <ClCompile Include="../../src/xenhid/thread.c" /> <ClCompile Include="../../src/xenhid/string.c" /> </ItemGroup> <ItemGroup> diff --git a/vs2017/xenhid/xenhid.vcxproj b/vs2017/xenhid/xenhid.vcxproj index a113120..3ecd8d9 100644 --- a/vs2017/xenhid/xenhid.vcxproj +++ b/vs2017/xenhid/xenhid.vcxproj @@ -61,6 +61,7 @@ <ItemGroup> <ClCompile Include="../../src/xenhid/driver.c" /> <ClCompile Include="../../src/xenhid/fdo.c" /> + <ClCompile Include="../../src/xenhid/thread.c" /> <ClCompile Include="../../src/xenhid/string.c" /> </ItemGroup> <ItemGroup> diff --git a/vs2019/xenhid/xenhid.vcxproj b/vs2019/xenhid/xenhid.vcxproj index 996df2c..4573a59 100644 --- a/vs2019/xenhid/xenhid.vcxproj +++ b/vs2019/xenhid/xenhid.vcxproj @@ -61,6 +61,7 @@ <ItemGroup> <ClCompile Include="../../src/xenhid/driver.c" /> <ClCompile Include="../../src/xenhid/fdo.c" /> + <ClCompile Include="../../src/xenhid/thread.c" /> <ClCompile Include="../../src/xenhid/string.c" /> </ItemGroup> <ItemGroup> -- 2.20.1
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |