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

[win-pv-devel] [PATCH 10/10] Add support for the FIFO event channel ABI



If it is available then the fifo ABI will be used. If it is not then the
two-level ABI will be used instead.
The ABI is released and re-acquired across suspend/resume so this should
allow moving between hosts with different capabilities.

Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
---
 include/xen.h                |  41 ++-
 src/xen/event_channel.c      | 128 ++++++++
 src/xenbus/evtchn.c          |  27 +-
 src/xenbus/evtchn_fifo.c     | 702 +++++++++++++++++++++++++++++++++++++++++++
 src/xenbus/evtchn_fifo.h     |  59 ++++
 src/xenbus/store.c           |  11 +-
 vs2012/xenbus/xenbus.vcxproj |   1 +
 vs2013/xenbus/xenbus.vcxproj |   1 +
 8 files changed, 962 insertions(+), 8 deletions(-)
 create mode 100644 src/xenbus/evtchn_fifo.c
 create mode 100644 src/xenbus/evtchn_fifo.h

diff --git a/include/xen.h b/include/xen.h
index 674676c..0039d7a 100644
--- a/include/xen.h
+++ b/include/xen.h
@@ -136,17 +136,26 @@ __checkReturn
 XEN_API
 NTSTATUS
 EventChannelBindInterDomain(
-    IN  domid_t                     RemoteDomain,
-    IN  evtchn_port_t               RemotePort,
-    OUT evtchn_port_t               *LocalPort
+    IN  domid_t         RemoteDomain,
+    IN  evtchn_port_t   RemotePort,
+    OUT evtchn_port_t   *LocalPort
     );
 
 __checkReturn
 XEN_API
 NTSTATUS
 EventChannelBindVirq(
-    IN  uint32_t            Virq,
-    OUT evtchn_port_t       *LocalPort
+    IN  uint32_t        Virq,
+    OUT evtchn_port_t   *LocalPort
+    );
+
+__checkReturn
+XEN_API
+NTSTATUS
+EventChannelQueryInterDomain(
+    IN  evtchn_port_t   LocalPort,
+    OUT domid_t         *RemoteDomain,
+    OUT evtchn_port_t   *RemotePort
     );
 
 __checkReturn
@@ -156,6 +165,28 @@ EventChannelClose(
     IN  evtchn_port_t   LocalPort
     );
 
+__checkReturn
+XEN_API
+NTSTATUS
+EventChannelExpandArray(
+    IN  PFN_NUMBER              Pfn
+    );
+
+__checkReturn
+XEN_API
+NTSTATUS
+EventChannelInitControl(
+    IN  PFN_NUMBER              Pfn,
+    IN  unsigned int            vcpu_id
+    );
+
+__checkReturn
+XEN_API
+NTSTATUS
+EventChannelReset(
+    VOID
+    );
+
 // GRANT TABLE
 
 __checkReturn
diff --git a/src/xen/event_channel.c b/src/xen/event_channel.c
index 23e4659..aa87fd4 100644
--- a/src/xen/event_channel.c
+++ b/src/xen/event_channel.c
@@ -175,6 +175,47 @@ fail1:
 __checkReturn
 XEN_API
 NTSTATUS
+EventChannelQueryInterDomain(
+    IN  evtchn_port_t               LocalPort,
+    OUT domid_t                     *RemoteDomain,
+    OUT evtchn_port_t               *RemotePort
+    )
+{
+    struct evtchn_status            op;
+    LONG_PTR                        rc;
+    NTSTATUS                        status;
+
+    op.dom = DOMID_SELF;
+    op.port = LocalPort;
+
+    rc = EventChannelOp(EVTCHNOP_status, &op);
+
+    if (rc < 0) {
+        ERRNO_TO_STATUS(-rc, status);
+        goto fail1;
+    }
+
+    status = STATUS_INVALID_PARAMETER;
+    if (op.status != EVTCHNSTAT_interdomain)
+        goto fail2;
+
+    *RemoteDomain = op.u.interdomain.dom;
+    *RemotePort = op.u.interdomain.port;
+
+    return STATUS_SUCCESS;
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+__checkReturn
+XEN_API
+NTSTATUS
 EventChannelClose(
     IN  evtchn_port_t   LocalPort
     )
@@ -199,3 +240,90 @@ fail1:
 
     return status;
 }
