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

[win-pv-devel] [PATCH 12/14 v2] Implement ring protocol



From: Owen Smith <owen.smith@xxxxxxxxxx>

Adds ring.h/.c which implements the console ring protocol and
handles the cancel safe queues for the outstanding read/write IRPs.
Connect the ring with the state protocol in the frontend.
Also fixes frontend state transitions to get allow the ring to
connect and operate correctly.

Signed-off-by: Owen Smith <owen.smith@xxxxxxxxxx>
---
 src/xencons/frontend.c         |  227 +++++----
 src/xencons/ring.c             | 1064 ++++++++++++++++++++++++++++++++++++++++
 src/xencons/ring.h             |   96 ++++
 vs2015/xencons/xencons.vcxproj |    1 +
 vs2017/xencons/xencons.vcxproj |    1 +
 5 files changed, 1306 insertions(+), 83 deletions(-)
 create mode 100755 src/xencons/ring.c
 create mode 100755 src/xencons/ring.h

diff --git a/src/xencons/frontend.c b/src/xencons/frontend.c
index a6e57d1..f7d3b23 100755
--- a/src/xencons/frontend.c
+++ b/src/xencons/frontend.c
@@ -44,6 +44,7 @@
 
 #include "driver.h"
 #include "frontend.h"
+#include "ring.h"
 #include "thread.h"
 #include "dbg_print.h"
 #include "assert.h"
@@ -82,6 +83,8 @@ struct _XENCONS_FRONTEND {
     PXENBUS_SUSPEND_CALLBACK    SuspendCallback;
     PXENBUS_DEBUG_CALLBACK      DebugCallback;
     PXENBUS_STORE_WATCH         Watch;
+
+    PXENCONS_RING               Ring;
 };
 
 static const PCHAR
@@ -592,11 +595,21 @@ FrontendClose(
         if (!FrontendIsOnline(Frontend))
             break;
 
-        FrontendSetXenbusState(Frontend,
-                               XenbusStateClosed);
-
         FrontendWaitForBackendXenbusStateChange(Frontend,
                                                 &State);
+
+        switch (State) {
+        case XenbusStateClosing:
+            FrontendSetXenbusState(Frontend,
+                                    XenbusStateClosed);
+            break;
+        case XenbusStateClosed:
+            break;
+        default:
+            FrontendSetXenbusState(Frontend,
+                                   XenbusStateClosing);
+            break;
+        }
     }
 
     FrontendReleaseBackend(Frontend);
@@ -631,11 +644,20 @@ FrontendPrepare(
         if (!FrontendIsOnline(Frontend))
             break;
 
-        FrontendSetXenbusState(Frontend,
-                               XenbusStateInitialising);
-
         FrontendWaitForBackendXenbusStateChange(Frontend,
                                                 &State);
+        switch (State) {
+        case XenbusStateInitWait:
+            break;
+        case XenbusStateClosed:
+            FrontendSetXenbusState(Frontend,
+                                   XenbusStateClosed);
+            break;
+        default:
+            FrontendSetXenbusState(Frontend,
+                                    XenbusStateInitialising);
+            break;
+        }
     }
 
     status = STATUS_UNSUCCESSFUL;
