--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+/*! \file console_interface.h
+ \brief XENBUS CONSOLE Interface
+
+ This interface provides access to XenConsole
+*/
+
+#ifndef _XENBUS_CONSOLE_INTERFACE_H
+#define _XENBUS_CONSOLE_INTERFACE_H
+
+#ifndef _WINDLL
+
+/*! \typedef XENBUS_CONSOLE_WAKEUP
+ \brief XenStore watch handle
+*/
+typedef struct _XENBUS_CONSOLE_WAKEUP XENBUS_CONSOLE_WAKEUP, *PXENBUS_CONSOLE_WAKEUP;
+
+/*! \typedef XENBUS_CONSOLE_ACQUIRE
+ \brief Acquire a reference to the CONSOLE interface
+
+ \param Interface The interface header
+*/
+typedef NTSTATUS
+(*XENBUS_CONSOLE_ACQUIRE)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENBUS_CONSOLE_RELEASE
+ \brief Release a reference to the CONSOLE interface
+
+ \param Interface The interface header
+*/
+typedef VOID
+(*XENBUS_CONSOLE_RELEASE)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENBUS_CONSOLE_CAN_READ
+ \brief Get characters from the console
+
+ \param Interface The interface header
+
+ \return A boolean which is true if there is data to read
+*/
+typedef BOOLEAN
+(*XENBUS_CONSOLE_CAN_READ)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENBUS_CONSOLE_READ
+ \brief Get characters from the console
+
+ \param Interface The interface header
+ \param Buffer A character buffer
+ \param Length The length of the buffer
+
+ \return The number of characters read
+*/
+typedef ULONG
+(*XENBUS_CONSOLE_READ)(
+ IN PINTERFACE Interface,
+ IN PCHAR Data,
+ IN ULONG Length
+ );
+
+/*! \typedef XENBUS_CONSOLE_CAN_WRITE
+ \brief Get characters from the console
+
+ \param Interface The interface header
+
+ \return A boolean which is true if there is space to write
+*/
+typedef BOOLEAN
+(*XENBUS_CONSOLE_CAN_WRITE)(
+ IN PINTERFACE Interface
+ );
+
+/*! \typedef XENBUS_CONSOLE_WRITE
+ \brief Send characters to the console
+
+ \param Interface The interface header
+ \param Buffer A character buffer
+ \param Length The length of the buffer
+
+ \return The number of characters written
+*/
+typedef ULONG
+(*XENBUS_CONSOLE_WRITE)(
+ IN PINTERFACE Interface,
+ IN PCHAR Data,
+ IN ULONG Length
+ );
+
+/*! \typedef XENBUS_CONSOLE_WAKEUP_ADD
+ \brief Add a wakeup item
+
+ \param Interface The interface header
+ \param Event A pointer to an event object to be signalled when there
+ is activity on the rings
+ \param Wakeup A pointer to a wakeup handle to be initialized
+*/
+typedef NTSTATUS
+(*XENBUS_CONSOLE_WAKEUP_ADD)(
+ IN PINTERFACE Interface,
+ IN PKEVENT Event,
+ OUT PXENBUS_CONSOLE_WAKEUP *Wakeup
+ );
+
+/*! \typedef XENBUS_CONSOLE_WAKEUP_REMOVE
+ \brief Remove a wakeup item
+
+ \param Interface The interface header
+ \param Wakeup The wakeup handle
+*/
+typedef VOID
+(*XENBUS_CONSOLE_WAKEUP_REMOVE)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_CONSOLE_WAKEUP Wakeup
+ );
+
+// {04c4f738-034a-4268-bd20-a92ac90d4f82}
+DEFINE_GUID(GUID_XENBUS_CONSOLE_INTERFACE,
+0x04c4f738, 0x034a, 0x4268, 0xbd, 0x20, 0xa9, 0x2a, 0xc9, 0x0d, 0x4f, 0x82);
+
+/*! \struct _XENBUS_CONSOLE_INTERFACE_V1
+ \brief CONSOLE interface version 1
+ \ingroup interfaces
+*/
+struct _XENBUS_CONSOLE_INTERFACE_V1 {
+ INTERFACE Interface;
+ XENBUS_CONSOLE_ACQUIRE ConsoleAcquire;
+ XENBUS_CONSOLE_RELEASE ConsoleRelease;
+ XENBUS_CONSOLE_CAN_READ ConsoleCanRead;
+ XENBUS_CONSOLE_READ ConsoleRead;
+ XENBUS_CONSOLE_CAN_WRITE ConsoleCanWrite;
+ XENBUS_CONSOLE_WRITE ConsoleWrite;
+ XENBUS_CONSOLE_WAKEUP_ADD ConsoleWakeupAdd;
+ XENBUS_CONSOLE_WAKEUP_REMOVE ConsoleWakeupRemove;
+};
+
+typedef struct _XENBUS_CONSOLE_INTERFACE_V1 XENBUS_CONSOLE_INTERFACE, *PXENBUS_CONSOLE_INTERFACE;
+
+/*! \def XENBUS_CONSOLE
+ \brief Macro at assist in method invocation
+*/
+#define XENBUS_CONSOLE(_Method, _Interface, ...) \
+ (_Interface)->Console ## _Method((PINTERFACE)(_Interface), __VA_ARGS__)
+
+#endif // _WINDLL
+
+#define XENBUS_CONSOLE_INTERFACE_VERSION_MIN 1
+#define XENBUS_CONSOLE_INTERFACE_VERSION_MAX 1
+
+#endif // _XENBUS_CONSOLE_INTERFACE_H
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _XENCONS_DEVICE_H
+#define _XENCONS_DEVICE_H
+
+// {0D3EDD21-8EF9-4DFF-856C-8C68BF4FDCA3}
+DEFINE_GUID(GUID_XENCONS_DEVICE,
+ 0xd3edd21, 0x8ef9, 0x4dff, 0x85, 0x6c, 0x8c, 0x68, 0xbf, 0x4f, 0xdc, 0xa3);
+
+#endif // _XENCONS_DEVICE_H
PDEVICE_OBJECT DeviceObject;
DEVICE_OBJECT_TYPE Type;
+ UNICODE_STRING Link;
+
DEVICE_PNP_STATE DevicePnpState;
DEVICE_PNP_STATE PreviousDevicePnpState;
#include <ntddk.h>
#include <wdmguid.h>
+#include <wdmsec.h>
#include <ntstrsafe.h>
#include <stdlib.h>
#include <debug_interface.h>
#include <suspend_interface.h>
#include <store_interface.h>
+#include <console_interface.h>
+#include <xencons_device.h>
#include <version.h>
#include "driver.h"
#include "registry.h"
#include "fdo.h"
+#include "stream.h"
#include "thread.h"
#include "names.h"
#include "dbg_print.h"
CM_PARTIAL_RESOURCE_DESCRIPTOR Translated;
} FDO_RESOURCE, *PFDO_RESOURCE;
+typedef struct _FDO_HANDLE {
+ LIST_ENTRY ListEntry;
+ PFILE_OBJECT FileObject;
+ PXENCONS_STREAM Stream;
+} FDO_HANDLE, *PFDO_HANDLE;
+
struct _XENCONS_FDO {
PXENCONS_DX Dx;
PDEVICE_OBJECT LowerDeviceObject;
FDO_RESOURCE Resource[RESOURCE_COUNT];
+ LIST_ENTRY HandleList;
+ KSPIN_LOCK HandleLock;
+
XENBUS_DEBUG_INTERFACE DebugInterface;
XENBUS_SUSPEND_INTERFACE SuspendInterface;
XENBUS_STORE_INTERFACE StoreInterface;
+ XENBUS_CONSOLE_INTERFACE ConsoleInterface;
PXENBUS_SUSPEND_CALLBACK SuspendCallbackLate;
};
IN PXENCONS_FDO Fdo
)
{
+ PXENCONS_DX Dx = Fdo->Dx;
POWER_STATE PowerState;
KIRQL Irql;
NTSTATUS status;
DevicePowerState,
PowerState);
+#pragma prefast(suppress:28123)
+ (VOID) IoSetDeviceInterfaceState(&Dx->Link, TRUE);
+
Trace("<====\n");
return STATUS_SUCCESS;
fail3:
- Error("fail3\n");
+ Error("fail4\n");
__FdoD0ToD3(Fdo);
IN PXENCONS_FDO Fdo
)
{
+ PXENCONS_DX Dx = Fdo->Dx;
POWER_STATE PowerState;
KIRQL Irql;
Trace("====>\n");
+#pragma prefast(suppress:28123)
+ (VOID) IoSetDeviceInterfaceState(&Dx->Link, FALSE);
+
PowerState.DeviceState = PowerDeviceD3;
PoSetPowerState(Fdo->Dx->DeviceObject,
DevicePowerState,
return status;
}
+static NTSTATUS
+FdoCreateHandle(
+ IN PXENCONS_FDO Fdo,
+ IN PFILE_OBJECT FileObject
+ )
+{
+ PFDO_HANDLE Handle;
+ KIRQL Irql;
+ NTSTATUS status;
+
+ Handle = __FdoAllocate(sizeof (FDO_HANDLE));
+
+ status = STATUS_NO_MEMORY;
+ if (Handle == NULL)
+ goto fail1;
+
+ status = StreamCreate(Fdo, &Handle->Stream);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ Handle->FileObject = FileObject;
+
+ KeAcquireSpinLock(&Fdo->HandleLock, &Irql);
+ InsertTailList(&Fdo->HandleList, &Handle->ListEntry);
+ KeReleaseSpinLock(&Fdo->HandleLock, Irql);
+
+ Trace("%p\n", Handle->FileObject);
+
+ return STATUS_SUCCESS;
+
+fail2:
+ Error("fail2\n");
+
+ ASSERT(IsZeroMemory(Handle, sizeof (FDO_HANDLE)));
+ __FdoFree(Handle);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+static PFDO_HANDLE
+FdoFindHandle(
+ IN PXENCONS_FDO Fdo,
+ IN PFILE_OBJECT FileObject
+ )
+{
+ KIRQL Irql;
+ PLIST_ENTRY ListEntry;
+ PFDO_HANDLE Handle;
+ NTSTATUS status;
+
+ KeAcquireSpinLock(&Fdo->HandleLock, &Irql);
+
+ for (ListEntry = Fdo->HandleList.Flink;
+ ListEntry != &Fdo->HandleList;
+ ListEntry = ListEntry->Flink) {
+ Handle = CONTAINING_RECORD(ListEntry,
+ FDO_HANDLE,
+ ListEntry);
+
+ if (Handle->FileObject == FileObject)
+ goto found;
+ }
+
+ status = STATUS_UNSUCCESSFUL;
+ goto fail1;
+
+found:
+ KeReleaseSpinLock(&Fdo->HandleLock, Irql);
+
+ return Handle;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ KeReleaseSpinLock(&Fdo->HandleLock, Irql);
+
+ return NULL;
+}
+
+static VOID
+FdoDestroyHandle(
+ IN PXENCONS_FDO Fdo,
+ IN PFDO_HANDLE Handle
+ )
+{
+ KIRQL Irql;
+
+ KeAcquireSpinLock(&Fdo->HandleLock, &Irql);
+ RemoveEntryList(&Handle->ListEntry);
+ KeReleaseSpinLock(&Fdo->HandleLock, Irql);
+
+ RtlZeroMemory(&Handle->ListEntry, sizeof (LIST_ENTRY));
+
+ Trace("%p\n", Handle->FileObject);
+
+ StreamDestroy(Handle->Stream);
+ Handle->Stream = NULL;
+
+ Handle->FileObject = NULL;
+
+ ASSERT(IsZeroMemory(Handle, sizeof (FDO_HANDLE)));
+ __FdoFree(Handle);
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoDispatchCreate(
+ IN PXENCONS_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+ status = FdoCreateHandle(Fdo, StackLocation->FileObject);
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoDispatchCleanup(
+ IN PXENCONS_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ PFDO_HANDLE Handle;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+ Handle = FdoFindHandle(Fdo, StackLocation->FileObject);
+
+ status = STATUS_UNSUCCESSFUL;
+ if (Handle == NULL)
+ goto fail1;
+
+ FdoDestroyHandle(Fdo, Handle);
+ status = STATUS_SUCCESS;
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoDispatchClose(
+ IN PXENCONS_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER(Fdo);
+
+ status = STATUS_SUCCESS;
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
+static DECLSPEC_NOINLINE NTSTATUS
+FdoDispatchReadWrite(
+ IN PXENCONS_FDO Fdo,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ PFDO_HANDLE Handle;
+ NTSTATUS status;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+ Handle = FdoFindHandle(Fdo, StackLocation->FileObject);
+
+ status = STATUS_UNSUCCESSFUL;
+ if (Handle == NULL)
+ goto fail1;
+
+ IoMarkIrpPending(Irp);
+
+ status = StreamPutQueue(Handle->Stream, Irp);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ return STATUS_PENDING;
+
+fail2:
+ Error("fail2\n");
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ Irp->IoStatus.Status = status;
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+ return status;
+}
+
static DECLSPEC_NOINLINE NTSTATUS
FdoDispatchDefault(
IN PXENCONS_FDO Fdo,
)
{
PIO_STACK_LOCATION StackLocation;
+ UCHAR MajorFunction;
NTSTATUS status;
StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ MajorFunction = StackLocation->MajorFunction;
+
+ Trace("====> (%02x:%s)\n",
+ MajorFunction,
+ MajorFunctionName(MajorFunction));
- switch (StackLocation->MajorFunction) {
+ switch (MajorFunction) {
case IRP_MJ_PNP:
status = FdoDispatchPnp(Fdo, Irp);
break;
status = FdoDispatchPower(Fdo, Irp);
break;
+ case IRP_MJ_CREATE:
+ status = FdoDispatchCreate(Fdo, Irp);
+ break;
+
+ case IRP_MJ_CLEANUP:
+ status = FdoDispatchCleanup(Fdo, Irp);
+ break;
+
+ case IRP_MJ_CLOSE:
+ status = FdoDispatchClose(Fdo, Irp);
+ break;
+
+ case IRP_MJ_READ:
+ case IRP_MJ_WRITE:
+ status = FdoDispatchReadWrite(Fdo, Irp);
+ break;
+
default:
status = FdoDispatchDefault(Fdo, Irp);
break;
}
+ Trace("<==== (%02x:%s)(%08x)\n",
+ MajorFunction,
+ MajorFunctionName(MajorFunction),
+ status);
+
return status;
}
DEFINE_FDO_GET_INTERFACE(Debug, PXENBUS_DEBUG_INTERFACE)
DEFINE_FDO_GET_INTERFACE(Suspend, PXENBUS_SUSPEND_INTERFACE)
DEFINE_FDO_GET_INTERFACE(Store, PXENBUS_STORE_INTERFACE)
+DEFINE_FDO_GET_INTERFACE(Console, PXENBUS_CONSOLE_INTERFACE)
NTSTATUS
FdoCreate(
Dx = (PXENCONS_DX)FunctionDeviceObject->DeviceExtension;
RtlZeroMemory(Dx, sizeof (XENCONS_DX));
+ status = IoRegisterDeviceInterface(PhysicalDeviceObject,
+ &GUID_XENCONS_DEVICE,
+ NULL,
+ &Dx->Link);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
Dx->Type = FUNCTION_DEVICE_OBJECT;
Dx->DeviceObject = FunctionDeviceObject;
Dx->DevicePnpState = Added;
status = STATUS_NO_MEMORY;
if (Fdo == NULL)
- goto fail2;
+ goto fail3;
Fdo->Dx = Dx;
Fdo->PhysicalDeviceObject = PhysicalDeviceObject;
status = ThreadCreate(FdoSystemPower, Fdo, &Fdo->SystemPowerThread);
if (!NT_SUCCESS(status))
- goto fail3;
+ goto fail4;
status = ThreadCreate(FdoDevicePower, Fdo, &Fdo->DevicePowerThread);
if (!NT_SUCCESS(status))
- goto fail4;
+ goto fail5;
status = __FdoAcquireLowerBusInterface(Fdo);
if (!NT_SUCCESS(status))
- goto fail5;
+ goto fail6;
if (FdoGetBusData(Fdo,
PCI_WHICHSPACE_CONFIG,
&DeviceID,
FIELD_OFFSET(PCI_COMMON_HEADER, DeviceID),
FIELD_SIZE(PCI_COMMON_HEADER, DeviceID)) == 0)
- goto fail6;
+ goto fail7;
__FdoSetVendorName(Fdo, DeviceID);
sizeof (Fdo->DebugInterface),
FALSE);
if (!NT_SUCCESS(status))
- goto fail7;
+ goto fail8;
status = FDO_QUERY_INTERFACE(Fdo,
XENBUS,
sizeof (Fdo->SuspendInterface),
FALSE);
if (!NT_SUCCESS(status))
- goto fail8;
+ goto fail9;
status = FDO_QUERY_INTERFACE(Fdo,
XENBUS,
sizeof (Fdo->StoreInterface),
FALSE);
if (!NT_SUCCESS(status))
- goto fail9;
+ goto fail10;
+
+ status = FDO_QUERY_INTERFACE(Fdo,
+ XENBUS,
+ CONSOLE,
+ (PINTERFACE)&Fdo->ConsoleInterface,
+ sizeof (Fdo->ConsoleInterface),
+ FALSE);
+ if (!NT_SUCCESS(status))
+ goto fail11;
+
+ InitializeListHead(&Fdo->HandleList);
+ KeInitializeSpinLock(&Fdo->HandleLock);
+
+ FunctionDeviceObject->Flags |= DO_BUFFERED_IO;
Dx->Fdo = Fdo;
FunctionDeviceObject->Flags &= ~DO_DEVICE_INITIALIZING;
return STATUS_SUCCESS;
-fail9:
- Error("fail9\n");
+fail11:
+ Error("fail11\n");
+
+ RtlZeroMemory(&Fdo->ConsoleInterface,
+ sizeof (XENBUS_CONSOLE_INTERFACE));
+
+fail10:
+ Error("fail10\n");
RtlZeroMemory(&Fdo->SuspendInterface,
sizeof (XENBUS_SUSPEND_INTERFACE));
-fail8:
- Error("fail8\n");
+fail9:
+ Error("fail9\n");
RtlZeroMemory(&Fdo->DebugInterface,
sizeof (XENBUS_DEBUG_INTERFACE));
-fail7:
- Error("fail7\n");
+fail8:
+ Error("fail8\n");
RtlZeroMemory(Fdo->VendorName, MAXNAMELEN);
-fail6:
- Error("fail6\n");
+fail7:
+ Error("fail7\n");
__FdoReleaseLowerBusInterface(Fdo);
-fail5:
- Error("fail5\n");
+fail6:
+ Error("fail6\n");
ThreadAlert(Fdo->DevicePowerThread);
ThreadJoin(Fdo->DevicePowerThread);
Fdo->DevicePowerThread = NULL;
-fail4:
- Error("fail4\n");
+fail5:
+ Error("fail5\n");
ThreadAlert(Fdo->SystemPowerThread);
ThreadJoin(Fdo->SystemPowerThread);
Fdo->SystemPowerThread = NULL;
-fail3:
- Error("fail3\n");
+fail4:
+ Error("fail4\n");
#pragma prefast(suppress:28183) // Fdo->LowerDeviceObject could be NULL
IoDetachDevice(Fdo->LowerDeviceObject);
ASSERT(IsZeroMemory(Fdo, sizeof (XENCONS_FDO)));
__FdoFree(Fdo);
+fail3:
+ Error("fail3\n");
+
+ RtlFreeUnicodeString(&Dx->Link);
+
fail2:
Error("fail2\n");
Dx->Fdo = NULL;
+ RtlZeroMemory(&Fdo->HandleLock, sizeof (KSPIN_LOCK));
+
+ ASSERT(IsListEmpty(&Fdo->HandleList));
+ RtlZeroMemory(&Fdo->HandleList, sizeof (LIST_ENTRY));
+
+ RtlZeroMemory(&Fdo->ConsoleInterface,
+ sizeof (XENBUS_CONSOLE_INTERFACE));
+
RtlZeroMemory(&Fdo->StoreInterface,
sizeof (XENBUS_STORE_INTERFACE));
ASSERT(IsZeroMemory(Fdo, sizeof (XENCONS_FDO)));
__FdoFree(Fdo);
+ RtlFreeUnicodeString(&Dx->Link);
+
IoDeleteDevice(FunctionDeviceObject);
}
#include <ntddk.h>
#include <debug_interface.h>
#include <suspend_interface.h>
+#include <store_interface.h>
+#include <console_interface.h>
#include "driver.h"
IN PIRP Irp
);
+#define DECLARE_FDO_GET_INTERFACE(_Interface, _Type) \
+extern VOID \
+FdoGet ## _Interface ## Interface( \
+ IN PXENCONS_FDO Fdo, \
+ OUT _Type _Interface ## Interface \
+ );
+
+DECLARE_FDO_GET_INTERFACE(Debug, PXENBUS_DEBUG_INTERFACE)
+DECLARE_FDO_GET_INTERFACE(Suspend, PXENBUS_SUSPEND_INTERFACE)
+DECLARE_FDO_GET_INTERFACE(Store, PXENBUS_STORE_INTERFACE)
+DECLARE_FDO_GET_INTERFACE(Console, PXENBUS_CONSOLE_INTERFACE)
+
extern NTSTATUS
FdoCreate(
IN PDEVICE_OBJECT PhysicalDeviceObject
#undef _DEVICE_USAGE_TYPE_NAME
}
+static FORCEINLINE const CHAR *
+MajorFunctionName(
+ IN ULONG Function
+ )
+{
+#define _MAJOR_FUNCTION_NAME(_Function) \
+ case IRP_MJ_ ## _Function: \
+ return #_Function;
+
+ switch (Function) {
+ _MAJOR_FUNCTION_NAME(CREATE);
+ _MAJOR_FUNCTION_NAME(CREATE_NAMED_PIPE);
+ _MAJOR_FUNCTION_NAME(CLOSE);
+ _MAJOR_FUNCTION_NAME(READ);
+ _MAJOR_FUNCTION_NAME(WRITE);
+ _MAJOR_FUNCTION_NAME(QUERY_INFORMATION);
+ _MAJOR_FUNCTION_NAME(SET_INFORMATION);
+ _MAJOR_FUNCTION_NAME(QUERY_EA);
+ _MAJOR_FUNCTION_NAME(SET_EA);
+ _MAJOR_FUNCTION_NAME(FLUSH_BUFFERS);
+ _MAJOR_FUNCTION_NAME(QUERY_VOLUME_INFORMATION);
+ _MAJOR_FUNCTION_NAME(SET_VOLUME_INFORMATION);
+ _MAJOR_FUNCTION_NAME(DIRECTORY_CONTROL);
+ _MAJOR_FUNCTION_NAME(FILE_SYSTEM_CONTROL);
+ _MAJOR_FUNCTION_NAME(DEVICE_CONTROL);
+ _MAJOR_FUNCTION_NAME(INTERNAL_DEVICE_CONTROL);
+ _MAJOR_FUNCTION_NAME(SHUTDOWN);
+ _MAJOR_FUNCTION_NAME(LOCK_CONTROL);
+ _MAJOR_FUNCTION_NAME(CLEANUP);
+ _MAJOR_FUNCTION_NAME(CREATE_MAILSLOT);
+ _MAJOR_FUNCTION_NAME(QUERY_SECURITY);
+ _MAJOR_FUNCTION_NAME(SET_SECURITY);
+ _MAJOR_FUNCTION_NAME(POWER);
+ _MAJOR_FUNCTION_NAME(SYSTEM_CONTROL);
+ _MAJOR_FUNCTION_NAME(DEVICE_CHANGE);
+ _MAJOR_FUNCTION_NAME(QUERY_QUOTA);
+ _MAJOR_FUNCTION_NAME(SET_QUOTA);
+ _MAJOR_FUNCTION_NAME(PNP);
+ default:
+ break;
+ }
+
+ return "UNKNOWN";
+
+#undef _MAJOR_FUNCTION_NAME
+}
+
#endif // _XENCONS_NAMES_H_
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <ntddk.h>
+
+#include "fdo.h"
+#include "stream.h"
+#include "thread.h"
+#include "names.h"
+#include "dbg_print.h"
+#include "assert.h"
+#include "util.h"
+
+#define STREAM_POOL 'ETRS'
+
+struct _XENCONS_STREAM {
+ PXENCONS_FDO Fdo;
+ PXENCONS_THREAD Thread;
+ IO_CSQ Csq;
+ LIST_ENTRY List;
+ KSPIN_LOCK Lock;
+ XENBUS_CONSOLE_INTERFACE ConsoleInterface;
+};
+
+static FORCEINLINE PVOID
+__StreamAllocate(
+ IN ULONG Length
+ )
+{
+ return __AllocatePoolWithTag(NonPagedPool, Length, STREAM_POOL);
+}
+
+static FORCEINLINE VOID
+__StreamFree(
+ IN PVOID Buffer
+ )
+{
+ __FreePoolWithTag(Buffer, STREAM_POOL);
+}
+
+IO_CSQ_INSERT_IRP_EX StreamCsqInsertIrpEx;
+
+NTSTATUS
+StreamCsqInsertIrpEx(
+ IN PIO_CSQ Csq,
+ IN PIRP Irp,
+ IN PVOID InsertContext OPTIONAL
+ )
+{
+ BOOLEAN ReInsert = (BOOLEAN)(ULONG_PTR)InsertContext;
+ PXENCONS_STREAM Stream;
+
+ Stream = CONTAINING_RECORD(Csq, XENCONS_STREAM, Csq);
+
+ if (ReInsert) {
+ // This only occurs if the worker thread de-queued the IRP but
+ // then found the console to be blocked.
+ InsertHeadList(&Stream->List, &Irp->Tail.Overlay.ListEntry);
+ } else {
+ InsertTailList(&Stream->List, &Irp->Tail.Overlay.ListEntry);
+ ThreadWake(Stream->Thread);
+ }
+
+ return STATUS_SUCCESS;
+}
+
+IO_CSQ_REMOVE_IRP StreamCsqRemoveIrp;
+
+VOID
+StreamCsqRemoveIrp(
+ IN PIO_CSQ Csq,
+ IN PIRP Irp
+ )
+{
+ UNREFERENCED_PARAMETER(Csq);
+
+ RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
+}
+
+IO_CSQ_PEEK_NEXT_IRP StreamCsqPeekNextIrp;
+
+PIRP
+StreamCsqPeekNextIrp(
+ IN PIO_CSQ Csq,
+ IN PIRP Irp,
+ IN PVOID PeekContext OPTIONAL
+ )
+{
+ PXENCONS_STREAM Stream;
+ PLIST_ENTRY ListEntry;
+ PIRP NextIrp;
+
+ UNREFERENCED_PARAMETER(PeekContext);
+
+ Stream = CONTAINING_RECORD(Csq, XENCONS_STREAM, Csq);
+
+ ListEntry = (Irp == NULL) ?
+ Stream->List.Flink :
+ Irp->Tail.Overlay.ListEntry.Flink;
+
+ if (ListEntry == &Stream->List)
+ return NULL;
+
+ NextIrp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.ListEntry);
+
+ return NextIrp;
+}
+
+#pragma warning(push)
+#pragma warning(disable:28167) // function changes IRQL
+
+IO_CSQ_ACQUIRE_LOCK StreamCsqAcquireLock;
+
+VOID
+StreamCsqAcquireLock(
+ IN PIO_CSQ Csq,
+ OUT PKIRQL Irql
+ )
+{
+ PXENCONS_STREAM Stream;
+
+ Stream = CONTAINING_RECORD(Csq, XENCONS_STREAM, Csq);
+
+ KeAcquireSpinLock(&Stream->Lock, Irql);
+}
+
+IO_CSQ_RELEASE_LOCK StreamCsqReleaseLock;
+
+VOID
+StreamCsqReleaseLock(
+ IN PIO_CSQ Csq,
+ IN KIRQL Irql
+ )
+{
+ PXENCONS_STREAM Stream;
+
+ Stream = CONTAINING_RECORD(Csq, XENCONS_STREAM, Csq);
+
+ KeReleaseSpinLock(&Stream->Lock, Irql);
+}
+
+#pragma warning(pop)
+
+IO_CSQ_COMPLETE_CANCELED_IRP StreamCsqCompleteCanceledIrp;
+
+VOID
+StreamCsqCompleteCanceledIrp(
+ IN PIO_CSQ Csq,
+ IN PIRP Irp
+ )
+{
+ PIO_STACK_LOCATION StackLocation;
+ UCHAR MajorFunction;
+
+ UNREFERENCED_PARAMETER(Csq);
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ MajorFunction = StackLocation->MajorFunction;
+
+ Irp->IoStatus.Information = 0;
+ Irp->IoStatus.Status = STATUS_CANCELLED;
+
+ Trace("COMPLETE (%02x:%s)\n",
+ MajorFunction,
+ MajorFunctionName(MajorFunction));
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+}
+
+static NTSTATUS
+StreamWorker(
+ IN PXENCONS_THREAD Self,
+ IN PVOID Context
+ )
+{
+ PXENCONS_STREAM Stream = Context;
+ PKEVENT Event;
+ PXENBUS_CONSOLE_WAKEUP Wakeup;
+ NTSTATUS status;
+
+ Trace("====>\n");
+
+ Event = ThreadGetEvent(Self);
+
+ status = XENBUS_CONSOLE(Acquire,
+ &Stream->ConsoleInterface);
+ if (!NT_SUCCESS(status))
+ goto fail1;
+
+ status = XENBUS_CONSOLE(WakeupAdd,
+ &Stream->ConsoleInterface,
+ Event,
+ &Wakeup);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ for (;;) {
+ PIRP Irp;
+
+ (VOID) KeWaitForSingleObject(Event,
+ Executive,
+ KernelMode,
+ FALSE,
+ NULL);
+ KeClearEvent(Event);
+
+ if (ThreadIsAlerted(Self))
+ break;
+
+ for (Irp = IoCsqRemoveNextIrp(&Stream->Csq, NULL);
+ Irp != NULL;
+ Irp = IoCsqRemoveNextIrp(&Stream->Csq, NULL)) {
+ PIO_STACK_LOCATION StackLocation;
+ UCHAR MajorFunction;
+ BOOLEAN Blocked;
+
+ StackLocation = IoGetCurrentIrpStackLocation(Irp);
+ MajorFunction = StackLocation->MajorFunction;
+
+ switch (MajorFunction) {
+ case IRP_MJ_READ:
+ Blocked = !XENBUS_CONSOLE(CanRead,
+ &Stream->ConsoleInterface);
+ break;
+
+ case IRP_MJ_WRITE:
+ Blocked = !XENBUS_CONSOLE(CanWrite,
+ &Stream->ConsoleInterface);
+ break;
+
+ default:
+ ASSERT(FALSE);
+
+ Blocked = TRUE;
+ break;
+ }
+
+ if (Blocked) {
+ status = IoCsqInsertIrpEx(&Stream->Csq,
+ Irp,
+ NULL,
+ (PVOID)TRUE);
+ ASSERT(NT_SUCCESS(status));
+
+ break;
+ }
+
+ switch (MajorFunction) {
+ case IRP_MJ_READ: {
+ ULONG Length;
+ PCHAR Buffer;
+ ULONG Read;
+
+ Length = StackLocation->Parameters.Read.Length;
+ Buffer = Irp->AssociatedIrp.SystemBuffer;
+
+ Read = XENBUS_CONSOLE(Read,
+ &Stream->ConsoleInterface,
+ Buffer,
+ Length);
+
+ Irp->IoStatus.Information = Read;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ break;
+ }
+ case IRP_MJ_WRITE: {
+ ULONG Length;
+ PCHAR Buffer;
+ ULONG Written;
+
+ Length = StackLocation->Parameters.Write.Length;
+ Buffer = Irp->AssociatedIrp.SystemBuffer;
+
+ Written = XENBUS_CONSOLE(Write,
+ &Stream->ConsoleInterface,
+ Buffer,
+ Length);
+
+ Irp->IoStatus.Information = Written;
+ Irp->IoStatus.Status = STATUS_SUCCESS;
+ break;
+ }
+ default:
+ ASSERT(FALSE);
+
+ Irp->IoStatus.Status = STATUS_UNSUCCESSFUL;
+ break;
+ }
+
+ Trace("COMPLETE (%02x:%s) (%u bytes)\n",
+ MajorFunction,
+ MajorFunctionName(MajorFunction),
+ Irp->IoStatus.Information);
+
+ IoCompleteRequest(Irp, IO_NO_INCREMENT);
+ }
+ }
+
+ XENBUS_CONSOLE(WakeupRemove,
+ &Stream->ConsoleInterface,
+ Wakeup);
+
+ XENBUS_CONSOLE(Release, &Stream->ConsoleInterface);
+
+ Trace("<====\n");
+
+ return STATUS_SUCCESS;
+
+fail2:
+ Error("fail2\n");
+
+ XENBUS_CONSOLE(Release, &Stream->ConsoleInterface);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+NTSTATUS
+StreamCreate(
+ IN PXENCONS_FDO Fdo,
+ OUT PXENCONS_STREAM *Stream
+ )
+{
+ NTSTATUS status;
+
+ *Stream = __StreamAllocate(sizeof (XENCONS_STREAM));
+
+ status = STATUS_NO_MEMORY;
+ if (*Stream == NULL)
+ goto fail1;
+
+ FdoGetConsoleInterface(Fdo, &(*Stream)->ConsoleInterface);
+
+ KeInitializeSpinLock(&(*Stream)->Lock);
+ InitializeListHead(&(*Stream)->List);
+
+ status = IoCsqInitializeEx(&(*Stream)->Csq,
+ StreamCsqInsertIrpEx,
+ StreamCsqRemoveIrp,
+ StreamCsqPeekNextIrp,
+ StreamCsqAcquireLock,
+ StreamCsqReleaseLock,
+ StreamCsqCompleteCanceledIrp);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ status = ThreadCreate(StreamWorker,
+ *Stream,
+ &(*Stream)->Thread);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ (*Stream)->Fdo = Fdo;
+
+ return STATUS_SUCCESS;
+
+fail3:
+ Error("fail3\n");
+
+ RtlZeroMemory(&(*Stream)->Csq, sizeof (IO_CSQ));
+
+fail2:
+ Error("fail2\n");
+
+ RtlZeroMemory(&(*Stream)->List, sizeof (LIST_ENTRY));
+ RtlZeroMemory(&(*Stream)->Lock, sizeof (KSPIN_LOCK));
+
+ RtlZeroMemory(&(*Stream)->ConsoleInterface,
+ sizeof (XENBUS_CONSOLE_INTERFACE));
+
+ ASSERT(IsZeroMemory(*Stream, sizeof (XENCONS_STREAM)));
+ __StreamFree(*Stream);
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+VOID
+StreamDestroy(
+ IN PXENCONS_STREAM Stream
+ )
+{
+ Stream->Fdo = NULL;
+
+ ThreadAlert(Stream->Thread);
+ ThreadJoin(Stream->Thread);
+ Stream->Thread = NULL;
+
+ RtlZeroMemory(&Stream->Csq, sizeof (IO_CSQ));
+
+ RtlZeroMemory(&Stream->List, sizeof (LIST_ENTRY));
+ RtlZeroMemory(&Stream->Lock, sizeof (KSPIN_LOCK));
+
+ RtlZeroMemory(&Stream->ConsoleInterface,
+ sizeof (XENBUS_CONSOLE_INTERFACE));
+
+ ASSERT(IsZeroMemory(Stream, sizeof (XENCONS_STREAM)));
+ __StreamFree(Stream);
+}
+
+NTSTATUS
+StreamPutQueue(
+ IN PXENCONS_STREAM Stream,
+ IN PIRP Irp
+ )
+{
+ return IoCsqInsertIrpEx(&Stream->Csq, Irp, NULL, (PVOID)FALSE);
+}
--- /dev/null
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * * Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer in the documentation and/or other
+ * materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _XENCONS_STREAM_H
+#define _XENCONS_STREAM_H
+
+#include <ntddk.h>
+
+#include "fdo.h"
+
+typedef struct _XENCONS_STREAM XENCONS_STREAM, *PXENCONS_STREAM;
+
+extern NTSTATUS
+StreamCreate(
+ IN PXENCONS_FDO Fdo,
+ OUT PXENCONS_STREAM *Stream
+ );
+
+extern VOID
+StreamDestroy(
+ IN PXENCONS_STREAM Stream
+ );
+
+extern NTSTATUS
+StreamPutQueue(
+ IN PXENCONS_STREAM Stream,
+ IN PIRP Irp
+ );
+
+#endif // _XENCONS_STREAM_H
<ClCompile Include="../../src/xencons/driver.c" />
<ClCompile Include="../../src/xencons/fdo.c" />
<ClCompile Include="../../src/xencons/registry.c" />
+ <ClCompile Include="../../src/xencons/stream.c" />
<ClCompile Include="../../src/xencons/thread.c" />
</ItemGroup>
<ItemGroup>