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

[win-pv-devel] [PATCH 2/4] Re-work interrupt code in FDO



This patch adds code to the FDO handler to acquire extra message signaled
(i.e. edge triggered) interrupt vectors that can be used for per-CPU event
channel upcalls (with extra support in Xen).
The existing callback via is also limited to upcall on CPU 0 meaning the
interrupt callback in the EVTCHN code can pass the current CPU value through
to the ABI.

Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
---
 src/common/names.h  | 122 ++++++-
 src/xenbus.inf      |  10 +-
 src/xenbus/evtchn.c |  55 +++-
 src/xenbus/fdo.c    | 894 +++++++++++++++++++++++++++++++++++++++++-----------
 src/xenbus/fdo.h    |  39 ++-
 src/xenbus/pdo.c    |   2 +-
 6 files changed, 897 insertions(+), 225 deletions(-)

diff --git a/src/common/names.h b/src/common/names.h
index 89894b9..f4a8bd0 100644
--- a/src/common/names.h
+++ b/src/common/names.h
@@ -196,32 +196,124 @@ PnpMinorFunctionName(
 }
 
 static FORCEINLINE const CHAR *
-PartialResourceDescriptorTypeName(
+ResourceDescriptorTypeName(
     IN  UCHAR   Type
     )
 {
-#define _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(_Type)   \
-    case CmResourceType ## _Type:                       \
+#define _RESOURCE_DESCRIPTOR_TYPE_NAME(_Type)   \
+    case CmResourceType ## _Type:               \
         return #_Type;
 
     switch (Type) {
-    _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(Null);
-    _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(Port);
-    _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(Interrupt);
-    _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(Memory);
-    _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(Dma);
-    _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(DeviceSpecific);
-    _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(BusNumber);
-    _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(MemoryLarge);
-    _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(ConfigData);
-    _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME(DevicePrivate);
+    _RESOURCE_DESCRIPTOR_TYPE_NAME(Null);
+    _RESOURCE_DESCRIPTOR_TYPE_NAME(Port);
+    _RESOURCE_DESCRIPTOR_TYPE_NAME(Interrupt);
+    _RESOURCE_DESCRIPTOR_TYPE_NAME(Memory);
+    _RESOURCE_DESCRIPTOR_TYPE_NAME(Dma);
+    _RESOURCE_DESCRIPTOR_TYPE_NAME(DeviceSpecific);
+    _RESOURCE_DESCRIPTOR_TYPE_NAME(BusNumber);
+    _RESOURCE_DESCRIPTOR_TYPE_NAME(MemoryLarge);
+    _RESOURCE_DESCRIPTOR_TYPE_NAME(ConfigData);
+    _RESOURCE_DESCRIPTOR_TYPE_NAME(DevicePrivate);
     default:
         break;
     }
 
     return "UNKNOWN";
 
-#undef  _PARTIAL_RESOURCE_DESCRIPTOR_TYPE_NAME
+#undef  _RESOURCE_DESCRIPTOR_TYPE_NAME
+}
+
+static FORCEINLINE const CHAR *
+ResourceDescriptorShareDispositionName(
+    IN  UCHAR   Disposition
+    )
+{
+#define _RESOURCE_DESCRIPTOR_SHARE_DISPOSITION_NAME(_Disposition)  \
+    case CmResourceShare ## _Disposition:                           \
+        return #_Disposition;
+
+    switch (Disposition) {
+    _RESOURCE_DESCRIPTOR_SHARE_DISPOSITION_NAME(Undetermined);
+    _RESOURCE_DESCRIPTOR_SHARE_DISPOSITION_NAME(DeviceExclusive);
+    _RESOURCE_DESCRIPTOR_SHARE_DISPOSITION_NAME(DriverExclusive);
+    _RESOURCE_DESCRIPTOR_SHARE_DISPOSITION_NAME(Shared);
+    default:
+        break;
+    }
+
+    return "UNKNOWN";
+
+#undef  _RESOURCE_DESCRIPTOR_SHARE_DISPOSITION_NAME
+}
+
+static FORCEINLINE const CHAR *
+IrqDevicePolicyName(
+    IN  IRQ_DEVICE_POLICY   Policy
+    )
+{
+#define _IRQ_DEVICE_POLICY_NAME(_Policy)    \
+    case IrqPolicy ## _Policy:              \
+        return #_Policy;
+
+    switch (Policy) {
+    _IRQ_DEVICE_POLICY_NAME(MachineDefault);
+    _IRQ_DEVICE_POLICY_NAME(AllCloseProcessors);
+    _IRQ_DEVICE_POLICY_NAME(OneCloseProcessor);
+    _IRQ_DEVICE_POLICY_NAME(AllProcessorsInMachine);
+    _IRQ_DEVICE_POLICY_NAME(SpecifiedProcessors);
+    _IRQ_DEVICE_POLICY_NAME(SpreadMessagesAcrossAllProcessors);
+    default:
+        break;
+    }
+
+    return "UNKNOWN";
+
+#undef  _IRQ_DEVICE_POLICY_NAME
+}
+
+static FORCEINLINE const CHAR *
+IrqPriorityName(
+    IN  IRQ_PRIORITY    Priority
+    )
+{
+#define _IRQ_PRIORITY_NAME(_Priority)   \
+    case IrqPriority ## _Priority:      \
+        return #_Priority;
+
+    switch (Priority) {
+    _IRQ_PRIORITY_NAME(Undefined);
+    _IRQ_PRIORITY_NAME(Low);
+    _IRQ_PRIORITY_NAME(Normal);
+    _IRQ_PRIORITY_NAME(High);
+    default:
+        break;
+    }
+
+    return "UNKNOWN";
+
+#undef  _IRQ_PRIORITY_NAME
+}
+
+static FORCEINLINE const CHAR *
+InterruptModeName(
+    IN  KINTERRUPT_MODE Mode
+    )
+{
+#define _INTERRUPT_MODE_NAME(_Mode) \
+    case _Mode:                     \
+        return #_Mode;
+
+    switch (Mode) {
+    _INTERRUPT_MODE_NAME(LevelSensitive);
+    _INTERRUPT_MODE_NAME(Latched);
+    default:
+        break;
+    }
+
+    return "UNKNOWN";
+
+#undef  _INTERRUPT_MODE_NAME
 }
 
 static FORCEINLINE const CHAR *
@@ -358,4 +450,6 @@ BusQueryIdTypeName(
 #undef  _BUS_QUERY_ID_TYPE_NAME
 }
 
+
+
 #endif // _COMMON_NAMES_H_
diff --git a/src/xenbus.inf b/src/xenbus.inf
index 544bb2c..b2c17c3 100644
--- a/src/xenbus.inf
+++ b/src/xenbus.inf
@@ -78,20 +78,26 @@ AddService=xenfilt,,XenFilt_Service,
 [XenBus_Service] 
 DisplayName=%XenBusDesc%
 ServiceType=%SERVICE_KERNEL_DRIVER% 
-StartType=%SERVICE_BOOT_START% 
+StartType=%SERVICE_DEMAND_START% 
 ErrorControl=%SERVICE_ERROR_NORMAL% 
 ServiceBinary=%12%\xenbus.sys 
 LoadOrderGroup="Boot Bus Extender"
-AddReg = XenBus_Parameters, XenBus_Interfaces
+AddReg = XenBus_Parameters, XenBus_Interfaces, XenBus_Interrupts
 
 [XenBus_Parameters]
 HKR,"Parameters",,0x00000010
 HKR,"Parameters","SupportedClasses",0x00010000,"VIF","VBD","IFACE"
 HKR,"Parameters","SyntheticClasses",0x00010000,"IFACE"
+HKR,"Parameters","ExtraInterrupts",0x00010001,64
 
 [XenBus_Interfaces]
 HKR,"Interfaces",,0x00000010
 
+[XenBus_Interrupts]
+HKR,"Interrupt Management",,0x00000010
+HKR,"Interrupt Management\MessageSignaledInterruptProperties",,0x00000010
+HKR,"Interrupt 
Management\MessageSignaledInterruptProperties","MSISupported",0x00010001,1
+
 [XenFilt_Service] 
 DisplayName=%XenFiltDesc%
 ServiceType=%SERVICE_KERNEL_DRIVER% 
diff --git a/src/xenbus/evtchn.c b/src/xenbus/evtchn.c
index 1bd5e5f..44043d4 100644
--- a/src/xenbus/evtchn.c
+++ b/src/xenbus/evtchn.c
@@ -88,7 +88,7 @@ struct _XENBUS_EVTCHN_CONTEXT {
     PXENBUS_FDO                     Fdo;
     KSPIN_LOCK                      Lock;
     LONG                            References;
-    ULONG                           Vector;
+    PXENBUS_INTERRUPT               Interrupt;
     BOOLEAN                         Enabled;
     XENBUS_SUSPEND_INTERFACE        SuspendInterface;
     PXENBUS_SUSPEND_CALLBACK        SuspendCallbackEarly;
@@ -127,11 +127,14 @@ EvtchnInterruptEnable(
     IN  PXENBUS_EVTCHN_CONTEXT  Context
     )
 {
+    ULONG                       Line;
     NTSTATUS                    status;
 
     Trace("<===>\n");
 
-    status = HvmSetParam(HVM_PARAM_CALLBACK_IRQ, Context->Vector);
+    Line = FdoGetInterruptLine(Context->Fdo, Context->Interrupt);
+
+    status = HvmSetParam(HVM_PARAM_CALLBACK_IRQ, Line);
     ASSERT(NT_SUCCESS(status));
 }
 
@@ -159,7 +162,7 @@ __EvtchnAcquireInterruptLock(
     IN  PXENBUS_EVTCHN_CONTEXT  Context
     )
 {
-    return FdoAcquireInterruptLock(Context->Fdo);
+    return FdoAcquireInterruptLock(Context->Fdo, Context->Interrupt);
 }
 
 static FORCEINLINE
@@ -170,7 +173,7 @@ __EvtchnReleaseInterruptLock(
     IN  __drv_restoresIRQL KIRQL    Irql
     )
 {
-    FdoReleaseInterruptLock(Context->Fdo, Irql);
+    FdoReleaseInterruptLock(Context->Fdo, Context->Interrupt, Irql);
 }
 
 static NTSTATUS
@@ -644,21 +647,32 @@ done:
     return DoneSomething;
 }
 
+static
+_Function_class_(KSERVICE_ROUTINE)
+__drv_requiresIRQL(HIGH_LEVEL)
 BOOLEAN
-EvtchnInterrupt(
-    IN  PXENBUS_EVTCHN_CONTEXT  Context
+EvtchnInterruptCallback(
+    IN  PKINTERRUPT         InterruptObject,
+    IN  PVOID               Argument
     )
 {
-    BOOLEAN                     DoneSomething;
+    PXENBUS_EVTCHN_CONTEXT  Context = Argument;
+    ULONG                   Cpu;
+    BOOLEAN                 DoneSomething;
+
+    UNREFERENCED_PARAMETER(InterruptObject);
+
+    ASSERT3U(KeGetCurrentIrql(), >=, DISPATCH_LEVEL);
+    Cpu = KeGetCurrentProcessorNumber();
 
     DoneSomething = FALSE;
 
     while (XENBUS_SHARED_INFO(UpcallPending,
                               &Context->SharedInfoInterface,
-                              0))
+                              Cpu))
         DoneSomething |= XENBUS_EVTCHN_ABI(Poll,
                                            &Context->EvtchnAbi,
-                                           0,
+                                           Cpu,
                                            EvtchnPollCallback,
                                            Context);
 
@@ -857,8 +871,6 @@ EvtchnAcquire(
 
     Trace("====>\n");
 
-    Context->Vector = FdoGetInterruptVector(Fdo);
-
     status = XENBUS_SUSPEND(Acquire, &Context->SuspendInterface);
     if (!NT_SUCCESS(status))
         goto fail1;
@@ -902,6 +914,15 @@ EvtchnAcquire(
     if (!NT_SUCCESS(status))
         goto fail7;
 
+    status = FdoAllocateInterrupt(Fdo,
+                                  LevelSensitive,
+                                  0,
+                                  EvtchnInterruptCallback,
+                                  Context,
+                                  &Context->Interrupt);
+    if (!NT_SUCCESS(status))
+        goto fail8;
+
     Trace("<====\n");
 
 done:
@@ -909,6 +930,11 @@ done:
 
     return STATUS_SUCCESS;
 
+fail8:
+    Error("fail8\n");
+
+    EvtchnAbiRelease(Context);
+
 fail7:
     Error("fail7\n");
 
@@ -948,8 +974,6 @@ fail2:
 
     XENBUS_SUSPEND(Release, &Context->SuspendInterface);
 
-    Context->Vector = 0;
-
 fail1:
     Error("fail1 (%08x)\n", status);
 
@@ -978,6 +1002,9 @@ EvtchnRelease(
     if (!IsListEmpty(&Context->List))
         BUG("OUTSTANDING EVENT CHANNELS");
 
+    FdoFreeInterrupt(Context->Fdo, Context->Interrupt);
+    Context->Interrupt = NULL;
+
     EvtchnAbiRelease(Context);
 
     XENBUS_SHARED_INFO(Release, &Context->SharedInfoInterface);
@@ -1001,8 +1028,6 @@ EvtchnRelease(
 
     XENBUS_SUSPEND(Release, &Context->SuspendInterface);
 
-    Context->Vector = 0;
-
     Trace("<====\n");
 
 done:
diff --git a/src/xenbus/fdo.c b/src/xenbus/fdo.c
index 215c997..cc0c775 100644
--- a/src/xenbus/fdo.c
+++ b/src/xenbus/fdo.c
@@ -45,6 +45,7 @@
 #include "fdo.h"
 #include "pdo.h"
 #include "thread.h"
+#include "high.h"
 #include "mutex.h"
 #include "shared_info.h"
 #include "evtchn.h"
@@ -64,16 +65,17 @@
 
 #define MAXNAMELEN  128
 
-typedef enum _XENBUS_RESOURCE_TYPE {
-    MEMORY_RESOURCE = 0,
-    INTERRUPT_RESOURCE,
-    RESOURCE_COUNT
-} XENBUS_RESOURCE_TYPE, *PXENBUS_RESOURCE_TYPE;
-
-typedef struct _XENBUS_RESOURCE {
-    CM_PARTIAL_RESOURCE_DESCRIPTOR Raw;
-    CM_PARTIAL_RESOURCE_DESCRIPTOR Translated;
-} XENBUS_RESOURCE, *PXENBUS_RESOURCE;
+struct _XENBUS_INTERRUPT {
+    PXENBUS_FDO         Fdo;
+    LIST_ENTRY          ListEntry;
+    KINTERRUPT_MODE     InterruptMode;
+    PKINTERRUPT         InterruptObject;
+    ULONG               Cpu;
+    UCHAR               Vector;
+    ULONG               Line;
+    PKSERVICE_ROUTINE   Callback;
+    PVOID               Argument;
+};
 
 struct _XENBUS_FDO {
     PXENBUS_DX                      Dx;
@@ -108,8 +110,8 @@ struct _XENBUS_FDO {
     PXENBUS_STORE_WATCH             BalloonWatch;
     MUTEX                           BalloonSuspendMutex;
 
-    XENBUS_RESOURCE                 Resource[RESOURCE_COUNT];
-    PKINTERRUPT                     InterruptObject;
+    PCM_PARTIAL_RESOURCE_LIST       RawResourceList;
+    PCM_PARTIAL_RESOURCE_LIST       TranslatedResourceList;
 
     PXENBUS_SUSPEND_CONTEXT         SuspendContext;
     PXENBUS_SHARED_INFO_CONTEXT     SharedInfoContext;
@@ -129,9 +131,11 @@ struct _XENBUS_FDO {
     XENBUS_BALLOON_INTERFACE        BalloonInterface;
     XENFILT_UNPLUG_INTERFACE        UnplugInterface;
 
+    PXENBUS_RANGE_SET               RangeSet;
+    LIST_ENTRY                      List;
+
     PXENBUS_EVTCHN_CHANNEL          Channel;
     PXENBUS_SUSPEND_CALLBACK        SuspendCallbackLate;
-    PXENBUS_RANGE_SET               RangeSet;
 };
 
 static FORCEINLINE PVOID
@@ -187,6 +191,16 @@ __FdoGetDevicePnpState(
     return Dx->DevicePnpState;
 }
 
+static FORCEINLINE DEVICE_PNP_STATE
+__FdoGetPreviousDevicePnpState(
+    IN  PXENBUS_FDO Fdo
+    )
+{
+    PXENBUS_DX      Dx = Fdo->Dx;
+
+    return Dx->PreviousDevicePnpState;
+}
+
 static FORCEINLINE VOID
 __FdoSetDevicePowerState(
     IN  PXENBUS_FDO         Fdo,
@@ -1383,219 +1397,595 @@ loop:
 }
 
 static VOID
-FdoParseResources(
+FdoDumpIoResourceDescriptor(
     IN  PXENBUS_FDO             Fdo,
-    IN  PCM_RESOURCE_LIST       RawResourceList,
-    IN  PCM_RESOURCE_LIST       TranslatedResourceList
+    IN  PIO_RESOURCE_DESCRIPTOR Descriptor
     )
 {
-    PCM_PARTIAL_RESOURCE_LIST   RawPartialList;
-    PCM_PARTIAL_RESOURCE_LIST   TranslatedPartialList;
-    ULONG                       Index;
+    Trace("%s: %s\n",
+          __FdoGetName(Fdo),
+          ResourceDescriptorTypeName(Descriptor->Type));
+
+    if (Descriptor->Option == 0)
+        Trace("Required\n");
+    else if (Descriptor->Option == IO_RESOURCE_ALTERNATIVE)
+        Trace("Alternative\n");
+    else if (Descriptor->Option == IO_RESOURCE_PREFERRED)
+        Trace("Preferred\n");
+    else if (Descriptor->Option == (IO_RESOURCE_ALTERNATIVE | 
IO_RESOURCE_PREFERRED))
+        Trace("Preferred Alternative\n");
+
+    Trace("ShareDisposition=%s Flags=%04x\n",
+          ResourceDescriptorShareDispositionName(Descriptor->ShareDisposition),
+          Descriptor->Flags);
+
+    switch (Descriptor->Type) {
+    case CmResourceTypeMemory:
+        Trace("Length = %08x Alignment = %08x\n MinimumAddress = %08x.%08x 
MaximumAddress = %08x.%08x\n",
+              Descriptor->u.Memory.Length,
+              Descriptor->u.Memory.Alignment,
+              Descriptor->u.Memory.MinimumAddress.HighPart,
+              Descriptor->u.Memory.MinimumAddress.LowPart,
+              Descriptor->u.Memory.MaximumAddress.HighPart,
+              Descriptor->u.Memory.MaximumAddress.LowPart);
+        break;
 
-    ASSERT3U(RawResourceList->Count, ==, 1);
-    RawPartialList = &RawResourceList->List[0].PartialResourceList;
+    case CmResourceTypeInterrupt:
+        Trace("MinimumVector=%08x MaximumVector=%08x AffinityPolicy=%s 
PriorityPolicy=%s TargettedProcessors = %p\n",
+              Descriptor->u.Interrupt.MinimumVector,
+              Descriptor->u.Interrupt.MaximumVector,
+              IrqDevicePolicyName(Descriptor->u.Interrupt.AffinityPolicy),
+              IrqPriorityName(Descriptor->u.Interrupt.PriorityPolicy),
+              (PVOID)Descriptor->u.Interrupt.TargetedProcessors);
+        break;
 
-    ASSERT3U(RawPartialList->Version, ==, 1);
-    ASSERT3U(RawPartialList->Revision, ==, 1);
+    default:
+        break;
+    }
+}
 
-    ASSERT3U(TranslatedResourceList->Count, ==, 1);
-    TranslatedPartialList = 
&TranslatedResourceList->List[0].PartialResourceList;
+static VOID
+FdoDumpIoResourceList(
+    IN  PXENBUS_FDO         Fdo,
+    IN  PIO_RESOURCE_LIST   List
+    )
+{
+    ULONG                   Index;
 
-    ASSERT3U(TranslatedPartialList->Version, ==, 1);
-    ASSERT3U(TranslatedPartialList->Revision, ==, 1);
+    for (Index = 0; Index < List->Count; Index++) {
+        PIO_RESOURCE_DESCRIPTOR Descriptor = &List->Descriptors[Index];
 
-    for (Index = 0; Index < TranslatedPartialList->Count; Index++) {
-        PCM_PARTIAL_RESOURCE_DESCRIPTOR RawPartialDescriptor;
-        PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedPartialDescriptor;
+        Trace("%s: %d\n",
+              __FdoGetName(Fdo),
+              Index);
 
-        RawPartialDescriptor = &RawPartialList->PartialDescriptors[Index];
-        TranslatedPartialDescriptor = 
&TranslatedPartialList->PartialDescriptors[Index];
+        FdoDumpIoResourceDescriptor(Fdo, Descriptor);
+    }
+}
 
-        Trace("%s: [%d] %02x:%s\n",
-              __FdoGetName(Fdo),
-              Index,
-              TranslatedPartialDescriptor->Type,
-              
PartialResourceDescriptorTypeName(TranslatedPartialDescriptor->Type));
-
-        switch (TranslatedPartialDescriptor->Type) {
-        case CmResourceTypeMemory:
-            Trace("RAW: SharedDisposition=%02x Flags=%04x Start = %08x.%08x 
Length = %08x\n",
-                  RawPartialDescriptor->ShareDisposition,
-                  RawPartialDescriptor->Flags,
-                  RawPartialDescriptor->u.Memory.Start.HighPart,
-                  RawPartialDescriptor->u.Memory.Start.LowPart,
-                  RawPartialDescriptor->u.Memory.Length);
-
-            Trace("TRANSLATED: SharedDisposition=%02x Flags=%04x Start = 
%08x.%08x Length = %08x\n",
-                  TranslatedPartialDescriptor->ShareDisposition,
-                  TranslatedPartialDescriptor->Flags,
-                  TranslatedPartialDescriptor->u.Memory.Start.HighPart,
-                  TranslatedPartialDescriptor->u.Memory.Start.LowPart,
-                  TranslatedPartialDescriptor->u.Memory.Length);
-
-            Fdo->Resource[MEMORY_RESOURCE].Raw = *RawPartialDescriptor;
-            Fdo->Resource[MEMORY_RESOURCE].Translated = 
*TranslatedPartialDescriptor;
+static NTSTATUS
+FdoFilterResourceRequirements(
+    IN  PXENBUS_FDO                 Fdo,
+    IN  PIRP                        Irp
+    )
+{
+    PIO_RESOURCE_REQUIREMENTS_LIST  Old;
+    ULONG                           Size;
+    PIO_RESOURCE_REQUIREMENTS_LIST  New;
+    IO_RESOURCE_DESCRIPTOR          Interrupt;
+    PIO_RESOURCE_LIST               List;
+    ULONG                           Index;
+    NTSTATUS                        status;
 
-            break;
+    status = FdoForwardIrpSynchronously(Fdo, Irp);
+    if (!NT_SUCCESS(status))
+        goto fail1;
 
-        case CmResourceTypeInterrupt:
-            Trace("RAW: SharedDisposition=%02x Flags=%04x Level = %08x Vector 
= %08x Affinity = %p\n",
-                  RawPartialDescriptor->ShareDisposition,
-                  RawPartialDescriptor->Flags,
-                  RawPartialDescriptor->u.Interrupt.Level,
-                  RawPartialDescriptor->u.Interrupt.Vector,
-                  (PVOID)RawPartialDescriptor->u.Interrupt.Affinity);
+    if (!__FdoIsActive(Fdo))
+        goto not_active;
 
-            Trace("TRANSLATED: SharedDisposition=%02x Flags=%04x Level = %08x 
Vector = %08x Affinity = %p\n",
-                  TranslatedPartialDescriptor->ShareDisposition,
-                  TranslatedPartialDescriptor->Flags,
-                  TranslatedPartialDescriptor->u.Interrupt.Level,
-                  TranslatedPartialDescriptor->u.Interrupt.Vector,
-                  (PVOID)TranslatedPartialDescriptor->u.Interrupt.Affinity);
+    Old = (PIO_RESOURCE_REQUIREMENTS_LIST)Irp->IoStatus.Information;
+    ASSERT3U(Old->AlternativeLists, ==, 1);
 
-            Fdo->Resource[INTERRUPT_RESOURCE].Raw = *RawPartialDescriptor;
-            Fdo->Resource[INTERRUPT_RESOURCE].Translated = 
*TranslatedPartialDescriptor;
+    Size = Old->ListSize +
+        (sizeof (IO_RESOURCE_DESCRIPTOR) * KeNumberProcessors);
 
-            break;
+    New = __AllocatePoolWithTag(PagedPool, Size, 'SUB');
 
-        default:
-            break;
+    status = STATUS_NO_MEMORY;
+    if (New == NULL)
+        goto fail2;
+
+    RtlCopyMemory(New, Old, Old->ListSize);
+    New->ListSize = Size;
+
+    List = &New->List[0];
+
+    for (Index = 0; Index < List->Count; Index++) {
+        PIO_RESOURCE_DESCRIPTOR Descriptor = &List->Descriptors[Index];
+
+        if (Descriptor->Type != CmResourceTypeInterrupt)
+            continue;
+
+        Descriptor->Flags |= CM_RESOURCE_INTERRUPT_POLICY_INCLUDED;
+        Descriptor->u.Interrupt.AffinityPolicy = IrqPolicySpecifiedProcessors;
+        Descriptor->u.Interrupt.TargetedProcessors = (KAFFINITY)1;
+    }
+
+    RtlZeroMemory(&Interrupt, sizeof (IO_RESOURCE_DESCRIPTOR));
+    Interrupt.Option = 0; // Required
+    Interrupt.Type = CmResourceTypeInterrupt;
+    Interrupt.ShareDisposition = CmResourceShareDeviceExclusive;
+    Interrupt.Flags = CM_RESOURCE_INTERRUPT_LATCHED |
+                      CM_RESOURCE_INTERRUPT_MESSAGE |
+                      CM_RESOURCE_INTERRUPT_POLICY_INCLUDED;
+
+    Interrupt.u.Interrupt.MinimumVector = CM_RESOURCE_INTERRUPT_MESSAGE_TOKEN;
+    Interrupt.u.Interrupt.MaximumVector = CM_RESOURCE_INTERRUPT_MESSAGE_TOKEN;
+    Interrupt.u.Interrupt.AffinityPolicy = IrqPolicySpecifiedProcessors;
+    Interrupt.u.Interrupt.PriorityPolicy = IrqPriorityUndefined;
+
+    for (Index = 0; Index < (ULONG)KeNumberProcessors; Index++) {
+        Interrupt.u.Interrupt.TargetedProcessors = (KAFFINITY)1 << Index;
+        List->Descriptors[List->Count++] = Interrupt;
+    }
+
+    FdoDumpIoResourceList(Fdo, List);
+
+    Irp->IoStatus.Information = (ULONG_PTR)New;
+    status = STATUS_SUCCESS;
+
+    ExFreePool(Old);
+
+not_active:
+    status = Irp->IoStatus.Status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    return status;
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    Irp->IoStatus.Status = status;
+    IoCompleteRequest(Irp, IO_NO_INCREMENT);
+
+    return status;
+}
+
+static VOID
+FdoDumpCmPartialResourceDescriptor(
+    IN  PXENBUS_FDO                     Fdo,
+    IN  BOOLEAN                         Translated,
+    IN  PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor
+    )
+{
+    Trace("%s: %s: %s SharedDisposition=%s Flags=%04x\n",
+          __FdoGetName(Fdo),
+          (Translated) ? "TRANSLATED" : "RAW",
+          ResourceDescriptorTypeName(Descriptor->Type),
+          ResourceDescriptorShareDispositionName(Descriptor->ShareDisposition),
+          Descriptor->Flags);
+    
+    switch (Descriptor->Type) {
+    case CmResourceTypeMemory:
+        Trace("%s: %s: Start = %08x.%08x Length = %08x\n",
+              __FdoGetName(Fdo),
+              (Translated) ? "TRANSLATED" : "RAW",
+              Descriptor->u.Memory.Start.HighPart,
+              Descriptor->u.Memory.Start.LowPart,
+              Descriptor->u.Memory.Length);
+        break;
+
+    case CmResourceTypeInterrupt:
+        if (Descriptor->Flags & CM_RESOURCE_INTERRUPT_MESSAGE) {
+            if (Translated)
+                Trace("%s: TRANSLATED: Level = %08x Vector = %08x Affinity = 
%p\n",
+                      __FdoGetName(Fdo),
+                      Descriptor->u.MessageInterrupt.Translated.Level,
+                      Descriptor->u.MessageInterrupt.Translated.Vector,
+                      
(PVOID)Descriptor->u.MessageInterrupt.Translated.Affinity);
+            else
+                Trace("%s: RAW: MessageCount = %08x Vector = %08x Affinity = 
%p\n",
+                      __FdoGetName(Fdo),
+                      Descriptor->u.MessageInterrupt.Raw.MessageCount,
+                      Descriptor->u.MessageInterrupt.Raw.Vector,
+                      (PVOID)Descriptor->u.MessageInterrupt.Raw.Affinity);
+        } else {
+            Trace("%s: %s: Level = %08x Vector = %08x Affinity = %p\n",
+                  __FdoGetName(Fdo),
+                  (Translated) ? "TRANSLATED" : "RAW",
+                  Descriptor->u.Interrupt.Level,
+                  Descriptor->u.Interrupt.Vector,
+                  (PVOID)Descriptor->u.Interrupt.Affinity);
         }
+        break;
+    default:
+        break;
     }
+}
 
-    Trace("<====\n");
+static VOID
+FdoDumpCmPartialResourceList(
+    IN  PXENBUS_FDO                 Fdo,
+    IN  BOOLEAN                     Translated,
+    IN  PCM_PARTIAL_RESOURCE_LIST   List
+    )
+{
+    ULONG                           Index;
+
+    Trace("%s: %s: Version = %d Revision = %d Count = %d\n",
+          __FdoGetName(Fdo),
+          (Translated) ? "TRANSLATED" : "RAW",
+          List->Version,
+          List->Revision,
+          List->Count);
+
+    for (Index = 0; Index < List->Count; Index++) {
+        PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor = 
&List->PartialDescriptors[Index];
+
+        Trace("%s: %s: %d\n",
+              __FdoGetName(Fdo),
+              (Translated) ? "TRANSLATED" : "RAW",
+              Index);
+
+        FdoDumpCmPartialResourceDescriptor(Fdo, Translated, Descriptor);
+    }
 }
 
-static FORCEINLINE PXENBUS_RESOURCE
-__FdoGetResource(
-    IN  PXENBUS_FDO             Fdo,
-    IN  XENBUS_RESOURCE_TYPE    Type
+static VOID
+FdoDumpCmFullResourceDescriptor(
+    IN  PXENBUS_FDO                     Fdo,
+    IN  BOOLEAN                         Translated,
+    IN  PCM_FULL_RESOURCE_DESCRIPTOR    Descriptor
     )
 {
-    ASSERT3U(Type, <, RESOURCE_COUNT);
+    Trace("%s: %s: InterfaceType = %s BusNumber = %d\n",
+          __FdoGetName(Fdo),
+          (Translated) ? "TRANSLATED" : "RAW",
+          InterfaceTypeName(Descriptor->InterfaceType),
+          Descriptor->BusNumber);
 
-    return &Fdo->Resource[Type];
+    FdoDumpCmPartialResourceList(Fdo, Translated, 
&Descriptor->PartialResourceList);
+}
+
+static VOID
+FdoDumpCmResourceList(
+    IN  PXENBUS_FDO         Fdo,
+    IN  BOOLEAN             Translated,
+    IN  PCM_RESOURCE_LIST   List
+    )
+{
+    FdoDumpCmFullResourceDescriptor(Fdo, Translated, &List->List[0]);
+}
+
+_IRQL_requires_max_(HIGH_LEVEL)
+_IRQL_saves_
+_IRQL_raises_(HIGH_LEVEL)
+KIRQL
+FdoAcquireInterruptLock(
+    IN  PXENBUS_FDO         Fdo,
+    IN  PXENBUS_INTERRUPT   Interrupt
+    )
+{
+    UNREFERENCED_PARAMETER(Fdo);
+
+    return KeAcquireInterruptSpinLock(Interrupt->InterruptObject);
+}
+
+_IRQL_requires_(HIGH_LEVEL)
+VOID
+FdoReleaseInterruptLock(
+    IN  PXENBUS_FDO                 Fdo,
+    IN  PXENBUS_INTERRUPT           Interrupt,
+    IN  __drv_restoresIRQL KIRQL    Irql
+    )
+{
+    UNREFERENCED_PARAMETER(Fdo);
+
+    KeReleaseInterruptSpinLock(Interrupt->InterruptObject, Irql);
 }
 
 static
 _Function_class_(KSERVICE_ROUTINE)
-_IRQL_requires_(HIGH_LEVEL)
-_IRQL_requires_same_
+__drv_requiresIRQL(HIGH_LEVEL)
 BOOLEAN
-FdoInterrupt(
+FdoInterruptCallback(
     IN  PKINTERRUPT             InterruptObject,
     IN  PVOID                   Context
     )
 {
-    PXENBUS_FDO                 Fdo = Context;
+    PXENBUS_INTERRUPT           Interrupt = Context;
 
-    UNREFERENCED_PARAMETER(InterruptObject);
+    if (Interrupt->Callback == NULL)
+        return FALSE;
 
-    ASSERT(Fdo != NULL);
-
-    return EvtchnInterrupt(__FdoGetEvtchnContext(Fdo));
+    return Interrupt->Callback(InterruptObject,
+                               Interrupt->Argument);
 }
 
 static NTSTATUS
 FdoConnectInterrupt(
-    IN  PXENBUS_FDO                 Fdo
+    IN  PXENBUS_FDO                     Fdo,
+    IN  PCM_PARTIAL_RESOURCE_DESCRIPTOR Raw,
+    IN  PCM_PARTIAL_RESOURCE_DESCRIPTOR Translated,
+    OUT PXENBUS_INTERRUPT               *Interrupt
     )
 {
-    PXENBUS_RESOURCE                Interrupt;
-    IO_CONNECT_INTERRUPT_PARAMETERS Connect;
-    NTSTATUS                        status;
+    IO_CONNECT_INTERRUPT_PARAMETERS     Connect;
+    ULONG                               Cpu;
+    NTSTATUS                            status;
 
     Trace("====>\n");
 
-    Interrupt = __FdoGetResource(Fdo, INTERRUPT_RESOURCE);
+    *Interrupt = __FdoAllocate(sizeof (XENBUS_INTERRUPT));
+
+    status = STATUS_NO_MEMORY;
+    if (*Interrupt == NULL)
+        goto fail1;
+
+    (*Interrupt)->Fdo = Fdo;
+    (*Interrupt)->InterruptMode = (Translated->Flags & 
CM_RESOURCE_INTERRUPT_LATCHED) ?
+                                  Latched :
+                                  LevelSensitive;
+
+    if (~Translated->Flags & CM_RESOURCE_INTERRUPT_MESSAGE)
+        (*Interrupt)->Line = Raw->u.Interrupt.Vector;
 
     RtlZeroMemory(&Connect, sizeof (IO_CONNECT_INTERRUPT_PARAMETERS));
     Connect.Version = CONNECT_FULLY_SPECIFIED;
     Connect.FullySpecified.PhysicalDeviceObject = 
__FdoGetPhysicalDeviceObject(Fdo);
-    Connect.FullySpecified.SynchronizeIrql = 
(KIRQL)Interrupt->Translated.u.Interrupt.Level;
-    Connect.FullySpecified.ShareVector = 
(BOOLEAN)(Interrupt->Translated.ShareDisposition == CmResourceShareShared);
-    Connect.FullySpecified.Vector = Interrupt->Translated.u.Interrupt.Vector;
-    Connect.FullySpecified.Irql = 
(KIRQL)Interrupt->Translated.u.Interrupt.Level;
-    Connect.FullySpecified.InterruptMode = (Interrupt->Translated.Flags & 
CM_RESOURCE_INTERRUPT_LATCHED) ?
-                                           Latched :
-                                           LevelSensitive;
-    Connect.FullySpecified.ProcessorEnableMask = 
Interrupt->Translated.u.Interrupt.Affinity;
-    Connect.FullySpecified.InterruptObject = &Fdo->InterruptObject;
-    Connect.FullySpecified.ServiceRoutine = FdoInterrupt;
-    Connect.FullySpecified.ServiceContext = Fdo;
+    Connect.FullySpecified.ShareVector = 
(BOOLEAN)(Translated->ShareDisposition == CmResourceShareShared);
+    Connect.FullySpecified.InterruptMode = (*Interrupt)->InterruptMode;
+    Connect.FullySpecified.InterruptObject = &(*Interrupt)->InterruptObject;
+    Connect.FullySpecified.ServiceRoutine = FdoInterruptCallback;
+    Connect.FullySpecified.ServiceContext = *Interrupt;
+
+    if (Translated->Flags & CM_RESOURCE_INTERRUPT_MESSAGE) {
+        Connect.FullySpecified.Vector = 
Translated->u.MessageInterrupt.Translated.Vector;
+        Connect.FullySpecified.Irql = 
(KIRQL)Translated->u.MessageInterrupt.Translated.Level;
+        Connect.FullySpecified.SynchronizeIrql = 
(KIRQL)Translated->u.MessageInterrupt.Translated.Level;
+        Connect.FullySpecified.ProcessorEnableMask = 
Translated->u.MessageInterrupt.Translated.Affinity;
+    } else {
+        Connect.FullySpecified.Vector = Translated->u.Interrupt.Vector;
+        Connect.FullySpecified.Irql = (KIRQL)Translated->u.Interrupt.Level;
+        Connect.FullySpecified.SynchronizeIrql = 
(KIRQL)Translated->u.Interrupt.Level;
+        Connect.FullySpecified.ProcessorEnableMask = 
Translated->u.Interrupt.Affinity;
+    }
 
     status = IoConnectInterruptEx(&Connect);
     if (!NT_SUCCESS(status))
-        goto fail1;
+        goto fail2;
+
+    (*Interrupt)->Vector = (UCHAR)Connect.FullySpecified.Vector;
+
+#if defined(__i386__)
+    (VOID)_BitScanReverse(&Cpu, Connect.FullySpecified.ProcessorEnableMask);
+#elif defined(__x86_64__)
+    (VOID)_BitScanReverse64(&Cpu, Connect.FullySpecified.ProcessorEnableMask);
+#else
+#error 'Unrecognised architecture'
+#endif
+
+    (*Interrupt)->Cpu = Cpu;
+
+    Info("%p: %s %s CPU %u VECTOR %02x\n",
+         (*Interrupt)->InterruptObject,
+         ResourceDescriptorShareDispositionName(Translated->ShareDisposition),
+         InterruptModeName((*Interrupt)->InterruptMode),
+         (*Interrupt)->Cpu,
+         (*Interrupt)->Vector);
 
     Trace("<====\n");
 
     return STATUS_SUCCESS;
 
+fail2:
+    Error("fail2\n");
+
+    __FdoFree(*Interrupt);
+    *Interrupt = NULL;
+
 fail1:
     Error("fail1 (%08x)\n", status);
 
     return status;
 }
 
-_IRQL_requires_max_(HIGH_LEVEL)
-_IRQL_saves_
-_IRQL_raises_(HIGH_LEVEL)
-KIRQL
-FdoAcquireInterruptLock(
-    IN  PXENBUS_FDO Fdo
+static VOID
+FdoDisconnectInterrupt(
+    IN  PXENBUS_FDO                     Fdo,
+    IN  PXENBUS_INTERRUPT               Interrupt
     )
 {
-    PKINTERRUPT     InterruptObject = Fdo->InterruptObject;
+    IO_DISCONNECT_INTERRUPT_PARAMETERS  Disconnect;
+
+    UNREFERENCED_PARAMETER(Fdo);
+
+    Trace("====>\n");
+
+    Info("%p: CPU %u VECTOR %02x\n",
+         Interrupt->InterruptObject,
+         Interrupt->Cpu,
+         Interrupt->Vector);
+
+    Interrupt->Cpu = 0;
+    Interrupt->Vector = 0;
+
+    RtlZeroMemory(&Disconnect, sizeof (IO_DISCONNECT_INTERRUPT_PARAMETERS));
+    Disconnect.Version = CONNECT_FULLY_SPECIFIED;
+    Disconnect.ConnectionContext.InterruptObject = Interrupt->InterruptObject;
 
-    return KeAcquireInterruptSpinLock(InterruptObject);
+    IoDisconnectInterruptEx(&Disconnect);
+
+    Interrupt->Line = 0;
+    Interrupt->InterruptObject = NULL;
+    Interrupt->InterruptMode = 0;
+    Interrupt->Fdo = NULL;
+
+    ASSERT(IsZeroMemory(Interrupt, sizeof (XENBUS_INTERRUPT)));
+    __FdoFree(Interrupt);
+
+    Trace("<====\n");
 }
-                      
-_IRQL_requires_(HIGH_LEVEL)
-VOID
-FdoReleaseInterruptLock(
-    IN  PXENBUS_FDO                 Fdo,
-    IN  __drv_restoresIRQL KIRQL    Irql
+
+static NTSTATUS
+FdoCreateInterrupt(
+    IN  PXENBUS_FDO     Fdo
     )
 {
-    PKINTERRUPT                     InterruptObject = Fdo->InterruptObject;
+    ULONG               Index;
+    PXENBUS_INTERRUPT   Interrupt;
+    NTSTATUS            status;
+
+    InitializeListHead(&Fdo->List);
+
+    for (Index = 0; Index < Fdo->TranslatedResourceList->Count; Index++) {
+        PCM_PARTIAL_RESOURCE_DESCRIPTOR Raw = 
&Fdo->RawResourceList->PartialDescriptors[Index];
+        PCM_PARTIAL_RESOURCE_DESCRIPTOR Translated = 
&Fdo->TranslatedResourceList->PartialDescriptors[Index];
+
+        if (Translated->Type != CmResourceTypeInterrupt)
+            continue;
+
+        status = FdoConnectInterrupt(Fdo, Raw, Translated, &Interrupt);
+        if (!NT_SUCCESS(status))
+            goto fail1;
+
+        InsertTailList(&Fdo->List, &Interrupt->ListEntry);
+    }
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    while (!IsListEmpty(&Fdo->List)) {
+        PLIST_ENTRY ListEntry;
+
+        ListEntry = RemoveHeadList(&Fdo->List);
+        ASSERT(ListEntry != &Fdo->List);
+
+        RtlZeroMemory(ListEntry, sizeof (LIST_ENTRY));
+
+        Interrupt = CONTAINING_RECORD(ListEntry, XENBUS_INTERRUPT, ListEntry);
+
+        FdoDisconnectInterrupt(Fdo, Interrupt);
+    }
+
+    RtlZeroMemory(&Fdo->List, sizeof (LIST_ENTRY));
 
-    KeReleaseInterruptSpinLock(InterruptObject, Irql);
+    return status;
 }
 
-ULONG
+NTSTATUS
+FdoAllocateInterrupt(
+    IN  PXENBUS_FDO         Fdo,
+    IN  KINTERRUPT_MODE     InterruptMode,
+    IN  ULONG               Cpu,
+    IN  KSERVICE_ROUTINE    Callback,
+    IN  PVOID               Argument OPTIONAL,
+    OUT PXENBUS_INTERRUPT   *Interrupt
+    )
+{
+    PLIST_ENTRY             ListEntry;
+    KIRQL                   Irql;
+    NTSTATUS                status;
+
+    for (ListEntry = Fdo->List.Flink;
+         ListEntry != &Fdo->List;
+         ListEntry = ListEntry->Flink) {
+        *Interrupt = CONTAINING_RECORD(ListEntry, XENBUS_INTERRUPT, ListEntry);
+
+        if ((*Interrupt)->Callback == NULL &&
+            (*Interrupt)->InterruptMode == InterruptMode &&
+            (*Interrupt)->Cpu == Cpu)
+            goto found;
+    }
+
+    *Interrupt = NULL;
+
+    status = STATUS_OBJECT_NAME_NOT_FOUND;
+    goto fail1;
+
+found:
+    Irql = FdoAcquireInterruptLock(Fdo, *Interrupt);
+    (*Interrupt)->Callback = Callback;
+    (*Interrupt)->Argument = Argument;
+    FdoReleaseInterruptLock(Fdo, *Interrupt, Irql);
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+UCHAR
 FdoGetInterruptVector(
-    IN  PXENBUS_FDO     Fdo
+    IN  PXENBUS_FDO         Fdo,
+    IN  PXENBUS_INTERRUPT   Interrupt
+    )
+{
+    UNREFERENCED_PARAMETER(Fdo);
+
+    return Interrupt->Vector;
+}
+
+ULONG
+FdoGetInterruptLine(
+    IN  PXENBUS_FDO         Fdo,
+    IN  PXENBUS_INTERRUPT   Interrupt
     )
 {
-    PXENBUS_RESOURCE    Interrupt;
+    UNREFERENCED_PARAMETER(Fdo);
+
+    return Interrupt->Line;
+}
 
-    Interrupt = __FdoGetResource(Fdo, INTERRUPT_RESOURCE);
+VOID
+FdoFreeInterrupt(
+    IN  PXENBUS_FDO         Fdo,
+    IN  PXENBUS_INTERRUPT   Interrupt
+    )
+{
+    KIRQL                   Irql;
 
-    return Interrupt->Raw.u.Interrupt.Vector;
+    Irql = FdoAcquireInterruptLock(Fdo, Interrupt);
+    Interrupt->Callback = NULL;
+    Interrupt->Argument = NULL;
+    FdoReleaseInterruptLock(Fdo, Interrupt, Irql);
 }
 
 static VOID
-FdoDisconnectInterrupt(
-    IN  PXENBUS_FDO                     Fdo
+FdoDestroyInterrupt(
+    IN  PXENBUS_FDO     Fdo
     )
 {
-    PKINTERRUPT                         InterruptObject;
-    IO_DISCONNECT_INTERRUPT_PARAMETERS  Disconnect;
+    while (!IsListEmpty(&Fdo->List)) {
+        PLIST_ENTRY         ListEntry;
+        PXENBUS_INTERRUPT   Interrupt;
 
-    Trace("====>\n");
+        ListEntry = RemoveHeadList(&Fdo->List);
+        ASSERT(ListEntry != &Fdo->List);
 
-    InterruptObject = Fdo->InterruptObject;
-    Fdo->InterruptObject = NULL;
+        RtlZeroMemory(ListEntry, sizeof (LIST_ENTRY));
 
-    RtlZeroMemory(&Disconnect, sizeof (IO_DISCONNECT_INTERRUPT_PARAMETERS));
-    Disconnect.Version = CONNECT_FULLY_SPECIFIED;
-    Disconnect.ConnectionContext.InterruptObject = InterruptObject;
+        Interrupt = CONTAINING_RECORD(ListEntry, XENBUS_INTERRUPT, ListEntry);
 
-    IoDisconnectInterruptEx(&Disconnect);
+#pragma warning(push)
+#pragma warning(disable:4054)   // 'type cast' : from function pointer to data 
pointer
+        ASSERT3P(Interrupt->Callback, ==, NULL);
+#pragma warning(pop)
 
-    Trace("<====\n");
+        ASSERT3P(Interrupt->Argument, ==, NULL);
+
+        FdoDisconnectInterrupt(Fdo, Interrupt);
+    }
+
+    RtlZeroMemory(&Fdo->List, sizeof (LIST_ENTRY));
 }
 
 static
@@ -1800,39 +2190,61 @@ FdoSuspendCallbackLate(
 
 static NTSTATUS
 FdoCreateIoSpace(
-    IN  PXENBUS_FDO     Fdo
+    IN  PXENBUS_FDO                 Fdo
     )
 {
-    PXENBUS_RESOURCE    Memory;
-    NTSTATUS            status;
+    ULONG                           Index;
+    PCM_PARTIAL_RESOURCE_DESCRIPTOR Translated;
+    PHYSICAL_ADDRESS                End;
+    NTSTATUS                        status;
+
+    for (Index = 0; Index < Fdo->TranslatedResourceList->Count; Index++) {
+        Translated = &Fdo->TranslatedResourceList->PartialDescriptors[Index];
 
-    Memory = __FdoGetResource(Fdo, MEMORY_RESOURCE);
+        if (Translated->Type == CmResourceTypeMemory)
+            goto found;
+    }
+
+    status = STATUS_OBJECT_NAME_NOT_FOUND;
+    goto fail1;
 
+found:
     status = XENBUS_RANGE_SET(Create,
                               &Fdo->RangeSetInterface,
                               "io_space",
                               &Fdo->RangeSet);
     if (!NT_SUCCESS(status))
-        goto fail1;
+        goto fail2;
 
     status = XENBUS_RANGE_SET(Put,
                               &Fdo->RangeSetInterface,
                               Fdo->RangeSet,
-                              Memory->Translated.u.Memory.Start.QuadPart,
-                              Memory->Translated.u.Memory.Length);
+                              Translated->u.Memory.Start.QuadPart,
+                              Translated->u.Memory.Length);
     if (!NT_SUCCESS(status))
-        goto fail2;
+        goto fail3;
+
+    End.QuadPart = Translated->u.Memory.Start.QuadPart + 
Translated->u.Memory.Length - 1;
+
+    Info("%08x.%08x - %08x.%08x\n",
+         Translated->u.Memory.Start.HighPart,
+         Translated->u.Memory.Start.LowPart,
+         End.HighPart,
+         End.LowPart);
 
     return STATUS_SUCCESS;
 
-fail2:
-    Error("fail2\n");
+fail3:
+    Error("fail3\n");
 
     XENBUS_RANGE_SET(Destroy,
                      &Fdo->RangeSetInterface,
                      Fdo->RangeSet);
     Fdo->RangeSet = NULL;
 
+fail2:
+    Error("fail2\n");
+
 fail1:
     Error("fail1 (%08x)\n", status);
 
@@ -1890,19 +2302,29 @@ FdoFreeIoSpace(
 
 static VOID
 FdoDestroyIoSpace(
-    IN  PXENBUS_FDO     Fdo
+    IN  PXENBUS_FDO                 Fdo
     )
 {
-    PXENBUS_RESOURCE    Memory;
-    NTSTATUS            status;
+    ULONG                           Index;
+    PCM_PARTIAL_RESOURCE_DESCRIPTOR Translated;
+    NTSTATUS                        status;
+
+    for (Index = 0; Index < Fdo->TranslatedResourceList->Count; Index++) {
+        Translated = &Fdo->TranslatedResourceList->PartialDescriptors[Index];
 
-    Memory = __FdoGetResource(Fdo, MEMORY_RESOURCE);
+        if (Translated->Type == CmResourceTypeMemory)
+            goto found;
+    }
+
+    ASSERT(FALSE);
+    return;
 
+found:
     status = XENBUS_RANGE_SET(Get,
                               &Fdo->RangeSetInterface,
                               Fdo->RangeSet,
-                              Memory->Translated.u.Memory.Start.QuadPart,
-                              Memory->Translated.u.Memory.Length);
+                              Translated->u.Memory.Start.QuadPart,
+                              Translated->u.Memory.Length);
     ASSERT(NT_SUCCESS(status));
 
     XENBUS_RANGE_SET(Destroy,
@@ -2214,39 +2636,111 @@ FdoS3ToS4(
     Trace("<====\n");
 }
 
+static VOID
+FdoFilterCmPartialResourceList(
+    IN  PXENBUS_FDO                 Fdo,
+    IN  PCM_PARTIAL_RESOURCE_LIST   List
+    )
+{
+    ULONG                           Index;
+
+    UNREFERENCED_PARAMETER(Fdo);
+
+    for (Index = 0; Index < List->Count; Index++) {
+        PCM_PARTIAL_RESOURCE_DESCRIPTOR Descriptor = 
&List->PartialDescriptors[Index];
+
+        //
+        // These are additional resources that XENBUS requested, so they must
+        // be filtered out before the underlying PCI bus driver sees them. 
Happily
+        // it appears that swapping the type to DevicePrivate causes PCI.SYS 
to ignore
+        // them.
+        //
+        if (Descriptor->Type == CmResourceTypeInterrupt &&
+            (Descriptor->Flags & CM_RESOURCE_INTERRUPT_MESSAGE))
+            Descriptor->Type = CmResourceTypeDevicePrivate;
+    }
+}
+
 static NTSTATUS
 FdoStartDevice(
-    IN  PXENBUS_FDO     Fdo,
-    IN  PIRP            Irp
+    IN  PXENBUS_FDO                 Fdo,
+    IN  PIRP                        Irp
     )
 {
-    PIO_STACK_LOCATION  StackLocation;
-    NTSTATUS            status;
+    PIO_STACK_LOCATION              StackLocation;
+    PCM_RESOURCE_LIST               ResourceList;
+    PCM_FULL_RESOURCE_DESCRIPTOR    Descriptor;
+    ULONG                           Size;
+    NTSTATUS                        status;
 
     ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
 
-    status = FdoForwardIrpSynchronously(Fdo, Irp);
-    if (!NT_SUCCESS(status))
+    StackLocation = IoGetCurrentIrpStackLocation(Irp);
+
+    // Raw
+
+    ResourceList = StackLocation->Parameters.StartDevice.AllocatedResources;
+    FdoDumpCmResourceList(Fdo, FALSE, ResourceList);
+
+    ASSERT3U(ResourceList->Count, ==, 1);
+    Descriptor = &ResourceList->List[0];
+
+    ASSERT3U(Descriptor->InterfaceType, ==, PCIBus);
+    ASSERT3U(Descriptor->BusNumber, ==, 0);
+
+    Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors) +
+           (Descriptor->PartialResourceList.Count) * sizeof 
(CM_PARTIAL_RESOURCE_DESCRIPTOR);
+
+    Fdo->RawResourceList = __FdoAllocate(Size);
+
+    status = STATUS_NO_MEMORY;
+    if (Fdo->RawResourceList == NULL)
         goto fail1;
 
-    StackLocation = IoGetCurrentIrpStackLocation(Irp);
+    RtlCopyMemory(Fdo->RawResourceList, &Descriptor->PartialResourceList, 
Size);
+
+    FdoFilterCmPartialResourceList(Fdo, &Descriptor->PartialResourceList);
+
+    // Translated
+
+    ResourceList = 
StackLocation->Parameters.StartDevice.AllocatedResourcesTranslated;
+    FdoDumpCmResourceList(Fdo, TRUE, ResourceList);
+
+    ASSERT3U(ResourceList->Count, ==, 1);
+    Descriptor = &ResourceList->List[0];
+
+    ASSERT3U(Descriptor->InterfaceType, ==, PCIBus);
+    ASSERT3U(Descriptor->BusNumber, ==, 0);
+
+    Size = FIELD_OFFSET(CM_PARTIAL_RESOURCE_LIST, PartialDescriptors) +
+           (Descriptor->PartialResourceList.Count) * sizeof 
(CM_PARTIAL_RESOURCE_DESCRIPTOR);
+
+    Fdo->TranslatedResourceList = __FdoAllocate(Size);
+
+    status = STATUS_NO_MEMORY;
+    if (Fdo->TranslatedResourceList == NULL)
+        goto fail2;
+
+    RtlCopyMemory(Fdo->TranslatedResourceList, 
&Descriptor->PartialResourceList, Size);
+
+    FdoFilterCmPartialResourceList(Fdo, &Descriptor->PartialResourceList);
 
-    FdoParseResources(Fdo,
-                      StackLocation->Parameters.StartDevice.AllocatedResources,
-                      
StackLocation->Parameters.StartDevice.AllocatedResourcesTranslated);
+    status = FdoForwardIrpSynchronously(Fdo, Irp);
+    if (!NT_SUCCESS(status))
+        goto fail3;
 
     if (!__FdoIsActive(Fdo))
         goto not_active;
 
-    status = FdoConnectInterrupt(Fdo);
+    status = FdoCreateInterrupt(Fdo);
     if (!NT_SUCCESS(status))
-        goto fail2;
+        goto fail4;
 
     KeInitializeEvent(&Fdo->ScanEvent, NotificationEvent, FALSE);
 
     status = ThreadCreate(FdoScan, Fdo, &Fdo->ScanThread);
     if (!NT_SUCCESS(status))
-        goto fail3;
+        goto fail5;
 
     InitializeMutex(&Fdo->BalloonSuspendMutex);
 
@@ -2254,20 +2748,20 @@ FdoStartDevice(
 
     status = ThreadCreate(FdoSuspend, Fdo, &Fdo->SuspendThread);
     if (!NT_SUCCESS(status))
-        goto fail4;
+        goto fail6;
 
     if (Fdo->BalloonInterface.Interface.Context != NULL) {
         KeInitializeEvent(&Fdo->BalloonEvent, NotificationEvent, FALSE);
 
         status = ThreadCreate(FdoBalloon, Fdo, &Fdo->BalloonThread);
         if (!NT_SUCCESS(status))
-            goto fail5;
+            goto fail7;
     }
 
 not_active:
     status = FdoD3ToD0(Fdo);
     if (!NT_SUCCESS(status))
-        goto fail6;
+        goto fail8;
 
     if (Fdo->BalloonInterface.Interface.Context != NULL) {
         BOOLEAN Warned;
@@ -2306,11 +2800,11 @@ not_active:
 
     return status;
 
-fail6:
-    Error("fail6\n");
+fail8:
+    Error("fail8\n");
 
     if (!__FdoIsActive(Fdo))
-        goto fail2;
+        goto fail4;
     
     if (Fdo->BalloonInterface.Interface.Context != NULL) {
         ThreadAlert(Fdo->BalloonThread);
@@ -2318,8 +2812,8 @@ fail6:
         Fdo->BalloonThread = NULL;
     }
 
-fail5:
-    Error("fail5\n");
+fail7:
+    Error("fail7\n");
 
     if (Fdo->BalloonInterface.Interface.Context != NULL)
         RtlZeroMemory(&Fdo->BalloonEvent, sizeof (KEVENT));
@@ -2328,8 +2822,8 @@ fail5:
     ThreadJoin(Fdo->SuspendThread);
     Fdo->SuspendThread = NULL;
 
-fail4:
-    Error("fail4\n");
+fail6:
+    Error("fail6\n");
 
     RtlZeroMemory(&Fdo->SuspendEvent, sizeof (KEVENT));
 
@@ -2339,17 +2833,27 @@ fail4:
     ThreadJoin(Fdo->ScanThread);
     Fdo->ScanThread = NULL;
 
-fail3:
-    Error("fail3\n");
+fail5:
+    Error("fail5\n");
 
     RtlZeroMemory(&Fdo->ScanEvent, sizeof (KEVENT));
 
-    FdoDisconnectInterrupt(Fdo);
+    FdoDestroyInterrupt(Fdo);
+
+fail4:
+    Error("fail4\n");
+
+fail3:
+    Error("fail3\n");
+
+    __FdoFree(Fdo->TranslatedResourceList);
+    Fdo->TranslatedResourceList = NULL;
 
 fail2:
     Error("fail2\n");
 
-    RtlZeroMemory(&Fdo->Resource, sizeof (XENBUS_RESOURCE) * RESOURCE_COUNT);
+    __FdoFree(Fdo->RawResourceList);
+    Fdo->RawResourceList = NULL;
 
 fail1:
     Error("fail1 (%08x)\n", status);
@@ -2445,10 +2949,14 @@ FdoStopDevice(
 
     RtlZeroMemory(&Fdo->ScanEvent, sizeof (KEVENT));
 
-    FdoDisconnectInterrupt(Fdo);
+    FdoDestroyInterrupt(Fdo);
 
 not_active:
-    RtlZeroMemory(&Fdo->Resource, sizeof (XENBUS_RESOURCE) * RESOURCE_COUNT);
+    __FdoFree(Fdo->TranslatedResourceList);
+    Fdo->TranslatedResourceList = NULL;
+
+    __FdoFree(Fdo->RawResourceList);
+    Fdo->RawResourceList = NULL;
 
     __FdoSetDevicePnpState(Fdo, Stopped);
     Irp->IoStatus.Status = STATUS_SUCCESS;
@@ -2554,6 +3062,9 @@ FdoRemoveDevice(
 
     ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
 
+    if (__FdoGetPreviousDevicePnpState(Fdo) != Started)
+        goto done;
+
     if (__FdoIsActive(Fdo)) {
         Trace("waiting for scan thread...\n");
 
@@ -2621,11 +3132,16 @@ FdoRemoveDevice(
 
     RtlZeroMemory(&Fdo->ScanEvent, sizeof (KEVENT));
 
-    FdoDisconnectInterrupt(Fdo);
+    FdoDestroyInterrupt(Fdo);
 
 not_active:
-    RtlZeroMemory(&Fdo->Resource, sizeof (XENBUS_RESOURCE) * RESOURCE_COUNT);
+    __FdoFree(Fdo->TranslatedResourceList);
+    Fdo->TranslatedResourceList = NULL;
+
+    __FdoFree(Fdo->RawResourceList);
+    Fdo->RawResourceList = NULL;
 
+done:
     __FdoSetDevicePnpState(Fdo, Deleted);
 
     Irp->IoStatus.Status = STATUS_SUCCESS;
@@ -2937,6 +3453,10 @@ FdoDispatchPnp(
           PnpMinorFunctionName(MinorFunction)); 
 
     switch (StackLocation->MinorFunction) {
+    case IRP_MN_FILTER_RESOURCE_REQUIREMENTS:
+        status = FdoFilterResourceRequirements(Fdo, Irp);
+        break;
+
     case IRP_MN_START_DEVICE:
         status = FdoStartDevice(Fdo, Irp);
         break;
diff --git a/src/xenbus/fdo.h b/src/xenbus/fdo.h
index fdb6f79..4916be4 100644
--- a/src/xenbus/fdo.h
+++ b/src/xenbus/fdo.h
@@ -38,6 +38,8 @@
 #include "driver.h"
 #include "types.h"
 
+typedef struct _XENBUS_INTERRUPT XENBUS_INTERRUPT, *PXENBUS_INTERRUPT;
+
 extern NTSTATUS
 FdoCreate(
     IN  PDEVICE_OBJECT  PhysicalDeviceObject,
@@ -140,11 +142,6 @@ FdoFreeIoSpace(
     IN  ULONG               Size
     );
 
-extern ULONG
-FdoGetInterruptVector(
-    IN  PXENBUS_FDO Fdo
-    );
-
 // Disable erroneous SAL warnings around use of interrupt locks
 #pragma warning(disable:28230)
 #pragma warning(disable:28285)
@@ -155,7 +152,8 @@ _IRQL_saves_
 _IRQL_raises_(HIGH_LEVEL)
 KIRQL
 FdoAcquireInterruptLock(
-    IN  PXENBUS_FDO Fdo
+    IN  PXENBUS_FDO         Fdo,
+    IN  PXENBUS_INTERRUPT   Interrupt
     );
 
 extern
@@ -163,9 +161,38 @@ _IRQL_requires_(HIGH_LEVEL)
 VOID
 FdoReleaseInterruptLock(
     IN  PXENBUS_FDO                 Fdo,
+    IN  PXENBUS_INTERRUPT           Interrupt,
     IN  __drv_restoresIRQL KIRQL    Irql
     );
 
+extern NTSTATUS
+FdoAllocateInterrupt(
+    IN  PXENBUS_FDO         Fdo,
+    IN  KINTERRUPT_MODE     InterruptMode,
+    IN  ULONG               Cpu,
+    IN  KSERVICE_ROUTINE    Callback,
+    IN  PVOID               Argument OPTIONAL,
+    OUT PXENBUS_INTERRUPT   *Interrupt
+    );
+
+extern UCHAR
+FdoGetInterruptVector(
+    IN  PXENBUS_FDO         Fdo,
+    IN  PXENBUS_INTERRUPT   Interrupt
+    );
+
+extern ULONG
+FdoGetInterruptLine(
+    IN  PXENBUS_FDO         Fdo,
+    IN  PXENBUS_INTERRUPT   Interrupt
+    );
+
+extern VOID
+FdoFreeInterrupt(
+    IN  PXENBUS_FDO         Fdo,
+    IN  PXENBUS_INTERRUPT   Interrupt
+    );
+
 #include "suspend.h"
 
 extern PXENBUS_SUSPEND_CONTEXT
diff --git a/src/xenbus/pdo.c b/src/xenbus/pdo.c
index 650e84d..ad0d4de 100644
--- a/src/xenbus/pdo.c
+++ b/src/xenbus/pdo.c
@@ -682,7 +682,7 @@ PdoParseResources(
               __PdoGetName(Pdo),
               Index,
               TranslatedPartialDescriptor->Type,
-              
PartialResourceDescriptorTypeName(TranslatedPartialDescriptor->Type));
+              ResourceDescriptorTypeName(TranslatedPartialDescriptor->Type));
 
         switch (TranslatedPartialDescriptor->Type) {
         case CmResourceTypeMemory:
-- 
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®.