@@ -725,7 +747,9 @@ FrontendConnect(
     if (!NT_SUCCESS(status))
         goto fail2;
 
-    // TODO: Connect Ring
+    status = RingConnect(Frontend->Ring);
+    if (!NT_SUCCESS(status))
+        goto fail3;
 
     Attempt = 0;
     do {
@@ -737,7 +761,10 @@ FrontendConnect(
         if (!NT_SUCCESS(status))
             break;
 
-        // TODO: StoreWrite Ring
+        status = RingStoreWrite(Frontend->Ring,
+                                Transaction);
+        if (!NT_SUCCESS(status))
+            goto abort;
 
         status = XENBUS_STORE(TransactionEnd,
                               &Frontend->StoreInterface,
@@ -748,12 +775,12 @@ FrontendConnect(
 
         continue;
 
-    //abort:
-    //    (VOID)XENBUS_STORE(TransactionEnd,
-    //                       &Frontend->StoreInterface,
-    //                       Transaction,
-    //                       FALSE);
-    //    break;
+    abort:
+        (VOID)XENBUS_STORE(TransactionEnd,
+                           &Frontend->StoreInterface,
+                           Transaction,
+                           FALSE);
+        break;
     } while (status == STATUS_RETRY);
 
     if (!NT_SUCCESS(status))
@@ -764,11 +791,24 @@ FrontendConnect(
         if (!FrontendIsOnline(Frontend))
             break;
 
-        FrontendSetXenbusState(Frontend,
-                               XenbusStateConnected);
-
         FrontendWaitForBackendXenbusStateChange(Frontend,
                                                 &State);
+
+        switch (State) {
+        case XenbusStateInitWait:
+            FrontendSetXenbusState(Frontend,
+                                   XenbusStateConnected);
+            break;
+        case XenbusStateConnected:
+            break;
+        case XenbusStateUnknown:
+        case XenbusStateClosing:
+        case XenbusStateClosed:
+            FrontendSetOffline(Frontend);
+            break;
+        default:
+            break;
+        }
     }
 
     status = STATUS_UNSUCCESSFUL;
@@ -784,7 +824,7 @@ FrontendConnect(
     if (NT_SUCCESS(status)) {
         Length = (ULONG)strlen(Buffer);
 
-        Frontend->Name = __FrontendAllocate(Length);
+        Frontend->Name = __FrontendAllocate(Length + 1);
         if (Frontend->Name)
             RtlCopyMemory(Frontend->Name, Buffer, Length);
 
@@ -802,7 +842,7 @@ FrontendConnect(
     if (NT_SUCCESS(status)) {
         Length = (ULONG)strlen(Buffer);
 
-        Frontend->Protocol = __FrontendAllocate(Length);
+        Frontend->Protocol = __FrontendAllocate(Length + 1);
         if (Frontend->Protocol)
             RtlCopyMemory(Frontend->Protocol, Buffer, Length);
 
@@ -820,12 +860,21 @@ fail5:
 fail4:
     Error("fail4\n");
 
-//fail3:
+    RingDisconnect(Frontend->Ring);
+
+fail3:
     Error("fail3\n");
 
+    XENBUS_DEBUG(Deregister,
+                 &Frontend->DebugInterface,
+                 Frontend->DebugCallback);
+    Frontend->DebugCallback = NULL;
+
 fail2:
     Error("fail2\n");
 
+    XENBUS_DEBUG(Release, &Frontend->DebugInterface);
+
 fail1:
     Error("fail1 (%08x)\n", status);
 
@@ -845,7 +894,7 @@ FrontendDisconnect(
     __FrontendFree(Frontend->Name);
     Frontend->Name = NULL;
 
-    // TODO: Disconnect Ring
+    RingDisconnect(Frontend->Ring);
 
     XENBUS_DEBUG(Deregister,
                  &Frontend->DebugInterface,
@@ -862,14 +911,22 @@ FrontendEnable(
     IN  PXENCONS_FRONTEND    Frontend
     )
 {
+    NTSTATUS                status;
+
     Trace("====>\n");
 
-    UNREFERENCED_PARAMETER(Frontend);
-    // TODO: Enable Ring
+    status = RingEnable(Frontend->Ring);
+    if (!NT_SUCCESS(status))
+        goto fail1;
 
     Trace("<====\n");
 
     return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
 }
 
 static VOID
@@ -879,8 +936,7 @@ FrontendDisable(
 {
     Trace("====>\n");
 
-    UNREFERENCED_PARAMETER(Frontend);
-    // TODO: Disable Ring
+    RingDisable(Frontend->Ring);
 
     Trace("<====\n");
 }
@@ -1048,6 +1104,7 @@ __FrontendResume(
 
     ASSERT3U(Frontend->State, == , FRONTEND_UNKNOWN);
     UNREFERENCED_PARAMETER(Frontend);
+    // Current backends dont like re-opening after being closed
     //(VOID)FrontendSetState(Frontend, FRONTEND_CLOSED);
 }
 
@@ -1059,7 +1116,7 @@ __FrontendSuspend(
     ASSERT3U(KeGetCurrentIrql(), == , DISPATCH_LEVEL);
 
     UNREFERENCED_PARAMETER(Frontend);
-    //(VOID)FrontendSetState(Frontend, FRONTEND_UNKNOWN);
+    (VOID)FrontendSetState(Frontend, FRONTEND_UNKNOWN);
 }
 
 static DECLSPEC_NOINLINE VOID
@@ -1186,7 +1243,8 @@ FrontendDestroy(
 
     RtlZeroMemory(&Frontend->EjectEvent, sizeof(KEVENT));
 
-    // TODO: Teardown Ring
+    RingDestroy(Frontend->Ring);
+    Frontend->Ring = NULL;
 
     RtlZeroMemory(&Frontend->StoreInterface,
                   sizeof(XENBUS_STORE_INTERFACE));
@@ -1294,40 +1352,42 @@ FrontendAbiAcquire(
     )
 {
     PXENCONS_FRONTEND               Frontend = (PXENCONS_FRONTEND)Context;
+    LONG                            Count;
     KIRQL                           Irql;
     NTSTATUS                        status;
 
-    InterlockedIncrement(&Frontend->RefCount);
+    Count = InterlockedIncrement(&Frontend->RefCount);
+    if (Count == 2) {
+        KeRaiseIrql(DISPATCH_LEVEL, &Irql);
 
-    KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+        status = XENBUS_SUSPEND(Acquire, &Frontend->SuspendInterface);
+        if (!NT_SUCCESS(status))
+            goto fail1;
 
-    status = XENBUS_SUSPEND(Acquire, &Frontend->SuspendInterface);
-    if (!NT_SUCCESS(status))
-        goto fail1;
+        __FrontendResume(Frontend);
 
-    __FrontendResume(Frontend);
+        status = XENBUS_SUSPEND(Register,
+                                &Frontend->SuspendInterface,
+                                SUSPEND_CALLBACK_LATE,
+                                FrontendSuspendCallback,
+                                Frontend,
+                                &Frontend->SuspendCallback);
+        if (!NT_SUCCESS(status))
+            goto fail2;
 
-    status = XENBUS_SUSPEND(Register,
-                            &Frontend->SuspendInterface,
-                            SUSPEND_CALLBACK_LATE,
-                            FrontendSuspendCallback,
-                            Frontend,
-                            &Frontend->SuspendCallback);
-    if (!NT_SUCCESS(status))
-        goto fail2;
+        KeLowerIrql(Irql);
 
-    KeLowerIrql(Irql);
+        KeClearEvent(&Frontend->EjectEvent);
+        ThreadWake(Frontend->EjectThread);
 
-    KeClearEvent(&Frontend->EjectEvent);
-    ThreadWake(Frontend->EjectThread);
-
-    Trace("waiting for eject thread\n");
+        Trace("waiting for eject thread\n");
 
-    (VOID)KeWaitForSingleObject(&Frontend->EjectEvent,
-                                Executive,
-                                KernelMode,
-                                FALSE,
-                                NULL);
+        (VOID)KeWaitForSingleObject(&Frontend->EjectEvent,
+                                    Executive,
+                                    KernelMode,
+                                    FALSE,
+                                    NULL);
+    }
 
     return STATUS_SUCCESS;
 
@@ -1358,31 +1418,31 @@ FrontendAbiRelease(
     KIRQL                           Irql;
 
     Count = InterlockedDecrement(&Frontend->RefCount);
+    if (Count == 1) {
+        KeRaiseIrql(DISPATCH_LEVEL, &Irql);
 
-    KeRaiseIrql(DISPATCH_LEVEL, &Irql);
-
-    XENBUS_SUSPEND(Deregister,
-                   &Frontend->SuspendInterface,
-                   Frontend->SuspendCallback);
-    Frontend->SuspendCallback = NULL;
-
-    __FrontendSuspend(Frontend);
+        XENBUS_SUSPEND(Deregister,
+                       &Frontend->SuspendInterface,
+                       Frontend->SuspendCallback);
+        Frontend->SuspendCallback = NULL;
 
-    XENBUS_SUSPEND(Release, &Frontend->SuspendInterface);
+        __FrontendSuspend(Frontend);
 
-    KeLowerIrql(Irql);
+        XENBUS_SUSPEND(Release, &Frontend->SuspendInterface);
 
-    KeClearEvent(&Frontend->EjectEvent);
-    ThreadWake(Frontend->EjectThread);
+        KeLowerIrql(Irql);
 
-    Trace("waiting for eject thread\n");
+        KeClearEvent(&Frontend->EjectEvent);
+        ThreadWake(Frontend->EjectThread);
 
-    (VOID)KeWaitForSingleObject(&Frontend->EjectEvent,
-                                Executive,
-                                KernelMode,
-                                FALSE,
-                                NULL);
+        Trace("waiting for eject thread\n");
 
+        (VOID)KeWaitForSingleObject(&Frontend->EjectEvent,
+                                    Executive,
+                                    KernelMode,
+                                    FALSE,
+                                    NULL);
+    }
     if (Count == 0)
         FrontendDestroy(Frontend);
 }
@@ -1403,9 +1463,7 @@ FrontendAbiD3ToD0(
 {
     PXENCONS_FRONTEND               Frontend = (PXENCONS_FRONTEND)Context;
 
-    UNREFERENCED_PARAMETER(Frontend);
-    //return FrontendSetState(Frontend, FRONTEND_ENABLED);
-    return STATUS_SUCCESS;
+    return FrontendSetState(Frontend, FRONTEND_ENABLED);
 }
 
 static VOID
@@ -1416,7 +1474,7 @@ FrontendAbiD0ToD3(
     PXENCONS_FRONTEND               Frontend = (PXENCONS_FRONTEND)Context;
 
     UNREFERENCED_PARAMETER(Frontend);
-    //(VOID) FrontendSetState(Frontend, FRONTEND_CLOSED);
+    (VOID) FrontendSetState(Frontend, FRONTEND_CLOSED);
 }
 
 static NTSTATUS
@@ -1425,9 +1483,9 @@ FrontendAbiOpen(
     IN  PFILE_OBJECT                FileObject
     )
 {
-    UNREFERENCED_PARAMETER(Context);
-    UNREFERENCED_PARAMETER(FileObject);
-    return STATUS_SUCCESS;
+    PXENCONS_FRONTEND               Frontend = (PXENCONS_FRONTEND)Context;
+
+    return RingOpen(Frontend->Ring, FileObject);
 }
 
 static NTSTATUS
@@ -1436,9 +1494,9 @@ FrontendAbiClose(
     IN  PFILE_OBJECT                FileObject
     )
 {
-    UNREFERENCED_PARAMETER(Context);
-    UNREFERENCED_PARAMETER(FileObject);
-    return STATUS_SUCCESS;
+    PXENCONS_FRONTEND               Frontend = (PXENCONS_FRONTEND)Context;
+
+    return RingClose(Frontend->Ring, FileObject);
 }
 
 static NTSTATUS
@@ -1455,7 +1513,7 @@ FrontendAbiPutQueue(
     switch (StackLocation->MajorFunction) {
     case IRP_MJ_READ:
     case IRP_MJ_WRITE:
-        return STATUS_DEVICE_NOT_READY;
+        return RingPutQueue(Frontend->Ring, Irp);
 
     case IRP_MJ_DEVICE_CONTROL:
         return FrontendGetProperty(Frontend, Irp);
@@ -1526,7 +1584,9 @@ FrontendCreate(
     FdoGetSuspendInterface(PdoGetFdo(Pdo), &Frontend->SuspendInterface);
     FdoGetStoreInterface(PdoGetFdo(Pdo), &Frontend->StoreInterface);
 
-    // TODO: Initialize Ring
+    status = RingCreate(Frontend, &Frontend->Ring);
+    if (!NT_SUCCESS(status))
+        goto fail4;
 
     KeInitializeEvent(&Frontend->EjectEvent, NotificationEvent, FALSE);
 
@@ -1546,9 +1606,10 @@ fail5:
 
     RtlZeroMemory(&Frontend->EjectEvent, sizeof(KEVENT));
 
-    // TODO: Teardown Ring
+    RingDestroy(Frontend->Ring);
+    Frontend->Ring = NULL;
 
-//fail4:
+fail4:
     Error("fail4\n");
 
     RtlZeroMemory(&Frontend->StoreInterface,
diff --git a/src/xencons/ring.c b/src/xencons/ring.c
new file mode 100755
index 0000000..20c4520
--- /dev/null
+++ b/src/xencons/ring.c
@@ -0,0 +1,1064 @@
+/* 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 <stdlib.h>
+
+#include <xen.h>
+#include <debug_interface.h>
+#include <store_interface.h>
+#include <gnttab_interface.h>
+#include <evtchn_interface.h>
+
+#include "frontend.h"
+#include "ring.h"
+#include "names.h"
+#include "dbg_print.h"
+#include "assert.h"
+#include "util.h"
+
+typedef struct _XENCONS_QUEUE {
+    IO_CSQ                  Csq;
+    LIST_ENTRY              List;
+    KSPIN_LOCK                 Lock;
+} XENCONS_QUEUE, *PXENCONS_QUEUE;
+
+struct _XENCONS_RING {
+    PXENCONS_FRONTEND           Frontend;
+    BOOLEAN                     Connected;
+    BOOLEAN                     Enabled;
+    KSPIN_LOCK                  Lock;
+    PXENBUS_GNTTAB_CACHE        GnttabCache;
+    struct xencons_interface    *Shared;
+    PMDL                        Mdl;
+    PXENBUS_GNTTAB_ENTRY        Entry;
+    KDPC                        Dpc;
+    ULONG                       Dpcs;
+    ULONG                       Events;
+    PXENBUS_EVTCHN_CHANNEL      Channel;
+    XENBUS_GNTTAB_INTERFACE     GnttabInterface;
+    XENBUS_STORE_INTERFACE      StoreInterface;
+    XENBUS_EVTCHN_INTERFACE     EvtchnInterface;
+    XENBUS_DEBUG_INTERFACE      DebugInterface;
+    PXENBUS_DEBUG_CALLBACK      DebugCallback;
+    XENCONS_QUEUE               Read;
+    XENCONS_QUEUE               Write;
+    ULONG                       BytesRead;
+    ULONG                       BytesWritten;
+};
+
+#define MAXNAMELEN          128
+#define XENCONS_RING_TAG  'GNIR'
+
+static FORCEINLINE PVOID
+__RingAllocate(
+    IN  ULONG   Length
+    )
+{
+    return __AllocatePoolWithTag(NonPagedPool, Length, XENCONS_RING_TAG);
+}
+
+static FORCEINLINE VOID
+__RingFree(
+    IN  PVOID   Buffer
+    )
+{
+    __FreePoolWithTag(Buffer, XENCONS_RING_TAG);
+}
+
+IO_CSQ_INSERT_IRP_EX RingCsqInsertIrpEx;
+
+NTSTATUS
+RingCsqInsertIrpEx(
+    IN  PIO_CSQ         Csq,
+    IN  PIRP            Irp,
+    IN  PVOID           InsertContext OPTIONAL
+    )
+{
+    BOOLEAN             ReInsert = (BOOLEAN)(ULONG_PTR)InsertContext;
+    PXENCONS_QUEUE      Queue;
+
+    Queue = CONTAINING_RECORD(Csq, XENCONS_QUEUE, Csq);
+
+    if (ReInsert) {
+        // This only occurs if the DPC de-queued the IRP but
+        // then found the console to be blocked.
+        InsertHeadList(&Queue->List, &Irp->Tail.Overlay.ListEntry);
+    } else {
+        InsertTailList(&Queue->List, &Irp->Tail.Overlay.ListEntry);
+    }
+
+    return STATUS_PENDING;
+}
+
+IO_CSQ_REMOVE_IRP RingCsqRemoveIrp;
+
+VOID
+RingCsqRemoveIrp(
+    IN  PIO_CSQ     Csq,
+    IN  PIRP        Irp
+    )
+{
+    UNREFERENCED_PARAMETER(Csq);
+
+    RemoveEntryList(&Irp->Tail.Overlay.ListEntry);
+}
+
+IO_CSQ_PEEK_NEXT_IRP RingCsqPeekNextIrp;
+
+PIRP
+RingCsqPeekNextIrp(
+    IN  PIO_CSQ     Csq,
+    IN  PIRP        Irp,
+    IN  PVOID       PeekContext OPTIONAL
+    )
+{
+    PXENCONS_QUEUE  Queue;
+    PLIST_ENTRY     ListEntry;
+    PIRP            NextIrp;
+
+    Queue = CONTAINING_RECORD(Csq, XENCONS_QUEUE, Csq);
+
+    ListEntry = (Irp == NULL) ?
+        Queue->List.Flink :
+        Irp->Tail.Overlay.ListEntry.Flink;
+
+    while (ListEntry != &Queue->List) {
+        PIO_STACK_LOCATION  StackLocation;
+
+        NextIrp = CONTAINING_RECORD(ListEntry, IRP, Tail.Overlay.ListEntry);
+        if (PeekContext == NULL)
+            return NextIrp;
+
+        StackLocation = IoGetCurrentIrpStackLocation(NextIrp);
+        if (StackLocation->FileObject == (PFILE_OBJECT)PeekContext)
+            return NextIrp;
+
+        ListEntry = ListEntry->Flink;
+    }
+
+    return NULL;
+}
+
+#pragma warning(push)
+#pragma warning(disable:28167) // function changes IRQL
+
+IO_CSQ_ACQUIRE_LOCK RingCsqAcquireLock;
+
+VOID
+RingCsqAcquireLock(
+    IN  PIO_CSQ     Csq,
+    OUT PKIRQL      Irql
+    )
+{
+    PXENCONS_QUEUE  Queue;
+
+    Queue = CONTAINING_RECORD(Csq, XENCONS_QUEUE, Csq);
+
+    KeAcquireSpinLock(&Queue->Lock, Irql);
+}
+
+IO_CSQ_RELEASE_LOCK RingCsqReleaseLock;
+
+VOID
+RingCsqReleaseLock(
+    IN  PIO_CSQ     Csq,
+    IN  KIRQL       Irql
+    )
+{
+    PXENCONS_QUEUE  Queue;
+
+    Queue = CONTAINING_RECORD(Csq, XENCONS_QUEUE, Csq);
+
+    KeReleaseSpinLock(&Queue->Lock, Irql);
+}
+
+#pragma warning(pop)
+
+IO_CSQ_COMPLETE_CANCELED_IRP RingCsqCompleteCanceledIrp;
+
+VOID
+RingCsqCompleteCanceledIrp(
+    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("CANCELLED (%02x:%s)\n",
+          MajorFunction,
+          MajorFunctionName(MajorFunction));
+
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+}
+
+static FORCEINLINE VOID
+__RingCancelRequests(
+    IN  PXENCONS_RING   Ring,
+    IN  PFILE_OBJECT    FileObject
+    )
+{
+    for (;;) {
+        PIRP    Irp;
+
+        Irp = IoCsqRemoveNextIrp(&Ring->Read.Csq, FileObject);
+        if (Irp == NULL)
+            break;
+
+        RingCsqCompleteCanceledIrp(&Ring->Read.Csq, Irp);
+    }
+    for (;;) {
+        PIRP    Irp;
+
+        Irp = IoCsqRemoveNextIrp(&Ring->Write.Csq, FileObject);
+        if (Irp == NULL)
+            break;
+
+        RingCsqCompleteCanceledIrp(&Ring->Write.Csq, Irp);
+    }
+}
+
+static VOID
+RingAcquireLock(
+    IN  PVOID       Argument
+    )
+{
+    PXENCONS_RING   Ring = Argument;
+
+    KeAcquireSpinLockAtDpcLevel(&Ring->Lock);
+}
+
+static VOID
+RingReleaseLock(
+    IN  PVOID       Argument
+    )
+{
+    PXENCONS_RING   Ring = Argument;
+
+#pragma prefast(suppress:26110)
+    KeReleaseSpinLockFromDpcLevel(&Ring->Lock);
+}
+
+NTSTATUS
+RingOpen(
+    IN  PXENCONS_RING   Ring,
+    IN  PFILE_OBJECT    FileObject
+    )
+{
+    UNREFERENCED_PARAMETER(Ring);
+    UNREFERENCED_PARAMETER(FileObject);
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+RingClose(
+    IN  PXENCONS_RING   Ring,
+    IN  PFILE_OBJECT    FileObject
+    )
+{
+    __RingCancelRequests(Ring, FileObject);
+    return STATUS_SUCCESS;
+}
+
+NTSTATUS
+RingPutQueue(
+    IN  PXENCONS_RING   Ring,
+    IN  PIRP            Irp
+    )
+{
+    PIO_STACK_LOCATION  StackLocation;
+    NTSTATUS            status;
+
+    StackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+    switch (StackLocation->MajorFunction) {
+    case IRP_MJ_READ:
+        status = IoCsqInsertIrpEx(&Ring->Read.Csq,
+                                  Irp,
+                                  NULL,
+                                  (PVOID)FALSE);
+        break;
+
+    case IRP_MJ_WRITE:
+        status = IoCsqInsertIrpEx(&Ring->Write.Csq,
+                                  Irp,
+                                  NULL,
+                                  (PVOID)FALSE);
+        break;
+
+    default:
+        ASSERT(FALSE);
+        status = STATUS_NOT_SUPPORTED; // Keep SDV happy
+        break;
+    }
+    if (status != STATUS_PENDING)
+        goto fail1;
+
+    KeInsertQueueDpc(&Ring->Dpc, NULL, NULL);
+    return STATUS_PENDING;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+static ULONG
+RingCopyFromRead(
+    IN  PXENCONS_RING           Ring,
+    IN  PCHAR                   Data,
+    IN  ULONG                   Length
+    )
+{
+    struct xencons_interface    *Shared;
+    XENCONS_RING_IDX            cons;
+    XENCONS_RING_IDX            prod;
+    ULONG                       Offset;
+
+    Shared = Ring->Shared;
+
+    KeMemoryBarrier();
+
+    cons = Shared->in_cons;
+    prod = Shared->in_prod;
+
+    KeMemoryBarrier();
+
+    Offset = 0;
+    while (Length != 0) {
+        ULONG   Available;
+        ULONG   Index;
+        ULONG   CopyLength;
+
+        Available = prod - cons;
+
+        if (Available == 0)
+            break;
+
+        Index = MASK_XENCONS_IDX(cons, Shared->in);
+
+        CopyLength = __min(Length, Available);
+        CopyLength = __min(CopyLength, sizeof(Shared->in) - Index);
+
+        RtlCopyMemory(Data + Offset, &Shared->in[Index], CopyLength);
+
+        Offset += CopyLength;
+        Length -= CopyLength;
+
+        cons += CopyLength;
+    }
+
+    KeMemoryBarrier();
+
+    Shared->in_cons = cons;
+
+    KeMemoryBarrier();
+
+    return Offset;
+}
+
+static ULONG
+RingCopyToWrite(
+    IN  PXENCONS_RING           Ring,
+    IN  PCHAR                   Data,
+    IN  ULONG                   Length
+    )
+{
+    struct xencons_interface    *Shared;
+    XENCONS_RING_IDX            cons;
+    XENCONS_RING_IDX            prod;
+    ULONG                       Offset;
+
+    Shared = Ring->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 BOOLEAN
+RingPoll(
+    IN  PXENCONS_RING   Ring
+    )
+{
+    PIRP                Irp;
+    PIO_STACK_LOCATION  StackLocation;
+    ULONG               Length;
+    PCHAR               Buffer;
+    NTSTATUS            status;
+
+    for (;;) {
+        ULONG           Read;
+
+        Irp = IoCsqRemoveNextIrp(&Ring->Read.Csq, NULL);
+        if (Irp == NULL)
+            break;
+
+        StackLocation = IoGetCurrentIrpStackLocation(Irp);
+        ASSERT(StackLocation->MajorFunction == IRP_MJ_READ);
+
+        Length = StackLocation->Parameters.Read.Length;
+        Buffer = Irp->AssociatedIrp.SystemBuffer;
+
+        Read = RingCopyFromRead(Ring,
+                                Buffer,
+                                Length);
+        if (Read == 0) {
+            status = IoCsqInsertIrpEx(&Ring->Read.Csq,
+                                      Irp,
+                                      NULL,
+                                      (PVOID)TRUE);
+            ASSERT(status == STATUS_PENDING);
+            break;
+        }
+
+        Ring->BytesRead += Read;
+
+        Irp->IoStatus.Information = Read;
+        Irp->IoStatus.Status = STATUS_SUCCESS;
+
+        Trace("COMPLETE (READ) (%u bytes)\n",
+              Irp->IoStatus.Information);
+
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    }
+
+    for (;;) {
+        ULONG           Written;
+
+        Irp = IoCsqRemoveNextIrp(&Ring->Write.Csq, NULL);
+        if (Irp == NULL)
+            break;
+
+        StackLocation = IoGetCurrentIrpStackLocation(Irp);
+        ASSERT(StackLocation->MajorFunction == IRP_MJ_WRITE);
+
+        Length = StackLocation->Parameters.Write.Length;
+        Buffer = Irp->AssociatedIrp.SystemBuffer;
+
+        Written = RingCopyToWrite(Ring,
+                                  Buffer,
+                                  Length);
+        if (Written == 0) {
+            status = IoCsqInsertIrpEx(&Ring->Write.Csq,
+                                      Irp,
+                                      NULL,
+                                      (PVOID)TRUE);
+            ASSERT(status == STATUS_PENDING);
+            break;
+        }
+
+        Ring->BytesWritten += Written;
+
+        Irp->IoStatus.Information = Written;
+        Irp->IoStatus.Status = STATUS_SUCCESS;
+
+        Trace("COMPLETE (WRITE) (%u bytes)\n",
+              Irp->IoStatus.Information);
+
+        IoCompleteRequest(Irp, IO_NO_INCREMENT);
+    }
+
+    return FALSE;
+}
+
+__drv_functionClass(KDEFERRED_ROUTINE)
+__drv_maxIRQL(DISPATCH_LEVEL)
+__drv_minIRQL(PASSIVE_LEVEL)
+__drv_sameIRQL
+static VOID
+RingDpc(
+    IN  PKDPC               Dpc,
+    IN  PVOID               Context,
+    IN  PVOID               Argument1,
+    IN  PVOID               Argument2
+    )
+{
+    PXENCONS_RING       Ring = Context;
+
+    UNREFERENCED_PARAMETER(Dpc);
+    UNREFERENCED_PARAMETER(Argument1);
+    UNREFERENCED_PARAMETER(Argument2);
+
+    ASSERT(Ring != NULL);
+
+    for (;;) {
+        BOOLEAN Enabled;
+        BOOLEAN Retry;
+        KIRQL   Irql;
+
+        KeAcquireSpinLock(&Ring->Lock, &Irql);
+        Enabled = Ring->Enabled;
+        KeReleaseSpinLock(&Ring->Lock, Irql);
+
+        if (!Enabled)
+            break;
+
+        KeRaiseIrql(DISPATCH_LEVEL, &Irql);
+        Retry = RingPoll(Ring);
+        KeLowerIrql(Irql);
+
+        if (!Retry)
+            break;
+    }
+
+    (VOID) XENBUS_EVTCHN(Unmask,
+                         &Ring->EvtchnInterface,
+                         Ring->Channel,
+                         FALSE,
+                         FALSE);
+}
+
+KSERVICE_ROUTINE    RingEvtchnCallback;
+
+BOOLEAN
+RingEvtchnCallback(
+    IN  PKINTERRUPT InterruptObject,
+    IN  PVOID       Argument
+    )
+{
+    PXENCONS_RING   Ring = Argument;
+
+    UNREFERENCED_PARAMETER(InterruptObject);
+
+    ASSERT(Ring != NULL);
+
+    Ring->Events++;
+
+    if (KeInsertQueueDpc(&Ring->Dpc, NULL, NULL))
+        Ring->Dpcs++;
+
+    return TRUE;
+}
+
+static VOID
+RingDebugCallback(
+    IN  PVOID       Argument,
+    IN  BOOLEAN     Crashing
+    )
+{
+    PXENCONS_RING   Ring = Argument;
+
+    UNREFERENCED_PARAMETER(Crashing);
+
+    XENBUS_DEBUG(Printf,
+                 &Ring->DebugInterface,
+                 "0x%p [%s]\n",
+                 Ring,
+                 (Ring->Enabled) ? "ENABLED" : "DISABLED");
+
+    // Dump shared ring
+    XENBUS_DEBUG(Printf,
+                 &Ring->DebugInterface,
+                 "SHARED: in_cons = %u in_prod = %u out_cons = %u out_prod = 
%u\n",
+                 Ring->Shared->in_cons,
+                 Ring->Shared->in_prod,
+                 Ring->Shared->out_cons,
+                 Ring->Shared->out_prod);
+
+    XENBUS_DEBUG(Printf,
+                 &Ring->DebugInterface,
+                 "BYTES: read = %u written = %u\n",
+                 Ring->BytesRead,
+                 Ring->BytesWritten);
+}
+
+NTSTATUS
+RingEnable(
+    IN  PXENCONS_RING   Ring
+    )
+{
+    Trace("====>\n");
+
+    KeAcquireSpinLockAtDpcLevel(&Ring->Lock);
+    Ring->Enabled = TRUE;
+    KeReleaseSpinLockFromDpcLevel(&Ring->Lock);
+
+    (VOID)KeInsertQueueDpc(&Ring->Dpc, NULL, NULL);
+
+    Trace("<====\n");
+
+    return STATUS_SUCCESS;
+}
+
+VOID
+RingDisable(
+    IN  PXENCONS_RING   Ring
+    )
+{
+    Trace("====>\n");
+
+    ASSERT3U(KeGetCurrentIrql(), == , DISPATCH_LEVEL);
+
+    KeAcquireSpinLockAtDpcLevel(&Ring->Lock);
+    Ring->Enabled = FALSE;
+    KeReleaseSpinLockFromDpcLevel(&Ring->Lock);
+
+    Trace("<====\n");
+}
+
+NTSTATUS
+RingConnect(
+    IN  PXENCONS_RING   Ring
+    )
+{
+    CHAR                Name[MAXNAMELEN];
+    NTSTATUS            status;
+
+    Trace("====>\n");
+
+    ASSERT(!Ring->Connected);
+
+    status = XENBUS_DEBUG(Acquire, &Ring->DebugInterface);
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    status = XENBUS_EVTCHN(Acquire, &Ring->EvtchnInterface);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    status = XENBUS_GNTTAB(Acquire, &Ring->GnttabInterface);
+    if (!NT_SUCCESS(status))
+        goto fail3;
+
+    status = XENBUS_STORE(Acquire, &Ring->StoreInterface);
+    if (!NT_SUCCESS(status))
+        goto fail4;
+
+    status = RtlStringCbPrintfA(Name,
+                                sizeof(Name),
+                                "console_%s_gnttab",
+                                PdoGetName(FrontendGetPdo(Ring->Frontend)));
+    if (!NT_SUCCESS(status))
+        goto fail5;
+
+    status = XENBUS_GNTTAB(CreateCache,
+                           &Ring->GnttabInterface,
+                           Name,
+                           0,
+                           RingAcquireLock,
+                           RingReleaseLock,
+                           Ring,
+                           &Ring->GnttabCache);
+    if (!NT_SUCCESS(status))
+        goto fail6;
+
+    Ring->Mdl = __AllocatePage();
+
+    status = STATUS_NO_MEMORY;
+    if (Ring->Mdl == NULL)
+        goto fail7;
+
+    ASSERT(Ring->Mdl->MdlFlags & MDL_MAPPED_TO_SYSTEM_VA);
+    Ring->Shared = Ring->Mdl->MappedSystemVa;
+    ASSERT(Ring->Shared != NULL);
+
+    status = XENBUS_GNTTAB(PermitForeignAccess,
+                           &Ring->GnttabInterface,
+                           Ring->GnttabCache,
+                           TRUE,
+                           FrontendGetBackendDomain(Ring->Frontend),
+                           MmGetMdlPfnArray(Ring->Mdl)[0],
+                           FALSE,
+                           &Ring->Entry);
+    if (!NT_SUCCESS(status))
+        goto fail8;
+
+    Ring->Channel = XENBUS_EVTCHN(Open,
+                                  &Ring->EvtchnInterface,
+                                  XENBUS_EVTCHN_TYPE_UNBOUND,
+                                  RingEvtchnCallback,
+                                  Ring,
+                                  FrontendGetBackendDomain(Ring->Frontend),
+                                  TRUE);
+
+    status = STATUS_UNSUCCESSFUL;
+    if (Ring->Channel == NULL)
+        goto fail9;
+
+    (VOID)XENBUS_EVTCHN(Unmask,
+                        &Ring->EvtchnInterface,
+                        Ring->Channel,
+                        FALSE,
+                        TRUE);
+
+    status = XENBUS_DEBUG(Register,
+                          &Ring->DebugInterface,
+                          __MODULE__ "|POLLER",
+                          RingDebugCallback,
+                          Ring,
+                          &Ring->DebugCallback);
+    if (!NT_SUCCESS(status))
+        goto fail10;
+
+    Ring->Connected = TRUE;
+
+    Trace("<====\n");
+    return STATUS_SUCCESS;
+
+fail10:
+    Error("fail10\n");
+
+    Ring->Events = 0;
+
+    XENBUS_EVTCHN(Close,
+                  &Ring->EvtchnInterface,
+                  Ring->Channel);
+    Ring->Channel = NULL;
+
+fail9:
+    Error("fail9\n");
+
+    (VOID)XENBUS_GNTTAB(RevokeForeignAccess,
+                        &Ring->GnttabInterface,
+                        Ring->GnttabCache,
+                        TRUE,
+                        Ring->Entry);
+    Ring->Entry = NULL;
+
+fail8:
+    Error("fail8\n");
+
+    RtlZeroMemory(Ring->Shared, PAGE_SIZE);
+
+    Ring->Shared = NULL;
+    __FreePage(Ring->Mdl);
+    Ring->Mdl = NULL;
+
+fail7:
+    Error("fail7\n");
+
+    XENBUS_GNTTAB(DestroyCache,
+                  &Ring->GnttabInterface,
+                  Ring->GnttabCache);
+    Ring->GnttabCache = NULL;
+
+fail6:
+    Error("fail6\n");
+
+fail5:
+    Error("fail5\n");
+
+    XENBUS_STORE(Release, &Ring->StoreInterface);
+
+fail4:
+    Error("fail4\n");
+
+    XENBUS_GNTTAB(Release, &Ring->GnttabInterface);
+
+fail3:
+    Error("fail3\n");
+
+    XENBUS_EVTCHN(Release, &Ring->EvtchnInterface);
+
+fail2:
+    Error("fail2\n");
+
+    XENBUS_DEBUG(Release, &Ring->DebugInterface);
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+NTSTATUS
+RingStoreWrite(
+    IN  PXENCONS_RING   Ring,
+    IN  PVOID           Transaction
+    )
+{
+    ULONG               Port;
+    ULONG               GrantRef;
+    NTSTATUS            status;
+
+    Port = XENBUS_EVTCHN(GetPort,
+                         &Ring->EvtchnInterface,
+                         Ring->Channel);
+
+    status = XENBUS_STORE(Printf,
+                          &Ring->StoreInterface,
+                          Transaction,
+                          FrontendGetPath(Ring->Frontend),
+                          "port",
+                          "%u",
+                          Port);
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    GrantRef = XENBUS_GNTTAB(GetReference,
+                             &Ring->GnttabInterface,
+                             Ring->Entry);
+
+    status = XENBUS_STORE(Printf,
+                          &Ring->StoreInterface,
+                          Transaction,
+                          FrontendGetPath(Ring->Frontend),
+                          "ring-ref",
+                          "%u",
+                          GrantRef);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    return STATUS_SUCCESS;
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+VOID
+RingDisconnect(
+    IN  PXENCONS_RING   Ring
+    )
+{
+    Trace("====>\n");
+
+    ASSERT(Ring->Connected);
+    Ring->Connected = FALSE;
+
+    XENBUS_DEBUG(Deregister,
+                 &Ring->DebugInterface,
+                 Ring->DebugCallback);
+    Ring->DebugCallback = NULL;
+
+    Ring->Dpcs = 0;
+    Ring->Events = 0;
+    Ring->BytesRead = 0;
+    Ring->BytesWritten = 0;
+
+    XENBUS_EVTCHN(Close,
+                  &Ring->EvtchnInterface,
+                  Ring->Channel);
+    Ring->Channel = NULL;
+
+    (VOID)XENBUS_GNTTAB(RevokeForeignAccess,
+                        &Ring->GnttabInterface,
+                        Ring->GnttabCache,
+                        TRUE,
+                        Ring->Entry);
+    Ring->Entry = NULL;
+
+    RtlZeroMemory(Ring->Shared, PAGE_SIZE);
+
+    Ring->Shared = NULL;
+    __FreePage(Ring->Mdl);
+    Ring->Mdl = NULL;
+
+    XENBUS_GNTTAB(DestroyCache,
+                  &Ring->GnttabInterface,
+                  Ring->GnttabCache);
+    Ring->GnttabCache = NULL;
+
+    XENBUS_STORE(Release, &Ring->StoreInterface);
+
+    XENBUS_GNTTAB(Release, &Ring->GnttabInterface);
+
+    XENBUS_EVTCHN(Release, &Ring->EvtchnInterface);
+
+    XENBUS_DEBUG(Release, &Ring->DebugInterface);
+
+    Trace("<====\n");
+}
+
+NTSTATUS
+RingCreate(
+    IN  PXENCONS_FRONTEND   Frontend,
+    OUT PXENCONS_RING       *Ring
+    )
+{
+    NTSTATUS                status;
+
+    *Ring = __RingAllocate(sizeof(XENCONS_RING));
+
+    status = STATUS_NO_MEMORY;
+    if (*Ring == NULL)
+        goto fail1;
+
+    (*Ring)->Frontend = Frontend;
+
+    FdoGetDebugInterface(PdoGetFdo(FrontendGetPdo(Frontend)),
+                         &(*Ring)->DebugInterface);
+
+    FdoGetEvtchnInterface(PdoGetFdo(FrontendGetPdo(Frontend)),
+                          &(*Ring)->EvtchnInterface);
+
+    FdoGetGnttabInterface(PdoGetFdo(FrontendGetPdo(Frontend)),
+                         &(*Ring)->GnttabInterface);
+
+    FdoGetStoreInterface(PdoGetFdo(FrontendGetPdo(Frontend)),
+                         &(*Ring)->StoreInterface);
+
+    KeInitializeSpinLock(&(*Ring)->Lock);
+
+    KeInitializeThreadedDpc(&(*Ring)->Dpc, RingDpc, *Ring);
+
+    KeInitializeSpinLock(&(*Ring)->Read.Lock);
+    InitializeListHead(&(*Ring)->Read.List);
+
+    status = IoCsqInitializeEx(&(*Ring)->Read.Csq,
+                               RingCsqInsertIrpEx,
+                               RingCsqRemoveIrp,
+                               RingCsqPeekNextIrp,
+                               RingCsqAcquireLock,
+                               RingCsqReleaseLock,
+                               RingCsqCompleteCanceledIrp);
+    if (!NT_SUCCESS(status))
+        goto fail2;
+
+    KeInitializeSpinLock(&(*Ring)->Write.Lock);
+    InitializeListHead(&(*Ring)->Write.List);
+
+    status = IoCsqInitializeEx(&(*Ring)->Write.Csq,
+                               RingCsqInsertIrpEx,
+                               RingCsqRemoveIrp,
+                               RingCsqPeekNextIrp,
+                               RingCsqAcquireLock,
+                               RingCsqReleaseLock,
+                               RingCsqCompleteCanceledIrp);
+    if (!NT_SUCCESS(status))
+        goto fail3;
+
+    return STATUS_SUCCESS;
+
+fail3:
+    Error("fail3\n");
+
+    RtlZeroMemory(&(*Ring)->Write.List, sizeof(LIST_ENTRY));
+    RtlZeroMemory(&(*Ring)->Write.Lock, sizeof(KSPIN_LOCK));
+
+    RtlZeroMemory(&(*Ring)->Read.Csq, sizeof(IO_CSQ));
+
+fail2:
+    Error("fail2\n");
+
+    RtlZeroMemory(&(*Ring)->Read.List, sizeof(LIST_ENTRY));
+    RtlZeroMemory(&(*Ring)->Read.Lock, sizeof(KSPIN_LOCK));
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+VOID
+RingDestroy(
+    IN  PXENCONS_RING   Ring
+    )
+{
+    ASSERT3U(KeGetCurrentIrql(), == , PASSIVE_LEVEL);
+    
+    // Cancel all outstanding IRPs
+    __RingCancelRequests(Ring, NULL);
+
+    ASSERT(IsListEmpty(&Ring->Read.List));
+    ASSERT(IsListEmpty(&Ring->Write.List));
+
+    RtlZeroMemory(&Ring->Write.Csq, sizeof(IO_CSQ));
+
+    RtlZeroMemory(&Ring->Write.List, sizeof(LIST_ENTRY));
+    RtlZeroMemory(&Ring->Write.Lock, sizeof(KSPIN_LOCK));
+
+    RtlZeroMemory(&Ring->Read.Csq, sizeof(IO_CSQ));
+
+    RtlZeroMemory(&Ring->Read.List, sizeof(LIST_ENTRY));
+    RtlZeroMemory(&Ring->Read.Lock, sizeof(KSPIN_LOCK));
+
+    RtlZeroMemory(&Ring->Dpc, sizeof(KDPC));
+
+    RtlZeroMemory(&Ring->Lock, sizeof(KSPIN_LOCK));
+
+    RtlZeroMemory(&Ring->StoreInterface,
+                  sizeof(XENBUS_STORE_INTERFACE));
+
+    RtlZeroMemory(&Ring->GnttabInterface,
+                  sizeof(XENBUS_GNTTAB_INTERFACE));
+
+    RtlZeroMemory(&Ring->EvtchnInterface,
+                  sizeof(XENBUS_EVTCHN_INTERFACE));
+
+    RtlZeroMemory(&Ring->DebugInterface,
+                  sizeof(XENBUS_DEBUG_INTERFACE));
+
+    Ring->Frontend = NULL;
+
+    ASSERT(IsZeroMemory(Ring, sizeof(XENCONS_RING)));
+    __RingFree(Ring);
+}
diff --git a/src/xencons/ring.h b/src/xencons/ring.h
new file mode 100755
index 0000000..aca32a2
--- /dev/null
+++ b/src/xencons/ring.h
@@ -0,0 +1,96 @@
+/* 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_RING_H
+#define _XENCONS_RING_H
+
+#include <ntddk.h>
+
+#include "frontend.h"
+
+typedef struct _XENCONS_RING XENCONS_RING, *PXENCONS_RING;
+
+extern NTSTATUS
+RingCreate(
+    IN  PXENCONS_FRONTEND   Frontend,
+    OUT PXENCONS_RING       *Ring
+    );
+
+extern VOID
+RingDestroy(
+    IN  PXENCONS_RING   Ring
+    );
+
+extern NTSTATUS
+RingConnect(
+    IN  PXENCONS_RING   Ring
+    );
+
+extern NTSTATUS
+RingStoreWrite(
+    IN  PXENCONS_RING   Ring,
+    IN  PVOID           Transaction
+    );
+
+extern VOID
+RingDisconnect(
+    IN  PXENCONS_RING   Ring
+    );
+
+extern NTSTATUS
+RingEnable(
+    IN  PXENCONS_RING   Ring
+    );
+
+extern VOID
+RingDisable(
+    IN  PXENCONS_RING   Ring
+    );
+
+extern NTSTATUS
+RingOpen(
+    IN  PXENCONS_RING   Ring,
+    IN  PFILE_OBJECT    FileObject
+    );
+
+extern NTSTATUS
+RingClose(
+    IN  PXENCONS_RING   Ring,
+    IN  PFILE_OBJECT    FileObject
+    );
+
+extern NTSTATUS
+RingPutQueue(
+    IN  PXENCONS_RING   Ring,
+    IN  PIRP            Irp
+    );
+
+#endif  // _XENCONS_RING_H
diff --git a/vs2015/xencons/xencons.vcxproj b/vs2015/xencons/xencons.vcxproj
index 8846b8e..435ef21 100644
--- a/vs2015/xencons/xencons.vcxproj
+++ b/vs2015/xencons/xencons.vcxproj
@@ -71,6 +71,7 @@
     <ClCompile Include="../../src/xencons/console.c" />
     <ClCompile Include="../../src/xencons/stream.c" />
     <ClCompile Include="../../src/xencons/frontend.c" />
+    <ClCompile Include="../../src/xencons/ring.c" />
     <ClCompile Include="../../src/xencons/thread.c" />
   </ItemGroup>
   <ItemGroup>
diff --git a/vs2017/xencons/xencons.vcxproj b/vs2017/xencons/xencons.vcxproj
index 9811da0..defb11e 100644
--- a/vs2017/xencons/xencons.vcxproj
+++ b/vs2017/xencons/xencons.vcxproj
@@ -79,6 +79,7 @@
     <ClCompile Include="../../src/xencons/console.c" />
     <ClCompile Include="../../src/xencons/stream.c" />
     <ClCompile Include="../../src/xencons/frontend.c" />
+    <ClCompile Include="../../src/xencons/ring.c" />
     <ClCompile Include="../../src/xencons/thread.c" />
   </ItemGroup>
   <ItemGroup>
-- 
2.8.3


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

 


Rackspace

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