IN PXENBUS_EVTCHN_CHANNEL Channel
);
+/*! \typedef XENBUS_EVTCHN_WAIT
+ \brief Wait for an event to the local end of the channel
+
+ \param Interface The interface header
+ \param Channel The channel handle
+ \param Timeout An optional timeout value (similar to KeWaitForSingleObject(), but non-zero values are allowed at DISPATCH_LEVEL).
+*/
+typedef NTSTATUS
+(*XENBUS_EVTCHN_WAIT)(
+ IN PINTERFACE Interface,
+ IN PXENBUS_EVTCHN_CHANNEL Channel,
+ IN PLARGE_INTEGER Timeout OPTIONAL
+ );
+
/*! \typedef XENBUS_EVTCHN_GET_PORT
\brief Get the local port number bound to the channel
XENBUS_EVTCHN_CLOSE EvtchnClose;
};
-typedef struct _XENBUS_EVTCHN_INTERFACE_V4 XENBUS_EVTCHN_INTERFACE, *PXENBUS_EVTCHN_INTERFACE;
+/*! \struct _XENBUS_EVTCHN_INTERFACE_V5
+ \brief EVTCHN interface version 5
+ \ingroup interfaces
+*/
+struct _XENBUS_EVTCHN_INTERFACE_V5 {
+ INTERFACE Interface;
+ XENBUS_EVTCHN_ACQUIRE EvtchnAcquire;
+ XENBUS_EVTCHN_RELEASE EvtchnRelease;
+ XENBUS_EVTCHN_OPEN EvtchnOpen;
+ XENBUS_EVTCHN_BIND EvtchnBind;
+ XENBUS_EVTCHN_UNMASK EvtchnUnmask;
+ XENBUS_EVTCHN_SEND EvtchnSend;
+ XENBUS_EVTCHN_TRIGGER EvtchnTrigger;
+ XENBUS_EVTCHN_WAIT EvtchnWait;
+ XENBUS_EVTCHN_GET_PORT EvtchnGetPort;
+ XENBUS_EVTCHN_CLOSE EvtchnClose;
+};
+
+typedef struct _XENBUS_EVTCHN_INTERFACE_V5 XENBUS_EVTCHN_INTERFACE, *PXENBUS_EVTCHN_INTERFACE;
/*! \def XENBUS_EVTCHN
\brief Macro at assist in method invocation
#endif // _WINDLL
#define XENBUS_EVTCHN_INTERFACE_VERSION_MIN 1
-#define XENBUS_EVTCHN_INTERFACE_VERSION_MAX 4
+#define XENBUS_EVTCHN_INTERFACE_VERSION_MAX 5
#endif // _XENBUS_EVTCHN_INTERFACE_H
// EM - XENFILT_EMULATED_INTERFACE
// REVISION S SI E D ST R C G U EM
-#define DEFINE_REVISION_TABLE \
- DEFINE_REVISION(0x08000009, 1, 2, 4, 1, 1, 1, 1, 1, 1, 1)
+#define DEFINE_REVISION_TABLE \
+ DEFINE_REVISION(0x08000009, 1, 2, 4, 1, 1, 1, 1, 1, 1, 1), \
+ DEFINE_REVISION(0x0800000A, 1, 2, 5, 1, 1, 1, 1, 1, 1, 1)
#endif // _REVISION_H
PKSERVICE_ROUTINE Callback;
PVOID Argument;
BOOLEAN Active; // Must be tested at >= DISPATCH_LEVEL
+ ULONG Events;
XENBUS_EVTCHN_TYPE Type;
XENBUS_EVTCHN_PARAMETERS Parameters;
BOOLEAN Mask;
Trace("%u\n", LocalPort);
+ Channel->Events = 0;
+
ASSERT(Channel->Closed);
Channel->Closed = FALSE;
KeMemoryBarrier();
if (!Channel->Closed) {
+ Channel->Events++;
+
RemoveEntryList(&Channel->PendingListEntry);
InitializeListHead(&Channel->PendingListEntry);
return Channel->LocalPort;
}
+static NTSTATUS
+EvtchnWait(
+ IN PINTERFACE Interface,
+ IN PXENBUS_EVTCHN_CHANNEL Channel,
+ IN PLARGE_INTEGER Timeout
+ )
+{
+ KIRQL Irql;
+ ULONG Events;
+ LARGE_INTEGER Start;
+ NTSTATUS status;
+
+ UNREFERENCED_PARAMETER(Interface);
+
+ ASSERT3U(KeGetCurrentIrql(), <=, DISPATCH_LEVEL);
+ KeRaiseIrql(DISPATCH_LEVEL, &Irql); // Prevent suspend
+
+ Events = Channel->Events;
+ KeMemoryBarrier();
+
+ KeQuerySystemTime(&Start);
+
+ for (;;) {
+ status = STATUS_SUCCESS;
+ if (Channel->Events != Events)
+ break;
+
+ if (Timeout != NULL) {
+ LARGE_INTEGER Now;
+
+ KeQuerySystemTime(&Now);
+
+ status = STATUS_TIMEOUT;
+ if (Timeout->QuadPart > 0) {
+ // Absolute timeout
+ if (Now.QuadPart > Timeout->QuadPart)
+ break;
+ } else if (Timeout->QuadPart < 0) {
+ LONGLONG Delta;
+
+ // Relative timeout
+ Delta = Now.QuadPart - Start.QuadPart;
+ if (Delta > -Timeout->QuadPart)
+ break;
+ } else {
+ // Immediate timeout
+ ASSERT(Timeout->QuadPart == 0);
+ break;
+ }
+ }
+
+ _mm_pause();
+ KeMemoryBarrier();
+ }
+
+ KeLowerIrql(Irql);
+
+ return status;
+}
+
static
_Function_class_(KSERVICE_ROUTINE)
__drv_requiresIRQL(HIGH_LEVEL)
}
}
-
-
static NTSTATUS
EvtchnAbiAcquire(
IN PXENBUS_EVTCHN_CONTEXT Context
default:
break;
}
+
+ XENBUS_DEBUG(Printf,
+ &Context->DebugInterface,
+ "Events = %lu\n",
+ Channel->Events);
}
}
}
EvtchnClose
};
+static struct _XENBUS_EVTCHN_INTERFACE_V5 EvtchnInterfaceVersion5 = {
+ { sizeof (struct _XENBUS_EVTCHN_INTERFACE_V5), 5, NULL, NULL, NULL },
+ EvtchnAcquire,
+ EvtchnRelease,
+ EvtchnOpen,
+ EvtchnBind,
+ EvtchnUnmask,
+ EvtchnSend,
+ EvtchnTrigger,
+ EvtchnWait,
+ EvtchnGetPort,
+ EvtchnClose,
+};
+
NTSTATUS
EvtchnInitialize(
IN PXENBUS_FDO Fdo,
status = STATUS_SUCCESS;
break;
}
+ case 5: {
+ struct _XENBUS_EVTCHN_INTERFACE_V5 *EvtchnInterface;
+
+ EvtchnInterface = (struct _XENBUS_EVTCHN_INTERFACE_V5 *)Interface;
+
+ status = STATUS_BUFFER_OVERFLOW;
+ if (Size < sizeof (struct _XENBUS_EVTCHN_INTERFACE_V5))
+ break;
+
+ *EvtchnInterface = EvtchnInterfaceVersion5;
+
+ ASSERT3U(Interface->Version, ==, Version);
+ Interface->Context = Context;
+
+ status = STATUS_SUCCESS;
+ break;
+ }
default:
status = STATUS_NOT_SUPPORTED;
break;
LIST_ENTRY WatchList;
LIST_ENTRY BufferList;
KDPC Dpc;
+ ULONG Polls;
+ ULONG Dpcs;
+ ULONG Events;
XENBUS_STORE_RESPONSE Response;
XENBUS_EVTCHN_INTERFACE EvtchnInterface;
PHYSICAL_ADDRESS Address;
ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
+ Context->Polls++;
+
do {
Read = Written = 0;
KeReleaseSpinLockFromDpcLevel(&Context->Lock);
}
+#define TIME_US(_us) ((_us) * 10)
+#define TIME_MS(_ms) (TIME_US((_ms) * 1000))
+#define TIME_S(_s) (TIME_MS((_s) * 1000))
+#define TIME_RELATIVE(_t) (-(_t))
+
+#define XENBUS_STORE_POLL_PERIOD 5
+
static PXENBUS_STORE_RESPONSE
StoreSubmitRequest(
IN PXENBUS_STORE_CONTEXT Context,
{
PXENBUS_STORE_RESPONSE Response;
KIRQL Irql;
+ LARGE_INTEGER Timeout;
ASSERT3U(Request->State, ==, XENBUS_STORE_REQUEST_PREPARED);
KeAcquireSpinLockAtDpcLevel(&Context->Lock);
InsertTailList(&Context->SubmittedList, &Request->ListEntry);
+
Request->State = XENBUS_STORE_REQUEST_SUBMITTED;
+ StorePollLocked(Context);
+ KeMemoryBarrier();
+
+ Timeout.QuadPart = TIME_RELATIVE(TIME_S(XENBUS_STORE_POLL_PERIOD));
while (Request->State != XENBUS_STORE_REQUEST_COMPLETED) {
+ NTSTATUS status;
+
+ status = XENBUS_EVTCHN(Wait,
+ &Context->EvtchnInterface,
+ Context->Channel,
+ &Timeout);
+ if (status == STATUS_TIMEOUT)
+ Warning("TIMED OUT\n");
+
StorePollLocked(Context);
- SchedYield();
+ KeMemoryBarrier();
}
KeReleaseSpinLockFromDpcLevel(&Context->Lock);
static VOID
StorePoll(
- IN PINTERFACE Interface
+ IN PINTERFACE Interface
)
{
- PXENBUS_STORE_CONTEXT Context = Interface->Context;
+ PXENBUS_STORE_CONTEXT Context = Interface->Context;
KeAcquireSpinLockAtDpcLevel(&Context->Lock);
- StorePollLocked(Context);
+ if (Context->References != 0)
+ StorePollLocked(Context);
KeReleaseSpinLockFromDpcLevel(&Context->Lock);
}
ASSERT(Context != NULL);
- KeInsertQueueDpc(&Context->Dpc, NULL, NULL);
+ Context->Events++;
+
+ if (KeInsertQueueDpc(&Context->Dpc, NULL, NULL))
+ Context->Dpcs++;
return TRUE;
}
&Context->EvtchnInterface,
Context->Channel,
FALSE);
+
+ // Trigger an initial poll
+ KeInsertQueueDpc(&Context->Dpc, NULL, NULL);
}
static PHYSICAL_ADDRESS
Shared->rsp_prod);
}
+ XENBUS_DEBUG(Printf,
+ &Context->DebugInterface,
+ "Events = %lu Dpcs = %lu Polls = %lu\n",
+ Context->Events,
+ Context->Dpcs,
+ Context->Polls);
+
if (!IsListEmpty(&Context->BufferList)) {
PLIST_ENTRY ListEntry;
XENBUS_SUSPEND(Release, &Context->SuspendInterface);
StoreDisable(Context);
+ StorePollLocked(Context);
RtlZeroMemory(&Context->Response, sizeof (XENBUS_STORE_RESPONSE));
XENBUS_EVTCHN(Release, &Context->EvtchnInterface);
ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
KeFlushQueuedDpcs();
+ Context->Polls = 0;
+ Context->Dpcs = 0;
+ Context->Events = 0;
+
Context->Fdo = NULL;
RtlZeroMemory(&Context->Dpc, sizeof (KDPC));