+
+__checkReturn
+XEN_API
+NTSTATUS
+EventChannelExpandArray(
+    IN  PFN_NUMBER              Pfn
+    )
+{
+    struct evtchn_expand_array  op;
+    LONG_PTR                    rc;
+    NTSTATUS                    status;
+
+    op.array_gfn = Pfn;
+
+    rc = EventChannelOp(EVTCHNOP_expand_array, &op);
+
+    if (rc < 0) {
+        ERRNO_TO_STATUS(-rc, status);
+        goto fail1;
+    }
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+__checkReturn
+XEN_API
+NTSTATUS
+EventChannelInitControl(
+    IN  PFN_NUMBER              Pfn,
+    IN  unsigned int            vcpu_id
+    )
+{
+    struct evtchn_init_control  op;
+    LONG_PTR                    rc;
+    NTSTATUS                    status;
+
+    op.control_gfn = Pfn;
+    op.offset = 0;
+    op.vcpu = vcpu_id;
+
+    rc = EventChannelOp(EVTCHNOP_init_control, &op);
+
+    if (rc < 0) {
+        ERRNO_TO_STATUS(-rc, status);
+        goto fail1;
+    }
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+__checkReturn
+XEN_API
+NTSTATUS
+EventChannelReset(
+    VOID
+    )
+{
+    struct evtchn_reset op;
+    LONG_PTR            rc;
+    NTSTATUS            status;
+
+    op.dom = DOMID_SELF;
+
+    rc = EventChannelOp(EVTCHNOP_reset, &op);
+
+    if (rc < 0) {
+        ERRNO_TO_STATUS(-rc, status);
+        goto fail1;
+    }
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
diff --git a/src/xenbus/evtchn.c b/src/xenbus/evtchn.c
index f13667e..2be0da8 100644
--- a/src/xenbus/evtchn.c
+++ b/src/xenbus/evtchn.c
@@ -36,6 +36,7 @@
 
 #include "evtchn.h"
 #include "evtchn_2l.h"
+#include "evtchn_fifo.h"
 #include "fdo.h"
 #include "hash_table.h"
 #include "dbg_print.h"
@@ -95,6 +96,7 @@ struct _XENBUS_EVTCHN_CONTEXT {
     PXENBUS_DEBUG_CALLBACK          DebugCallback;
     XENBUS_SHARED_INFO_INTERFACE    SharedInfoInterface;
     PXENBUS_EVTCHN_ABI_CONTEXT      EvtchnTwoLevelContext;
+    PXENBUS_EVTCHN_ABI_CONTEXT      EvtchnFifoContext;
     XENBUS_EVTCHN_ABI               EvtchnAbi;
     PXENBUS_HASH_TABLE              Table;
     LIST_ENTRY                      List;
@@ -234,7 +236,9 @@ EvtchnOpenInterDomain(
     RemotePort = va_arg(Arguments, ULONG);
     Mask = va_arg(Arguments, BOOLEAN);
 
-    status = EventChannelBindInterDomain(RemoteDomain, RemotePort, &LocalPort);
+    status = EventChannelBindInterDomain(RemoteDomain,
+                                         RemotePort,
+                                         &LocalPort);
     if (!NT_SUCCESS(status))
         goto fail1;
 
@@ -666,6 +670,13 @@ EvtchnAbiAcquire(
 {
     NTSTATUS                    status;
 
+    EvtchnFifoGetAbi(Context->EvtchnFifoContext,
+                     &Context->EvtchnAbi);
+
+    status = XENBUS_EVTCHN_ABI(Acquire, &Context->EvtchnAbi);
+    if (NT_SUCCESS(status))
+        goto done;
+
     EvtchnTwoLevelGetAbi(Context->EvtchnTwoLevelContext,
                          &Context->EvtchnAbi);
 
@@ -673,6 +684,7 @@ EvtchnAbiAcquire(
     if (!NT_SUCCESS(status))
         goto fail1;
 
+done:
     return STATUS_SUCCESS;
 
 fail1:
@@ -1024,6 +1036,10 @@ EvtchnInitialize(
     if (!NT_SUCCESS(status))
         goto fail3;
 
+    status = EvtchnFifoInitialize(Fdo, &(*Context)->EvtchnFifoContext);
+    if (!NT_SUCCESS(status))
+        goto fail4;
+
     status = SuspendGetInterface(FdoGetSuspendContext(Fdo),
                                  XENBUS_SUSPEND_INTERFACE_VERSION_MAX,
                                  (PINTERFACE)&(*Context)->SuspendInterface,
@@ -1054,6 +1070,12 @@ EvtchnInitialize(
 
     return STATUS_SUCCESS;
 
+fail4:
+    Error("fail4\n");
+
+    EvtchnTwoLevelTeardown((*Context)->EvtchnTwoLevelContext);
+    (*Context)->EvtchnTwoLevelContext = NULL;
+
 fail3:
     Error("fail3\n");
 
@@ -1131,6 +1153,9 @@ EvtchnTeardown(
     RtlZeroMemory(&Context->SuspendInterface,
                   sizeof (XENBUS_SUSPEND_INTERFACE));
 
+    EvtchnFifoTeardown(Context->EvtchnFifoContext);
+    Context->EvtchnFifoContext = NULL;
+
     EvtchnTwoLevelTeardown(Context->EvtchnTwoLevelContext);
     Context->EvtchnTwoLevelContext = NULL;
 
diff --git a/src/xenbus/evtchn_fifo.c b/src/xenbus/evtchn_fifo.c
new file mode 100644
index 0000000..d37b1cd
--- /dev/null
+++ b/src/xenbus/evtchn_fifo.c
@@ -0,0 +1,702 @@
+/* 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 <stdarg.h>
+#include <xen.h>
+#include <util.h>
+
+#include "evtchn_fifo.h"
+#include "shared_info.h"
+#include "fdo.h"
+#include "dbg_print.h"
+#include "assert.h"
+
+#define MAX_HVM_VCPUS   128
+
+typedef struct _XENBUS_EVTCHN_FIFO_CONTEXT {
+    PXENBUS_FDO                     Fdo;
+    KSPIN_LOCK                      Lock;
+    LONG                            References;
+    PMDL                            ControlBlockMdl[MAX_HVM_VCPUS];
+    PMDL                            *EventPageMdl;
+    ULONG                           EventPageCount;
+    ULONG                           Head[EVTCHN_FIFO_MAX_QUEUES];
+} XENBUS_EVTCHN_FIFO_CONTEXT, *PXENBUS_EVTCHN_FIFO_CONTEXT;
+
+#define EVENT_WORDS_PER_PAGE    (PAGE_SIZE / sizeof (event_word_t))
+
+#define XENBUS_EVTCHN_FIFO_TAG  'OFIF'
+
+static FORCEINLINE PVOID
+__EvtchnFifoAllocate(
+    IN  ULONG   Length
+    )
+{
+    return __AllocatePoolWithTag(NonPagedPool, Length, XENBUS_EVTCHN_FIFO_TAG);
+}
+
+static FORCEINLINE VOID
+__EvtchnFifoFree(
+    IN  PVOID   Buffer
+    )
+{
+    ExFreePoolWithTag(Buffer, XENBUS_EVTCHN_FIFO_TAG);
+}
+
+static event_word_t *
+EvtchnFifoEventWord(
+    IN  PXENBUS_EVTCHN_FIFO_CONTEXT Context,
+    IN  ULONG                       Port
+    )
+{
+    ULONG                           Index;
+    PMDL                            Mdl;
+    event_word_t                    *EventWord;
+
+    Index = Port / EVENT_WORDS_PER_PAGE;
+    ASSERT3U(Index, <, Context->EventPageCount);
+
+    Mdl = Context->EventPageMdl[Index];
+
+    EventWord = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
+    ASSERT(EventWord != NULL);
+
+    ASSERT3U(Port, >=, Index * EVENT_WORDS_PER_PAGE);
+    Port -= Index * EVENT_WORDS_PER_PAGE;
+
+    return &EventWord[Port];
+}
+
+static FORCEINLINE BOOLEAN
+__EvtchnFifoTestFlag(
+    IN  event_word_t    *EventWord,
+    IN  ULONG           Flag
+    )
+{
+    KeMemoryBarrier();
+
+    return !!(*EventWord & (1 << Flag));
+}
+
+static FORCEINLINE BOOLEAN
+__EvtchnFifoTestAndSetFlag(
+    IN  event_word_t    *EventWord,
+    IN  ULONG           Flag
+    )
+{
+    KeMemoryBarrier();
+
+    return !!InterlockedBitTestAndSet((LONG *)EventWord, Flag);
+}
+
+static FORCEINLINE BOOLEAN
+__EvtchnFifoTestAndClearFlag(
+    IN  event_word_t    *EventWord,
+    IN  ULONG           Flag
+    )
+{
+    KeMemoryBarrier();
+
+    return !!InterlockedBitTestAndReset((LONG *)EventWord, Flag);
+}
+
+static FORCEINLINE VOID
+__EvtchnFifoSetFlag(
+    IN  event_word_t    *EventWord,
+    IN  ULONG           Flag
+    )
+{
+    *EventWord |= (1 << Flag);
+    KeMemoryBarrier();
+}
+
+static FORCEINLINE VOID
+__EvtchnFifoClearFlag(
+    IN  event_word_t    *EventWord,
+    IN  ULONG           Flag
+    )
+{
+    *EventWord &= ~(1 << Flag);
+    KeMemoryBarrier();
+}
+
+static FORCEINLINE ULONG
+__EvtchnFifoUnlink(
+    IN  event_word_t    *EventWord
+    )
+{
+    LONG                Old;
+    LONG                New;
+
+    do {
+        Old = *EventWord;
+
+        // Clear linked bit and link value
+        New = Old & ~((1 << EVTCHN_FIFO_LINKED) | EVTCHN_FIFO_LINK_MASK);
+    } while (InterlockedCompareExchange((LONG *)EventWord, New, Old) != Old);
+
+    return Old & EVTCHN_FIFO_LINK_MASK;
+}
+
+static NTSTATUS
+EvtchnFifoExpand(
+    IN  PXENBUS_EVTCHN_FIFO_CONTEXT Context,
+    IN  ULONG                       Port
+    )
+{
+    LONG                            Index;
+    ULONG                           EventPageCount;
+    PMDL                            *EventPageMdl;
+    PMDL                            Mdl;
+    ULONG                           Start;
+    ULONG                           End;
+    NTSTATUS                        status;
+
+    Index = Port / EVENT_WORDS_PER_PAGE;
+    ASSERT3U(Index, >=, (LONG)Context->EventPageCount);
+
+    EventPageCount = Index + 1;
+    EventPageMdl = __EvtchnFifoAllocate(sizeof (PMDL) * EventPageCount);
+
+    status = STATUS_NO_MEMORY;
+    if (EventPageMdl == NULL)
+        goto fail1;
+
+    for (Index = 0; Index < (LONG)Context->EventPageCount; Index++)
+        EventPageMdl[Index] = Context->EventPageMdl[Index];
+
+    Index = Context->EventPageCount;
+    while (Index < (LONG)EventPageCount) {
+        event_word_t        *EventWord;
+        PFN_NUMBER          Pfn;
+        PHYSICAL_ADDRESS    Address;
+
+        Mdl = __AllocatePage();
+
+        status = STATUS_NO_MEMORY;
+        if (Mdl == NULL)
+            goto fail2;
+
+        EventWord = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
+        ASSERT(EventWord != NULL);
+
+        for (Port = 0; Port < EVENT_WORDS_PER_PAGE; Port++)
+            __EvtchnFifoSetFlag(&EventWord[Port], EVTCHN_FIFO_MASKED);
+
+        Pfn = MmGetMdlPfnArray(Mdl)[0];
+
+        status = EventChannelExpandArray(Pfn);
+        if (!NT_SUCCESS(status))
+            goto fail3;
+
+        Address.QuadPart = (ULONGLONG)Pfn << PAGE_SHIFT;
+
+        LogPrintf(LOG_LEVEL_INFO,
+                  "EVTCHN_FIFO: EVENTARRAY[%u] @ %08x.%08x\n",
+                  Index,
+                  Address.HighPart,
+                  Address.LowPart);
+
+        EventPageMdl[Index++] = Mdl;
+    }
+
+    Start = Context->EventPageCount * EVENT_WORDS_PER_PAGE;
+    End = (EventPageCount * EVENT_WORDS_PER_PAGE) - 1;
+
+    Info("added ports [%08x - %08x]\n", Start, End);
+
+    if (Context->EventPageMdl != NULL)
+        __EvtchnFifoFree(Context->EventPageMdl);
+
+    Context->EventPageMdl = EventPageMdl;
+    Context->EventPageCount = EventPageCount;
+
+    return STATUS_SUCCESS;
+
+fail3:
+    Error("fail3\n");
+
+    __FreePage(Mdl);
+
+fail2:
+    Error("fail2\n");
+
+    while (--Index >= (LONG)Context->EventPageCount) {
+        Mdl = EventPageMdl[Index];
+
+        __FreePage(Mdl);
+    }
+
+    __EvtchnFifoFree(EventPageMdl);
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+static VOID
+EvtchnFifoContract(
+    IN  PXENBUS_EVTCHN_FIFO_CONTEXT Context
+    )
+{
+    LONG                            Index;
+
+    Index = Context->EventPageCount;
+    while (--Index >= 0) {
+        PMDL    Mdl;
+
+        Mdl = Context->EventPageMdl[Index];
+
+        __FreePage(Mdl);
+    }
+
+    __EvtchnFifoFree(Context->EventPageMdl);
+
+    Context->EventPageMdl = NULL;
+    Context->EventPageCount = 0;
+}
+
+static BOOLEAN
+EvtchnFifoPollPriority(
+    IN  PXENBUS_EVTCHN_FIFO_CONTEXT Context,
+    IN  evtchn_fifo_control_block_t *ControlBlock,
+    IN  ULONG                       Priority,
+    IN  PULONG                      Ready,
+    IN  XENBUS_EVTCHN_ABI_EVENT     Event,
+    IN  PVOID                       Argument
+    )
+{
+    ULONG                           Head;
+    ULONG                           Port;
+    event_word_t                    *EventWord;
+    BOOLEAN                         DoneSomething;
+
+    Head = Context->Head[Priority];
+
+    if (Head == 0) {
+        KeMemoryBarrier();
+        Head = ControlBlock->head[Priority];
+    }
+
+    Port = Head;
+    EventWord = EvtchnFifoEventWord(Context, Port);
+
+    Head = __EvtchnFifoUnlink(EventWord);
+
+    if (Head == 0)
+        *Ready &= ~(1ull << Priority);
+
+    DoneSomething = FALSE;
+
+    if (!__EvtchnFifoTestFlag(EventWord, EVTCHN_FIFO_MASKED) &&
+        __EvtchnFifoTestFlag(EventWord, EVTCHN_FIFO_PENDING))
+        DoneSomething = Event(Argument, Port);
+
+    Context->Head[Priority] = Head;
+
+    return DoneSomething;
+}
+
+static BOOLEAN
+EvtchnFifoPoll(
+    IN  PXENBUS_EVTCHN_ABI_CONTEXT  _Context,
+    IN  ULONG                       Cpu,
+    IN  XENBUS_EVTCHN_ABI_EVENT     Event,
+    IN  PVOID                       Argument
+    )
+{
+    PXENBUS_EVTCHN_FIFO_CONTEXT     Context = (PVOID)_Context;
+    unsigned int                    vcpu_id = SystemVirtualCpuIndex(Cpu);
+    PMDL                            Mdl;
+    evtchn_fifo_control_block_t     *ControlBlock;
+    ULONG                           Ready;
+    ULONG                           Priority;
+    BOOLEAN                         DoneSomething;
+
+    Mdl = Context->ControlBlockMdl[vcpu_id];
+
+    ControlBlock = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
+    ASSERT(ControlBlock != NULL);
+
+    Ready = InterlockedExchange((LONG *)&ControlBlock->ready, 0);
+    DoneSomething = FALSE;
+
+    while (_BitScanReverse(&Priority, Ready)) {
+        DoneSomething |= EvtchnFifoPollPriority(Context,
+                                                ControlBlock,
+                                                Priority,
+                                                &Ready,
+                                                Event,
+                                                Argument);
+        Ready |= InterlockedExchange((LONG *)&ControlBlock->ready, 0);
+    }
+
+    return DoneSomething;
+}
+
+static NTSTATUS
+EvtchnFifoPortEnable(
+    IN  PXENBUS_EVTCHN_ABI_CONTEXT  _Context,
+    IN  ULONG                       Port
+    )
+{
+    PXENBUS_EVTCHN_FIFO_CONTEXT     Context = (PVOID)_Context;
+    KIRQL                           Irql;
+    NTSTATUS                        status;
+
+    KeAcquireSpinLock(&Context->Lock, &Irql);
+
+    if (Port / EVENT_WORDS_PER_PAGE >= Context->EventPageCount) {
+        status = EvtchnFifoExpand(Context, Port);
+
+        if (!NT_SUCCESS(status))
+            goto fail1;
+    }
+
+    KeReleaseSpinLock(&Context->Lock, Irql);
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    KeReleaseSpinLock(&Context->Lock, Irql);
+
+    return status;
+}
+
+static VOID
+EvtchnFifoPortAck(
+    IN  PXENBUS_EVTCHN_ABI_CONTEXT  _Context,
+    IN  ULONG                       Port
+    )
+{
+    PXENBUS_EVTCHN_FIFO_CONTEXT     Context = (PVOID)_Context;
+    event_word_t                    *EventWord;
+
+    EventWord = EvtchnFifoEventWord(Context, Port);
+    __EvtchnFifoClearFlag(&EventWord[Port], EVTCHN_FIFO_PENDING);
+}
+
+static VOID
+EvtchnFifoPortMask(
+    IN  PXENBUS_EVTCHN_ABI_CONTEXT  _Context,
+    IN  ULONG                       Port
+    )
+{
+    PXENBUS_EVTCHN_FIFO_CONTEXT     Context = (PVOID)_Context;
+    event_word_t                    *EventWord;
+
+    EventWord = EvtchnFifoEventWord(Context, Port);
+    __EvtchnFifoSetFlag(&EventWord[Port], EVTCHN_FIFO_MASKED);
+}
+
+static BOOLEAN
+EvtchnFifoPortUnmask(
+    IN  PXENBUS_EVTCHN_ABI_CONTEXT  _Context,
+    IN  ULONG                       Port
+    )
+{
+    PXENBUS_EVTCHN_FIFO_CONTEXT     Context = (PVOID)_Context;
+    event_word_t                    *EventWord;
+    LONG                            Old;
+    LONG                            New;
+
+    EventWord = EvtchnFifoEventWord(Context, Port);
+
+    // Clear masked bit, spinning if busy
+    do {
+        Old = *EventWord & ~(1 << EVTCHN_FIFO_BUSY);
+        New = Old & ~(1 << EVTCHN_FIFO_MASKED);
+    } while (InterlockedCompareExchange((LONG *)EventWord, New, Old) != Old);
+
+    // Check whether the port was masked
+    if (~Old & (1 << EVTCHN_FIFO_MASKED))
+        return FALSE;
+
+    // If we cleared the mask then check whether something is pending
+    if (!__EvtchnFifoTestAndClearFlag(EventWord, EVTCHN_FIFO_PENDING))
+        return FALSE;
+
+    return TRUE;
+}
+
+static VOID
+EvtchnFifoPortDisable(
+    IN  PXENBUS_EVTCHN_ABI_CONTEXT  _Context,
+    IN  ULONG                       Port
+    )
+{
+    EvtchnFifoPortMask(_Context, Port);
+}
+
+static VOID
+EvtchnFifoReset(
+    IN  PXENBUS_EVTCHN_FIFO_CONTEXT Context
+    )
+{
+    ULONGLONG                       Value;
+    ULONG                           LocalPort;
+    ULONG                           RemotePort;
+    USHORT                          RemoteDomain;
+    NTSTATUS                        status;
+
+    UNREFERENCED_PARAMETER(Context);
+
+    status = HvmGetParam(HVM_PARAM_STORE_EVTCHN, &Value);
+    ASSERT(NT_SUCCESS(status));
+
+    LocalPort = (LONG)Value;
+
+    //
+    // When we reset the event channel ABI we will lose our
+    // binding to the STORE event channel, which was set up
+    // by the toolstack during domain build.
+    // We need to get the binding back, so we must query the
+    // remote domain and port, and then re-bind after the
+    // reset.
+    //
+
+    status = EventChannelQueryInterDomain(LocalPort,
+                                          &RemoteDomain,
+                                          &RemotePort);
+    ASSERT(NT_SUCCESS(status));
+
+    LogPrintf(LOG_LEVEL_INFO, "EVTCHN_FIFO: RESET\n");
+    (VOID) EventChannelReset();
+
+    status = EventChannelBindInterDomain(RemoteDomain,
+                                         RemotePort,
+                                         &LocalPort);
+    ASSERT(NT_SUCCESS(status));
+
+    Value = LocalPort;
+
+    status = HvmSetParam(HVM_PARAM_STORE_EVTCHN, Value);
+    ASSERT(NT_SUCCESS(status));
+}
+
+static NTSTATUS
+EvtchnFifoAcquire(
+    IN  PXENBUS_EVTCHN_ABI_CONTEXT  _Context
+    )
+{
+    PXENBUS_EVTCHN_FIFO_CONTEXT     Context = (PVOID)_Context;
+    KIRQL                           Irql;
+    LONG                            Cpu;
+    PMDL                            Mdl;
+    NTSTATUS                        status;
+
+    KeAcquireSpinLock(&Context->Lock, &Irql);
+
+    if (Context->References++ != 0)
+        goto done;
+
+    Trace("====>\n");
+
+    Cpu = 0;
+    while (Cpu < KeNumberProcessors) {
+        unsigned int        vcpu_id;
+        PFN_NUMBER          Pfn;
+        PHYSICAL_ADDRESS    Address;
+
+        Mdl = __AllocatePage();
+
+        status = STATUS_NO_MEMORY;
+        if (Mdl == NULL)
+            goto fail1;
+
+        vcpu_id = SystemVirtualCpuIndex(Cpu);
+        Pfn = MmGetMdlPfnArray(Mdl)[0];
+
+        status = EventChannelInitControl(Pfn, vcpu_id);
+        if (!NT_SUCCESS(status))
+            goto fail2;
+
+        Address.QuadPart = (ULONGLONG)Pfn << PAGE_SHIFT;
+
+        LogPrintf(LOG_LEVEL_INFO,
+                  "EVTCHN_FIFO: CONTROLBLOCK[%u] @ %08x.%08x\n",
+                  vcpu_id,
+                  Address.HighPart,
+                  Address.LowPart);
+
+        Context->ControlBlockMdl[vcpu_id] = Mdl;
+        Cpu++;
+    }
+
+    Trace("<====\n");
+
+done:
+    KeReleaseSpinLock(&Context->Lock, Irql);
+
+    return STATUS_SUCCESS;
+
+fail2:
+    __FreePage(Mdl);
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    (VOID) EventChannelReset();
+
+    while (--Cpu >= 0) {
+        unsigned int    vcpu_id;
+
+        vcpu_id = SystemVirtualCpuIndex(Cpu);
+
+        Mdl = Context->ControlBlockMdl[vcpu_id];
+        Context->ControlBlockMdl[vcpu_id] = NULL;
+
+        __FreePage(Mdl);
+    }
+
+    --Context->References;
+    ASSERT3U(Context->References, ==, 0);
+    KeReleaseSpinLock(&Context->Lock, Irql);
+
+    return status;
+}
+
+VOID
+EvtchnFifoRelease(
+    IN  PXENBUS_EVTCHN_ABI_CONTEXT  _Context
+    )
+{
+    PXENBUS_EVTCHN_FIFO_CONTEXT     Context = (PVOID)_Context;
+    KIRQL                           Irql;
+    LONG                            Cpu;
+
+    KeAcquireSpinLock(&Context->Lock, &Irql);
+
+    if (--Context->References > 0)
+        goto done;
+
+    Trace("====>\n");
+
+    EvtchnFifoReset(Context);
+
+    EvtchnFifoContract(Context);
+
+    Cpu = KeNumberProcessors;
+    while (--Cpu >= 0) {
+        unsigned int    vcpu_id;
+        PMDL            Mdl;
+
+        vcpu_id = SystemVirtualCpuIndex(Cpu);
+
+        Mdl = Context->ControlBlockMdl[vcpu_id];
+        Context->ControlBlockMdl[vcpu_id] = NULL;
+
+        __FreePage(Mdl);
+    }
+
+    Trace("<====\n");
+
+done:
+    KeReleaseSpinLock(&Context->Lock, Irql);
+}
+
+static XENBUS_EVTCHN_ABI EvtchnAbiFifo = {
+    NULL,
+    EvtchnFifoAcquire,
+    EvtchnFifoRelease,
+    EvtchnFifoPoll,
+    EvtchnFifoPortEnable,
+    EvtchnFifoPortDisable,
+    EvtchnFifoPortAck,
+    EvtchnFifoPortMask,
+    EvtchnFifoPortUnmask
+};
+
+NTSTATUS
+EvtchnFifoInitialize(
+    IN  PXENBUS_FDO                     Fdo,
+    OUT PXENBUS_EVTCHN_ABI_CONTEXT      *_Context
+    )
+{
+    PXENBUS_EVTCHN_FIFO_CONTEXT    Context;
+    NTSTATUS                            status;
+
+    Trace("====>\n");
+
+    Context = __EvtchnFifoAllocate(sizeof (XENBUS_EVTCHN_FIFO_CONTEXT));
+
+    status = STATUS_NO_MEMORY;
+    if (Context == NULL)
+        goto fail1;
+
+    KeInitializeSpinLock(&Context->Lock);
+
+    Context->Fdo = Fdo;
+
+    *_Context = (PVOID)Context;
+
+    Trace("<====\n");
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+VOID
+EvtchnFifoGetAbi(
+    IN  PXENBUS_EVTCHN_ABI_CONTEXT      _Context,
+    OUT PXENBUS_EVTCHN_ABI              Abi)
+{
+    *Abi = EvtchnAbiFifo;
+
+    Abi->Context = (PVOID)_Context;
+}
+
+VOID
+EvtchnFifoTeardown(
+    IN  PXENBUS_EVTCHN_ABI_CONTEXT      _Context
+    )
+{
+    PXENBUS_EVTCHN_FIFO_CONTEXT    Context = (PVOID)_Context;
+
+    Trace("====>\n");
+
+    Context->Fdo = NULL;
+
+    RtlZeroMemory(&Context->Lock, sizeof (KSPIN_LOCK));
+
+    ASSERT(IsZeroMemory(Context, sizeof (XENBUS_EVTCHN_FIFO_CONTEXT)));
+    __EvtchnFifoFree(Context);
+
+    Trace("<====\n");
+}
diff --git a/src/xenbus/evtchn_fifo.h b/src/xenbus/evtchn_fifo.h
new file mode 100644
index 0000000..bf96b19
--- /dev/null
+++ b/src/xenbus/evtchn_fifo.h
@@ -0,0 +1,59 @@
+/* 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_EVTCHN_FIFO_H
+#define _XENBUS_EVTCHN_FIFO_H
+
+#include <ntddk.h>
+#include <xen.h>
+
+#include "evtchn_abi.h"
+#include "fdo.h"
+
+extern NTSTATUS
+EvtchnFifoInitialize(
+    IN  PXENBUS_FDO                 Fdo,
+    OUT PXENBUS_EVTCHN_ABI_CONTEXT  *Context
+    );
+
+extern VOID
+EvtchnFifoGetAbi(
+    IN  PXENBUS_EVTCHN_ABI_CONTEXT  Context,
+    OUT PXENBUS_EVTCHN_ABI          Abi
+    );
+
+extern VOID
+EvtchnFifoTeardown(
+    IN  PXENBUS_EVTCHN_ABI_CONTEXT  Context
+    );
+
+#endif  // _XENBUS_EVTCHN_FIFO_H
+
diff --git a/src/xenbus/store.c b/src/xenbus/store.c
index 62ec60b..22c2a12 100644
--- a/src/xenbus/store.c
+++ b/src/xenbus/store.c
@@ -1825,13 +1825,20 @@ StoreEnable(
     IN PXENBUS_STORE_CONTEXT    Context
     )
 {
-    ULONGLONG                   Port;
+    ULONGLONG                   Value;
+    ULONG                       Port;
     BOOLEAN                     Pending;
     NTSTATUS                    status;
 
-    status = HvmGetParam(HVM_PARAM_STORE_EVTCHN, &Port);
+    status = HvmGetParam(HVM_PARAM_STORE_EVTCHN, &Value);
     ASSERT(NT_SUCCESS(status));
 
+    Port = (ULONG)Value;
+
+    LogPrintf(LOG_LEVEL_INFO,
+              "STORE: EVTCHN %u\n",
+              Port);
+
     Context->Channel = XENBUS_EVTCHN(Open,
                                      &Context->EvtchnInterface,
                                      XENBUS_EVTCHN_TYPE_FIXED,
diff --git a/vs2012/xenbus/xenbus.vcxproj b/vs2012/xenbus/xenbus.vcxproj
index 6cd12d1..3c184e0 100644
--- a/vs2012/xenbus/xenbus.vcxproj
+++ b/vs2012/xenbus/xenbus.vcxproj
@@ -89,6 +89,7 @@
                <ClCompile Include="..\..\src\xenbus\driver.c" />
                <ClCompile Include="..\..\src\xenbus\evtchn.c" />
                <ClCompile Include="..\..\src\xenbus\evtchn_2l.c" />
+               <ClCompile Include="..\..\src\xenbus\evtchn_fifo.c" />
                <ClCompile Include="..\..\src\xenbus\fdo.c" />
                <ClCompile Include="..\..\src\xenbus\gnttab.c" />
                <ClCompile Include="..\..\src\xenbus\pdo.c" />
diff --git a/vs2013/xenbus/xenbus.vcxproj b/vs2013/xenbus/xenbus.vcxproj
index 0f37f68..ecb602b 100644
--- a/vs2013/xenbus/xenbus.vcxproj
+++ b/vs2013/xenbus/xenbus.vcxproj
@@ -129,6 +129,7 @@
     <ClCompile Include="..\..\src\xenbus\driver.c" />
     <ClCompile Include="..\..\src\xenbus\evtchn.c" />
     <ClCompile Include="..\..\src\xenbus\evtchn_2l.c" />
+    <ClCompile Include="..\..\src\xenbus\evtchn_fifo.c" />
     <ClCompile Include="..\..\src\xenbus\fdo.c" />
     <ClCompile Include="..\..\src\xenbus\gnttab.c" />
     <ClCompile Include="..\..\src\xenbus\pdo.c" />
-- 
2.1.1


_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
http://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®.