--- /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_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_WRITE
+ \brief Send characters to the console
+
+ \param Interface The interface header
+ \param Buffer A character buffer
+ \param Length The length of the buffer
+ \param CRLF Substitute LF with CRLF
+*/
+typedef NTSTATUS
+(*XENBUS_CONSOLE_WRITE)(
+ IN PINTERFACE Interface,
+ IN PCHAR Data,
+ IN ULONG Length,
+ IN BOOLEAN CRLF
+ );
+
+// {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_WRITE ConsoleWrite;
+};
+
+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.
+ */
+
+#include <ntddk.h>
+#include <ntstrsafe.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <xen.h>
+
+#include "console.h"
+#include "evtchn.h"
+#include "fdo.h"
+#include "high.h"
+#include "dbg_print.h"
+#include "assert.h"
+#include "util.h"
+
+typedef struct _XENBUS_CONSOLE_BUFFER {
+ LIST_ENTRY ListEntry;
+ ULONG Offset;
+ ULONG Length;
+ CHAR Data[1]; // Variable length array
+} XENBUS_CONSOLE_BUFFER, *PXENBUS_CONSOLE_BUFFER;
+
+struct _XENBUS_CONSOLE_CONTEXT {
+ PXENBUS_FDO Fdo;
+ KSPIN_LOCK Lock;
+ LONG References;
+ struct xencons_interface *Shared;
+ LIST_ENTRY OutList;
+ HIGH_LOCK OutLock;
+ KDPC Dpc;
+ ULONG Polls;
+ ULONG Dpcs;
+ ULONG Events;
+ XENBUS_EVTCHN_INTERFACE EvtchnInterface;
+ PHYSICAL_ADDRESS Address;
+ PXENBUS_EVTCHN_CHANNEL Channel;
+ XENBUS_SUSPEND_INTERFACE SuspendInterface;
+ XENBUS_DEBUG_INTERFACE DebugInterface;
+ PXENBUS_SUSPEND_CALLBACK SuspendCallbackEarly;
+ PXENBUS_SUSPEND_CALLBACK SuspendCallbackLate;
+ PXENBUS_DEBUG_CALLBACK DebugCallback;
+ BOOLEAN Enabled;
+};
+
+C_ASSERT(sizeof (struct xencons_interface) <= PAGE_SIZE);
+
+#define XENBUS_CONSOLE_TAG 'SNOC'
+
+static FORCEINLINE PVOID
+__ConsoleAllocate(
+ IN ULONG Length
+ )
+{
+ return __AllocatePoolWithTag(NonPagedPool, Length, XENBUS_CONSOLE_TAG);
+}
+
+static FORCEINLINE VOID
+__ConsoleFree(
+ IN PVOID Buffer
+ )
+{
+ __FreePoolWithTag(Buffer, XENBUS_CONSOLE_TAG);
+}
+
+static ULONG
+ConsoleCopyToRing(
+ IN PXENBUS_CONSOLE_CONTEXT Context,
+ IN PCHAR Data,
+ IN ULONG Length
+ )
+{
+ struct xencons_interface *Shared;
+ XENCONS_RING_IDX cons;
+ XENCONS_RING_IDX prod;
+ ULONG Offset;
+
+ Shared = Context->Shared;
+
+ KeMemoryBarrier();
+
+ prod = Shared->out_prod;
+ cons = Shared->out_cons;
+
+ KeMemoryBarrier();
+
+ Offset = 0;
+ while (Length != 0) {
+ ULONG Available;
+ ULONG Index;
+ ULONG CopyLength;
+
+ Available = cons + sizeof (Shared->out) - prod;
+
+ if (Available == 0)
+ break;
+
+ Index = MASK_XENCONS_IDX(prod, Shared->out);
+
+ CopyLength = __min(Length, Available);
+ CopyLength = __min(CopyLength, sizeof (Shared->out) - Index);
+
+ RtlCopyMemory(&Shared->out[Index], Data + Offset, CopyLength);
+
+ Offset += CopyLength;
+ Length -= CopyLength;
+
+ prod += CopyLength;
+ }
+
+ KeMemoryBarrier();
+
+ Shared->out_prod = prod;
+
+ KeMemoryBarrier();
+
+ return Offset;
+}
+
+static FORCEINLINE PXENBUS_CONSOLE_BUFFER
+__ConsoleGetHeadBuffer(
+ IN PXENBUS_CONSOLE_CONTEXT Context
+ )
+{
+ PLIST_ENTRY ListEntry;
+ PXENBUS_CONSOLE_BUFFER Buffer;
+ KIRQL Irql;
+
+ AcquireHighLock(&Context->OutLock, &Irql);
+ ListEntry = (!IsListEmpty(&Context->OutList)) ?
+ Context->OutList.Flink :
+ NULL;
+ ReleaseHighLock(&Context->OutLock, Irql);
+
+ if (ListEntry == NULL)
+ return NULL;
+
+ Buffer = CONTAINING_RECORD(ListEntry,
+ XENBUS_CONSOLE_BUFFER,
+ ListEntry);
+
+ return Buffer;
+}
+
+static FORCEINLINE VOID
+__ConsoleRemoveHeadBuffer(
+ IN PXENBUS_CONSOLE_CONTEXT Context
+ )
+{
+ KIRQL Irql;
+
+ AcquireHighLock(&Context->OutLock, &Irql);
+ (VOID) RemoveHeadList(&Context->OutList);
+ ReleaseHighLock(&Context->OutLock, Irql);
+}
+
+static FORCEINLINE VOID
+__ConsoleAddTailBuffer(
+ IN PXENBUS_CONSOLE_CONTEXT Context,
+ IN PXENBUS_CONSOLE_BUFFER Buffer
+ )
+{
+ KIRQL Irql;
+
+ AcquireHighLock(&Context->OutLock, &Irql);
+ InsertTailList(&Context->OutList, &Buffer->ListEntry);
+ ReleaseHighLock(&Context->OutLock, Irql);
+}
+
+static BOOLEAN
+ConsoleOut(
+ IN PXENBUS_CONSOLE_CONTEXT Context
+ )
+{
+ PXENBUS_CONSOLE_BUFFER Buffer;
+ ULONG Written;
+
+ Buffer = __ConsoleGetHeadBuffer(Context);
+
+ if (Buffer == NULL)
+ return FALSE;
+
+ Written = ConsoleCopyToRing(Context,
+ Buffer->Data + Buffer->Offset,
+ Buffer->Length - Buffer->Offset);
+
+ Buffer->Offset += Written;
+
+ ASSERT3U(Buffer->Offset, <=, Buffer->Length);
+ if (Buffer->Offset == Buffer->Length) {
+ __ConsoleRemoveHeadBuffer(Context);
+ __ConsoleFree(Buffer);
+ }
+
+ if (Written != 0)
+ XENBUS_EVTCHN(Send,
+ &Context->EvtchnInterface,
+ Context->Channel);
+
+ return TRUE;
+}
+
+static VOID
+ConsoleFlush(
+ IN PXENBUS_CONSOLE_CONTEXT Context
+ )
+{
+ for (;;) {
+ if (!ConsoleOut(Context))
+ break;
+ }
+}
+
+static
+_Function_class_(KDEFERRED_ROUTINE)
+_IRQL_requires_max_(DISPATCH_LEVEL)
+_IRQL_requires_min_(DISPATCH_LEVEL)
+_IRQL_requires_(DISPATCH_LEVEL)
+_IRQL_requires_same_
+VOID
+ConsoleDpc(
+ IN PKDPC Dpc,
+ IN PVOID _Context,
+ IN PVOID Argument1,
+ IN PVOID Argument2
+ )
+{
+ PXENBUS_CONSOLE_CONTEXT Context = _Context;
+
+ UNREFERENCED_PARAMETER(Dpc);
+ UNREFERENCED_PARAMETER(Argument1);
+ UNREFERENCED_PARAMETER(Argument2);
+
+ ASSERT(Context != NULL);
+
+ KeAcquireSpinLockAtDpcLevel(&Context->Lock);
+ if (Context->References != 0)
+ (VOID) ConsoleOut(Context);
+ KeReleaseSpinLockFromDpcLevel(&Context->Lock);
+}
+
+static
+_Function_class_(KSERVICE_ROUTINE)
+_IRQL_requires_(HIGH_LEVEL)
+_IRQL_requires_same_
+BOOLEAN
+ConsoleEvtchnCallback(
+ IN PKINTERRUPT InterruptObject,
+ IN PVOID Argument
+ )
+{
+ PXENBUS_CONSOLE_CONTEXT Context = Argument;
+
+ UNREFERENCED_PARAMETER(InterruptObject);
+
+ ASSERT(Context != NULL);
+
+ Context->Events++;
+
+ if (KeInsertQueueDpc(&Context->Dpc, NULL, NULL))
+ Context->Dpcs++;
+
+ return TRUE;
+}
+
+static VOID
+ConsoleDisable(
+ IN PXENBUS_CONSOLE_CONTEXT Context
+ )
+{
+ LogPrintf(LOG_LEVEL_INFO,
+ "CONSOLE: DISABLE\n");
+
+ Context->Enabled = FALSE;
+
+ XENBUS_EVTCHN(Close,
+ &Context->EvtchnInterface,
+ Context->Channel);
+ Context->Channel = NULL;
+}
+
+static VOID
+ConsoleEnable(
+ IN PXENBUS_CONSOLE_CONTEXT Context
+ )
+{
+ ULONGLONG Value;
+ ULONG Port;
+ NTSTATUS status;
+
+ status = HvmGetParam(HVM_PARAM_CONSOLE_EVTCHN, &Value);
+ ASSERT(NT_SUCCESS(status));
+
+ Port = (ULONG)Value;
+
+ Context->Channel = XENBUS_EVTCHN(Open,
+ &Context->EvtchnInterface,
+ XENBUS_EVTCHN_TYPE_FIXED,
+ ConsoleEvtchnCallback,
+ Context,
+ Port,
+ FALSE);
+ ASSERT(Context->Channel != NULL);
+
+ XENBUS_EVTCHN(Unmask,
+ &Context->EvtchnInterface,
+ Context->Channel,
+ FALSE);
+
+ Context->Enabled = TRUE;
+
+ LogPrintf(LOG_LEVEL_INFO,
+ "CONSOLE: ENABLE (%u)\n",
+ Port);
+
+ // Trigger an initial poll
+ if (KeInsertQueueDpc(&Context->Dpc, NULL, NULL))
+ Context->Dpcs++;
+}
+
+static PHYSICAL_ADDRESS
+ConsoleGetAddress(
+ PXENBUS_CONSOLE_CONTEXT Context
+ )
+{
+ PHYSICAL_ADDRESS Address;
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER(Context);
+
+ status = HvmGetParam(HVM_PARAM_CONSOLE_PFN,
+ (PULONGLONG)&Address.QuadPart);
+ ASSERT(NT_SUCCESS(status));
+
+ Address.QuadPart <<= PAGE_SHIFT;
+
+ LogPrintf(LOG_LEVEL_INFO,
+ "CONSOLE: PAGE @ %08x.%08x\n",
+ Address.HighPart,
+ Address.LowPart);
+
+ return Address;
+}
+
+static VOID
+ConsoleSuspendCallbackEarly(
+ IN PVOID Argument
+ )
+{
+ PXENBUS_CONSOLE_CONTEXT Context = Argument;
+ PHYSICAL_ADDRESS Address;
+
+ Address = ConsoleGetAddress(Context);
+ ASSERT3U(Address.QuadPart, ==, Context->Address.QuadPart);
+}
+
+static VOID
+ConsoleSuspendCallbackLate(
+ IN PVOID Argument
+ )
+{
+ PXENBUS_CONSOLE_CONTEXT Context = Argument;
+ struct xencons_interface *Shared;
+ KIRQL Irql;
+
+ Shared = Context->Shared;
+
+ KeAcquireSpinLock(&Context->Lock, &Irql);
+
+ ConsoleDisable(Context);
+ ConsoleEnable(Context);
+
+ KeReleaseSpinLock(&Context->Lock, Irql);
+}
+
+static VOID
+ConsoleDebugCallback(
+ IN PVOID Argument,
+ IN BOOLEAN Crashing
+ )
+{
+ PXENBUS_CONSOLE_CONTEXT Context = Argument;
+
+ XENBUS_DEBUG(Printf,
+ &Context->DebugInterface,
+ "Address = %08x.%08x\n",
+ Context->Address.HighPart,
+ Context->Address.LowPart);
+
+ if (!Crashing) {
+ struct xencons_interface *Shared;
+
+ Shared = Context->Shared;
+
+ XENBUS_DEBUG(Printf,
+ &Context->DebugInterface,
+ "out_cons = %08x out_prod = %08x\n",
+ Shared->out_cons,
+ Shared->out_prod);
+
+ XENBUS_DEBUG(Printf,
+ &Context->DebugInterface,
+ "in_cons = %08x in_prod = %08x\n",
+ Shared->in_cons,
+ Shared->in_prod);
+ }
+
+ XENBUS_DEBUG(Printf,
+ &Context->DebugInterface,
+ "Events = %lu Dpcs = %lu Polls = %lu\n",
+ Context->Events,
+ Context->Dpcs,
+ Context->Polls);
+}
+
+static NTSTATUS
+ConsoleWrite(
+ IN PINTERFACE Interface,
+ IN PCHAR Data,
+ IN ULONG Length,
+ IN BOOLEAN CRLF
+ )
+{
+ PXENBUS_CONSOLE_CONTEXT Context = Interface->Context;
+ ULONG Extra;
+ PXENBUS_CONSOLE_BUFFER Buffer;
+ ULONG Index;
+ KIRQL Irql;
+ NTSTATUS status;
+
+ Extra = 0;
+ if (CRLF) {
+ for (Index = 0; Index < Length; Index++) {
+ if (Data[Index] == '\n')
+ Extra++;
+ }
+ }
+
+ Buffer = __ConsoleAllocate(FIELD_OFFSET(XENBUS_CONSOLE_BUFFER, Data) +
+ Length + Extra);
+
+ status = STATUS_NO_MEMORY;
+ if (Buffer == NULL)
+ goto fail1;
+
+ Index = 0;
+ while (Index < Length + Extra) {
+ if (CRLF && *Data == '\n')
+ Buffer->Data[Index++] = '\r';
+
+ Buffer->Data[Index++] = *Data++;
+ }
+
+ Buffer->Length = Length + Extra;
+
+ AcquireHighLock(&Context->OutLock, &Irql);
+ InsertTailList(&Context->OutList, &Buffer->ListEntry);
+ ReleaseHighLock(&Context->OutLock, Irql);
+
+ if (KeInsertQueueDpc(&Context->Dpc, NULL, NULL))
+ Context->Dpcs++;
+
+ return STATUS_SUCCESS;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+static NTSTATUS
+ConsoleAcquire(
+ IN PINTERFACE Interface
+ )
+{
+ PXENBUS_CONSOLE_CONTEXT Context = Interface->Context;
+ KIRQL Irql;
+ NTSTATUS status;
+
+ KeAcquireSpinLock(&Context->Lock, &Irql);
+
+ if (Context->References++ != 0)
+ goto done;
+
+ Trace("====>\n");
+
+ Context->Address = ConsoleGetAddress(Context);
+ Context->Shared = (struct xencons_interface *)MmMapIoSpace(Context->Address,
+ PAGE_SIZE,
+ MmCached);
+ status = STATUS_UNSUCCESSFUL;
+ if (Context->Shared == NULL)
+ goto fail1;
+
+ status = XENBUS_EVTCHN(Acquire, &Context->EvtchnInterface);
+ if (!NT_SUCCESS(status))
+ goto fail2;
+
+ ConsoleEnable(Context);
+
+ status = XENBUS_SUSPEND(Acquire, &Context->SuspendInterface);
+ if (!NT_SUCCESS(status))
+ goto fail3;
+
+ status = XENBUS_SUSPEND(Register,
+ &Context->SuspendInterface,
+ SUSPEND_CALLBACK_EARLY,
+ ConsoleSuspendCallbackEarly,
+ Context,
+ &Context->SuspendCallbackEarly);
+ if (!NT_SUCCESS(status))
+ goto fail4;
+
+ status = XENBUS_SUSPEND(Register,
+ &Context->SuspendInterface,
+ SUSPEND_CALLBACK_LATE,
+ ConsoleSuspendCallbackLate,
+ Context,
+ &Context->SuspendCallbackLate);
+ if (!NT_SUCCESS(status))
+ goto fail5;
+
+ status = XENBUS_DEBUG(Acquire, &Context->DebugInterface);
+ if (!NT_SUCCESS(status))
+ goto fail6;
+
+ status = XENBUS_DEBUG(Register,
+ &Context->DebugInterface,
+ __MODULE__ "|CONSOLE",
+ ConsoleDebugCallback,
+ Context,
+ &Context->DebugCallback);
+ if (!NT_SUCCESS(status))
+ goto fail7;
+
+ Trace("<====\n");
+
+done:
+ KeReleaseSpinLock(&Context->Lock, Irql);
+
+ return STATUS_SUCCESS;
+
+fail7:
+ Error("fail7\n");
+
+ XENBUS_DEBUG(Release, &Context->DebugInterface);
+
+fail6:
+ Error("fail6\n");
+
+ XENBUS_SUSPEND(Deregister,
+ &Context->SuspendInterface,
+ Context->SuspendCallbackLate);
+ Context->SuspendCallbackLate = NULL;
+
+fail5:
+ Error("fail5\n");
+
+ XENBUS_SUSPEND(Deregister,
+ &Context->SuspendInterface,
+ Context->SuspendCallbackEarly);
+ Context->SuspendCallbackEarly = NULL;
+
+fail4:
+ Error("fail4\n");
+
+ XENBUS_SUSPEND(Release, &Context->SuspendInterface);
+
+fail3:
+ Error("fail3\n");
+
+ ConsoleDisable(Context);
+
+ XENBUS_EVTCHN(Release, &Context->EvtchnInterface);
+
+fail2:
+ Error("fail2\n");
+
+ MmUnmapIoSpace(Context->Shared, PAGE_SIZE);
+ Context->Shared = NULL;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ Context->Address.QuadPart = 0;
+
+ --Context->References;
+ ASSERT3U(Context->References, ==, 0);
+ KeReleaseSpinLock(&Context->Lock, Irql);
+
+ return status;
+}
+
+static VOID
+ConsoleRelease(
+ IN PINTERFACE Interface
+ )
+{
+ PXENBUS_CONSOLE_CONTEXT Context = Interface->Context;
+ KIRQL Irql;
+
+ KeAcquireSpinLock(&Context->Lock, &Irql);
+
+ if (--Context->References > 0)
+ goto done;
+
+ Trace("====>\n");
+
+ ConsoleFlush(Context);
+
+ XENBUS_DEBUG(Deregister,
+ &Context->DebugInterface,
+ Context->DebugCallback);
+ Context->DebugCallback = NULL;
+
+ XENBUS_DEBUG(Release, &Context->DebugInterface);
+
+ XENBUS_SUSPEND(Deregister,
+ &Context->SuspendInterface,
+ Context->SuspendCallbackLate);
+ Context->SuspendCallbackLate = NULL;
+
+ XENBUS_SUSPEND(Deregister,
+ &Context->SuspendInterface,
+ Context->SuspendCallbackEarly);
+ Context->SuspendCallbackEarly = NULL;
+
+ XENBUS_SUSPEND(Release, &Context->SuspendInterface);
+
+ ConsoleDisable(Context);
+
+ XENBUS_EVTCHN(Release, &Context->EvtchnInterface);
+
+ MmUnmapIoSpace(Context->Shared, PAGE_SIZE);
+ Context->Shared = NULL;
+
+ Context->Address.QuadPart = 0;
+
+ Trace("<====\n");
+
+done:
+ KeReleaseSpinLock(&Context->Lock, Irql);
+}
+
+static struct _XENBUS_CONSOLE_INTERFACE_V1 ConsoleInterfaceVersion1 = {
+ { sizeof (struct _XENBUS_CONSOLE_INTERFACE_V1), 1, NULL, NULL, NULL },
+ ConsoleAcquire,
+ ConsoleRelease,
+ ConsoleWrite
+};
+
+NTSTATUS
+ConsoleInitialize(
+ IN PXENBUS_FDO Fdo,
+ OUT PXENBUS_CONSOLE_CONTEXT *Context
+ )
+{
+ NTSTATUS status;
+
+ Trace("====>\n");
+
+ *Context = __ConsoleAllocate(sizeof (XENBUS_CONSOLE_CONTEXT));
+
+ status = STATUS_NO_MEMORY;
+ if (*Context == NULL)
+ goto fail1;
+
+ status = EvtchnGetInterface(FdoGetEvtchnContext(Fdo),
+ XENBUS_EVTCHN_INTERFACE_VERSION_MAX,
+ (PINTERFACE)&(*Context)->EvtchnInterface,
+ sizeof ((*Context)->EvtchnInterface));
+ ASSERT(NT_SUCCESS(status));
+ ASSERT((*Context)->EvtchnInterface.Interface.Context != NULL);
+
+ status = SuspendGetInterface(FdoGetSuspendContext(Fdo),
+ XENBUS_SUSPEND_INTERFACE_VERSION_MAX,
+ (PINTERFACE)&(*Context)->SuspendInterface,
+ sizeof ((*Context)->SuspendInterface));
+ ASSERT(NT_SUCCESS(status));
+ ASSERT((*Context)->SuspendInterface.Interface.Context != NULL);
+
+ status = DebugGetInterface(FdoGetDebugContext(Fdo),
+ XENBUS_DEBUG_INTERFACE_VERSION_MAX,
+ (PINTERFACE)&(*Context)->DebugInterface,
+ sizeof ((*Context)->DebugInterface));
+ ASSERT(NT_SUCCESS(status));
+ ASSERT((*Context)->DebugInterface.Interface.Context != NULL);
+
+ KeInitializeSpinLock(&(*Context)->Lock);
+
+ InitializeListHead(&(*Context)->OutList);
+ InitializeHighLock(&(*Context)->OutLock);
+
+ KeInitializeDpc(&(*Context)->Dpc, ConsoleDpc, *Context);
+
+ (*Context)->Fdo = Fdo;
+
+ Trace("<====\n");
+
+ return STATUS_SUCCESS;
+
+fail1:
+ Error("fail1 (%08x)\n", status);
+
+ return status;
+}
+
+NTSTATUS
+ConsoleGetInterface(
+ IN PXENBUS_CONSOLE_CONTEXT Context,
+ IN ULONG Version,
+ IN OUT PINTERFACE Interface,
+ IN ULONG Size
+ )
+{
+ NTSTATUS status;
+
+ ASSERT(Context != NULL);
+
+ switch (Version) {
+ case 1: {
+ struct _XENBUS_CONSOLE_INTERFACE_V1 *ConsoleInterface;
+
+ ConsoleInterface = (struct _XENBUS_CONSOLE_INTERFACE_V1 *)Interface;
+
+ status = STATUS_BUFFER_OVERFLOW;
+ if (Size < sizeof (struct _XENBUS_CONSOLE_INTERFACE_V1))
+ break;
+
+ *ConsoleInterface = ConsoleInterfaceVersion1;
+
+ ASSERT3U(Interface->Version, ==, Version);
+ Interface->Context = Context;
+
+ status = STATUS_SUCCESS;
+ break;
+ }
+ default:
+ status = STATUS_NOT_SUPPORTED;
+ break;
+ }
+
+ return status;
+}
+
+ULONG
+ConsoleGetReferences(
+ IN PXENBUS_CONSOLE_CONTEXT Context
+ )
+{
+ return Context->References;
+}
+
+VOID
+ConsoleTeardown(
+ IN PXENBUS_CONSOLE_CONTEXT Context
+ )
+{
+ Trace("====>\n");
+
+ ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+ KeFlushQueuedDpcs();
+
+ Context->Polls = 0;
+ Context->Dpcs = 0;
+ Context->Events = 0;
+
+ Context->Fdo = NULL;
+
+ RtlZeroMemory(&Context->Dpc, sizeof (KDPC));
+
+ RtlZeroMemory(&Context->OutLock, sizeof (HIGH_LOCK));
+ ASSERT(IsListEmpty(&Context->OutList));
+ RtlZeroMemory(&Context->OutList, sizeof (LIST_ENTRY));
+
+ RtlZeroMemory(&Context->Lock, sizeof (KSPIN_LOCK));
+
+ RtlZeroMemory(&Context->DebugInterface,
+ sizeof (XENBUS_DEBUG_INTERFACE));
+
+ RtlZeroMemory(&Context->SuspendInterface,
+ sizeof (XENBUS_SUSPEND_INTERFACE));
+
+ RtlZeroMemory(&Context->EvtchnInterface,
+ sizeof (XENBUS_EVTCHN_INTERFACE));
+
+ ASSERT(IsZeroMemory(Context, sizeof (XENBUS_CONSOLE_CONTEXT)));
+ __ConsoleFree(Context);
+
+ Trace("<====\n");
+}
#include "evtchn.h"
#include "debug.h"
#include "store.h"
+#include "console.h"
#include "cache.h"
#include "gnttab.h"
#include "suspend.h"
PXENBUS_EVTCHN_CONTEXT EvtchnContext;
PXENBUS_DEBUG_CONTEXT DebugContext;
PXENBUS_STORE_CONTEXT StoreContext;
+ PXENBUS_CONSOLE_CONTEXT ConsoleContext;
PXENBUS_RANGE_SET_CONTEXT RangeSetContext;
PXENBUS_CACHE_CONTEXT CacheContext;
PXENBUS_GNTTAB_CONTEXT GnttabContext;
XENBUS_SUSPEND_INTERFACE SuspendInterface;
XENBUS_EVTCHN_INTERFACE EvtchnInterface;
XENBUS_STORE_INTERFACE StoreInterface;
+ XENBUS_CONSOLE_INTERFACE ConsoleInterface;
XENBUS_RANGE_SET_INTERFACE RangeSetInterface;
XENBUS_BALLOON_INTERFACE BalloonInterface;
PXENBUS_EVTCHN_CHANNEL Channel;
PXENBUS_SUSPEND_CALLBACK SuspendCallbackLate;
+ PLOG_DISPOSITION LogDisposition;
};
static FORCEINLINE PVOID
DEFINE_FDO_GET_CONTEXT(Evtchn, PXENBUS_EVTCHN_CONTEXT)
DEFINE_FDO_GET_CONTEXT(Debug, PXENBUS_DEBUG_CONTEXT)
DEFINE_FDO_GET_CONTEXT(Store, PXENBUS_STORE_CONTEXT)
+DEFINE_FDO_GET_CONTEXT(Console, PXENBUS_CONSOLE_CONTEXT)
DEFINE_FDO_GET_CONTEXT(RangeSet, PXENBUS_RANGE_SET_CONTEXT)
DEFINE_FDO_GET_CONTEXT(Cache, PXENBUS_CACHE_CONTEXT)
DEFINE_FDO_GET_CONTEXT(Gnttab, PXENBUS_GNTTAB_CONTEXT)
return status;
}
+static VOID
+FdoOutputBuffer(
+ IN PVOID Argument,
+ IN PCHAR Buffer,
+ IN ULONG Length
+ )
+{
+ PXENBUS_FDO Fdo = Argument;
+
+ (VOID) XENBUS_CONSOLE(Write,
+ &Fdo->ConsoleInterface,
+ Buffer,
+ Length,
+ TRUE);
+}
+
static FORCEINLINE NTSTATUS
__FdoD3ToD0(
IN PXENBUS_FDO Fdo
Fdo->Channel,
FALSE);
+ status = LogAddDisposition(LOG_LEVEL_INFO |
+ LOG_LEVEL_WARNING |
+ LOG_LEVEL_ERROR |
+ LOG_LEVEL_CRITICAL,
+ FdoOutputBuffer,
+ Fdo,
+ &Fdo->LogDisposition);
+ ASSERT(NT_SUCCESS(status));
+
status = XENBUS_STORE(WatchAdd,
&Fdo->StoreInterface,
NULL,
fail2:
Error("fail2\n");
+ LogRemoveDisposition(Fdo->LogDisposition);
+ Fdo->LogDisposition = NULL;
+
XENBUS_EVTCHN(Close,
&Fdo->EvtchnInterface,
Fdo->Channel);
Fdo->ScanWatch);
Fdo->ScanWatch = NULL;
+ LogRemoveDisposition(Fdo->LogDisposition);
+ Fdo->LogDisposition = NULL;
+
XENBUS_EVTCHN(Close,
&Fdo->EvtchnInterface,
Fdo->Channel);
if (!NT_SUCCESS(status))
goto fail6;
+ status = XENBUS_CONSOLE(Acquire, &Fdo->ConsoleInterface);
+ if (!NT_SUCCESS(status))
+ goto fail7;
+
if (Fdo->BalloonInterface.Interface.Context != NULL) {
status = XENBUS_BALLOON(Acquire, &Fdo->BalloonInterface);
if (!NT_SUCCESS(status))
- goto fail7;
+ goto fail8;
}
status = __FdoD3ToD0(Fdo);
if (!NT_SUCCESS(status))
- goto fail8;
+ goto fail9;
status = XENBUS_SUSPEND(Register,
&Fdo->SuspendInterface,
Fdo,
&Fdo->SuspendCallbackLate);
if (!NT_SUCCESS(status))
- goto fail9;
+ goto fail10;
KeLowerIrql(Irql);
return STATUS_SUCCESS;
+fail10:
+ Error("fail10\n");
+
+ __FdoD0ToD3(Fdo);
+
fail9:
Error("fail9\n");
- __FdoD0ToD3(Fdo);
+ if (Fdo->BalloonInterface.Interface.Context != NULL)
+ XENBUS_BALLOON(Release, &Fdo->BalloonInterface);
fail8:
Error("fail8\n");
- if (Fdo->BalloonInterface.Interface.Context != NULL)
- XENBUS_BALLOON(Release, &Fdo->BalloonInterface);
+ XENBUS_CONSOLE(Release, &Fdo->ConsoleInterface);
fail7:
Error("fail7\n");
if (Fdo->BalloonInterface.Interface.Context != NULL)
XENBUS_BALLOON(Release, &Fdo->BalloonInterface);
+ XENBUS_CONSOLE(Release, &Fdo->ConsoleInterface);
+
XENBUS_STORE(Release, &Fdo->StoreInterface);
XENBUS_EVTCHN(Release, &Fdo->EvtchnInterface);
BUG_ON(SharedInfoGetReferences(Fdo->SharedInfoContext) != 0);
BUG_ON(EvtchnGetReferences(Fdo->EvtchnContext) != 0);
BUG_ON(StoreGetReferences(Fdo->StoreContext) != 0);
+ BUG_ON(ConsoleGetReferences(Fdo->ConsoleContext) != 0);
BUG_ON(GnttabGetReferences(Fdo->GnttabContext) != 0);
BUG_ON(BalloonGetReferences(Fdo->BalloonContext) != 0);
if (!NT_SUCCESS(status))
goto fail13;
- status = RangeSetInitialize(Fdo, &Fdo->RangeSetContext);
+ status = ConsoleInitialize(Fdo, &Fdo->ConsoleContext);
if (!NT_SUCCESS(status))
goto fail14;
- status = CacheInitialize(Fdo, &Fdo->CacheContext);
+ status = RangeSetInitialize(Fdo, &Fdo->RangeSetContext);
if (!NT_SUCCESS(status))
goto fail15;
- status = GnttabInitialize(Fdo, &Fdo->GnttabContext);
+ status = CacheInitialize(Fdo, &Fdo->CacheContext);
if (!NT_SUCCESS(status))
goto fail16;
- status = UnplugInitialize(Fdo, &Fdo->UnplugContext);
+ status = GnttabInitialize(Fdo, &Fdo->GnttabContext);
if (!NT_SUCCESS(status))
goto fail17;
+ status = UnplugInitialize(Fdo, &Fdo->UnplugContext);
+ if (!NT_SUCCESS(status))
+ goto fail18;
+
if (FdoIsBalloonEnabled(Fdo)) {
status = BalloonInitialize(Fdo, &Fdo->BalloonContext);
if (!NT_SUCCESS(status))
- goto fail18;
+ goto fail19;
}
status = DebugGetInterface(__FdoGetDebugContext(Fdo),
ASSERT(NT_SUCCESS(status));
ASSERT(Fdo->StoreInterface.Interface.Context != NULL);
+ status = ConsoleGetInterface(__FdoGetConsoleContext(Fdo),
+ XENBUS_CONSOLE_INTERFACE_VERSION_MAX,
+ (PINTERFACE)&Fdo->ConsoleInterface,
+ sizeof (Fdo->ConsoleInterface));
+ ASSERT(NT_SUCCESS(status));
+ ASSERT(Fdo->ConsoleInterface.Interface.Context != NULL);
+
status = RangeSetGetInterface(__FdoGetRangeSetContext(Fdo),
XENBUS_RANGE_SET_INTERFACE_VERSION_MAX,
(PINTERFACE)&Fdo->RangeSetInterface,
return STATUS_SUCCESS;
-fail18:
- Error("fail18\n");
+fail19:
+ Error("fail19\n");
UnplugTeardown(Fdo->UnplugContext);
Fdo->UnplugContext = NULL;
-fail17:
- Error("fail17\n");
+fail18:
+ Error("fail18\n");
GnttabTeardown(Fdo->GnttabContext);
Fdo->GnttabContext = NULL;
-fail16:
- Error("fail16\n");
+fail17:
+ Error("fail17\n");
CacheTeardown(Fdo->CacheContext);
Fdo->CacheContext = NULL;
-fail15:
- Error("fail15\n");
+fail16:
+ Error("fail16\n");
RangeSetTeardown(Fdo->RangeSetContext);
Fdo->RangeSetContext = NULL;
+fail15:
+ Error("fail15\n");
+
+ ConsoleTeardown(Fdo->ConsoleContext);
+ Fdo->ConsoleContext = NULL;
+
fail14:
Error("fail14\n");
RtlZeroMemory(&Fdo->RangeSetInterface,
sizeof (XENBUS_RANGE_SET_INTERFACE));
+ RtlZeroMemory(&Fdo->ConsoleInterface,
+ sizeof (XENBUS_CONSOLE_INTERFACE));
+
RtlZeroMemory(&Fdo->StoreInterface,
sizeof (XENBUS_STORE_INTERFACE));
RangeSetTeardown(Fdo->RangeSetContext);
Fdo->RangeSetContext = NULL;
+ ConsoleTeardown(Fdo->ConsoleContext);
+ Fdo->ConsoleContext = NULL;
+
StoreTeardown(Fdo->StoreContext);
Fdo->StoreContext = NULL;