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

[win-pv-devel] [PATCH 6/6] Make XEN, XENFILT and XENBUS processor group aware



Processor groups have been around for a long time in Windows and
contnuing to ignore them becomes ever more painful when trying to
pass the HCM multiple processor group device test. This patch, therefore,
modifies all the code that uses the non-group-aware kernel calls to use
the newer group aware calls.

Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
---
 include/evtchn_interface.h      |  36 ++++-
 include/shared_info_interface.h |   4 +-
 include/xen.h                   |   1 +
 src/xen/driver.c                |   2 +
 src/xen/system.c                | 165 ++++++++++---------
 src/xenbus.inf                  |   1 +
 src/xenbus/cache.c              |  65 +++++---
 src/xenbus/driver.c             |   2 +
 src/xenbus/evtchn.c             | 342 ++++++++++++++++++++++++++--------------
 src/xenbus/evtchn_2l.c          |  21 ++-
 src/xenbus/evtchn_abi.h         |  30 ++--
 src/xenbus/evtchn_fifo.c        |  52 +++---
 src/xenbus/fdo.c                |  56 ++++---
 src/xenbus/fdo.h                |   3 +-
 src/xenbus/pdo.c                |  87 +---------
 src/xenbus/shared_info.c        |  31 ++--
 src/xenbus/sync.c               | 280 ++++++++++++++++++--------------
 src/xenfilt/driver.c            |   2 +
 vs2012/xen/xen.vcxproj          |   4 +-
 vs2012/xenbus/xenbus.vcxproj    |   4 +-
 vs2012/xenfilt/xenfilt.vcxproj  |   4 +-
 vs2013/xen/xen.vcxproj          |   4 +-
 vs2013/xenbus/xenbus.vcxproj    |   4 +-
 vs2013/xenfilt/xenfilt.vcxproj  |   4 +-
 24 files changed, 690 insertions(+), 514 deletions(-)

diff --git a/include/evtchn_interface.h b/include/evtchn_interface.h
index 1bc456a..6f8fe42 100644
--- a/include/evtchn_interface.h
+++ b/include/evtchn_interface.h
@@ -112,18 +112,27 @@ typedef PXENBUS_EVTCHN_CHANNEL
     ...
     );
 
+typedef NTSTATUS
+(*XENBUS_EVTCHN_BIND_V2)(
+    IN  PINTERFACE              Interface,
+    IN  PXENBUS_EVTCHN_CHANNEL  Channel,
+    IN  ULONG                   Cpu
+    );
+
 /*! \typedef XENBUS_EVTCHN_BIND
     \brief Bind an event channel to a specific CPU
 
     \param Interface The interface header
     \param Channel The channel handle
-    \param Cpu The CPU that should handle events
+    \param Group The group number of the CPU that should handle events
+    \param Number The relative number of the CPU that should handle events
 */
 typedef NTSTATUS
 (*XENBUS_EVTCHN_BIND)(
     IN  PINTERFACE              Interface,
     IN  PXENBUS_EVTCHN_CHANNEL  Channel,
-    IN  ULONG                   Cpu
+    IN  USHORT                  Group,
+    IN  UCHAR                   Number
     );
 
 typedef BOOLEAN
