|
[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
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |