[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[win-pv-devel] [PATCH] Add basic support for PV console



Xen toolstacks have, for some time, created a PV console even for HVM
guests but, so far, Windows has had no frontend for this.

This patch adds the basic plumbing for the PV console, under a new
interface called XENBUS_CONSOLE. This interface is currently private to
XENBUS (so not accessible by child drivers) and will initially only support
writing.
The patch adds a new log disposition that will write INFO, WARNING and
ERROR level messages, so these can now be seen by attaching to the console
backend in the toolstack domain.

Future patches will add read support and a new character device to make
the console available to user-space.

Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
---
 get_xen_headers.py              |   1 +
 include/console_interface.h     | 107 ++++++
 include/xen.h                   |  19 +
 include/xen/public/io/console.h |  51 +++
 src/xen/log.h                   |  15 -
 src/xenbus/console.c            | 820 ++++++++++++++++++++++++++++++++++++++++
 src/xenbus/console.h            |  67 ++++
 src/xenbus/fdo.c                | 109 +++++-
 vs2012/xenbus/xenbus.vcxproj    |   1 +
 vs2013/xenbus/xenbus.vcxproj    |   1 +
 vs2015/xenbus/xenbus.vcxproj    |   1 +
 11 files changed, 1158 insertions(+), 34 deletions(-)
 create mode 100644 include/console_interface.h
 create mode 100644 include/xen/public/io/console.h
 create mode 100644 src/xenbus/console.c
 create mode 100644 src/xenbus/console.h

diff --git a/get_xen_headers.py b/get_xen_headers.py
index f4e24d1..32f27ed 100755
--- a/get_xen_headers.py
+++ b/get_xen_headers.py
@@ -83,6 +83,7 @@ if __name__ == '__main__':
     copy_file(working, 'public\\hvm', 'hvm_info_table.h')
 
     copy_file(working, 'public\\io', 'xs_wire.h')
+    copy_file(working, 'public\\io', 'console.h')
 
     put_branch(working)
 
diff --git a/include/console_interface.h b/include/console_interface.h
new file mode 100644
index 0000000..bcea6fb
--- /dev/null
+++ b/include/console_interface.h
@@ -0,0 +1,107 @@
+/* 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
diff --git a/include/xen.h b/include/xen.h
index 21511b8..470ccd4 100644
--- a/include/xen.h
+++ b/include/xen.h
@@ -56,6 +56,7 @@
 #define EINVAL  XEN_EINVAL
 
 #include <public/io/xs_wire.h>
+#include <public/io/console.h>
 #include <public/version.h>
 
 #ifndef XEN_API
@@ -412,6 +413,24 @@ LogResume(
     VOID
     );
 
+typedef struct _LOG_DISPOSITION LOG_DISPOSITION, *PLOG_DISPOSITION;
+
+XEN_API
+NTSTATUS
+LogAddDisposition(
+    IN  LOG_LEVEL           Mask,
+    IN  VOID                (*Function)(PVOID, PCHAR, ULONG),
+    IN  PVOID               Argument OPTIONAL,
+    OUT PLOG_DISPOSITION    *Disposition
+    );
+
+XEN_API
+VOID
+LogRemoveDisposition(
+    IN  PLOG_DISPOSITION    Disposition
+    );
+
+
 // SYSTEM
 
 XEN_API
diff --git a/include/xen/public/io/console.h b/include/xen/public/io/console.h
new file mode 100644
index 0000000..6496018
--- /dev/null
+++ b/include/xen/public/io/console.h
@@ -0,0 +1,51 @@
+/******************************************************************************
+ * console.h
+ *
+ * Console I/O interface for Xen guest OSes.
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to
+ * deal in the Software without restriction, including without limitation the
+ * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
+ * sell copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+ * DEALINGS IN THE SOFTWARE.
+ *
+ * Copyright (c) 2005, Keir Fraser
+ */
+
+#ifndef __XEN_PUBLIC_IO_CONSOLE_H__
+#define __XEN_PUBLIC_IO_CONSOLE_H__
+
+typedef uint32_t XENCONS_RING_IDX;
+
+#define MASK_XENCONS_IDX(idx, ring) ((idx) & (sizeof(ring)-1))
+
+struct xencons_interface {
+    char in[1024];
+    char out[2048];
+    XENCONS_RING_IDX in_cons, in_prod;
+    XENCONS_RING_IDX out_cons, out_prod;
+};
+
+#endif /* __XEN_PUBLIC_IO_CONSOLE_H__ */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-file-style: "BSD"
+ * c-basic-offset: 4
+ * tab-width: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
diff --git a/src/xen/log.h b/src/xen/log.h
index 67b4f16..6af3158 100644
--- a/src/xen/log.h
+++ b/src/xen/log.h
@@ -34,21 +34,6 @@
 
 #include <xen.h>
 
-typedef struct _LOG_DISPOSITION LOG_DISPOSITION, *PLOG_DISPOSITION;
-
-extern NTSTATUS
-LogAddDisposition(
-    IN  LOG_LEVEL           Mask,
-    IN  VOID                (*Function)(PVOID, PCHAR, ULONG),
-    IN  PVOID               Argument OPTIONAL,
-    OUT PLOG_DISPOSITION    *Disposition
-    );
-
-extern VOID
-LogRemoveDisposition(
-    IN  PLOG_DISPOSITION    Disposition
-    );
-
 extern NTSTATUS
 LogInitialize(
     VOID
diff --git a/src/xenbus/console.c b/src/xenbus/console.c
new file mode 100644
index 0000000..36e113e
--- /dev/null
+++ b/src/xenbus/console.c
@@ -0,0 +1,820 @@
+/* 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");
+}
diff --git a/src/xenbus/console.h b/src/xenbus/console.h
new file mode 100644
index 0000000..87be7ec
--- /dev/null
+++ b/src/xenbus/console.h
@@ -0,0 +1,67 @@
+/* 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 _XENBUS_CONSOLE_H
+#define _XENBUS_CONSOLE_H
+
+#include <ntddk.h>
+#include <xen.h>
+#include <console_interface.h>
+
+typedef struct _XENBUS_CONSOLE_CONTEXT  XENBUS_CONSOLE_CONTEXT, 
*PXENBUS_CONSOLE_CONTEXT;
+
+#include "fdo.h"
+
+extern NTSTATUS
+ConsoleInitialize(
+    IN  PXENBUS_FDO             Fdo,
+    OUT PXENBUS_CONSOLE_CONTEXT *Context
+    );
+
+extern NTSTATUS
+ConsoleGetInterface(
+    IN      PXENBUS_CONSOLE_CONTEXT Context,
+    IN      ULONG                   Version,
+    IN OUT  PINTERFACE              Interface,
+    IN      ULONG                   Size
+    );
+
+extern ULONG
+ConsoleGetReferences(
+    IN  PXENBUS_CONSOLE_CONTEXT Context
+    );
+
+extern VOID
+ConsoleTeardown(
+    IN  PXENBUS_CONSOLE_CONTEXT Context
+    );
+
+#endif  // _XENBUS_CONSOLE_H
diff --git a/src/xenbus/fdo.c b/src/xenbus/fdo.c
index 7e68b36..41d789b 100644
--- a/src/xenbus/fdo.c
+++ b/src/xenbus/fdo.c
@@ -51,6 +51,7 @@
 #include "evtchn.h"
 #include "debug.h"
 #include "store.h"
+#include "console.h"
 #include "cache.h"
 #include "gnttab.h"
 #include "suspend.h"
@@ -122,6 +123,7 @@ struct _XENBUS_FDO {
     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;
@@ -132,6 +134,7 @@ struct _XENBUS_FDO {
     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;
 
@@ -140,6 +143,7 @@ struct _XENBUS_FDO {
 
     PXENBUS_EVTCHN_CHANNEL          Channel;
     PXENBUS_SUSPEND_CALLBACK        SuspendCallbackLate;
+    PLOG_DISPOSITION                LogDisposition;
 };
 
 static FORCEINLINE PVOID
@@ -785,6 +789,7 @@ DEFINE_FDO_GET_CONTEXT(SharedInfo, 
PXENBUS_SHARED_INFO_CONTEXT)
 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)
@@ -2608,6 +2613,22 @@ fail1:
     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
@@ -2637,6 +2658,15 @@ __FdoD3ToD0(
                   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,
@@ -2711,6 +2741,9 @@ fail3:
 fail2:
     Error("fail2\n");
 
+    LogRemoveDisposition(Fdo->LogDisposition);
+    Fdo->LogDisposition = NULL;
+
     XENBUS_EVTCHN(Close,
                   &Fdo->EvtchnInterface,
                   Fdo->Channel);
@@ -2760,6 +2793,9 @@ __FdoD0ToD3(
                         Fdo->ScanWatch);
     Fdo->ScanWatch = NULL;
 
+    LogRemoveDisposition(Fdo->LogDisposition);
+    Fdo->LogDisposition = NULL;
+
     XENBUS_EVTCHN(Close,
                   &Fdo->EvtchnInterface,
                   Fdo->Channel);
@@ -2975,15 +3011,19 @@ FdoD3ToD0(
     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,
@@ -2992,7 +3032,7 @@ FdoD3ToD0(
                             Fdo,
                             &Fdo->SuspendCallbackLate);
     if (!NT_SUCCESS(status))
-        goto fail9;
+        goto fail10;
 
     KeLowerIrql(Irql);
 
@@ -3023,16 +3063,21 @@ not_active:
 
     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");
@@ -3156,6 +3201,8 @@ FdoD0ToD3(
     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);
@@ -3224,6 +3271,7 @@ FdoS3ToS4(
     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);
 
@@ -5090,26 +5138,30 @@ FdoCreate(
     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),
@@ -5140,6 +5192,13 @@ FdoCreate(
     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,
@@ -5172,30 +5231,36 @@ done:
 
     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");
 
@@ -5318,6 +5383,9 @@ FdoDestroy(
         RtlZeroMemory(&Fdo->RangeSetInterface,
                       sizeof (XENBUS_RANGE_SET_INTERFACE));
 
+        RtlZeroMemory(&Fdo->ConsoleInterface,
+                      sizeof (XENBUS_CONSOLE_INTERFACE));
+
         RtlZeroMemory(&Fdo->StoreInterface,
                       sizeof (XENBUS_STORE_INTERFACE));
 
@@ -5347,6 +5415,9 @@ FdoDestroy(
         RangeSetTeardown(Fdo->RangeSetContext);
         Fdo->RangeSetContext = NULL;
 
+        ConsoleTeardown(Fdo->ConsoleContext);
+        Fdo->ConsoleContext = NULL;
+
         StoreTeardown(Fdo->StoreContext);
         Fdo->StoreContext = NULL;
 
diff --git a/vs2012/xenbus/xenbus.vcxproj b/vs2012/xenbus/xenbus.vcxproj
index 2cffb9f..5bb3be9 100644
--- a/vs2012/xenbus/xenbus.vcxproj
+++ b/vs2012/xenbus/xenbus.vcxproj
@@ -68,6 +68,7 @@
   <ItemGroup>
     <ClCompile Include="..\..\src\common\registry.c" />
     <ClCompile Include="..\..\src\xenbus\bus.c" />
+    <ClCompile Include="..\..\src\xenbus\console.c" />
     <ClCompile Include="..\..\src\xenbus\dma.c" />
     <ClCompile Include="..\..\src\xenbus\debug.c" />
     <ClCompile Include="..\..\src\xenbus\driver.c" />
diff --git a/vs2013/xenbus/xenbus.vcxproj b/vs2013/xenbus/xenbus.vcxproj
index 396245f..0856ddc 100644
--- a/vs2013/xenbus/xenbus.vcxproj
+++ b/vs2013/xenbus/xenbus.vcxproj
@@ -71,6 +71,7 @@
   <ItemGroup>
     <ClCompile Include="..\..\src\common\registry.c" />
     <ClCompile Include="..\..\src\xenbus\bus.c" />
+    <ClCompile Include="..\..\src\xenbus\console.c" />
     <ClCompile Include="..\..\src\xenbus\dma.c" />
     <ClCompile Include="..\..\src\xenbus\debug.c" />
     <ClCompile Include="..\..\src\xenbus\driver.c" />
diff --git a/vs2015/xenbus/xenbus.vcxproj b/vs2015/xenbus/xenbus.vcxproj
index 7fbc7bd..038d3d7 100644
--- a/vs2015/xenbus/xenbus.vcxproj
+++ b/vs2015/xenbus/xenbus.vcxproj
@@ -66,6 +66,7 @@
   <ItemGroup>
     <ClCompile Include="..\..\src\common\registry.c" />
     <ClCompile Include="..\..\src\xenbus\bus.c" />
+    <ClCompile Include="..\..\src\xenbus\console.c" />
     <ClCompile Include="..\..\src\xenbus\dma.c" />
     <ClCompile Include="..\..\src\xenbus\debug.c" />
     <ClCompile Include="..\..\src\xenbus\driver.c" />
-- 
2.5.3


_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.