@@ -225,7 +234,7 @@ struct _XENBUS_EVTCHN_INTERFACE_V2 {
     XENBUS_EVTCHN_ACQUIRE   EvtchnAcquire;
     XENBUS_EVTCHN_RELEASE   EvtchnRelease;
     XENBUS_EVTCHN_OPEN      EvtchnOpen;
-    XENBUS_EVTCHN_BIND      EvtchnBind;
+    XENBUS_EVTCHN_BIND_V2   EvtchnBindVersion2;
     XENBUS_EVTCHN_UNMASK_V1 EvtchnUnmaskVersion1;
     XENBUS_EVTCHN_SEND      EvtchnSend;
     XENBUS_EVTCHN_TRIGGER   EvtchnTrigger;
@@ -242,6 +251,23 @@ struct _XENBUS_EVTCHN_INTERFACE_V3 {
     XENBUS_EVTCHN_ACQUIRE   EvtchnAcquire;
     XENBUS_EVTCHN_RELEASE   EvtchnRelease;
     XENBUS_EVTCHN_OPEN      EvtchnOpen;
+    XENBUS_EVTCHN_BIND_V2   EvtchnBindVersion2;
+    XENBUS_EVTCHN_UNMASK    EvtchnUnmask;
+    XENBUS_EVTCHN_SEND      EvtchnSend;
+    XENBUS_EVTCHN_TRIGGER   EvtchnTrigger;
+    XENBUS_EVTCHN_GET_PORT  EvtchnGetPort;
+    XENBUS_EVTCHN_CLOSE     EvtchnClose;
+};
+
+/*! \struct _XENBUS_EVTCHN_INTERFACE_V4
+    \brief EVTCHN interface version 4
+    \ingroup interfaces
+*/
+struct _XENBUS_EVTCHN_INTERFACE_V4 {
+    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;
@@ -250,7 +276,7 @@ struct _XENBUS_EVTCHN_INTERFACE_V3 {
     XENBUS_EVTCHN_CLOSE     EvtchnClose;
 };
 
-typedef struct _XENBUS_EVTCHN_INTERFACE_V3 XENBUS_EVTCHN_INTERFACE, 
*PXENBUS_EVTCHN_INTERFACE;
+typedef struct _XENBUS_EVTCHN_INTERFACE_V4 XENBUS_EVTCHN_INTERFACE, 
*PXENBUS_EVTCHN_INTERFACE;
 
 /*! \def XENBUS_EVTCHN
     \brief Macro at assist in method invocation
@@ -261,7 +287,7 @@ typedef struct _XENBUS_EVTCHN_INTERFACE_V3 
XENBUS_EVTCHN_INTERFACE, *PXENBUS_EVT
 #endif  // _WINDLL
 
 #define XENBUS_EVTCHN_INTERFACE_VERSION_MIN 1
-#define XENBUS_EVTCHN_INTERFACE_VERSION_MAX 3
+#define XENBUS_EVTCHN_INTERFACE_VERSION_MAX 4
 
 #endif  // _XENBUS_EVTCHN_INTERFACE_H
 
diff --git a/include/shared_info_interface.h b/include/shared_info_interface.h
index 0e5a0d7..287feab 100644
--- a/include/shared_info_interface.h
+++ b/include/shared_info_interface.h
@@ -66,7 +66,7 @@ typedef VOID
 typedef BOOLEAN
 (*XENBUS_SHARED_INFO_UPCALL_PENDING)(
     IN  PINTERFACE  Interface,
-    IN  ULONG       Cpu
+    IN  ULONG       Index
     );
 
 typedef BOOLEAN
@@ -81,7 +81,7 @@ typedef BOOLEAN
 typedef BOOLEAN
 (*XENBUS_SHARED_INFO_EVTCHN_POLL)(
     IN  PINTERFACE                  Interface,
-    IN  ULONG                       Cpu,
+    IN  ULONG                       Index,
     IN  XENBUS_SHARED_INFO_EVENT    Event,
     IN  PVOID                       Argument
     );
diff --git a/include/xen.h b/include/xen.h
index 29e32f9..cf9c2d9 100644
--- a/include/xen.h
+++ b/include/xen.h
@@ -45,6 +45,7 @@
 #include <public/grant_table.h>
 #include <public/sched.h>
 #include <public/hvm/params.h>
+#include <public/hvm/hvm_info_table.h>
 
 // xs_wire.h gates the definition of the xsd_errors enumeration
 // on whether EINVAL is defined. Unfortunately EINVAL is actually
diff --git a/src/xen/driver.c b/src/xen/driver.c
index a319541..66a5e80 100644
--- a/src/xen/driver.c
+++ b/src/xen/driver.c
@@ -32,6 +32,7 @@
 #define XEN_API __declspec(dllexport)
 
 #include <ntddk.h>
+#include <procgrp.h>
 #include <xen.h>
 
 #include "hypercall.h"
@@ -126,6 +127,7 @@ DllInitialize(
     UNREFERENCED_PARAMETER(RegistryPath);
 
     ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
+    WdmlibProcgrpInitialize();
 
     __DbgPrintEnable();
 
diff --git a/src/xen/system.c b/src/xen/system.c
index b21efd8..a602d8b 100644
--- a/src/xen/system.c
+++ b/src/xen/system.c
@@ -32,6 +32,7 @@
 #define XEN_API __declspec(dllexport)
 
 #include <ntddk.h>
+#include <procgrp.h>
 #include <ntstrsafe.h>
 #include <stdlib.h>
 #include <stdarg.h>
@@ -47,19 +48,19 @@
 
 #define XEN_SYSTEM_TAG  'TSYS'
 
-typedef struct _SYSTEM_CPU {
-    ULONG   Index;
+typedef struct _SYSTEM_PROCESSOR {
     CHAR    Manufacturer[13];
     UCHAR   ApicID;
     UCHAR   ProcessorID;
-} SYSTEM_CPU, *PSYSTEM_CPU;
+} SYSTEM_PROCESSOR, *PSYSTEM_PROCESSOR;
 
 typedef struct _SYSTEM_CONTEXT {
-    LONG        References;
-    PACPI_MADT  Madt;
-    PSYSTEM_CPU Cpu[MAXIMUM_PROCESSORS];
-    PVOID       PowerStateHandle;
-    PVOID       ProcessorChangeHandle;
+    LONG                References;
+    PACPI_MADT          Madt;
+    PSYSTEM_PROCESSOR   Processor;
+    ULONG               ProcessorCount;
+    PVOID               PowerStateHandle;
+    PVOID               ProcessorChangeHandle;
 } SYSTEM_CONTEXT, *PSYSTEM_CONTEXT;
 
 static SYSTEM_CONTEXT   SystemContext;
@@ -334,51 +335,51 @@ _IRQL_requires_min_(DISPATCH_LEVEL)
 _IRQL_requires_(DISPATCH_LEVEL)
 _IRQL_requires_same_
 VOID
-SystemCpuInformation(
-    IN  PKDPC       Dpc,
-    IN  PVOID       _Context,
-    IN  PVOID       Argument1,
-    IN  PVOID       Argument2
+SystemProcessorInformation(
+    IN  PKDPC           Dpc,
+    IN  PVOID           _Context,
+    IN  PVOID           Argument1,
+    IN  PVOID           Argument2
     )
 {
-    PSYSTEM_CONTEXT Context = &SystemContext;
-    PKEVENT         Event = _Context;
-    ULONG           Index;
-    PSYSTEM_CPU     Cpu;
-    ULONG           EBX;
-    ULONG           ECX;
-    ULONG           EDX;
+    PSYSTEM_CONTEXT     Context = &SystemContext;
+    PKEVENT             Event = _Context;
+    ULONG               Index;
+    PROCESSOR_NUMBER    ProcNumber;
+    PSYSTEM_PROCESSOR   Processor;
+    ULONG               EBX;
+    ULONG               ECX;
+    ULONG               EDX;
 
     UNREFERENCED_PARAMETER(Dpc);
     UNREFERENCED_PARAMETER(Argument1);
     UNREFERENCED_PARAMETER(Argument2);
 
-    Index = KeGetCurrentProcessorNumber();
-    Cpu = Context->Cpu[Index];
+    Index = KeGetCurrentProcessorNumberEx(&ProcNumber);
+    ASSERT3U(Index, <, Context->ProcessorCount);
 
-    ASSERT(Cpu != NULL);
-    ASSERT3U(Cpu->Index, ==, Index);
+    Processor = &Context->Processor[Index];
 
-    Info("====> (%u)\n", Index);
+    Info("====> (%u:%u)\n", ProcNumber.Group, ProcNumber.Number);
 
     __CpuId(0, NULL, &EBX, &ECX, &EDX);
 
-    RtlCopyMemory(&Cpu->Manufacturer[0], &EBX, sizeof (ULONG));
-    RtlCopyMemory(&Cpu->Manufacturer[4], &EDX, sizeof (ULONG));
-    RtlCopyMemory(&Cpu->Manufacturer[8], &ECX, sizeof (ULONG));
+    RtlCopyMemory(&Processor->Manufacturer[0], &EBX, sizeof (ULONG));
+    RtlCopyMemory(&Processor->Manufacturer[4], &EDX, sizeof (ULONG));
+    RtlCopyMemory(&Processor->Manufacturer[8], &ECX, sizeof (ULONG));
 
     __CpuId(1, NULL, &EBX, NULL, NULL);
 
-    Cpu->ApicID = EBX >> 24;
-    Cpu->ProcessorID = SystemApicIDToProcessorID(Cpu->ApicID);
+    Processor->ApicID = EBX >> 24;
+    Processor->ProcessorID = SystemApicIDToProcessorID(Processor->ApicID);
 
-    Info("Manufacturer: %s\n", Cpu->Manufacturer);
-    Info("APIC ID: %02X\n", Cpu->ApicID);
-    Info("PROCESSOR ID: %02X\n", Cpu->ProcessorID);
+    Info("Manufacturer: %s\n", Processor->Manufacturer);
+    Info("APIC ID: %02X\n", Processor->ApicID);
+    Info("PROCESSOR ID: %02X\n", Processor->ProcessorID);
 
     KeSetEvent(Event, IO_NO_INCREMENT, FALSE);
 
-    Info("<==== (%u)\n", Index);
+    Info("<==== (%u:%u)\n", ProcNumber.Group, ProcNumber.Number);
 }
 
 static
@@ -391,42 +392,62 @@ SystemProcessorChangeCallback(
     )
 {
     PSYSTEM_CONTEXT                             Context = &SystemContext;
+    PROCESSOR_NUMBER                            ProcNumber;
     ULONG                                       Index;
+    NTSTATUS                                    status;
 
     UNREFERENCED_PARAMETER(Argument);
 
     Index = Change->NtNumber;
-    Trace("====> (%u:%s)\n", Index, ProcessorChangeName(Change->State));
+
+    status = KeGetProcessorNumberFromIndex(Index, &ProcNumber);
+    ASSERT(NT_SUCCESS(status));
+
+    Trace("====> (%u:%u:%s)\n",
+          ProcNumber.Group,
+          ProcNumber.Number,
+          ProcessorChangeName(Change->State));
 
     switch (Change->State) {
     case KeProcessorAddStartNotify: {
-        PSYSTEM_CPU Cpu;
+        PSYSTEM_PROCESSOR   Processor;
+        ULONG               ProcessorCount;
+
+        if (Index < Context->ProcessorCount)
+            break;
 
-        Cpu = __SystemAllocate(sizeof (SYSTEM_CPU));
+        ProcessorCount = Index + 1;
+        Processor = __SystemAllocate(sizeof (SYSTEM_PROCESSOR) *
+                                     ProcessorCount);
 
-        if (Cpu == NULL) {
+        if (Processor == NULL) {
             *Status = STATUS_NO_MEMORY;
             break;
         }
 
-        Cpu->Index = Index;
-        ASSERT3P(Context->Cpu[Index], ==, NULL);
-        Context->Cpu[Index] = Cpu;
+        if (Context->ProcessorCount != 0) {
+            RtlCopyMemory(Processor,
+                          Context->Processor,
+                          sizeof (SYSTEM_PROCESSOR) *
+                          Context->ProcessorCount);
+            __SystemFree(Context->Processor);
+        }
+
+        Context->Processor = Processor;
+        Context->ProcessorCount = ProcessorCount;
         break;
     }
     case KeProcessorAddCompleteNotify: {
-        PSYSTEM_CPU Cpu = Context->Cpu[Index];
-        KEVENT      Event;
-        KDPC        Dpc;
+        KEVENT              Event;
+        KDPC                Dpc;
 
-        ASSERT(Cpu != NULL);
-        ASSERT3U(Cpu->Index, ==, Index);
+        ASSERT3U(Index, <, Context->ProcessorCount);
 
         KeInitializeEvent(&Event, NotificationEvent, FALSE);
 
-        KeInitializeDpc(&Dpc, SystemCpuInformation, &Event);
+        KeInitializeDpc(&Dpc, SystemProcessorInformation, &Event);
         KeSetImportanceDpc(&Dpc, HighImportance);
-        KeSetTargetProcessorDpc(&Dpc, (CCHAR)Index);
+        KeSetTargetProcessorDpcEx(&Dpc, &ProcNumber);
 
         KeInsertQueueDpc(&Dpc, NULL, NULL);
 
@@ -437,20 +458,15 @@ SystemProcessorChangeCallback(
                                      NULL);
         break;
     }
-    case KeProcessorAddFailureNotify: {
-        PSYSTEM_CPU Cpu = Context->Cpu[Index];
-
-        ASSERT(Cpu != NULL);
-        ASSERT3U(Cpu->Index, ==, Index);
-
-        Context->Cpu[Index] = NULL;
-        __SystemFree(Cpu);
-
+    default:
+        ASSERT(FALSE);
         break;
     }
-    }
 
-    Trace("<==== (%u:%s)\n", Index, ProcessorChangeName(Change->State));
+    Trace("<==== (%u:%u:%s)\n",
+          ProcNumber.Group,
+          ProcNumber.Number,
+          ProcessorChangeName(Change->State));
 }
 
 static NTSTATUS
@@ -459,16 +475,19 @@ SystemRegisterProcessorChangeCallback(
     )
 {
     PSYSTEM_CONTEXT Context = &SystemContext;
+    PVOID           Handle;
     NTSTATUS        status;
 
-    Context->ProcessorChangeHandle = 
KeRegisterProcessorChangeCallback(SystemProcessorChangeCallback,
-                                                                       NULL,
-                                                                       
KE_PROCESSOR_CHANGE_ADD_EXISTING);
+    Handle = KeRegisterProcessorChangeCallback(SystemProcessorChangeCallback,
+                                               NULL,
+                                               
KE_PROCESSOR_CHANGE_ADD_EXISTING);
 
     status = STATUS_UNSUCCESSFUL;
-    if (Context->ProcessorChangeHandle == NULL)
+    if (Handle == NULL)
         goto fail1;
 
+    Context->ProcessorChangeHandle = Handle;
+
     return STATUS_SUCCESS;
 
 fail1:
@@ -483,22 +502,12 @@ SystemDeregisterProcessorChangeCallback(
     )
 {
     PSYSTEM_CONTEXT Context = &SystemContext;
-    ULONG           Index;
 
     KeDeregisterProcessorChangeCallback(Context->ProcessorChangeHandle);
     Context->ProcessorChangeHandle = NULL;
 
-    for (Index = 0; Index < MAXIMUM_PROCESSORS; Index++) {
-        PSYSTEM_CPU Cpu = Context->Cpu[Index];
-
-        if (Cpu == NULL)
-            continue;
-
-        Context->Cpu[Index] = NULL;
-        __SystemFree(Cpu);
-    }
-
-    ASSERT(IsZeroMemory(Context->Cpu, sizeof (SYSTEM_CPU) * 
MAXIMUM_PROCESSORS));
+    __SystemFree(Context->Processor);
+    Context->ProcessorCount = 0;
 }
 
 static NTSTATUS
@@ -732,11 +741,11 @@ SystemVirtualCpuIndex(
     )
 {
     PSYSTEM_CONTEXT     Context = &SystemContext;
-    PSYSTEM_CPU         Cpu = Context->Cpu[Index];
+    PSYSTEM_PROCESSOR   Processor = &Context->Processor[Index];
 
-    ASSERT(Cpu != NULL);
+    ASSERT3U(Index, <, Context->ProcessorCount);
 
-    return Cpu->ProcessorID;
+    return Processor->ProcessorID;
 }
 
 VOID
diff --git a/src/xenbus.inf b/src/xenbus.inf
index 5377fd0..90dcf64 100644
--- a/src/xenbus.inf
+++ b/src/xenbus.inf
@@ -96,6 +96,7 @@ HKR,"Interfaces",,0x00000010
 HKR,"Interrupt Management",,0x00000010
 HKR,"Interrupt Management\MessageSignaledInterruptProperties",,0x00000010
 HKR,"Interrupt 
Management\MessageSignaledInterruptProperties","MSISupported",0x00010001,1
+HKR,"Interrupt Management\GroupPolicy",0x00010001,1
 
 [XenFilt_Service] 
 DisplayName=%XenFiltDesc%
diff --git a/src/xenbus/cache.c b/src/xenbus/cache.c
index 3620f88..ba7dcdf 100644
--- a/src/xenbus/cache.c
+++ b/src/xenbus/cache.c
@@ -30,6 +30,7 @@
  */
 
 #include <ntddk.h>
+#include <procgrp.h>
 #include <ntstrsafe.h>
 #include <stdlib.h>
 
@@ -79,8 +80,9 @@ struct _XENBUS_CACHE {
     PVOID                   Argument;
     LIST_ENTRY              GetList;
     PLIST_ENTRY             PutList;
-    LONG                    Count;
-    XENBUS_CACHE_MAGAZINE   Magazine[MAXIMUM_PROCESSORS];
+    LONG                    ObjectCount;
+    PXENBUS_CACHE_MAGAZINE  Magazine;
+    ULONG                   MagazineCount;
     XENBUS_CACHE_FIST       FIST;
 };
 
@@ -223,7 +225,7 @@ CacheGetObjectFromList(
     KIRQL                       Irql = PASSIVE_LEVEL;
     NTSTATUS                    status;
 
-    Count = InterlockedDecrement(&Cache->Count);
+    Count = InterlockedDecrement(&Cache->ObjectCount);
 
     status = STATUS_NO_MEMORY;
     if (Count < 0)
@@ -253,7 +255,7 @@ CacheGetObjectFromList(
     return Object;
 
 fail1:
-    (VOID) InterlockedIncrement(&Cache->Count);
+    (VOID) InterlockedIncrement(&Cache->ObjectCount);
 
     return NULL;    
 }
@@ -292,19 +294,18 @@ CachePutObjectToList(
 
     KeMemoryBarrier();
 
-    (VOID) InterlockedIncrement(&Cache->Count);
+    (VOID) InterlockedIncrement(&Cache->ObjectCount);
 }
 
 static PVOID
 CacheGetObjectFromMagazine(
     IN  PXENBUS_CACHE       Cache,
-    IN  ULONG               Cpu
+    IN  ULONG               Index
     )
 {
     PXENBUS_CACHE_MAGAZINE  Magazine;
-    ULONG                   Index;
 
-    Magazine = &Cache->Magazine[Cpu];
+    Magazine = &Cache->Magazine[Index];
 
     for (Index = 0; Index < XENBUS_CACHE_MAGAZINE_SLOTS; Index++) {
         PVOID   Object;
@@ -323,14 +324,13 @@ CacheGetObjectFromMagazine(
 static BOOLEAN
 CachePutObjectToMagazine(
     IN  PXENBUS_CACHE       Cache,
-    IN  ULONG               Cpu,
+    IN  ULONG               Index,
     IN  PVOID               Object
     )
 {
     PXENBUS_CACHE_MAGAZINE  Magazine;
-    ULONG                   Index;
 
-    Magazine = &Cache->Magazine[Cpu];
+    Magazine = &Cache->Magazine[Index];
 
     for (Index = 0; Index < XENBUS_CACHE_MAGAZINE_SLOTS; Index++) {
         if (Magazine->Slot[Index] == NULL) {
@@ -350,7 +350,7 @@ CacheGet(
     )
 {
     KIRQL               Irql;
-    ULONG               Cpu;
+    ULONG               Index;
     PVOID               Object;
 
     UNREFERENCED_PARAMETER(Interface);
@@ -370,9 +370,9 @@ CacheGet(
     }
 
     KeRaiseIrql(DISPATCH_LEVEL, &Irql);
-    Cpu = KeGetCurrentProcessorNumber();
+    Index = KeGetCurrentProcessorNumberEx(NULL);
 
-    Object = CacheGetObjectFromMagazine(Cache, Cpu);
+    Object = CacheGetObjectFromMagazine(Cache, Index);
     if (Object != NULL)
         goto done;
 
@@ -397,14 +397,14 @@ CachePut(
     )
 {
     KIRQL               Irql;
-    ULONG               Cpu;
+    ULONG               Index;
 
     UNREFERENCED_PARAMETER(Interface);
 
     KeRaiseIrql(DISPATCH_LEVEL, &Irql);
-    Cpu = KeGetCurrentProcessorNumber();
+    Index = KeGetCurrentProcessorNumberEx(NULL);
 
-    if (CachePutObjectToMagazine(Cache, Cpu, Object))
+    if (CachePutObjectToMagazine(Cache, Index, Object))
         goto done;
 
     CachePutObjectToList(Cache, Object, Locked);
@@ -418,12 +418,12 @@ CacheFlushMagazines(
     IN  PXENBUS_CACHE   Cache
     )
 {
-    ULONG               Cpu;
+    ULONG               Index;
 
-    for (Cpu = 0; Cpu < MAXIMUM_PROCESSORS; Cpu++) {
+    for (Index = 0; Index < Cache->MagazineCount; Index++) {
         PVOID   Object;
 
-        while ((Object = CacheGetObjectFromMagazine(Cache, Cpu)) != NULL)
+        while ((Object = CacheGetObjectFromMagazine(Cache, Index)) != NULL)
             CachePutObjectToList(Cache, Object, TRUE);
     }
 }
@@ -609,6 +609,13 @@ CacheCreate(
     if (!NT_SUCCESS(status))
         goto fail4;
 
+    (*Cache)->MagazineCount = 
KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
+    (*Cache)->Magazine = __CacheAllocate(sizeof (XENBUS_CACHE_MAGAZINE) * 
(*Cache)->MagazineCount);
+
+    status = STATUS_NO_MEMORY;
+    if ((*Cache)->Magazine == NULL)
+        goto fail5;
+
     (*Cache)->Reservation = Reservation;
 
     KeAcquireSpinLock(&Context->Lock, &Irql);
@@ -619,6 +626,11 @@ CacheCreate(
 
     return STATUS_SUCCESS;
 
+fail5:
+    Error("fail5\n");
+
+    (*Cache)->MagazineCount = 0;
+
 fail4:
     Error("fail4\n");
 
@@ -669,9 +681,14 @@ CacheDestroy(
 
     Cache->Reservation = 0;
     CacheFlushMagazines(Cache);
-    CacheSpill(Cache, Cache->Count);
+    CacheSpill(Cache, Cache->ObjectCount);
+
+    ASSERT3U(Cache->ObjectCount, ==, 0);
 
-    ASSERT3U(Cache->Count, ==, 0);
+    ASSERT(IsZeroMemory(Cache->Magazine, sizeof (XENBUS_CACHE_MAGAZINE) * 
Cache->MagazineCount));
+    __CacheFree(Cache->Magazine);
+    Cache->Magazine = NULL;
+    Cache->MagazineCount = 0;
 
     RtlZeroMemory(&Cache->GetList, sizeof (LIST_ENTRY));
 
@@ -720,7 +737,7 @@ CacheDebugCallback(
                          &Context->DebugInterface,
                          "- %s: Count = %d (Reservation = %d)\n",
                          Cache->Name,
-                         Cache->Count,
+                         Cache->ObjectCount,
                          Cache->Reservation);
         }
     }
@@ -776,7 +793,7 @@ CacheMonitor(
 
             Cache = CONTAINING_RECORD(ListEntry, XENBUS_CACHE, ListEntry);
 
-            Count = Cache->Count;
+            Count = Cache->ObjectCount;
 
             if (Count < Cache->Reservation)
                 CacheFill(Cache, Cache->Reservation - Count);
diff --git a/src/xenbus/driver.c b/src/xenbus/driver.c
index e74d369..a1115a4 100644
--- a/src/xenbus/driver.c
+++ b/src/xenbus/driver.c
@@ -30,6 +30,7 @@
  */
 
 #include <ntddk.h>
+#include <procgrp.h>
 #include <ntstrsafe.h>
 
 #include "registry.h"
@@ -500,6 +501,7 @@ DriverEntry(
     ASSERT3P(__DriverGetDriverObject(), ==, NULL);
 
     ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
+    WdmlibProcgrpInitialize();
 
     __DbgPrintEnable();
 
diff --git a/src/xenbus/evtchn.c b/src/xenbus/evtchn.c
index f44c3cf..889179c 100644
--- a/src/xenbus/evtchn.c
+++ b/src/xenbus/evtchn.c
@@ -30,6 +30,7 @@
  */
 
 #include <ntddk.h>
+#include <procgrp.h>
 #include <stdarg.h>
 #include <xen.h>
 
@@ -84,17 +85,24 @@ struct _XENBUS_EVTCHN_CHANNEL {
     XENBUS_EVTCHN_PARAMETERS    Parameters;
     BOOLEAN                     Mask;
     ULONG                       LocalPort;
-    ULONG                       Cpu;
+    PROCESSOR_NUMBER            ProcNumber;
     BOOLEAN                     Closed;
 };
 
+typedef struct _XENBUS_EVTCHN_PROCESSOR {
+    PXENBUS_INTERRUPT   Interrupt;
+    LIST_ENTRY          PendingList;
+    KDPC                Dpc;
+    BOOLEAN             UpcallEnabled;
+} XENBUS_EVTCHN_PROCESSOR, *PXENBUS_EVTCHN_PROCESSOR;
+
 struct _XENBUS_EVTCHN_CONTEXT {
     PXENBUS_FDO                     Fdo;
     KSPIN_LOCK                      Lock;
     LONG                            References;
-    PXENBUS_INTERRUPT               LevelSensitiveInterrupt;
-    PXENBUS_INTERRUPT               LatchedInterrupt[MAXIMUM_PROCESSORS];
-    KAFFINITY                       Affinity;
+    PXENBUS_INTERRUPT               Interrupt;
+    PXENBUS_EVTCHN_PROCESSOR        Processor;
+    ULONG                           ProcessorCount;
     XENBUS_SUSPEND_INTERFACE        SuspendInterface;
     PXENBUS_SUSPEND_CALLBACK        SuspendCallbackEarly;
     PXENBUS_SUSPEND_CALLBACK        SuspendCallbackLate;
@@ -107,8 +115,6 @@ struct _XENBUS_EVTCHN_CONTEXT {
     BOOLEAN                         UseEvtchnFifoAbi;
     PXENBUS_HASH_TABLE              Table;
     LIST_ENTRY                      List;
-    LIST_ENTRY                      PendingList[MAXIMUM_PROCESSORS];
-    KDPC                            Dpc[MAXIMUM_PROCESSORS];
 };
 
 #define XENBUS_EVTCHN_TAG  'CTVE'
@@ -402,7 +408,7 @@ EvtchnReap(
     RemoveEntryList(&Channel->ListEntry);
     RtlZeroMemory(&Channel->ListEntry, sizeof (LIST_ENTRY));
 
-    Channel->Cpu = 0;
+    RtlZeroMemory(&Channel->ProcNumber, sizeof (PROCESSOR_NUMBER));
 
     ASSERT(IsListEmpty(&Channel->PendingListEntry));
     RtlZeroMemory(&Channel->PendingListEntry, sizeof (LIST_ENTRY));
@@ -428,18 +434,22 @@ EvtchnReap(
 
 static BOOLEAN
 EvtchnPollCallback(
-    IN  PVOID               Argument,
-    IN  ULONG               LocalPort
+    IN  PVOID                   Argument,
+    IN  ULONG                   LocalPort
     )
 {
-    PXENBUS_EVTCHN_CONTEXT  Context = Argument;
-    ULONG                   Cpu;
-    PXENBUS_EVTCHN_CHANNEL  Channel;
-    BOOLEAN                 Pending;
-    NTSTATUS                status;
+    PXENBUS_EVTCHN_CONTEXT      Context = Argument;
+    ULONG                       Index;
+    PXENBUS_EVTCHN_PROCESSOR    Processor;
+    PXENBUS_EVTCHN_CHANNEL      Channel;
+    BOOLEAN                     Pending;
+    NTSTATUS                    status;
 
     ASSERT3U(KeGetCurrentIrql(), >=, DISPATCH_LEVEL);
-    Cpu = KeGetCurrentProcessorNumber();
+    Index = KeGetCurrentProcessorNumberEx(NULL);
+
+    ASSERT3U(Index, <, Context->ProcessorCount);
+    Processor = &Context->Processor[Index];
 
     status = HashTableLookup(Context->Table,
                              LocalPort,
@@ -452,7 +462,7 @@ EvtchnPollCallback(
     Pending = !IsListEmpty(&Channel->PendingListEntry);
 
     if (!Pending)
-        InsertTailList(&Context->PendingList[Cpu],
+        InsertTailList(&Processor->PendingList,
                        &Channel->PendingListEntry);
 
 done:
@@ -462,23 +472,27 @@ done:
 static BOOLEAN
 EvtchnPoll(
     IN  PXENBUS_EVTCHN_CONTEXT  Context,
-    IN  ULONG                   Cpu,
+    IN  ULONG                   Index,
     IN  PLIST_ENTRY             List
     )
 {
+    PXENBUS_EVTCHN_PROCESSOR    Processor;
     BOOLEAN                     DoneSomething;
     PLIST_ENTRY                 ListEntry;
 
+    ASSERT3U(Index, <, Context->ProcessorCount);
+    Processor = &Context->Processor[Index];
+
     (VOID) XENBUS_EVTCHN_ABI(Poll,
                              &Context->EvtchnAbi,
-                             Cpu,
+                             Index,
                              EvtchnPollCallback,
                              Context);
 
     DoneSomething = FALSE;
 
-    ListEntry = Context->PendingList[Cpu].Flink;
-    while (ListEntry != &Context->PendingList[Cpu]) {
+    ListEntry = Processor->PendingList.Flink;
+    while (ListEntry != &Processor->PendingList) {
         PLIST_ENTRY             Next = ListEntry->Flink;
         PXENBUS_EVTCHN_CHANNEL  Channel;
 
@@ -518,23 +532,25 @@ EvtchnPoll(
 static VOID
 EvtchnFlush(
     IN  PXENBUS_EVTCHN_CONTEXT  Context,
-    IN  ULONG                   Cpu
+    IN  ULONG                   Index
     )
 {
+    PXENBUS_EVTCHN_PROCESSOR    Processor;
     LIST_ENTRY                  List;
     PXENBUS_INTERRUPT           Interrupt;
     KIRQL                       Irql;
 
-    Interrupt = (Context->Affinity != 0) ? // Latched available
-                Context->LatchedInterrupt[Cpu] :
-                Context->LevelSensitiveInterrupt;
+    ASSERT3U(Index, <, Context->ProcessorCount);
+    Processor = &Context->Processor[Index];
+
+    Interrupt = (Processor->UpcallEnabled) ?
+                Processor->Interrupt :
+                Context->Interrupt;
 
     InitializeListHead(&List);
 
     Irql = FdoAcquireInterruptLock(Context->Fdo, Interrupt);
-
-    (VOID) EvtchnPoll(Context, Cpu, &List);
-
+    (VOID) EvtchnPoll(Context, Index, &List);
     FdoReleaseInterruptLock(Context->Fdo, Interrupt, Irql);
 
     while (!IsListEmpty(&List)) {
@@ -571,21 +587,21 @@ EvtchnDpc(
     )
 {
     PXENBUS_EVTCHN_CONTEXT  Context = _Context;
-    ULONG                   Cpu;
+    ULONG                   Index;
 
     UNREFERENCED_PARAMETER(Dpc);
     UNREFERENCED_PARAMETER(Argument1);
     UNREFERENCED_PARAMETER(Argument2);
 
     ASSERT3U(KeGetCurrentIrql(), >=, DISPATCH_LEVEL);
-    Cpu = KeGetCurrentProcessorNumber();
+    Index = KeGetCurrentProcessorNumberEx(NULL);
 
     KeAcquireSpinLockAtDpcLevel(&Context->Lock);
 
     if (Context->References == 0)
         goto done;
 
-    EvtchnFlush(Context, Cpu);
+    EvtchnFlush(Context, Index);
 
 done:
     KeReleaseSpinLockFromDpcLevel(&Context->Lock);
@@ -598,28 +614,34 @@ EvtchnTrigger(
     )
 {
     PXENBUS_EVTCHN_CONTEXT      Context = Interface->Context;
-    PKDPC                       Dpc;
     KIRQL                       Irql;
-    ULONG                       Cpu;
+    PROCESSOR_NUMBER            ProcNumber;
+    ULONG                       Index;
+    PXENBUS_EVTCHN_PROCESSOR    Processor;
     PXENBUS_INTERRUPT           Interrupt;
     BOOLEAN                     Pending;
 
     ASSERT3U(Channel->Magic, ==, XENBUS_EVTCHN_CHANNEL_MAGIC);
 
     KeAcquireSpinLock(&Channel->Lock, &Irql);
-    Cpu = Channel->Cpu;
+    ProcNumber = Channel->ProcNumber;
     KeReleaseSpinLock(&Channel->Lock, Irql);
 
-    Interrupt = (Context->Affinity != 0) ? // Latched available
-                Context->LatchedInterrupt[Cpu] :
-                Context->LevelSensitiveInterrupt;
+    Index = KeGetProcessorIndexFromNumber(&ProcNumber);
+
+    ASSERT3U(Index, <, Context->ProcessorCount);
+    Processor = &Context->Processor[Index];
+
+    Interrupt = (Processor->UpcallEnabled) ?
+                Processor->Interrupt :
+                Context->Interrupt;
 
     Irql = FdoAcquireInterruptLock(Context->Fdo, Interrupt);
 
     Pending = !IsListEmpty(&Channel->PendingListEntry);
 
     if (!Pending)
-        InsertTailList(&Context->PendingList[Cpu],
+        InsertTailList(&Processor->PendingList,
                        &Channel->PendingListEntry);
 
     FdoReleaseInterruptLock(Context->Fdo, Interrupt, Irql);
@@ -627,18 +649,21 @@ EvtchnTrigger(
     if (Pending)
         return;
 
-    Dpc = &Context->Dpc[Cpu];
-    KeInsertQueueDpc(Dpc, NULL, NULL);
+    KeInsertQueueDpc(&Processor->Dpc, NULL, NULL);
 }
 
 static NTSTATUS
 EvtchnBind(
     IN  PINTERFACE              Interface,
     IN  PXENBUS_EVTCHN_CHANNEL  Channel,
-    IN  ULONG                   Cpu
+    IN  USHORT                  Group,
+    IN  UCHAR                   Number
     )
 {
     PXENBUS_EVTCHN_CONTEXT      Context = Interface->Context;
+    PROCESSOR_NUMBER            ProcNumber;
+    ULONG                       Index;
+    PXENBUS_EVTCHN_PROCESSOR    Processor;
     ULONG                       LocalPort;
     unsigned int                vcpu_id;
     KIRQL                       Irql;
@@ -646,8 +671,16 @@ EvtchnBind(
 
     ASSERT3U(Channel->Magic, ==, XENBUS_EVTCHN_CHANNEL_MAGIC);
 
+    ProcNumber.Group = Group;
+    ProcNumber.Number = Number;
+
+    Index = KeGetProcessorIndexFromNumber(&ProcNumber);
+
+    ASSERT3U(Index, <, Context->ProcessorCount);
+    Processor = &Context->Processor[Index];
+
     status = STATUS_NOT_SUPPORTED;
-    if (~Context->Affinity & ((KAFFINITY)1 << Cpu))
+    if (!Processor->UpcallEnabled)
         goto fail1;
 
     KeAcquireSpinLock(&Channel->Lock, &Irql);
@@ -655,19 +688,20 @@ EvtchnBind(
     if (!Channel->Active)
         goto done;
 
-    if (Channel->Cpu == Cpu)
+    if (Channel->ProcNumber.Group == Group &&
+        Channel->ProcNumber.Number == Number)
         goto done;
 
     LocalPort = Channel->LocalPort;
-    vcpu_id = SystemVirtualCpuIndex(Cpu);
+    vcpu_id = SystemVirtualCpuIndex(Index);
 
     status = EventChannelBindVirtualCpu(LocalPort, vcpu_id);
     if (!NT_SUCCESS(status))
         goto fail2;
 
-    Channel->Cpu = Cpu;
+    Channel->ProcNumber = ProcNumber;
 
-    Info("[%u]: CPU %u\n", LocalPort, Cpu);
+    Info("[%u]: CPU %u:%u\n", LocalPort, Group, Number);
 
 done:
     KeReleaseSpinLock(&Channel->Lock, Irql);
@@ -685,6 +719,18 @@ fail1:
     return status;
 }
 
+static NTSTATUS
+EvtchnBindVersion2(
+    IN  PINTERFACE              Interface,
+    IN  PXENBUS_EVTCHN_CHANNEL  Channel,
+    IN  ULONG                   Cpu
+    )
+{
+    ASSERT3U(Cpu, <, MAXIMUM_PROCESSORS);
+
+    return EvtchnBind(Interface, Channel, 0, (CHAR)Cpu);
+}
+
 static VOID
 EvtchnUnmask(
     IN  PINTERFACE              Interface,
@@ -842,27 +888,26 @@ EvtchnInterruptCallback(
     )
 {
     PXENBUS_EVTCHN_CONTEXT  Context = Argument;
-    ULONG                   Cpu;
+    ULONG                   Index;
     BOOLEAN                 DoneSomething;
 
     UNREFERENCED_PARAMETER(InterruptObject);
 
     ASSERT3U(KeGetCurrentIrql(), >=, DISPATCH_LEVEL);
-    Cpu = KeGetCurrentProcessorNumber();
+    Index = KeGetCurrentProcessorNumberEx(NULL);
 
     DoneSomething = FALSE;
     while (XENBUS_SHARED_INFO(UpcallPending,
                               &Context->SharedInfoInterface,
-                              Cpu))
-        DoneSomething |= EvtchnPoll(Context, Cpu, NULL);
+                              Index))
+        DoneSomething |= EvtchnPoll(Context, Index, NULL);
 
     return DoneSomething;
 }
 
 static NTSTATUS
 EvtchnAbiAcquire(
-    IN  PXENBUS_EVTCHN_CONTEXT  Context,
-    OUT PKAFFINITY              Affinity
+    IN  PXENBUS_EVTCHN_CONTEXT  Context
     )
 {
     NTSTATUS                    status;
@@ -872,8 +917,7 @@ EvtchnAbiAcquire(
                          &Context->EvtchnAbi);
 
         status = XENBUS_EVTCHN_ABI(Acquire,
-                                   &Context->EvtchnAbi,
-                                   Affinity);
+                                   &Context->EvtchnAbi);
         if (!NT_SUCCESS(status))
             goto use_two_level;
 
@@ -886,8 +930,7 @@ use_two_level:
                          &Context->EvtchnAbi);
 
     status = XENBUS_EVTCHN_ABI(Acquire,
-                               &Context->EvtchnAbi,
-                               Affinity);
+                               &Context->EvtchnAbi);
     if (!NT_SUCCESS(status))
         goto fail1;
 
@@ -917,32 +960,38 @@ EvtchnInterruptEnable(
     IN  PXENBUS_EVTCHN_CONTEXT  Context
     )
 {
-    LONG                        Cpu;
+    ULONG                       Index;
     ULONG                       Line;
     NTSTATUS                    status;
 
     Trace("====>\n");
 
-    for (Cpu = 0; Cpu < MAXIMUM_PROCESSORS; Cpu++) {
-        unsigned int    vcpu_id;
-        UCHAR           Vector;
+    for (Index = 0; Index < Context->ProcessorCount; Index++) {
+        PXENBUS_EVTCHN_PROCESSOR    Processor;
+        unsigned int                vcpu_id;
+        UCHAR                       Vector;
+
+        Processor = &Context->Processor[Index];
 
-        if (Context->LatchedInterrupt[Cpu] == NULL)
+        if (Processor->Interrupt == NULL)
             continue;
 
-        vcpu_id = SystemVirtualCpuIndex(Cpu);
-        Vector = FdoGetInterruptVector(Context->Fdo,
-                                       Context->LatchedInterrupt[Cpu]);
+        vcpu_id = SystemVirtualCpuIndex(Index);
+        Vector = FdoGetInterruptVector(Context->Fdo, Processor->Interrupt);
 
         status = HvmSetEvtchnUpcallVector(vcpu_id, Vector);
         if (NT_SUCCESS(status)) {
-            Info("CPU %u\n", Cpu);
-            Context->Affinity |= (KAFFINITY)1 << Cpu;
+            PROCESSOR_NUMBER    ProcNumber;
+
+            status = KeGetProcessorNumberFromIndex(Index, &ProcNumber);
+            ASSERT(NT_SUCCESS(status));
+
+            Info("CPU %u:%u\n", ProcNumber.Group, ProcNumber.Number);
+            Processor->UpcallEnabled = TRUE;
         }
     }
 
-    Line = FdoGetInterruptLine(Context->Fdo,
-                               Context->LevelSensitiveInterrupt);
+    Line = FdoGetInterruptLine(Context->Fdo, Context->Interrupt);
 
     status = HvmSetParam(HVM_PARAM_CALLBACK_IRQ, Line);
     ASSERT(NT_SUCCESS(status));
@@ -955,7 +1004,7 @@ EvtchnInterruptDisable(
     IN  PXENBUS_EVTCHN_CONTEXT  Context
     )
 {
-    ULONG                       Cpu;
+    ULONG                       Index;
     NTSTATUS                    status;
 
     UNREFERENCED_PARAMETER(Context);
@@ -965,20 +1014,21 @@ EvtchnInterruptDisable(
     status = HvmSetParam(HVM_PARAM_CALLBACK_IRQ, 0);
     ASSERT(NT_SUCCESS(status));
 
-    for (Cpu = 0; Cpu < MAXIMUM_PROCESSORS; Cpu++) {
-        unsigned int    vcpu_id;
+    for (Index = 0; Index < Context->ProcessorCount; Index++) {
+        PXENBUS_EVTCHN_PROCESSOR    Processor;
+        unsigned int                vcpu_id;
+
+        Processor = &Context->Processor[Index];
 
-        if (~Context->Affinity & (KAFFINITY)1 << Cpu)
+        if (!Processor->UpcallEnabled)
             continue;
 
-        vcpu_id = SystemVirtualCpuIndex(Cpu);
+        vcpu_id = SystemVirtualCpuIndex(Index);
 
         (VOID) HvmSetEvtchnUpcallVector(vcpu_id, 0);
-        Context->Affinity &= ~((KAFFINITY)1 << Cpu);
+        Processor->UpcallEnabled = FALSE;
     }
 
-    ASSERT3U(Context->Affinity, ==, 0);
-
     Trace("<====\n");
 }
 
@@ -1019,17 +1069,13 @@ EvtchnSuspendCallbackLate(
     )
 {
     PXENBUS_EVTCHN_CONTEXT  Context = Argument;
-    KAFFINITY               Affinity;
     NTSTATUS                status;
 
     EvtchnAbiRelease(Context);
 
-    status = EvtchnAbiAcquire(Context, &Affinity);
+    status = EvtchnAbiAcquire(Context);
     ASSERT(NT_SUCCESS(status));
 
-    // Affinity must be a superset of Context->Affinity
-    ASSERT3U(Affinity & Context->Affinity, ==, Context->Affinity);
-
     EvtchnInterruptDisable(Context);
     EvtchnInterruptEnable(Context);
 }
@@ -1127,8 +1173,8 @@ EvtchnAcquire(
     PXENBUS_EVTCHN_CONTEXT  Context = Interface->Context;
     PXENBUS_FDO             Fdo = Context->Fdo;
     KIRQL                   Irql;
-    ULONG                   Cpu;
-    KAFFINITY               Affinity;
+    PROCESSOR_NUMBER        ProcNumber;
+    ULONG                   Index;
     NTSTATUS                status;
 
     KeAcquireSpinLock(&Context->Lock, &Irql);
@@ -1177,29 +1223,56 @@ EvtchnAcquire(
     if (!NT_SUCCESS(status))
         goto fail6;
 
-    status = EvtchnAbiAcquire(Context, &Affinity);
+    status = EvtchnAbiAcquire(Context);
     if (!NT_SUCCESS(status))
         goto fail7;
 
-    Context->LevelSensitiveInterrupt = FdoAllocateInterrupt(Fdo,
-                                                            LevelSensitive,
-                                                            0,
-                                                            
EvtchnInterruptCallback,
-                                                            Context);
+    status = KeGetProcessorNumberFromIndex(0, &ProcNumber);
+    ASSERT(NT_SUCCESS(status));
+
+    Context->Interrupt = FdoAllocateInterrupt(Fdo,
+                                              LevelSensitive,
+                                              ProcNumber.Group,
+                                              ProcNumber.Number,
+                                              EvtchnInterruptCallback,
+                                              Context);
 
     status = STATUS_UNSUCCESSFUL;
-    if (Context->LevelSensitiveInterrupt == NULL)
+    if (Context->Interrupt == NULL)
         goto fail8;
 
-    for (Cpu = 0; Cpu < MAXIMUM_PROCESSORS; Cpu++) {
-        if (~Affinity & (KAFFINITY)1 << Cpu)
+    Context->ProcessorCount = 
KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
+    Context->Processor = __EvtchnAllocate(sizeof (XENBUS_EVTCHN_PROCESSOR) * 
Context->ProcessorCount);
+
+    status = STATUS_NO_MEMORY;
+    if (Context->Processor == NULL)
+        goto fail9;
+
+    for (Index = 0; Index < Context->ProcessorCount; Index++) {
+        PXENBUS_EVTCHN_PROCESSOR    Processor;
+
+        if (!XENBUS_EVTCHN_ABI(IsProcessorEnabled,
+                               &Context->EvtchnAbi,
+                               Index))
             continue;
 
-        Context->LatchedInterrupt[Cpu] = FdoAllocateInterrupt(Fdo,
-                                                              Latched,
-                                                              Cpu,
-                                                              
EvtchnInterruptCallback,
-                                                              Context);
+        status = KeGetProcessorNumberFromIndex(Index, &ProcNumber);
+        ASSERT(NT_SUCCESS(status));
+
+        Processor = &Context->Processor[Index];
+
+        Processor->Interrupt = FdoAllocateInterrupt(Fdo,
+                                                    Latched,
+                                                    ProcNumber.Group,
+                                                    ProcNumber.Number,
+                                                    EvtchnInterruptCallback,
+                                                    Context);
+        ASSERT(Processor->Interrupt != NULL);
+
+        InitializeListHead(&Processor->PendingList);
+
+        KeInitializeDpc(&Processor->Dpc, EvtchnDpc, Context);
+        KeSetTargetProcessorDpcEx(&Processor->Dpc, &ProcNumber);
     }
 
     EvtchnInterruptEnable(Context);
@@ -1211,6 +1284,11 @@ done:
 
     return STATUS_SUCCESS;
 
+fail9:
+    Error("fail9\n");
+
+    Context->ProcessorCount = 0;
+
 fail8:
     Error("fail8\n");
 
@@ -1273,7 +1351,7 @@ EvtchnRelease(
     PXENBUS_EVTCHN_CONTEXT  Context = Interface->Context;
     PXENBUS_FDO             Fdo = Context->Fdo;
     KIRQL                   Irql;
-    ULONG                   Cpu;
+    ULONG                   Index;
 
     KeAcquireSpinLock(&Context->Lock, &Irql);
 
@@ -1284,18 +1362,30 @@ EvtchnRelease(
 
     EvtchnInterruptDisable(Context);
 
-    for (Cpu = 0; Cpu < MAXIMUM_PROCESSORS; Cpu++) {
-        if (Context->LatchedInterrupt[Cpu] == NULL)
+    for (Index = 0; Index < Context->ProcessorCount; Index++) {
+        PXENBUS_EVTCHN_PROCESSOR Processor;
+
+        ASSERT(Context->Processor != NULL);
+        Processor = &Context->Processor[Index];
+
+        if (Processor->Interrupt == NULL)
             continue;
 
-        EvtchnFlush(Context, Cpu);
+        EvtchnFlush(Context, Index);
+
+        RtlZeroMemory(&Processor->Dpc, sizeof (KDPC));
+        RtlZeroMemory(&Processor->PendingList, sizeof (LIST_ENTRY));
 
-        FdoFreeInterrupt(Fdo, Context->LatchedInterrupt[Cpu]);
-        Context->LatchedInterrupt[Cpu] = NULL;
+        FdoFreeInterrupt(Fdo, Processor->Interrupt);
+        Processor->Interrupt = NULL;
     }
 
-    FdoFreeInterrupt(Fdo, Context->LevelSensitiveInterrupt);
-    Context->LevelSensitiveInterrupt = NULL;
+    ASSERT(IsZeroMemory(Context->Processor, sizeof (XENBUS_EVTCHN_PROCESSOR) * 
Context->ProcessorCount));
+    __EvtchnFree(Context->Processor);
+    Context->ProcessorCount = 0;
+
+    FdoFreeInterrupt(Fdo, Context->Interrupt);
+    Context->Interrupt = NULL;
 
     if (!IsListEmpty(&Context->List))
         BUG("OUTSTANDING EVENT CHANNELS");
@@ -1346,7 +1436,7 @@ static struct _XENBUS_EVTCHN_INTERFACE_V2 
EvtchnInterfaceVersion2 = {
     EvtchnAcquire,
     EvtchnRelease,
     EvtchnOpen,
-    EvtchnBind,
+    EvtchnBindVersion2,
     EvtchnUnmaskVersion1,
     EvtchnSend,
     EvtchnTrigger,
@@ -1359,6 +1449,19 @@ static struct _XENBUS_EVTCHN_INTERFACE_V3 
EvtchnInterfaceVersion3 = {
     EvtchnAcquire,
     EvtchnRelease,
     EvtchnOpen,
+    EvtchnBindVersion2,
+    EvtchnUnmask,
+    EvtchnSend,
+    EvtchnTrigger,
+    EvtchnGetPort,
+    EvtchnClose
+};
+
+static struct _XENBUS_EVTCHN_INTERFACE_V4 EvtchnInterfaceVersion4 = {
+    { sizeof (struct _XENBUS_EVTCHN_INTERFACE_V4), 4, NULL, NULL, NULL },
+    EvtchnAcquire,
+    EvtchnRelease,
+    EvtchnOpen,
     EvtchnBind,
     EvtchnUnmask,
     EvtchnSend,
@@ -1375,7 +1478,6 @@ EvtchnInitialize(
 {
     HANDLE                      ParametersKey;
     ULONG                       UseEvtchnFifoAbi;
-    ULONG                       Cpu;
     NTSTATUS                    status;
 
     Trace("====>\n");
@@ -1433,15 +1535,6 @@ EvtchnInitialize(
     InitializeListHead(&(*Context)->List);
     KeInitializeSpinLock(&(*Context)->Lock);
 
-    for (Cpu = 0; Cpu < MAXIMUM_PROCESSORS; Cpu++) {
-        PKDPC   Dpc = &(*Context)->Dpc[Cpu];
-
-        InitializeListHead(&(*Context)->PendingList[Cpu]);
-
-        KeInitializeDpc(Dpc, EvtchnDpc, *Context);
-        KeSetTargetProcessorDpc(Dpc, (CCHAR)Cpu);
-    }
-
     (*Context)->Fdo = Fdo;
 
     Trace("<====\n");
@@ -1536,6 +1629,23 @@ EvtchnGetInterface(
         status = STATUS_SUCCESS;
         break;
     }
+    case 4: {
+        struct _XENBUS_EVTCHN_INTERFACE_V4  *EvtchnInterface;
+
+        EvtchnInterface = (struct _XENBUS_EVTCHN_INTERFACE_V4 *)Interface;
+
+        status = STATUS_BUFFER_OVERFLOW;
+        if (Size < sizeof (struct _XENBUS_EVTCHN_INTERFACE_V4))
+            break;
+
+        *EvtchnInterface = EvtchnInterfaceVersion4;
+
+        ASSERT3U(Interface->Version, ==, Version);
+        Interface->Context = Context;
+
+        status = STATUS_SUCCESS;
+        break;
+    }
     default:
         status = STATUS_NOT_SUPPORTED;
         break;
@@ -1556,10 +1666,8 @@ EvtchnTeardown(
 
     Context->Fdo = NULL;
 
-    RtlZeroMemory(&Context->Dpc, sizeof (KDPC) * MAXIMUM_PROCESSORS);
     RtlZeroMemory(&Context->Lock, sizeof (KSPIN_LOCK));
     RtlZeroMemory(&Context->List, sizeof (LIST_ENTRY));
-    RtlZeroMemory(&Context->PendingList, sizeof (LIST_ENTRY) * 
MAXIMUM_PROCESSORS);
 
     RtlZeroMemory(&Context->SharedInfoInterface,
                   sizeof (XENBUS_SHARED_INFO_INTERFACE));
diff --git a/src/xenbus/evtchn_2l.c b/src/xenbus/evtchn_2l.c
index fde520f..249543d 100644
--- a/src/xenbus/evtchn_2l.c
+++ b/src/xenbus/evtchn_2l.c
@@ -66,9 +66,20 @@ __EvtchnTwoLevelFree(
 }
 
 static BOOLEAN
+EvtchnTwoLevelIsProcessorEnabled(
+    IN  PXENBUS_EVTCHN_ABI_CONTEXT      _Context,
+    IN  ULONG                           Index
+    )
+{
+    UNREFERENCED_PARAMETER(_Context);
+
+    return (SystemVirtualCpuIndex(Index) == 0) ? TRUE : FALSE;
+}
+
+static BOOLEAN
 EvtchnTwoLevelPoll(
     IN  PXENBUS_EVTCHN_ABI_CONTEXT      _Context,
-    IN  ULONG                           Cpu,
+    IN  ULONG                           Index,
     IN  XENBUS_EVTCHN_ABI_EVENT         Event,
     IN  PVOID                           Argument
     )
@@ -77,7 +88,7 @@ EvtchnTwoLevelPoll(
 
     return XENBUS_SHARED_INFO(EvtchnPoll,
                               &Context->SharedInfoInterface,
-                              Cpu,
+                              Index,
                               Event,
                               Argument);
 }
@@ -148,8 +159,7 @@ EvtchnTwoLevelPortUnmask(
 
 static NTSTATUS
 EvtchnTwoLevelAcquire(
-    IN  PXENBUS_EVTCHN_ABI_CONTEXT      _Context,
-    OUT PKAFFINITY                      Affinity
+    IN  PXENBUS_EVTCHN_ABI_CONTEXT      _Context
     )
 {
     PXENBUS_EVTCHN_TWO_LEVEL_CONTEXT    Context = (PVOID)_Context;
@@ -167,8 +177,6 @@ EvtchnTwoLevelAcquire(
     if (!NT_SUCCESS(status))
         goto fail1;
 
-    *Affinity = (KAFFINITY)1;
-
     Trace("<====\n");
 
 done:
@@ -215,6 +223,7 @@ static XENBUS_EVTCHN_ABI EvtchnAbiTwoLevel = {
     NULL,
     EvtchnTwoLevelAcquire,
     EvtchnTwoLevelRelease,
+    EvtchnTwoLevelIsProcessorEnabled,
     EvtchnTwoLevelPoll,
     EvtchnTwoLevelPortEnable,
     EvtchnTwoLevelPortDisable,
diff --git a/src/xenbus/evtchn_abi.h b/src/xenbus/evtchn_abi.h
index 2e1bf43..404f85a 100644
--- a/src/xenbus/evtchn_abi.h
+++ b/src/xenbus/evtchn_abi.h
@@ -39,8 +39,7 @@ typedef PVOID *PXENBUS_EVTCHN_ABI_CONTEXT;
 
 typedef NTSTATUS
 (*XENBUS_EVTCHN_ABI_ACQUIRE)(
-    IN  PXENBUS_EVTCHN_ABI_CONTEXT  Context,
-    OUT PKAFFINITY                  Affinity
+    IN  PXENBUS_EVTCHN_ABI_CONTEXT  Context
     );
 
 typedef VOID
@@ -49,6 +48,12 @@ typedef VOID
     );
 
 typedef BOOLEAN
+(*XENBUS_EVTCHN_ABI_IS_PROCESSOR_ENABLED)(
+    IN  PXENBUS_EVTCHN_ABI_CONTEXT  Context,
+    IN  ULONG                       Index
+    );
+
+typedef BOOLEAN
 (*XENBUS_EVTCHN_ABI_EVENT)(
     IN  PVOID   Argument,
     IN  ULONG   Port
@@ -57,7 +62,7 @@ typedef BOOLEAN
 typedef BOOLEAN
 (*XENBUS_EVTCHN_ABI_POLL)(
     IN  PXENBUS_EVTCHN_ABI_CONTEXT  Context,
-    IN  ULONG                       Cpu,
+    IN  ULONG                       Index,
     IN  XENBUS_EVTCHN_ABI_EVENT     Event,
     IN  PVOID                       Argument
     );
@@ -93,15 +98,16 @@ typedef BOOLEAN
     );
 
 typedef struct _XENBUS_EVTCHN_ABI {
-    PXENBUS_EVTCHN_ABI_CONTEXT      Context;
-    XENBUS_EVTCHN_ABI_ACQUIRE       EvtchnAbiAcquire;
-    XENBUS_EVTCHN_ABI_RELEASE       EvtchnAbiRelease;
-    XENBUS_EVTCHN_ABI_POLL          EvtchnAbiPoll;
-    XENBUS_EVTCHN_ABI_PORT_ENABLE   EvtchnAbiPortEnable;
-    XENBUS_EVTCHN_ABI_PORT_DISABLE  EvtchnAbiPortDisable;
-    XENBUS_EVTCHN_ABI_PORT_ACK      EvtchnAbiPortAck;
-    XENBUS_EVTCHN_ABI_PORT_MASK     EvtchnAbiPortMask;
-    XENBUS_EVTCHN_ABI_PORT_UNMASK   EvtchnAbiPortUnmask;
+    PXENBUS_EVTCHN_ABI_CONTEXT              Context;
+    XENBUS_EVTCHN_ABI_ACQUIRE               EvtchnAbiAcquire;
+    XENBUS_EVTCHN_ABI_RELEASE               EvtchnAbiRelease;
+    XENBUS_EVTCHN_ABI_IS_PROCESSOR_ENABLED  EvtchnAbiIsProcessorEnabled;
+    XENBUS_EVTCHN_ABI_POLL                  EvtchnAbiPoll;
+    XENBUS_EVTCHN_ABI_PORT_ENABLE           EvtchnAbiPortEnable;
+    XENBUS_EVTCHN_ABI_PORT_DISABLE          EvtchnAbiPortDisable;
+    XENBUS_EVTCHN_ABI_PORT_ACK              EvtchnAbiPortAck;
+    XENBUS_EVTCHN_ABI_PORT_MASK             EvtchnAbiPortMask;
+    XENBUS_EVTCHN_ABI_PORT_UNMASK           EvtchnAbiPortUnmask;
 } XENBUS_EVTCHN_ABI, *PXENBUS_EVTCHN_ABI;
 
 #define XENBUS_EVTCHN_ABI(_Method, _Abi, ...)   \
diff --git a/src/xenbus/evtchn_fifo.c b/src/xenbus/evtchn_fifo.c
index 4268809..5996b82 100644
--- a/src/xenbus/evtchn_fifo.c
+++ b/src/xenbus/evtchn_fifo.c
@@ -30,6 +30,7 @@
  */
 
 #include <ntddk.h>
+#include <procgrp.h>
 #include <stdarg.h>
 #include <xen.h>
 
@@ -40,16 +41,14 @@
 #include "assert.h"
 #include "util.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                            ControlBlockMdl[HVM_MAX_VCPUS];
     PMDL                            *EventPageMdl;
     ULONG                           EventPageCount;
-    ULONG                           
Head[MAX_HVM_VCPUS][EVTCHN_FIFO_MAX_QUEUES];
+    ULONG                           
Head[HVM_MAX_VCPUS][EVTCHN_FIFO_MAX_QUEUES];
 } XENBUS_EVTCHN_FIFO_CONTEXT, *PXENBUS_EVTCHN_FIFO_CONTEXT;
 
 #define EVENT_WORDS_PER_PAGE    (PAGE_SIZE / sizeof (event_word_t))
@@ -280,6 +279,18 @@ EvtchnFifoContract(
 }
 
 static BOOLEAN
+EvtchnFifoIsProcessorEnabled(
+    IN  PXENBUS_EVTCHN_ABI_CONTEXT  _Context,
+    IN  ULONG                       Index
+    )
+{
+    PXENBUS_EVTCHN_FIFO_CONTEXT     Context = (PVOID)_Context;
+    unsigned int                    vcpu_id = SystemVirtualCpuIndex(Index);
+
+    return (Context->ControlBlockMdl[vcpu_id] != NULL) ? TRUE : FALSE;
+}
+
+static BOOLEAN
 EvtchnFifoPollPriority(
     IN  PXENBUS_EVTCHN_FIFO_CONTEXT Context,
     IN  unsigned int                vcpu_id,
@@ -331,13 +342,13 @@ EvtchnFifoPollPriority(
 static BOOLEAN
 EvtchnFifoPoll(
     IN  PXENBUS_EVTCHN_ABI_CONTEXT  _Context,
-    IN  ULONG                       Cpu,
+    IN  ULONG                       Index,
     IN  XENBUS_EVTCHN_ABI_EVENT     Event,
     IN  PVOID                       Argument
     )
 {
     PXENBUS_EVTCHN_FIFO_CONTEXT     Context = (PVOID)_Context;
-    unsigned int                    vcpu_id = SystemVirtualCpuIndex(Cpu);
+    unsigned int                    vcpu_id = SystemVirtualCpuIndex(Index);
     PMDL                            Mdl;
     evtchn_fifo_control_block_t     *ControlBlock;
     ULONG                           Ready;
@@ -346,11 +357,14 @@ EvtchnFifoPoll(
 
     Mdl = Context->ControlBlockMdl[vcpu_id];
 
+    DoneSomething = FALSE;
+    if (Mdl == NULL)
+        goto done;
+
     ControlBlock = MmGetSystemAddressForMdlSafe(Mdl, NormalPagePriority);
     ASSERT(ControlBlock != NULL);
 
     Ready = InterlockedExchange((LONG *)&ControlBlock->ready, 0);
-    DoneSomething = FALSE;
 
     while (_BitScanReverse(&Priority, Ready)) {
         DoneSomething |= EvtchnFifoPollPriority(Context,
@@ -362,6 +376,7 @@ EvtchnFifoPoll(
         Ready |= InterlockedExchange((LONG *)&ControlBlock->ready, 0);
     }
 
+done:
     return DoneSomething;
 }
 
@@ -502,13 +517,12 @@ EvtchnFifoReset(
 
 static NTSTATUS
 EvtchnFifoAcquire(
-    IN  PXENBUS_EVTCHN_ABI_CONTEXT  _Context,
-    OUT PKAFFINITY                  Affinity
+    IN  PXENBUS_EVTCHN_ABI_CONTEXT  _Context
     )
 {
     PXENBUS_EVTCHN_FIFO_CONTEXT     Context = (PVOID)_Context;
     KIRQL                           Irql;
-    LONG                            Cpu;
+    LONG                            Index;
     PMDL                            Mdl;
     NTSTATUS                        status;
 
@@ -519,10 +533,8 @@ EvtchnFifoAcquire(
 
     Trace("====>\n");
 
-    *Affinity = 0;
-    Cpu = 0;
-
-    while (Cpu < (LONG)KeQueryActiveProcessorCount(NULL)) {
+    Index = 0;
+    while (Index < (LONG)KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS)) {
         unsigned int        vcpu_id;
         PFN_NUMBER          Pfn;
         PHYSICAL_ADDRESS    Address;
@@ -533,7 +545,7 @@ EvtchnFifoAcquire(
         if (Mdl == NULL)
             goto fail1;
 
-        vcpu_id = SystemVirtualCpuIndex(Cpu);
+        vcpu_id = SystemVirtualCpuIndex(Index);
         Pfn = MmGetMdlPfnArray(Mdl)[0];
 
         status = EventChannelInitControl(Pfn, vcpu_id);
@@ -550,8 +562,7 @@ EvtchnFifoAcquire(
 
         Context->ControlBlockMdl[vcpu_id] = Mdl;
 
-        *Affinity |= (KAFFINITY)1 << Cpu;
-        Cpu++;
+        Index++;
     }
 
     Trace("<====\n");
@@ -569,10 +580,10 @@ fail1:
 
     (VOID) EventChannelReset();
 
-    while (--Cpu >= 0) {
+    while (--Index >= 0) {
         unsigned int    vcpu_id;
 
-        vcpu_id = SystemVirtualCpuIndex(Cpu);
+        vcpu_id = SystemVirtualCpuIndex(Index);
 
         Mdl = Context->ControlBlockMdl[vcpu_id];
         Context->ControlBlockMdl[vcpu_id] = NULL;
@@ -607,7 +618,7 @@ EvtchnFifoRelease(
 
     EvtchnFifoContract(Context);
 
-    vcpu_id = MAX_HVM_VCPUS;
+    vcpu_id = HVM_MAX_VCPUS;
     while (--vcpu_id >= 0) {
         PMDL            Mdl;
 
@@ -630,6 +641,7 @@ static XENBUS_EVTCHN_ABI EvtchnAbiFifo = {
     NULL,
     EvtchnFifoAcquire,
     EvtchnFifoRelease,
+    EvtchnFifoIsProcessorEnabled,
     EvtchnFifoPoll,
     EvtchnFifoPortEnable,
     EvtchnFifoPortDisable,
diff --git a/src/xenbus/fdo.c b/src/xenbus/fdo.c
index b30c4bc..8d8b125 100644
--- a/src/xenbus/fdo.c
+++ b/src/xenbus/fdo.c
@@ -32,6 +32,7 @@
 #define INITGUID 1
 
 #include <ntddk.h>
+#include <procgrp.h>
 #include <wdmguid.h>
 #include <ntstrsafe.h>
 #include <stdlib.h>
@@ -70,7 +71,7 @@ struct _XENBUS_INTERRUPT {
     LIST_ENTRY          ListEntry;
     KINTERRUPT_MODE     InterruptMode;
     PKINTERRUPT         InterruptObject;
-    ULONG               Cpu;
+    PROCESSOR_NUMBER    ProcNumber;
     UCHAR               Vector;
     ULONG               Line;
     PKSERVICE_ROUTINE   Callback;
@@ -1205,12 +1206,15 @@ FdoSuspend(
     )
 {
     PXENBUS_FDO         Fdo = Context;
+    GROUP_AFFINITY      Affinity;
     PKEVENT             Event;
 
     Info("====>\n");
 
     // We really want to know what CPU this thread will run on
-    KeSetSystemAffinityThread((KAFFINITY)1);
+    Affinity.Group = 0;
+    Affinity.Mask = (KAFFINITY)1;
+    KeSetSystemGroupAffinityThread(&Affinity, NULL);
 
     Event = ThreadGetEvent(Self);
 
@@ -1521,7 +1525,7 @@ FdoDumpIoResourceDescriptor(
     else if (Descriptor->Option == (IO_RESOURCE_ALTERNATIVE | 
IO_RESOURCE_PREFERRED))
         Trace("Preferred Alternative\n");
 
-    Trace("ShareDisposition=%s Flags=%04x\n",
+    Trace("ShareDisposition = %s Flags = %04x\n",
           ResourceDescriptorShareDispositionName(Descriptor->ShareDisposition),
           Descriptor->Flags);
 
@@ -1537,11 +1541,12 @@ FdoDumpIoResourceDescriptor(
         break;
 
     case CmResourceTypeInterrupt:
-        Trace("MinimumVector=%08x MaximumVector=%08x AffinityPolicy=%s 
PriorityPolicy=%s TargettedProcessors = %p\n",
+        Trace("MinimumVector = %08x MaximumVector = %08x AffinityPolicy = %s 
PriorityPolicy = %s Group = %u TargettedProcessors = %p\n",
               Descriptor->u.Interrupt.MinimumVector,
               Descriptor->u.Interrupt.MaximumVector,
               IrqDevicePolicyName(Descriptor->u.Interrupt.AffinityPolicy),
               IrqPriorityName(Descriptor->u.Interrupt.PriorityPolicy),
+              Descriptor->u.Interrupt.Group,
               (PVOID)Descriptor->u.Interrupt.TargetedProcessors);
         break;
 
@@ -1594,7 +1599,7 @@ FdoFilterResourceRequirements(
     Old = (PIO_RESOURCE_REQUIREMENTS_LIST)Irp->IoStatus.Information;
     ASSERT3U(Old->AlternativeLists, ==, 1);
 
-    Count = KeQueryActiveProcessorCount(NULL);
+    Count = KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
 
     Size = Old->ListSize +
         (sizeof (IO_RESOURCE_DESCRIPTOR) * Count);
@@ -1618,6 +1623,7 @@ FdoFilterResourceRequirements(
 
         Descriptor->Flags |= CM_RESOURCE_INTERRUPT_POLICY_INCLUDED;
         Descriptor->u.Interrupt.AffinityPolicy = IrqPolicySpecifiedProcessors;
+        Descriptor->u.Interrupt.Group = 0;
         Descriptor->u.Interrupt.TargetedProcessors = (KAFFINITY)1;
     }
 
@@ -1635,7 +1641,13 @@ FdoFilterResourceRequirements(
     Interrupt.u.Interrupt.PriorityPolicy = IrqPriorityUndefined;
 
     for (Index = 0; Index < Count; Index++) {
-        Interrupt.u.Interrupt.TargetedProcessors = (KAFFINITY)1 << Index;
+        PROCESSOR_NUMBER    ProcNumber;
+
+        status = KeGetProcessorNumberFromIndex(Index, &ProcNumber);
+        ASSERT(NT_SUCCESS(status));
+
+        Interrupt.u.Interrupt.Group = ProcNumber.Group;
+        Interrupt.u.Interrupt.TargetedProcessors = (KAFFINITY)1 << 
ProcNumber.Number;
         List->Descriptors[List->Count++] = Interrupt;
     }
 
@@ -1825,7 +1837,7 @@ FdoConnectInterrupt(
 {
     IO_CONNECT_INTERRUPT_PARAMETERS     Connect;
     BOOLEAN                             Found;
-    ULONG                               Cpu;
+    ULONG                               Number;
     NTSTATUS                            status;
 
     Trace("====>\n");
@@ -1845,7 +1857,7 @@ FdoConnectInterrupt(
         (*Interrupt)->Line = Raw->u.Interrupt.Vector;
 
     RtlZeroMemory(&Connect, sizeof (IO_CONNECT_INTERRUPT_PARAMETERS));
-    Connect.Version = CONNECT_FULLY_SPECIFIED;
+    Connect.Version = CONNECT_FULLY_SPECIFIED_GROUP;
     Connect.FullySpecified.PhysicalDeviceObject = 
__FdoGetPhysicalDeviceObject(Fdo);
     Connect.FullySpecified.ShareVector = 
(BOOLEAN)(Translated->ShareDisposition == CmResourceShareShared);
     Connect.FullySpecified.InterruptMode = (*Interrupt)->InterruptMode;
@@ -1857,11 +1869,13 @@ FdoConnectInterrupt(
         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.Group = 
Translated->u.MessageInterrupt.Translated.Group;
         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.Group = Translated->u.Interrupt.Group;
         Connect.FullySpecified.ProcessorEnableMask = 
Translated->u.Interrupt.Affinity;
     }
 
@@ -1871,22 +1885,25 @@ FdoConnectInterrupt(
 
     (*Interrupt)->Vector = (UCHAR)Connect.FullySpecified.Vector;
 
+    (*Interrupt)->ProcNumber.Group = Connect.FullySpecified.Group;
+
 #if defined(__i386__)
-    Found = _BitScanReverse(&Cpu, Connect.FullySpecified.ProcessorEnableMask);
+    Found = _BitScanReverse(&Number, 
Connect.FullySpecified.ProcessorEnableMask);
 #elif defined(__x86_64__)
-    Found = _BitScanReverse64(&Cpu, 
Connect.FullySpecified.ProcessorEnableMask);
+    Found = _BitScanReverse64(&Number, 
Connect.FullySpecified.ProcessorEnableMask);
 #else
 #error 'Unrecognised architecture'
 #endif
     ASSERT(Found);
 
-    (*Interrupt)->Cpu = Cpu;
+    (*Interrupt)->ProcNumber.Number = (UCHAR)Number;
 
-    Info("%p: %s %s CPU %u VECTOR %02x\n",
+    Info("%p: %s %s CPU %u:%u VECTOR %02x\n",
          (*Interrupt)->InterruptObject,
          ResourceDescriptorShareDispositionName(Translated->ShareDisposition),
          InterruptModeName((*Interrupt)->InterruptMode),
-         (*Interrupt)->Cpu,
+         (*Interrupt)->ProcNumber.Group,
+         (*Interrupt)->ProcNumber.Number,
          (*Interrupt)->Vector);
 
     Trace("<====\n");
@@ -1917,12 +1934,13 @@ FdoDisconnectInterrupt(
 
     Trace("====>\n");
 
-    Info("%p: CPU %u VECTOR %02x\n",
+    Info("%p: CPU %u:%u VECTOR %02x\n",
          Interrupt->InterruptObject,
-         Interrupt->Cpu,
+         Interrupt->ProcNumber.Group,
+         Interrupt->ProcNumber.Number,
          Interrupt->Vector);
 
-    Interrupt->Cpu = 0;
+    RtlZeroMemory(&Interrupt->ProcNumber, sizeof (PROCESSOR_NUMBER));
     Interrupt->Vector = 0;
 
     RtlZeroMemory(&Disconnect, sizeof (IO_DISCONNECT_INTERRUPT_PARAMETERS));
@@ -1994,7 +2012,8 @@ PXENBUS_INTERRUPT
 FdoAllocateInterrupt(
     IN  PXENBUS_FDO         Fdo,
     IN  KINTERRUPT_MODE     InterruptMode,
-    IN  ULONG               Cpu,
+    IN  USHORT              Group,
+    IN  UCHAR               Number,
     IN  KSERVICE_ROUTINE    Callback,
     IN  PVOID               Argument OPTIONAL
     )
@@ -2010,7 +2029,8 @@ FdoAllocateInterrupt(
 
         if (Interrupt->Callback == NULL &&
             Interrupt->InterruptMode == InterruptMode &&
-            Interrupt->Cpu == Cpu)
+            Interrupt->ProcNumber.Group == Group &&
+            Interrupt->ProcNumber.Number == Number)
             goto found;
     }
 
diff --git a/src/xenbus/fdo.h b/src/xenbus/fdo.h
index a07b55f..4b99ba0 100644
--- a/src/xenbus/fdo.h
+++ b/src/xenbus/fdo.h
@@ -169,7 +169,8 @@ extern PXENBUS_INTERRUPT
 FdoAllocateInterrupt(
     IN  PXENBUS_FDO         Fdo,
     IN  KINTERRUPT_MODE     InterruptMode,
-    IN  ULONG               Cpu,
+    IN  USHORT              Group,
+    IN  UCHAR               Number,
     IN  KSERVICE_ROUTINE    Callback,
     IN  PVOID               Argument OPTIONAL
     );
diff --git a/src/xenbus/pdo.c b/src/xenbus/pdo.c
index 58eeadd..7eb967c 100644
--- a/src/xenbus/pdo.c
+++ b/src/xenbus/pdo.c
@@ -821,100 +821,14 @@ PdoS3ToS4(
     Trace("(%s) <====\n", __PdoGetName(Pdo));
 }
 
-static VOID
-PdoParseResources(
-    IN  PXENBUS_PDO             Pdo,
-    IN  PCM_RESOURCE_LIST       RawResourceList,
-    IN  PCM_RESOURCE_LIST       TranslatedResourceList
-    )
-{
-    PCM_PARTIAL_RESOURCE_LIST   RawPartialList;
-    PCM_PARTIAL_RESOURCE_LIST   TranslatedPartialList;
-    ULONG                       Index;
-
-    UNREFERENCED_PARAMETER(Pdo);
-
-    ASSERT3U(RawResourceList->Count, ==, 1);
-    RawPartialList = &RawResourceList->List[0].PartialResourceList;
-
-    ASSERT3U(RawPartialList->Version, ==, 1);
-    ASSERT3U(RawPartialList->Revision, ==, 1);
-
-    ASSERT3U(TranslatedResourceList->Count, ==, 1);
-    TranslatedPartialList = 
&TranslatedResourceList->List[0].PartialResourceList;
-
-    ASSERT3U(TranslatedPartialList->Version, ==, 1);
-    ASSERT3U(TranslatedPartialList->Revision, ==, 1);
-
-    for (Index = 0; Index < TranslatedPartialList->Count; Index++) {
-        PCM_PARTIAL_RESOURCE_DESCRIPTOR RawPartialDescriptor;
-        PCM_PARTIAL_RESOURCE_DESCRIPTOR TranslatedPartialDescriptor;
-
-        RawPartialDescriptor = &RawPartialList->PartialDescriptors[Index];
-        TranslatedPartialDescriptor = 
&TranslatedPartialList->PartialDescriptors[Index];
-
-        Trace("%s: [%d] %02x:%s\n",
-              __PdoGetName(Pdo),
-              Index,
-              TranslatedPartialDescriptor->Type,
-              ResourceDescriptorTypeName(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);
-            break;
-
-        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);
-
-            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);
-            break;
-
-        default:
-            break;
-        }
-    }
-
-    Trace("<====\n");
-}
-
 static NTSTATUS
 PdoStartDevice(
     IN  PXENBUS_PDO     Pdo,
     IN  PIRP            Irp
     )
 {
-    PIO_STACK_LOCATION  StackLocation;
     NTSTATUS            status;
 
-    StackLocation = IoGetCurrentIrpStackLocation(Irp);
-
-    PdoParseResources(Pdo,
-                      StackLocation->Parameters.StartDevice.AllocatedResources,
-                      
StackLocation->Parameters.StartDevice.AllocatedResourcesTranslated);
-
     PdoD3ToD0(Pdo);
 
     __PdoSetDevicePnpState(Pdo, Started);
@@ -1375,6 +1289,7 @@ PdoQueryResourceRequirements(
     Interrupt.u.Interrupt.MaximumVector = (ULONG)-1;
     Interrupt.u.Interrupt.AffinityPolicy = IrqPolicyOneCloseProcessor;
     Interrupt.u.Interrupt.PriorityPolicy = IrqPriorityUndefined;
+    Interrupt.u.Interrupt.Group = ALL_PROCESSOR_GROUPS;
 
     Size = sizeof (IO_RESOURCE_DESCRIPTOR) * 2;
     Size += FIELD_OFFSET(IO_RESOURCE_LIST, Descriptors);
diff --git a/src/xenbus/shared_info.c b/src/xenbus/shared_info.c
index 09d035a..1b71ba1 100644
--- a/src/xenbus/shared_info.c
+++ b/src/xenbus/shared_info.c
@@ -30,6 +30,7 @@
  */
 
 #include <ntddk.h>
+#include <procgrp.h>
 #include <xen.h>
 
 #include "shared_info.h"
@@ -155,12 +156,12 @@ SharedInfoEvtchnMaskAll(
 static BOOLEAN
 SharedInfoUpcallPending(
     IN  PINTERFACE              Interface,
-    IN  ULONG                   Cpu
+    IN  ULONG                   Index
     )
 {
     PXENBUS_SHARED_INFO_CONTEXT Context = Interface->Context;
     shared_info_t               *Shared = Context->Shared;
-    int                         vcpu_id = SystemVirtualCpuIndex(Cpu);
+    int                         vcpu_id = SystemVirtualCpuIndex(Index);
     UCHAR                       Pending;
 
     KeMemoryBarrier();
@@ -173,14 +174,14 @@ SharedInfoUpcallPending(
 static BOOLEAN
 SharedInfoEvtchnPoll(
     IN  PINTERFACE                  Interface,
-    IN  ULONG                       Cpu,
+    IN  ULONG                       Index,
     IN  XENBUS_SHARED_INFO_EVENT    Event,
     IN  PVOID                       Argument OPTIONAL
     )
 {
     PXENBUS_SHARED_INFO_CONTEXT     Context = Interface->Context;
     shared_info_t                   *Shared = Context->Shared;
-    int                             vcpu_id = SystemVirtualCpuIndex(Cpu);
+    int                             vcpu_id = SystemVirtualCpuIndex(Index);
     ULONG                           Port;
     ULONG_PTR                       SelectorMask;
     BOOLEAN                         DoneSomething;
@@ -457,28 +458,36 @@ SharedInfoDebugCallback(
 
     if (!Crashing) {
         shared_info_t   *Shared;
-        ULONG           Cpu;
+        ULONG           Index;
         ULONG           Selector;
 
         Shared = Context->Shared;
 
         KeMemoryBarrier();
 
-        for (Cpu = 0; Cpu < KeQueryActiveProcessorCount(NULL); Cpu++) {
-            int vcpu_id = SystemVirtualCpuIndex(Cpu);
+        for (Index = 0;
+             Index < KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
+             Index++) {
+            PROCESSOR_NUMBER    ProcNumber;
+            int                 vcpu_id;
+
+            (VOID) KeGetProcessorNumberFromIndex(Index, &ProcNumber);
+            vcpu_id = SystemVirtualCpuIndex(Index);
 
             XENBUS_DEBUG(Printf,
                          &Context->DebugInterface,
-                         "CPU %u: PENDING: %s\n",
-                         Cpu,
+                         "CPU %u:%u: PENDING: %s\n",
+                         ProcNumber.Group,
+                         ProcNumber.Number,
                          Shared->vcpu_info[vcpu_id].evtchn_upcall_pending ?
                          "TRUE" :
                          "FALSE");
 
             XENBUS_DEBUG(Printf,
                          &Context->DebugInterface,
-                         "CPU %u: SELECTOR MASK: %p\n",
-                         Cpu,
+                         "CPU %u:u: SELECTOR MASK: %p\n",
+                         ProcNumber.Group,
+                         ProcNumber.Number,
                          (PVOID)Shared->vcpu_info[vcpu_id].evtchn_pending_sel);
         }
 
diff --git a/src/xenbus/sync.c b/src/xenbus/sync.c
index d4af525..835b46b 100644
--- a/src/xenbus/sync.c
+++ b/src/xenbus/sync.c
@@ -30,6 +30,7 @@
  */
 
 #include <ntddk.h>
+#include <procgrp.h>
 #include <stdarg.h>
 #include <xen.h>
 
@@ -39,80 +40,83 @@
 #include "util.h"
 
 // Routines to capture all CPUs in a spinning state with interrupts
-// disabled (so that we remain in a known code context) and optionally
-// execute a function on each CPU.
+// disabled (so that we remain in a known code context).
 // These routines are used for suspend/resume and live snapshot.
 
 // The general sequence of steps is follows:
 //
-// - SyncCaptureAndCall() is called on an arbitrary CPU
+// - SyncCapture() is called on an arbitrary CPU. It must be called at
+//   DISPATCH_LEVEL so it cannot be pre-empted and moved to another CPU.
+//   It schedules a DPC on each of the other CPUs and spins until all
+//   CPUs are executing the DPC, which will in-turn spin awaiting
+//   further instruction.
 //
-// - It raises to DISPATCH_LEVEL to avoid pre-emption and schedules
-//   a DPC on each of the other CPUs.
+// - SyncDisableInterrputs() instructs the DPC routines to all raise
+//   to HIGH_LEVEL and disable interrupts for its CPU. It then raises
+//   to HIGH_LEVEL itself, spins waiting for confirmation from each
+//   DPC that it has disabled interrupts and then disables interrupts
+//   itself.
 //
-// - It, and the DPC routines, all raise to HIGH_LEVEL, clear a
-//   a bit corresponding to their CPU in a 'captured' mask, and then
-//   spin waiting for the mask to become zero (i.e. all CPUs captured).
+//   NOTE: There is a back-off in trying to disable interrupts. It is
+//         possible that CPU A is waiting for an IPI to CPU B to
+//         complete, but CPU B is spinning with interrupts disabled.
+//         Thus the DPC on CPU A will never make it to HIGH_LEVEL and
+//         hence never get to disable interrupts. Thus if, while
+//         spinning with interrupts disabled, one DPC notices that
+//         another DPC has not made it, it briefly enables interrupts
+//         and drops back down to DISPATCH_LEVEL before trying again.
+//         This should allow any pending IPI to complete.
 //
-//   NOTE: There is a back-off in this spin. It is possible that CPU A
-//         is waiting for an IPI to CPU B to complete, but CPU B is
-//         spinning at HIGH_LEVEL. Thus CPU A will never make it to
-//         HIGH_LEVEL. Thus if, while spinning at HIGH_LEVEL, we notice
-//         that another CPU has not made it, we set our bit in the
-//         'captured' mask again and briefly drop down to DISPATCH_LEVEL
-//         before trying again. This should allow any pending IPI to
-//         complete.
+// - SyncEnableInterrupts() instructs the DPC routines to all enable
+//   interrupts and drop back to DISPATCH_LEVEL before enabling
+//   interrupts and dropping back to DISPATCH_LEVEL itself.
 //
-// - Once all CPUs are captured, each disables interrupts, executes an
-//   optional function. All the DPC routined clear a bit corresponding
-//   to their CPU in a 'completed' mask and then spin waiting for the
-//   mask to become zero. The requesting CPU also executes the optional
-//   function bit it then waits for the mask to only contain the bit
-//   corresponding to its CPU and then returns from
-//   SyncCaptureAndCall() at HIGH_LEVEL.
-//
-// - A subsequent call to SyncRelease() will clear the last
-//   remaining bit (clearly it is necessarily executed on the same CPU
-//   as SyncCaptureAndCall()) and thus allow all the DPC
-//   routines to lower back to DISPATCH_LEVEL and complete.
-//
-// - SyncRelease() also lowers back to DISPATCH_LEVEL and then
-//   back to the IRQL is was originally entered at.
+// - SyncRelease() instructs the DPC routines to exit, thus allowing
+//   the scheduler to run on the other CPUs again. It spins until all
+//   DPCs have completed and then returns.
+
+#pragma data_seg("sync")
+__declspec(allocate("sync"))
+static UCHAR        __Section[PAGE_SIZE];
+
+typedef struct  _SYNC_PROCESSOR {
+    KDPC                Dpc;
+    BOOLEAN             DisableInterrupts;
+    BOOLEAN             Exit;
+} SYNC_PROCESSOR, *PSYNC_PROCESSOR;
 
 typedef struct  _SYNC_CONTEXT {
-    KDPC                Dpc[MAXIMUM_PROCESSORS];
     ULONG               Sequence;
-    LONG                CpuCount;
+    LONG                ProcessorCount;
     LONG                CompletionCount;
-    BOOLEAN             DisableInterrupts[MAXIMUM_PROCESSORS];
-    BOOLEAN             Exit[MAXIMUM_PROCESSORS];
+    SYNC_PROCESSOR      Processor[1];
 } SYNC_CONTEXT, *PSYNC_CONTEXT;
 
-static LONG SyncOwner = MAXIMUM_PROCESSORS;
+static PSYNC_CONTEXT    SyncContext = (PVOID)__Section;
+static LONG             SyncOwner = -1;
 
 static FORCEINLINE VOID
 __SyncAcquire(
-    IN  LONG    Cpu
+    IN  LONG    Index
     )
 {
     LONG        Old;
 
-    Old = InterlockedExchange(&SyncOwner, Cpu);
-    ASSERT3U(Old, ==, MAXIMUM_PROCESSORS);
+    Old = InterlockedExchange(&SyncOwner, Index);
+    ASSERT3U(Old, ==, -1);
 }
 
 static FORCEINLINE VOID
 __SyncRelease(
-    IN  LONG    Cpu
+    IN  LONG    Index
     )
 {
     LONG        Old;
 
-    Old = InterlockedExchange(&SyncOwner, MAXIMUM_PROCESSORS);
-    ASSERT3U(Old, ==, Cpu);
+    Old = InterlockedExchange(&SyncOwner, -1);
+    ASSERT3U(Old, ==, Index);
 }
 
-static SYNC_CONTEXT  SyncContext;
 
 KDEFERRED_ROUTINE   SyncWorker;
 
@@ -122,53 +126,57 @@ KDEFERRED_ROUTINE   SyncWorker;
 VOID
 #pragma prefast(suppress:28166) // Function does not restore IRQL
 SyncWorker(
-    IN  PKDPC   Dpc,
-    IN  PVOID   Context,
-    IN  PVOID   Argument1,
-    IN  PVOID   Argument2
+    IN  PKDPC           Dpc,
+    IN  PVOID           _Context,
+    IN  PVOID           Argument1,
+    IN  PVOID           Argument2
     )
 {
-    BOOLEAN     InterruptsDisabled;
-    ULONG       Cpu;
+    PSYNC_CONTEXT       Context = SyncContext;
+    BOOLEAN             InterruptsDisabled;
+    ULONG               Index;
+    PSYNC_PROCESSOR     Processor;
+    PROCESSOR_NUMBER    ProcNumber;
 
     UNREFERENCED_PARAMETER(Dpc);
-    UNREFERENCED_PARAMETER(Context);
+    UNREFERENCED_PARAMETER(_Context);
     UNREFERENCED_PARAMETER(Argument1);
     UNREFERENCED_PARAMETER(Argument2);
 
     InterruptsDisabled = FALSE;
-    Cpu = KeGetCurrentProcessorNumber();
+    Index = KeGetCurrentProcessorNumberEx(&ProcNumber);
+    Processor = &Context->Processor[Index];
 
-    Trace("====> (%u)\n", Cpu);
-    InterlockedIncrement(&SyncContext.CompletionCount);
+    Trace("====> (%u:%u)\n", ProcNumber.Group, ProcNumber.Number);
+    InterlockedIncrement(&Context->CompletionCount);
 
     for (;;) {
         ULONG   Sequence;
 
-        if (SyncContext.Exit[Cpu])
+        if (Processor->Exit)
             break;
 
-        if (SyncContext.DisableInterrupts[Cpu] == InterruptsDisabled) {
+        if (Processor->DisableInterrupts == InterruptsDisabled) {
             _mm_pause();
             KeMemoryBarrier();
 
             continue;
         }
 
-        Sequence = SyncContext.Sequence;
+        Sequence = Context->Sequence;
 
-        if (SyncContext.DisableInterrupts[Cpu]) {
+        if (Processor->DisableInterrupts) {
             ULONG       Attempts;
             NTSTATUS    status;
 
             (VOID) KfRaiseIrql(HIGH_LEVEL);
             status = STATUS_SUCCESS;
 
-            InterlockedIncrement(&SyncContext.CompletionCount);
+            InterlockedIncrement(&Context->CompletionCount);
 
             Attempts = 0;
-            while (SyncContext.Sequence == Sequence &&
-                   SyncContext.CompletionCount < SyncContext.CpuCount) {
+            while (Context->Sequence == Sequence &&
+                   Context->CompletionCount < Context->ProcessorCount) {
                 _mm_pause();
                 KeMemoryBarrier();
 
@@ -177,14 +185,14 @@ SyncWorker(
                     LONG    New;
 
                     do {
-                        Old = SyncContext.CompletionCount;
+                        Old = Context->CompletionCount;
                         New = Old - 1;
 
-                        if (Old == SyncContext.CpuCount)
+                        if (Old == Context->ProcessorCount)
                             break;
-                    } while 
(InterlockedCompareExchange(&SyncContext.CompletionCount, New, Old) != Old);
+                    } while 
(InterlockedCompareExchange(&Context->CompletionCount, New, Old) != Old);
 
-                    if (Old < SyncContext.CpuCount) {
+                    if (Old < Context->ProcessorCount) {
 #pragma prefast(suppress:28138) // Use constant rather than variable
                         KeLowerIrql(DISPATCH_LEVEL);
                         status = STATUS_UNSUCCESSFUL;
@@ -207,10 +215,10 @@ SyncWorker(
 #pragma prefast(suppress:28138) // Use constant rather than variable
             KeLowerIrql(DISPATCH_LEVEL);
 
-            InterlockedIncrement(&SyncContext.CompletionCount);
+            InterlockedIncrement(&Context->CompletionCount);
 
-            while (SyncContext.Sequence == Sequence &&
-                   SyncContext.CompletionCount < SyncContext.CpuCount) {
+            while (Context->Sequence == Sequence &&
+                   Context->CompletionCount < Context->ProcessorCount) {
                 _mm_pause();
                 KeMemoryBarrier();
             }
@@ -218,8 +226,8 @@ SyncWorker(
         }
     }
 
-    Trace("<==== (%u)\n", Cpu);
-    InterlockedIncrement(&SyncContext.CompletionCount);
+    Trace("<==== (%u:%u)\n", ProcNumber.Group, ProcNumber.Number);
+    InterlockedIncrement(&Context->CompletionCount);
 
     ASSERT(!InterruptsDisabled);
 }
@@ -231,44 +239,55 @@ SyncCapture(
     VOID
     )
 {
-    ULONG       Cpu;
-    ULONG       Index;
+    PSYNC_CONTEXT       Context = SyncContext;
+    LONG                Index;
+    PROCESSOR_NUMBER    ProcNumber;
+    USHORT              Group;
+    UCHAR               Number;
 
     ASSERT3U(KeGetCurrentIrql(), ==, DISPATCH_LEVEL);
 
-    Cpu = KeGetCurrentProcessorNumber();
-    __SyncAcquire(Cpu);
+    Index = KeGetCurrentProcessorNumberEx(&ProcNumber);
+    __SyncAcquire(Index);
 
-    Trace("====> (%u)\n", Cpu);
+    Group = ProcNumber.Group;
+    Number = ProcNumber.Number;
 
-    ASSERT(IsZeroMemory(&SyncContext, sizeof (SYNC_CONTEXT)));
+    Trace("====> (%u:%u)\n", Group, Number);
 
-    SyncContext.Sequence++;
-    SyncContext.CompletionCount = 0;
-    SyncContext.CpuCount = KeQueryActiveProcessorCount(NULL);
+    ASSERT(IsZeroMemory(Context, sizeof (SYNC_CONTEXT)));
 
-    for (Index = 0; Index < (ULONG)SyncContext.CpuCount; Index++) {
-        PKDPC   Dpc = &SyncContext.Dpc[Index];
+    Context->Sequence++;
+    Context->CompletionCount = 0;
 
-        SyncContext.DisableInterrupts[Index] = FALSE;
-        SyncContext.Exit[Index] = FALSE;
+    Context->ProcessorCount = 
KeQueryActiveProcessorCountEx(ALL_PROCESSOR_GROUPS);
 
-        if (Index == Cpu)
+    for (Index = 0; Index < Context->ProcessorCount; Index++) {
+        PSYNC_PROCESSOR Processor = &Context->Processor[Index];
+        NTSTATUS        status;
+
+        ASSERT3U((ULONG_PTR)(Processor + 1), <, (ULONG_PTR)__Section + 
PAGE_SIZE);
+
+        status = KeGetProcessorNumberFromIndex(Index, &ProcNumber);
+        ASSERT(NT_SUCCESS(status));
+
+        if (ProcNumber.Group == Group &&
+            ProcNumber.Number == Number)
             continue;
 
-        KeInitializeDpc(Dpc, SyncWorker, NULL);
-        KeSetTargetProcessorDpc(Dpc, (CCHAR)Index);
-        KeInsertQueueDpc(Dpc, NULL, NULL);
+        KeInitializeDpc(&Processor->Dpc, SyncWorker, NULL);
+        KeSetTargetProcessorDpcEx(&Processor->Dpc, &ProcNumber);
+        KeInsertQueueDpc(&Processor->Dpc, NULL, NULL);
     }
 
-    InterlockedIncrement(&SyncContext.CompletionCount);
+    InterlockedIncrement(&Context->CompletionCount);
 
-    while (SyncContext.CompletionCount < SyncContext.CpuCount) {
+    while (Context->CompletionCount < Context->ProcessorCount) {
         _mm_pause();
         KeMemoryBarrier();
     }
 
-    Trace("<==== (%u)\n", Cpu);
+    Trace("<==== (%u:%u)\n", Group, Number);
 }
 
 __drv_requiresIRQL(DISPATCH_LEVEL)
@@ -278,26 +297,32 @@ SyncDisableInterrupts(
     VOID
     )
 {
-    ULONG       Index;
-    ULONG       Attempts;
-    NTSTATUS    status;
+    PSYNC_CONTEXT   Context = SyncContext;
+    LONG            Index;
+    ULONG           Attempts;
+    NTSTATUS        status;
 
     Trace("====>\n");
 
-    SyncContext.Sequence++;
-    SyncContext.CompletionCount = 0;
+    Context->Sequence++;
+    Context->CompletionCount = 0;
+
+    for (Index = 0; Index < Context->ProcessorCount; Index++) {
+        PSYNC_PROCESSOR Processor = &Context->Processor[Index];
 
-    for (Index = 0; Index < (ULONG)SyncContext.CpuCount; Index++)
-        SyncContext.DisableInterrupts[Index] = TRUE;
+        Processor->DisableInterrupts = TRUE;
+    }
+
+    KeMemoryBarrier();
 
 again:
     (VOID) KfRaiseIrql(HIGH_LEVEL);
     status = STATUS_SUCCESS;
 
-    InterlockedIncrement(&SyncContext.CompletionCount);
+    InterlockedIncrement(&Context->CompletionCount);
 
     Attempts = 0;
-    while (SyncContext.CompletionCount < SyncContext.CpuCount) {
+    while (Context->CompletionCount < Context->ProcessorCount) {
         _mm_pause();
         KeMemoryBarrier();
 
@@ -306,18 +331,18 @@ again:
             LONG    New;
 
             do {
-                Old = SyncContext.CompletionCount;
+                Old = Context->CompletionCount;
                 New = Old - 1;
 
-                if (Old == SyncContext.CpuCount)
+                if (Old == Context->ProcessorCount)
                     break;
-            } while (InterlockedCompareExchange(&SyncContext.CompletionCount, 
New, Old) != Old);
+            } while (InterlockedCompareExchange(&Context->CompletionCount, 
New, Old) != Old);
 
-            if (Old < SyncContext.CpuCount) {
+            if (Old < Context->ProcessorCount) {
                 LogPrintf(LOG_LEVEL_WARNING,
                           "SYNC: %d < %d\n",
                           Old,
-                          SyncContext.CpuCount);
+                          Context->ProcessorCount);
 
 #pragma prefast(suppress:28138) // Use constant rather than variable
                 KeLowerIrql(DISPATCH_LEVEL);
@@ -339,23 +364,29 @@ VOID
 SyncEnableInterrupts(
     )
 {
-    KIRQL   Irql;
-    ULONG   Index;
+    PSYNC_CONTEXT   Context = SyncContext;
+    KIRQL           Irql;
+    LONG            Index;
 
     _enable();
 
     Irql = KeGetCurrentIrql();
     ASSERT3U(Irql, ==, HIGH_LEVEL);
 
-    SyncContext.Sequence++;
-    SyncContext.CompletionCount = 0;
+    Context->Sequence++;
+    Context->CompletionCount = 0;
+
+    for (Index = 0; Index < Context->ProcessorCount; Index++) {
+        PSYNC_PROCESSOR Processor = &Context->Processor[Index];
+
+        Processor->DisableInterrupts = FALSE;
+    }
 
-    for (Index = 0; Index < (ULONG)SyncContext.CpuCount; Index++)
-        SyncContext.DisableInterrupts[Index] = FALSE;
+    KeMemoryBarrier();
 
-    InterlockedIncrement(&SyncContext.CompletionCount);
+    InterlockedIncrement(&Context->CompletionCount);
 
-    while (SyncContext.CompletionCount < SyncContext.CpuCount) {
+    while (Context->CompletionCount < Context->ProcessorCount) {
         _mm_pause();
         KeMemoryBarrier();
     }
@@ -373,28 +404,33 @@ SyncRelease(
     VOID
     )
 {
-    ULONG       Cpu;
-    ULONG       Index;
+    PSYNC_CONTEXT   Context = SyncContext;
+    LONG            Index;
 
     Trace("====>\n");
 
-    SyncContext.Sequence++;
-    SyncContext.CompletionCount = 0;
+    Context->Sequence++;
+    Context->CompletionCount = 0;
+
+    for (Index = 0; Index < Context->ProcessorCount; Index++) {
+        PSYNC_PROCESSOR Processor = &Context->Processor[Index];
+
+        Processor->Exit = TRUE;
+    }
 
-    for (Index = 0; Index < (ULONG)SyncContext.CpuCount; Index++)
-        SyncContext.Exit[Index] = TRUE;
+    KeMemoryBarrier();
 
-    InterlockedIncrement(&SyncContext.CompletionCount);
+    InterlockedIncrement(&Context->CompletionCount);
 
-    while (SyncContext.CompletionCount < SyncContext.CpuCount) {
+    while (Context->CompletionCount < Context->ProcessorCount) {
         _mm_pause();
         KeMemoryBarrier();
     }
 
-    RtlZeroMemory(&SyncContext, sizeof (SYNC_CONTEXT));
+    RtlZeroMemory(Context, sizeof (SYNC_CONTEXT));
 
-    Cpu = KeGetCurrentProcessorNumber();
-    __SyncRelease(Cpu);
+    Index = KeGetCurrentProcessorNumberEx(NULL);
+    __SyncRelease(Index);
 
     Trace("<====\n");
 }
diff --git a/src/xenfilt/driver.c b/src/xenfilt/driver.c
index 420e827..16ed6f7 100644
--- a/src/xenfilt/driver.c
+++ b/src/xenfilt/driver.c
@@ -30,6 +30,7 @@
  */
 
 #include <ntddk.h>
+#include <procgrp.h>
 #include <xen.h>
 
 #include "registry.h"
@@ -775,6 +776,7 @@ DriverEntry(
     ASSERT3P(__DriverGetDriverObject(), ==, NULL);
 
     ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
+    WdmlibProcgrpInitialize();
 
     __DbgPrintEnable();
 
diff --git a/vs2012/xen/xen.vcxproj b/vs2012/xen/xen.vcxproj
index 0d92eac..df966af 100644
--- a/vs2012/xen/xen.vcxproj
+++ b/vs2012/xen/xen.vcxproj
@@ -34,7 +34,7 @@
       <Inputs>..\..\include\version.hx</Inputs>
     </CustomBuildStep>
     <ClCompile>
-      
<PreprocessorDefinitions>__MODULE__="XEN";POOL_NX_OPTIN=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      
<PreprocessorDefinitions>__MODULE__="XEN";POOL_NX_OPTIN=1;NT_PROCESSOR_GROUPS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <WarningLevel>EnableAllWarnings</WarningLevel>
       
<DisableSpecificWarnings>4711;4548;4820;4668;4255;6001;6054;28196;%(DisableSpecificWarnings)</DisableSpecificWarnings>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
@@ -42,7 +42,7 @@
     </ClCompile>
     <Link>
       <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
-      
<AdditionalDependencies>$(DDK_LIB_PATH)/libcntpr.lib;$(DDK_LIB_PATH)/aux_klib.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      
<AdditionalDependencies>$(DDK_LIB_PATH)/libcntpr.lib;$(DDK_LIB_PATH)/aux_klib.lib;$(DDK_LIB_PATH)/procgrp.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <ModuleDefinitionFile>../../src/xen/xen.def</ModuleDefinitionFile>
       <EnableCOMDATFolding>false</EnableCOMDATFolding>
     </Link>
diff --git a/vs2012/xenbus/xenbus.vcxproj b/vs2012/xenbus/xenbus.vcxproj
index 3319372..ab78a02 100644
--- a/vs2012/xenbus/xenbus.vcxproj
+++ b/vs2012/xenbus/xenbus.vcxproj
@@ -34,7 +34,7 @@
       <Inputs>..\..\src\xenbus.inf</Inputs>
     </CustomBuildStep>
     <ClCompile>
-      
<PreprocessorDefinitions>__MODULE__="XENBUS";POOL_NX_OPTIN=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      
<PreprocessorDefinitions>__MODULE__="XENBUS";POOL_NX_OPTIN=1;NT_PROCESSOR_GROUPS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <WarningLevel>EnableAllWarnings</WarningLevel>
       
<DisableSpecificWarnings>4711;4548;4820;4668;4255;6001;6054;28196;%(DisableSpecificWarnings)</DisableSpecificWarnings>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
@@ -42,7 +42,7 @@
     </ClCompile>
     <Link>
       <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
-      
<AdditionalDependencies>$(ProjectDir)..\$(ConfigurationName)\$(Platform)\xen.lib;$(DDK_LIB_PATH)/libcntpr.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      
<AdditionalDependencies>$(ProjectDir)..\$(ConfigurationName)\$(Platform)\xen.lib;$(DDK_LIB_PATH)/libcntpr.lib;$(DDK_LIB_PATH)/procgrp.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <EnableCOMDATFolding>false</EnableCOMDATFolding>
     </Link>
     <Inf>
diff --git a/vs2012/xenfilt/xenfilt.vcxproj b/vs2012/xenfilt/xenfilt.vcxproj
index 5dbb903..34efda4 100644
--- a/vs2012/xenfilt/xenfilt.vcxproj
+++ b/vs2012/xenfilt/xenfilt.vcxproj
@@ -26,7 +26,7 @@
   </PropertyGroup>
   <ItemDefinitionGroup>
     <ClCompile>
-      
<PreprocessorDefinitions>__MODULE__="XENFILT";POOL_NX_OPTIN=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      
<PreprocessorDefinitions>__MODULE__="XENFILT";POOL_NX_OPTIN=1;NT_PROCESSOR_GROUPS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <WarningLevel>EnableAllWarnings</WarningLevel>
       
<DisableSpecificWarnings>4711;4548;4820;4668;4255;6001;6054;28196;%(DisableSpecificWarnings)</DisableSpecificWarnings>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
@@ -34,7 +34,7 @@
     </ClCompile>
     <Link>
       <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
-      
<AdditionalDependencies>$(ProjectDir)..\$(ConfigurationName)\$(Platform)\xen.lib;$(DDK_LIB_PATH)/libcntpr.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      
<AdditionalDependencies>$(ProjectDir)..\$(ConfigurationName)\$(Platform)\xen.lib;$(DDK_LIB_PATH)/libcntpr.lib;$(DDK_LIB_PATH)/procgrp.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <EnableCOMDATFolding>false</EnableCOMDATFolding>
     </Link>
     <Inf>
diff --git a/vs2013/xen/xen.vcxproj b/vs2013/xen/xen.vcxproj
index a12f060..cd40452 100644
--- a/vs2013/xen/xen.vcxproj
+++ b/vs2013/xen/xen.vcxproj
@@ -34,7 +34,7 @@
       </CustomBuildStep>
     <ClCompile>
       
<AdditionalIncludeDirectories>$(WindowsSdkDir)\include\km;..\..\include;..\..\include\xen;..\..\src\common;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
-      
<PreprocessorDefinitions>__MODULE__="XEN";POOL_NX_OPTIN=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      
<PreprocessorDefinitions>__MODULE__="XEN";POOL_NX_OPTIN=1;NT_PROCESSOR_GROUPS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       <WarningLevel>EnableAllWarnings</WarningLevel>
       
<DisableSpecificWarnings>4711;4548;4820;4668;4255;6001;6054;28196;%(DisableSpecificWarnings)</DisableSpecificWarnings>
       <MultiProcessorCompilation>true</MultiProcessorCompilation>
@@ -45,7 +45,7 @@
     </ResourceCompile>
     <Link>
       <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
-      
<AdditionalDependencies>$(DDK_LIB_PATH)/libcntpr.lib;$(DDK_LIB_PATH)/aux_klib.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      
<AdditionalDependencies>$(DDK_LIB_PATH)/libcntpr.lib;$(DDK_LIB_PATH)/aux_klib.lib;$(DDK_LIB_PATH)/procgrp.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <ModuleDefinitionFile>../../src/xen/xen.def</ModuleDefinitionFile>
       <EnableCOMDATFolding>false</EnableCOMDATFolding>
     </Link>
diff --git a/vs2013/xenbus/xenbus.vcxproj b/vs2013/xenbus/xenbus.vcxproj
index eb476a9..ca486c9 100644
--- a/vs2013/xenbus/xenbus.vcxproj
+++ b/vs2013/xenbus/xenbus.vcxproj
@@ -33,7 +33,7 @@
         <Inputs>..\..\src\xenbus.inf</Inputs>
     </CustomBuildStep>
     <ClCompile>
-      
<PreprocessorDefinitions>__MODULE__="XENBUS";POOL_NX_OPTIN=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      
<PreprocessorDefinitions>__MODULE__="XENBUS";POOL_NX_OPTIN=1;NT_PROCESSOR_GROUPS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       
<AdditionalIncludeDirectories>$(WindowsSdkDir)\include\km;..\..\include;..\..\include\xen;..\..\src\common;</AdditionalIncludeDirectories>
       <WarningLevel>EnableAllWarnings</WarningLevel>
       
<DisableSpecificWarnings>4711;4548;4820;4668;4255;6001;6054;28196;%(DisableSpecificWarnings)</DisableSpecificWarnings>
@@ -45,7 +45,7 @@
     </ResourceCompile>
     <Link>
       <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
-      
<AdditionalDependencies>$(ProjectDir)..\$(ConfigurationName)\$(Platform)\xen.lib;$(DDK_LIB_PATH)/libcntpr.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      
<AdditionalDependencies>$(ProjectDir)..\$(ConfigurationName)\$(Platform)\xen.lib;$(DDK_LIB_PATH)/libcntpr.lib;$(DDK_LIB_PATH)/procgrp.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <EnableCOMDATFolding>false</EnableCOMDATFolding>
     </Link>
     <Inf>
diff --git a/vs2013/xenfilt/xenfilt.vcxproj b/vs2013/xenfilt/xenfilt.vcxproj
index b7759a7..db4a437 100644
--- a/vs2013/xenfilt/xenfilt.vcxproj
+++ b/vs2013/xenfilt/xenfilt.vcxproj
@@ -25,7 +25,7 @@
   </PropertyGroup>
   <ItemDefinitionGroup>
     <ClCompile>
-      
<PreprocessorDefinitions>__MODULE__="XENFILT";POOL_NX_OPTIN=1;%(PreprocessorDefinitions)</PreprocessorDefinitions>
+      
<PreprocessorDefinitions>__MODULE__="XENFILT";POOL_NX_OPTIN=1;NT_PROCESSOR_GROUPS;%(PreprocessorDefinitions)</PreprocessorDefinitions>
       
<AdditionalIncludeDirectories>$(WindowsSdkDir)\include\km;..\..\include;..\..\include\xen;..\..\src\common;</AdditionalIncludeDirectories>
       <WarningLevel>EnableAllWarnings</WarningLevel>
       
<DisableSpecificWarnings>4711;4548;4820;4668;4255;6001;6054;28196;%(DisableSpecificWarnings)</DisableSpecificWarnings>
@@ -37,7 +37,7 @@
     </ResourceCompile>
     <Link>
       <ImageHasSafeExceptionHandlers>false</ImageHasSafeExceptionHandlers>
-      
<AdditionalDependencies>$(ProjectDir)..\$(ConfigurationName)\$(Platform)\xen.lib;$(DDK_LIB_PATH)/libcntpr.lib;%(AdditionalDependencies)</AdditionalDependencies>
+      
<AdditionalDependencies>$(ProjectDir)..\$(ConfigurationName)\$(Platform)\xen.lib;$(DDK_LIB_PATH)/libcntpr.lib;$(DDK_LIB_PATH)/procgrp.lib;%(AdditionalDependencies)</AdditionalDependencies>
       <EnableCOMDATFolding>false</EnableCOMDATFolding>
     </Link>
     <Inf>
-- 
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®.