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

[win-pv-devel] [PATCH 3/3] Introduce new mechanism to unplug emulated devices



This makes an incompatible change and so the PDO revision is bumped up
without retaining any previous revisions.

With this patch a new unplug interface is exported by XENBUS (so it is
available for query before installing XENFILT). This interface exports
a Request method which is now the one true way of requesting unplug
of emulated devices. Co-installers need not mess with registry keys
any more. Instead drivers should request unplug when they find their
PDOs blocked by aliasing emulated devices, or when they successfully
come online. The reason for the latter case is that unplug is now
single-shot. It needs to be re-requested by PV drivers each time their
PDOs come online otherwise emulated devices will be re-instated on
next reboot.

Signed-off-by: Paul Durrant <paul.durrant@xxxxxxxxxx>
---
 include/revision.h             |   6 +-
 include/unplug_interface.h     |  70 +++---
 include/xen.h                  |  26 +++
 src/coinst/coinst.c            |   2 +-
 src/common/registry.c          |  42 ++++
 src/common/registry.h          |  16 +-
 src/xen/driver.c               | 113 ++++++++--
 src/xen/driver.h               |  40 ++++
 src/xen/unplug.c               | 421 +++++++++++++++++++++++++++++++++++++
 src/xen/unplug.h               |  48 +++++
 src/xenbus.inf                 |  17 +-
 src/xenbus/fdo.c               | 104 ++++-----
 src/xenbus/fdo.h               |  10 +-
 src/xenbus/pdo.c               |  14 +-
 src/xenbus/suspend.c           |  37 +---
 src/xenbus/unplug.c            | 241 +++++++++++++++++++++
 src/xenbus/unplug.h            |  62 ++++++
 src/xenfilt/driver.c           | 132 +++---------
 src/xenfilt/driver.h           |  12 --
 src/xenfilt/pdo.c              |   2 -
 src/xenfilt/unplug.c           | 467 -----------------------------------------
 src/xenfilt/unplug.h           |  59 ------
 vs2012/xen/xen.vcxproj         |   1 +
 vs2012/xenbus/xenbus.vcxproj   |   1 +
 vs2012/xenfilt/xenfilt.vcxproj |   1 -
 vs2013/xen/xen.vcxproj         |   1 +
 vs2013/xenbus/xenbus.vcxproj   |   1 +
 vs2013/xenfilt/xenfilt.vcxproj |   1 -
 28 files changed, 1126 insertions(+), 821 deletions(-)
 create mode 100644 src/xen/driver.h
 create mode 100644 src/xen/unplug.c
 create mode 100644 src/xen/unplug.h
 create mode 100644 src/xenbus/unplug.c
 create mode 100644 src/xenbus/unplug.h
 delete mode 100644 src/xenfilt/unplug.c
 delete mode 100644 src/xenfilt/unplug.h

diff --git a/include/revision.h b/include/revision.h
index 9a91a33..dfe4995 100644
--- a/include/revision.h
+++ b/include/revision.h
@@ -43,8 +43,8 @@
 // G  - XENBUS_GNTTAB_INTERFACE
 // EM - XENFILT_EMULATED_INTERFACE
 
-//                    REVISION   S  SI   E   D  ST   R   C   G  EM
-#define DEFINE_REVISION_TABLE                                      \
-    DEFINE_REVISION(0x08000008,  1,  2,  4,  1,  1,  1,  1,  1,  1)
+//                    REVISION   S  SI   E   D  ST   R   C   G   U  EM
+#define DEFINE_REVISION_TABLE                                           \
+    DEFINE_REVISION(0x08000009,  1,  2,  4,  1,  1,  1,  1,  1,  1,  1)
 
 #endif  // _REVISION_H
diff --git a/include/unplug_interface.h b/include/unplug_interface.h
index 8817f53..83b3dc9 100644
--- a/include/unplug_interface.h
+++ b/include/unplug_interface.h
@@ -30,75 +30,87 @@
  */
 
 /*! \file unplug_interface.h
-    \brief XENFILT UNPLUG Interface
+    \brief XENBUS UNPLUG Interface
 
-    This interface provides a primitive to re-unplug emulated devices,
-    which is required on resume-from-suspend
+    This interface provides a method to request emulated device unplug
 */
 
-#ifndef _XENFILT_UNPLUG_INTERFACE_H
-#define _XENFILT_UNPLUG_INTERFACE_H
+#ifndef _XENBUS_UNPLUG_INTERFACE_H
+#define _XENBUS_UNPLUG_INTERFACE_H
 
 #ifndef _WINDLL
 
-/*! \typedef XENFILT_UNPLUG_ACQUIRE
+/*! \typedef XENBUS_UNPLUG_ACQUIRE
     \brief Acquire a reference to the UNPLUG interface
 
     \param Interface The interface header
 */  
 typedef NTSTATUS
-(*XENFILT_UNPLUG_ACQUIRE)(
+(*XENBUS_UNPLUG_ACQUIRE)(
     IN  PINTERFACE  Interface
     );
 
-/*! \typedef XENFILT_UNPLUG_RELEASE
+/*! \typedef XENBUS_UNPLUG_RELEASE
     \brief Release a reference to the UNPLUG interface
 
     \param Interface The interface header
 */  
 typedef VOID
-(*XENFILT_UNPLUG_RELEASE)(
+(*XENBUS_UNPLUG_RELEASE)(
     IN  PINTERFACE  Interface
     );
 
-/*! \typedef XENFILT_UNPLUG_REPLAY
-    \brief Re-unplug emulated devices that were previously unplugged
-    at boot time
+/*! \enum _XENBUS_UNPLUG_DEVICE_TYPE
+    \brief Type of device to be unplugged
+*/
+typedef enum _XENBUS_UNPLUG_DEVICE_TYPE {
+    XENBUS_UNPLUG_DEVICE_TYPE_INVALID = 0,
+    XENBUS_UNPLUG_DEVICE_TYPE_NICS,     /*!< NICs */
+    XENBUS_UNPLUG_DEVICE_TYPE_DISKS,    /*!< Disks */
+} XENBUS_UNPLUG_DEVICE_TYPE, *PXENBUS_UNPLUG_DEVICE_TYPE;
+
+/*! \typedef XENBUS_UNPLUG_REQUEST
+    \brief Request unplug of a type of emulated device
 
     \param Interface The interface header
+    \param Type The type of device
+    \param Make Set to TRUE if the request is being made, FALSE if it is
+           being revoked.
 */  
 typedef VOID
-(*XENFILT_UNPLUG_REPLAY)(
-    IN  PINTERFACE  Interface
+(*XENBUS_UNPLUG_REQUEST)(
+    IN  PINTERFACE                  Interface,
+    IN  XENBUS_UNPLUG_DEVICE_TYPE   Type,
+    IN  BOOLEAN                     Make
     );
 
-// {D5657CFD-3DB5-4A23-A94F-61FD89247FE7}
-DEFINE_GUID(GUID_XENFILT_UNPLUG_INTERFACE,
-0xd5657cfd, 0x3db5, 0x4a23, 0xa9, 0x4f, 0x61, 0xfd, 0x89, 0x24, 0x7f, 0xe7);
+// {73db6517-3d06-4937-989f-199b7501e229}
+DEFINE_GUID(GUID_XENBUS_UNPLUG_INTERFACE,
+0x73db6517, 0x3d06, 0x4937, 0x98, 0x9f, 0x19, 0x9b, 0x75, 0x01, 0xe2, 0x29);
 
-/*! \struct _XENFILT_UNPLUG_INTERFACE_V1
+/*! \struct _XENBUS_UNPLUG_INTERFACE_V1
     \brief UNPLUG interface version 1
     \ingroup interfaces
 */
-struct _XENFILT_UNPLUG_INTERFACE_V1 {
+struct _XENBUS_UNPLUG_INTERFACE_V1 {
     INTERFACE               Interface;
-    XENFILT_UNPLUG_ACQUIRE  Acquire;
-    XENFILT_UNPLUG_RELEASE  Release;
-    XENFILT_UNPLUG_REPLAY   Replay;
+    XENBUS_UNPLUG_ACQUIRE   UnplugAcquire;
+    XENBUS_UNPLUG_RELEASE   UnplugRelease;
+    XENBUS_UNPLUG_REQUEST   UnplugRequest;
 };
 
-typedef struct _XENFILT_UNPLUG_INTERFACE_V1 XENFILT_UNPLUG_INTERFACE, 
*PXENFILT_UNPLUG_INTERFACE;
+typedef struct _XENBUS_UNPLUG_INTERFACE_V1 XENBUS_UNPLUG_INTERFACE, 
*PXENBUS_UNPLUG_INTERFACE;
 
-/*! \def XENFILT_UNPLUG
+/*! \def XENBUS_UNPLUG
     \brief Macro at assist in method invocation
 */
-#define XENFILT_UNPLUG(_Method, _Interface, ...)    \
-    (_Interface)-> ## _Method((PINTERFACE)(_Interface), __VA_ARGS__)
+#define XENBUS_UNPLUG(_Method, _Interface, ...)    \
+    (_Interface)->Unplug ## _Method((PINTERFACE)(_Interface), __VA_ARGS__)
 
 #endif  // _WINDLL
 
-#define XENFILT_UNPLUG_INTERFACE_VERSION_MIN  1
-#define XENFILT_UNPLUG_INTERFACE_VERSION_MAX  1
+#define XENBUS_UNPLUG_INTERFACE_VERSION_MIN  1
+#define XENBUS_UNPLUG_INTERFACE_VERSION_MAX  1
 
-#endif  // _XENFILT_UNPLUG_INTERFACE_H
+#endif  // _XENBUS_UNPLUG_INTERFACE_H
 
diff --git a/include/xen.h b/include/xen.h
index cf9c2d9..6007582 100644
--- a/include/xen.h
+++ b/include/xen.h
@@ -307,6 +307,32 @@ ModuleLookup(
     OUT PULONG_PTR  Offset
     );
 
+// UNPLUG
+
+typedef enum _UNPLUG_TYPE {
+    UNPLUG_DISKS = 0,
+    UNPLUG_NICS,
+    UNPLUG_TYPE_COUNT
+} UNPLUG_TYPE, *PUNPLUG_TYPE;
+
+XEN_API
+VOID
+UnplugDevices(
+    VOID
+    );
+
+XEN_API
+NTSTATUS
+UnplugIncrementValue(
+    IN  UNPLUG_TYPE Type
+    );
+
+XEN_API
+NTSTATUS
+UnplugDecrementValue(
+    IN  UNPLUG_TYPE Type
+    );
+
 // LOG
 
 typedef enum _LOG_LEVEL {
diff --git a/src/coinst/coinst.c b/src/coinst/coinst.c
index 0b8c306..2b980a1 100644
--- a/src/coinst/coinst.c
+++ b/src/coinst/coinst.c
@@ -1298,7 +1298,7 @@ fail1:
     return FALSE;
 }
 
-#define DEFINE_REVISION(_N, _S, _SI, _E, _D, _ST, _R, _C, _G, _EM) \
+#define DEFINE_REVISION(_N, _S, _SI, _E, _D, _ST, _R, _C, _G, _U, _EM) \
     (_N)
 
 static DWORD    DeviceRevision[] = {
diff --git a/src/common/registry.c b/src/common/registry.c
index 4caeaa5..cb9e31d 100644
--- a/src/common/registry.c
+++ b/src/common/registry.c
@@ -116,6 +116,40 @@ fail1:
 }
 
 NTSTATUS
+RegistryCreateKey(
+    IN  HANDLE          Parent,
+    IN  PUNICODE_STRING Path,
+    IN  ULONG           Options,
+    OUT PHANDLE         Key
+    )
+{
+    OBJECT_ATTRIBUTES   Attributes;
+    NTSTATUS            status;
+
+    InitializeObjectAttributes(&Attributes,
+                               Path,
+                               OBJ_CASE_INSENSITIVE | OBJ_KERNEL_HANDLE,
+                               Parent,
+                               NULL);
+
+    status = ZwCreateKey(Key,
+                         KEY_ALL_ACCESS,
+                         &Attributes,
+                         0,
+                         NULL,
+                         Options,
+                         NULL
+                         );
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    return STATUS_SUCCESS;
+
+fail1:
+    return status;
+}
+
+NTSTATUS
 RegistryOpenServiceKey(
     IN  ACCESS_MASK     DesiredAccess,
     OUT PHANDLE         Key
@@ -125,6 +159,14 @@ RegistryOpenServiceKey(
 }
 
 NTSTATUS
+RegistryCreateServiceKey(
+    OUT PHANDLE         Key
+    )
+{
+    return RegistryCreateKey(NULL, &RegistryPath, REG_OPTION_NON_VOLATILE, 
Key);
+}
+
+NTSTATUS
 RegistryOpenSoftwareKey(
     IN  PDEVICE_OBJECT  DeviceObject,
     IN  ACCESS_MASK     DesiredAccess,
diff --git a/src/common/registry.h b/src/common/registry.h
index 7f0fa23..3920b6d 100644
--- a/src/common/registry.h
+++ b/src/common/registry.h
@@ -53,12 +53,25 @@ RegistryOpenKey(
     );
 
 extern NTSTATUS
+RegistryCreateKey(
+    IN  HANDLE          Parent,
+    IN  PUNICODE_STRING Path,
+    IN  ULONG           Options,
+    OUT PHANDLE         Key
+    );
+
+extern NTSTATUS
 RegistryOpenServiceKey(
     IN  ACCESS_MASK DesiredAccess,
     OUT PHANDLE     Key
     );
 
 extern NTSTATUS
+RegistryCreateServiceKey(
+    OUT PHANDLE     Key
+    );
+
+extern NTSTATUS
 RegistryOpenSoftwareKey(
     IN  PDEVICE_OBJECT  DeviceObject,
     IN  ACCESS_MASK     DesiredAccess,
@@ -83,8 +96,7 @@ RegistryOpenSubKey(
 extern NTSTATUS
 RegistryCreateSubKey(
     IN  HANDLE      Key,
-    IN  PCHAR       Name,
-    IN  ULONG       Options,
+    IN  PCHAR       Name,    IN  ULONG       Options,
     OUT PHANDLE     SubKey
     );
 
diff --git a/src/xen/driver.c b/src/xen/driver.c
index 66a5e80..9662ff6 100644
--- a/src/xen/driver.c
+++ b/src/xen/driver.c
@@ -35,12 +35,15 @@
 #include <procgrp.h>
 #include <xen.h>
 
+#include "registry.h"
+#include "driver.h"
 #include "hypercall.h"
 #include "log.h"
 #include "module.h"
 #include "process.h"
 #include "system.h"
 #include "acpi.h"
+#include "unplug.h"
 #include "bug_check.h"
 #include "dbg_print.h"
 #include "assert.h"
@@ -51,6 +54,7 @@ extern PULONG   InitSafeBootMode;
 typedef struct _XEN_DRIVER {
     PLOG_DISPOSITION    TraceDisposition;
     PLOG_DISPOSITION    InfoDisposition;
+    HANDLE              UnplugKey;
 } XEN_DRIVER, *PXEN_DRIVER;
 
 static XEN_DRIVER   Driver;
@@ -102,6 +106,30 @@ fail1:
     return STATUS_INCOMPATIBLE_DRIVER_BLOCKED;
 }
 
+static FORCEINLINE VOID
+__DriverSetUnplugKey(
+    IN  HANDLE  Key
+    )
+{
+    Driver.UnplugKey = Key;
+}
+
+static FORCEINLINE HANDLE
+__DriverGetUnplugKey(
+    VOID
+    )
+{
+    return Driver.UnplugKey;
+}
+
+HANDLE
+DriverGetUnplugKey(
+    VOID
+    )
+{
+    return __DriverGetUnplugKey();
+}
+
 static VOID
 DriverOutputBuffer(
     IN  PVOID   Argument,
@@ -122,9 +150,9 @@ DllInitialize(
     IN  PUNICODE_STRING RegistryPath
     )
 {
-    NTSTATUS    status;
-
-    UNREFERENCED_PARAMETER(RegistryPath);
+    HANDLE              ServiceKey;
+    HANDLE              UnplugKey;
+    NTSTATUS            status;
 
     ExInitializeDriverRuntime(DrvRtPoolNxOptIn);
     WdmlibProcgrpInitialize();
@@ -165,59 +193,103 @@ DllInitialize(
          MONTH,
          YEAR);
 
-    status = AcpiInitialize();
+    status = RegistryInitialize(RegistryPath);
     if (!NT_SUCCESS(status))
         goto fail2;
 
-    status = SystemInitialize();
+    status = RegistryCreateServiceKey(&ServiceKey);
     if (!NT_SUCCESS(status))
         goto fail3;
 
-    status = HypercallInitialize();
+    status = RegistryCreateSubKey(ServiceKey,
+                                  "Unplug",
+                                  REG_OPTION_NON_VOLATILE,
+                                  &UnplugKey);
     if (!NT_SUCCESS(status))
         goto fail4;
 
-    status = BugCheckInitialize();
+    __DriverSetUnplugKey(UnplugKey);
+
+    status = AcpiInitialize();
     if (!NT_SUCCESS(status))
         goto fail5;
 
-    status = ModuleInitialize();
+    status = SystemInitialize();
     if (!NT_SUCCESS(status))
         goto fail6;
 
-    status = ProcessInitialize();
+    status = HypercallInitialize();
     if (!NT_SUCCESS(status))
         goto fail7;
 
+    status = BugCheckInitialize();
+    if (!NT_SUCCESS(status))
+        goto fail8;
+
+    status = ModuleInitialize();
+    if (!NT_SUCCESS(status))
+        goto fail9;
+
+    status = ProcessInitialize();
+    if (!NT_SUCCESS(status))
+        goto fail10;
+
+    status = UnplugInitialize();
+    if (!NT_SUCCESS(status))
+        goto fail11;
+
+    RegistryCloseKey(ServiceKey);
+
 done:
     Trace("<====\n");
 
     return STATUS_SUCCESS;
 
+fail11:
+    Error("fail11\n");
+
+    ProcessTeardown();
+
+fail10:
+    Error("fail10\n");
+
+    ModuleTeardown();
+
+fail9:
+    Error("fail9\n");
+
+    BugCheckTeardown();
+
+fail8:
+    Error("fail8\n");
+
+    HypercallTeardown();
+
 fail7:
     Error("fail7\n");
 
-    ModuleTeardown();
+    SystemTeardown();
 
 fail6:
     Error("fail6\n");
 
-    BugCheckTeardown();
+    AcpiTeardown();
 
 fail5:
     Error("fail5\n");
 
-    HypercallTeardown();
+    RegistryCloseKey(UnplugKey);
+    __DriverSetUnplugKey(NULL);
 
 fail4:
     Error("fail4\n");
 
-    SystemTeardown();
+    RegistryCloseKey(ServiceKey);
 
 fail3:
     Error("fail3\n");
 
-    AcpiTeardown();
+    RegistryTeardown();
 
 fail2:
     Error("fail2\n");
@@ -231,7 +303,7 @@ fail2:
     LogTeardown();
 
 fail1:
-    Error("fail1 (%08x)", status);
+    Error("fail1 (%08x)\n", status);
 
     ASSERT(IsZeroMemory(&Driver, sizeof (XEN_DRIVER)));
 
@@ -243,11 +315,15 @@ DllUnload(
     VOID
     )
 {
+    HANDLE  UnplugKey;
+
     Trace("====>\n");
 
     if (*InitSafeBootMode > 0)
         goto done;
 
+    UnplugTeardown();
+
     ProcessTeardown();
 
     ModuleTeardown();
@@ -258,6 +334,13 @@ DllUnload(
 
     SystemTeardown();
 
+    UnplugKey = __DriverGetUnplugKey();
+
+    RegistryCloseKey(UnplugKey);
+    __DriverSetUnplugKey(NULL);
+
+    RegistryTeardown();
+
     Info("XEN %d.%d.%d (%d) (%02d.%02d.%04d)\n",
          MAJOR_VERSION,
          MINOR_VERSION,
diff --git a/src/xen/driver.h b/src/xen/driver.h
new file mode 100644
index 0000000..c4f7a6f
--- /dev/null
+++ b/src/xen/driver.h
@@ -0,0 +1,40 @@
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * *   Redistributions of source code must retain the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer.
+ * *   Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer in the documentation and/or other
+ *     materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _XEN_DRIVER_H
+#define _XEN_DRIVER_H
+
+extern HANDLE
+DriverGetUnplugKey(
+    VOID
+    );
+
+#endif  // _XEN_DRIVER_H
diff --git a/src/xen/unplug.c b/src/xen/unplug.c
new file mode 100644
index 0000000..77b6b8e
--- /dev/null
+++ b/src/xen/unplug.c
@@ -0,0 +1,421 @@
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * *   Redistributions of source code must retain the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer.
+ * *   Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer in the documentation and/or other
+ *     materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#define XEN_API __declspec(dllexport)
+
+#include <ntddk.h>
+#include <ntstrsafe.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <xen.h>
+#include <version.h>
+
+#include "driver.h"
+#include "high.h"
+#include "registry.h"
+#include "unplug.h"
+#include "dbg_print.h"
+#include "assert.h"
+#include "util.h"
+
+#define UNPLUG_TAG  'LPNU'
+
+typedef struct _UNPLUG_CONTEXT {
+    LONG        References;
+    HIGH_LOCK   Lock;
+    BOOLEAN     BlackListed;
+    BOOLEAN     Request[UNPLUG_TYPE_COUNT];
+    BOOLEAN     BootEmulated;
+} UNPLUG_CONTEXT, *PUNPLUG_CONTEXT;
+
+static UNPLUG_CONTEXT   UnplugContext;
+
+static FORCEINLINE PVOID
+__UnplugAllocate(
+    IN  ULONG   Length
+    )
+{
+    return __AllocatePoolWithTag(NonPagedPool, Length, UNPLUG_TAG);
+}
+
+static FORCEINLINE VOID
+__UnplugFree(
+    IN  PVOID   Buffer
+    )
+{
+    ExFreePoolWithTag(Buffer, UNPLUG_TAG);
+}
+
+static VOID
+UnplugSetBootEmulated(
+    VOID
+    )
+{
+    PUNPLUG_CONTEXT Context = &UnplugContext;
+    CHAR            Key[] = "XEN:BOOT_EMULATED=";
+    PANSI_STRING    Option;
+    PCHAR           Value;
+    NTSTATUS        status;
+
+    status = RegistryQuerySystemStartOption(Key, &Option);
+    if (!NT_SUCCESS(status))
+        return;
+
+    Value = Option->Buffer + sizeof (Key) - 1;
+
+    if (strcmp(Value, "TRUE") == 0)
+        Context->BootEmulated = TRUE;
+
+    RegistryFreeSzValue(Option);
+}
+
+static VOID
+UnplugDeviceType(
+    IN  UNPLUG_TYPE Type
+    )
+{
+    PUNPLUG_CONTEXT Context = &UnplugContext;
+
+    switch (Type) {
+    case UNPLUG_DISKS:
+        if (Context->BootEmulated) {
+#pragma prefast(suppress:28138)
+            WRITE_PORT_USHORT((PUSHORT)0x10, 0x0004);
+
+            LogPrintf(LOG_LEVEL_WARNING, "UNPLUG: AUX DISKS\n");
+        } else {
+#pragma prefast(suppress:28138)
+            WRITE_PORT_USHORT((PUSHORT)0x10, 0x0001);
+
+            LogPrintf(LOG_LEVEL_WARNING, "UNPLUG: DISKS\n");
+        }
+        break;
+    case UNPLUG_NICS:
+#pragma prefast(suppress:28138)
+        WRITE_PORT_USHORT((PUSHORT)0x10, 0x0002);
+
+        LogPrintf(LOG_LEVEL_WARNING, "UNPLUG: NICS\n");
+        break;
+    default:
+        ASSERT(FALSE);
+    }
+}
+
+static NTSTATUS
+UnplugPreamble(
+    VOID
+    )
+{
+    PUNPLUG_CONTEXT Context = &UnplugContext;
+    USHORT          Magic;
+    UCHAR           Version;
+    NTSTATUS        status;
+
+    // See docs/misc/hvm-emulated-unplug.markdown for details of the
+    // protocol in use here
+
+#pragma prefast(suppress:28138)
+    Magic = READ_PORT_USHORT((PUSHORT)0x10);
+
+    if (Magic == 0xd249) {
+        Context->BlackListed = TRUE;
+        goto done;
+    }
+
+    status = STATUS_NOT_SUPPORTED;
+    if (Magic != 0x49d2)
+        goto fail1;
+
+#pragma prefast(suppress:28138)
+    Version = READ_PORT_UCHAR((PUCHAR)0x12);
+    if (Version != 0) {
+#pragma prefast(suppress:28138)
+        WRITE_PORT_USHORT((PUSHORT)0x12, 0xFFFF);   // FIXME
+
+#pragma prefast(suppress:28138)
+        WRITE_PORT_ULONG((PULONG)0x10,
+                         (MAJOR_VERSION << 16) |
+                         (MINOR_VERSION << 8) |
+                         MICRO_VERSION);
+
+#pragma prefast(suppress:28138)
+        Magic = READ_PORT_USHORT((PUSHORT)0x10);
+        if (Magic == 0xd249)
+            Context->BlackListed = TRUE;
+    }
+
+done:
+    LogPrintf(LOG_LEVEL_WARNING,
+              "UNPLUG: PRE-AMBLE (DRIVERS %s)\n",
+              (Context->BlackListed) ? "BLACKLISTED" : "NOT BLACKLISTED");
+
+    return STATUS_SUCCESS;
+
+fail1:
+    return status;
+}
+
+static VOID
+UnplugSetRequest(
+    IN  UNPLUG_TYPE     Type
+    )
+{
+    PUNPLUG_CONTEXT     Context = &UnplugContext;
+    HANDLE              UnplugKey;
+    PCHAR               ValueName;
+    ULONG               Value;
+    KIRQL               Irql;
+    NTSTATUS            status;
+
+    Trace("====>\n");
+
+    ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+    UnplugKey = DriverGetUnplugKey();
+
+    switch (Type) {
+    case UNPLUG_DISKS:
+        ValueName = "DISKS";
+        break;
+    case UNPLUG_NICS:
+        ValueName = "NICS";
+        break;
+    default:
+        ValueName = NULL;
+        ASSERT(FALSE);
+    }
+
+    status = RegistryQueryDwordValue(UnplugKey,
+                                     ValueName,
+                                     &Value);
+    if (!NT_SUCCESS(status))
+        goto done;
+
+    (VOID) RegistryDeleteValue(UnplugKey, ValueName);
+
+    Info("%s\n", ValueName);
+
+    AcquireHighLock(&Context->Lock, &Irql);
+    Context->Request[Type] = (Value != 0) ? TRUE : FALSE;
+    ReleaseHighLock(&Context->Lock, Irql);
+
+done:
+    Trace("<====\n");
+}
+
+XEN_API
+NTSTATUS
+UnplugIncrementValue(
+    IN  UNPLUG_TYPE     Type
+    )
+{
+    HANDLE              UnplugKey;
+    PCHAR               ValueName;
+    ULONG               Value;
+    NTSTATUS            status;
+
+    ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+    UnplugKey = DriverGetUnplugKey();
+
+    switch (Type) {
+    case UNPLUG_DISKS:
+        ValueName = "DISKS";
+        break;
+    case UNPLUG_NICS:
+        ValueName = "NICS";
+        break;
+    default:
+        ValueName = NULL;
+        ASSERT(FALSE);
+    }
+
+    status = RegistryQueryDwordValue(UnplugKey,
+                                     ValueName,
+                                     &Value);
+    if (!NT_SUCCESS(status))
+        Value = 0;
+
+    Value++;
+
+    status = RegistryUpdateDwordValue(UnplugKey,
+                                      ValueName,
+                                      Value);
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    Info("%s %u\n", ValueName, Value);
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+XEN_API
+NTSTATUS
+UnplugDecrementValue(
+    IN  UNPLUG_TYPE     Type
+    )
+{
+    HANDLE              UnplugKey;
+    PCHAR               ValueName;
+    LONG                Value;
+    NTSTATUS            status;
+
+    ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+    UnplugKey = DriverGetUnplugKey();
+
+    switch (Type) {
+    case UNPLUG_DISKS:
+        ValueName = "DISKS";
+        break;
+    case UNPLUG_NICS:
+        ValueName = "NICS";
+        break;
+    default:
+        ValueName = NULL;
+        ASSERT(FALSE);
+    }
+
+    status = RegistryQueryDwordValue(UnplugKey,
+                                     ValueName,
+                                     (PULONG)&Value);
+    if (!NT_SUCCESS(status))
+        goto fail1;
+
+    status = STATUS_INVALID_PARAMETER;
+    if (--Value < 0)
+        goto fail2;
+
+    status = RegistryUpdateDwordValue(UnplugKey,
+                                      ValueName,
+                                      (ULONG)Value);
+    if (!NT_SUCCESS(status))
+        goto fail3;
+
+    Info("%s %u\n", ValueName, (ULONG)Value);
+
+    return STATUS_SUCCESS;
+
+fail3:
+    Error("fail3\n");
+
+fail2:
+    Error("fail2\n");
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+XEN_API
+VOID
+UnplugDevices(
+    VOID
+    )
+{
+    PUNPLUG_CONTEXT Context = &UnplugContext;
+    UNPLUG_TYPE     Type;
+    KIRQL           Irql;
+    NTSTATUS        status;
+
+    AcquireHighLock(&Context->Lock, &Irql);
+
+    status = UnplugPreamble();
+    ASSERT(NT_SUCCESS(status));
+
+    for (Type = 0; Type < UNPLUG_TYPE_COUNT; Type++) {
+        if (Context->Request[Type])
+            UnplugDeviceType(Type);
+    }
+
+    ReleaseHighLock(&Context->Lock, Irql);
+}
+
+NTSTATUS
+UnplugInitialize(
+    VOID
+    )
+{
+    PUNPLUG_CONTEXT Context = &UnplugContext;
+    LONG            References;
+    UNPLUG_TYPE     Type;
+    NTSTATUS        status;
+
+    References = InterlockedIncrement(&Context->References);
+
+    status = STATUS_OBJECTID_EXISTS;
+    if (References != 1)
+        goto fail1;
+
+    InitializeHighLock(&Context->Lock);
+
+    for (Type = 0; Type < UNPLUG_TYPE_COUNT; Type++)
+        UnplugSetRequest(Type);
+
+    UnplugSetBootEmulated();
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    (VOID) InterlockedDecrement(&Context->References);
+
+    ASSERT(IsZeroMemory(Context, sizeof (UNPLUG_CONTEXT)));
+
+    return status;
+}
+
+VOID
+UnplugTeardown(
+    VOID
+    )
+{
+    PUNPLUG_CONTEXT Context = &UnplugContext;
+    UNPLUG_TYPE     Type;
+
+    Context->BootEmulated = FALSE;
+
+    for (Type = 0; Type < UNPLUG_TYPE_COUNT; Type++)
+        Context->Request[Type] = FALSE;
+
+    RtlZeroMemory(&Context->Lock, sizeof (HIGH_LOCK));
+
+    (VOID) InterlockedDecrement(&Context->References);
+
+    ASSERT(IsZeroMemory(Context, sizeof (UNPLUG_CONTEXT)));
+}
diff --git a/src/xen/unplug.h b/src/xen/unplug.h
new file mode 100644
index 0000000..bd8e67c
--- /dev/null
+++ b/src/xen/unplug.h
@@ -0,0 +1,48 @@
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * *   Redistributions of source code must retain the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer.
+ * *   Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer in the documentation and/or other
+ *     materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _XEN_UNPLUG_H
+#define _XEN_UNPLUG_H
+
+#include <ntddk.h>
+#include <xen.h>
+
+extern NTSTATUS
+UnplugInitialize(
+    VOID
+    );
+
+extern VOID
+UnplugTeardown(
+    VOID
+    );
+
+#endif  // _XEN_UNPLUG_H
diff --git a/src/xenbus.inf b/src/xenbus.inf
index 90dcf64..7f9370f 100644
--- a/src/xenbus.inf
+++ b/src/xenbus.inf
@@ -71,8 +71,8 @@ 
xenbus_coinst_@MAJOR_VERSION@_@MINOR_VERSION@_@MICRO_VERSION@_@BUILD_NUMBER@.dll
 [XenBus_Inst] 
 CopyFiles=XenBus_Copyfiles
 
-[XenBus_Inst.Services] 
-AddService=xenbus,0x02,XenBus_Service,
+[XenBus_Inst.Services]
+AddService=xenbus,0x02,XenBus_Service
 AddService=xenfilt,,XenFilt_Service,
 
 [XenBus_Service] 
@@ -82,16 +82,13 @@ StartType=%SERVICE_BOOT_START%
 ErrorControl=%SERVICE_ERROR_NORMAL% 
 ServiceBinary=%12%\xenbus.sys 
 LoadOrderGroup="Boot Bus Extender"
-AddReg = XenBus_Parameters, XenBus_Interfaces, XenBus_Interrupts
+AddReg = XenBus_Parameters, XenBus_Interrupts
 
 [XenBus_Parameters]
 HKR,"Parameters",,0x00000010
 HKR,"Parameters","SupportedClasses",0x00010000,"VIF","VBD","IFACE"
 HKR,"Parameters","SyntheticClasses",0x00010000,"IFACE"
 
-[XenBus_Interfaces]
-HKR,"Interfaces",,0x00000010
-
 [XenBus_Interrupts]
 HKR,"Interrupt Management",,0x00000010
 HKR,"Interrupt Management\MessageSignaledInterruptProperties",,0x00000010
@@ -105,19 +102,13 @@ StartType=%SERVICE_BOOT_START%
 ErrorControl=%SERVICE_ERROR_NORMAL% 
 ServiceBinary=%12%\xenfilt.sys 
 LoadOrderGroup="Boot Bus Extender"
-AddReg = XenFilt_Parameters, XenFilt_Unplug, XenFilt_Interfaces
+AddReg = XenFilt_Parameters
 
 [XenFilt_Parameters]
 HKR,"Parameters",,0x00000010
 HKR,"Parameters","ACPI\PNP0A03",0x00000000,"DEVICE"
 HKR,"Parameters","PCIIDE\IDEChannel",0x00000000,"DISK"
 
-[XenFilt_Unplug]
-HKR,"Unplug",,0x00000010
-
-[XenFilt_Interfaces]
-HKR,"Interfaces",,0x00000010
-
 [XenBus_Inst.CoInstallers]
 CopyFiles=CoInst_CopyFiles
 AddReg=CoInst_AddReg
diff --git a/src/xenbus/fdo.c b/src/xenbus/fdo.c
index 8208111..e8a6f22 100644
--- a/src/xenbus/fdo.c
+++ b/src/xenbus/fdo.c
@@ -38,8 +38,6 @@
 #include <stdlib.h>
 #include <xen.h>
 
-#include <unplug_interface.h>
-
 #include "names.h"
 #include "registry.h"
 #include "fdo.h"
@@ -58,6 +56,7 @@
 #include "balloon.h"
 #include "driver.h"
 #include "range_set.h"
+#include "unplug.h"
 #include "dbg_print.h"
 #include "assert.h"
 #include "util.h"
@@ -122,6 +121,7 @@ struct _XENBUS_FDO {
     PXENBUS_RANGE_SET_CONTEXT       RangeSetContext;
     PXENBUS_CACHE_CONTEXT           CacheContext;
     PXENBUS_GNTTAB_CONTEXT          GnttabContext;
+    PXENBUS_UNPLUG_CONTEXT          UnplugContext;
     PXENBUS_BALLOON_CONTEXT         BalloonContext;
 
     XENBUS_DEBUG_INTERFACE          DebugInterface;
@@ -130,7 +130,6 @@ struct _XENBUS_FDO {
     XENBUS_STORE_INTERFACE          StoreInterface;
     XENBUS_RANGE_SET_INTERFACE      RangeSetInterface;
     XENBUS_BALLOON_INTERFACE        BalloonInterface;
-    XENFILT_UNPLUG_INTERFACE        UnplugInterface;
 
     PXENBUS_RANGE_SET               RangeSet;
     LIST_ENTRY                      List;
@@ -548,6 +547,7 @@ DEFINE_FDO_GET_CONTEXT(Store, PXENBUS_STORE_CONTEXT)
 DEFINE_FDO_GET_CONTEXT(RangeSet, PXENBUS_RANGE_SET_CONTEXT)
 DEFINE_FDO_GET_CONTEXT(Cache, PXENBUS_CACHE_CONTEXT)
 DEFINE_FDO_GET_CONTEXT(Gnttab, PXENBUS_GNTTAB_CONTEXT)
+DEFINE_FDO_GET_CONTEXT(Unplug, PXENBUS_UNPLUG_CONTEXT)
 DEFINE_FDO_GET_CONTEXT(Balloon, PXENBUS_BALLOON_CONTEXT)
 
 __drv_functionClass(IO_COMPLETION_ROUTINE)
@@ -2508,15 +2508,9 @@ FdoD3ToD0(
             goto fail7;
     }
 
-    if (Fdo->UnplugInterface.Interface.Context != NULL) {
-        status = XENFILT_UNPLUG(Acquire, &Fdo->UnplugInterface);
-        if (!NT_SUCCESS(status))
-            goto fail8;
-    }
-
     status = __FdoD3ToD0(Fdo);
     if (!NT_SUCCESS(status))
-        goto fail9;
+        goto fail8;
 
     status = XENBUS_SUSPEND(Register,
                             &Fdo->SuspendInterface,
@@ -2525,7 +2519,7 @@ FdoD3ToD0(
                             Fdo,
                             &Fdo->SuspendCallbackLate);
     if (!NT_SUCCESS(status))
-        goto fail10;
+        goto fail9;
 
     KeLowerIrql(Irql);
 
@@ -2556,16 +2550,10 @@ not_active:
 
     return STATUS_SUCCESS;
 
-fail10:
-    Error("fail10\n");
-
-    __FdoD0ToD3(Fdo);
-
 fail9:
     Error("fail9\n");
 
-    if (Fdo->UnplugInterface.Interface.Context != NULL)
-        XENFILT_UNPLUG(Release, &Fdo->UnplugInterface);
+    __FdoD0ToD3(Fdo);
 
 fail8:
     Error("fail8\n");
@@ -2692,9 +2680,6 @@ FdoD0ToD3(
 
     __FdoD0ToD3(Fdo);
 
-    if (Fdo->UnplugInterface.Interface.Context != NULL)
-        XENFILT_UNPLUG(Release, &Fdo->UnplugInterface);
-
     if (Fdo->BalloonInterface.Interface.Context != NULL)
         XENBUS_BALLOON(Release, &Fdo->BalloonInterface);
 
@@ -2733,8 +2718,7 @@ FdoS4ToS3(
 
     HypercallPopulate();
 
-    if (Fdo->UnplugInterface.Interface.Context != NULL)
-        XENFILT_UNPLUG(Replay, &Fdo->UnplugInterface);
+    UnplugDevices();
 
     KeLowerIrql(Irql);
 
@@ -4471,15 +4455,6 @@ fail1:
                       (_Size),                                                 
         \
                       (_Optional))
 
-VOID
-FdoGetUnplugInterface(
-    IN  PXENBUS_FDO                 Fdo,
-    OUT PXENFILT_UNPLUG_INTERFACE   UnplugInterface
-    )
-{
-    *UnplugInterface = Fdo->UnplugInterface;
-}
-
 static BOOLEAN
 FdoIsBalloonEnabled(
     IN  PXENBUS_FDO Fdo
@@ -4581,44 +4556,39 @@ FdoCreate(
     if (!__FdoIsActive(Fdo))
         goto done;
 
-    status = FDO_QUERY_INTERFACE(Fdo,
-                                 XENFILT,
-                                 UNPLUG,
-                                 (PINTERFACE)&Fdo->UnplugInterface,
-                                 sizeof (Fdo->UnplugInterface),
-                                 TRUE);
+    status = DebugInitialize(Fdo, &Fdo->DebugContext);
     if (!NT_SUCCESS(status))
         goto fail7;
 
-    status = DebugInitialize(Fdo, &Fdo->DebugContext);
+    status = SuspendInitialize(Fdo, &Fdo->SuspendContext);
     if (!NT_SUCCESS(status))
         goto fail8;
 
-    status = SuspendInitialize(Fdo, &Fdo->SuspendContext);
+    status = SharedInfoInitialize(Fdo, &Fdo->SharedInfoContext);
     if (!NT_SUCCESS(status))
         goto fail9;
 
-    status = SharedInfoInitialize(Fdo, &Fdo->SharedInfoContext);
+    status = EvtchnInitialize(Fdo, &Fdo->EvtchnContext);
     if (!NT_SUCCESS(status))
         goto fail10;
 
-    status = EvtchnInitialize(Fdo, &Fdo->EvtchnContext);
+    status = StoreInitialize(Fdo, &Fdo->StoreContext);
     if (!NT_SUCCESS(status))
         goto fail11;
 
-    status = StoreInitialize(Fdo, &Fdo->StoreContext);
+    status = RangeSetInitialize(Fdo, &Fdo->RangeSetContext);
     if (!NT_SUCCESS(status))
         goto fail12;
 
-    status = RangeSetInitialize(Fdo, &Fdo->RangeSetContext);
+    status = CacheInitialize(Fdo, &Fdo->CacheContext);
     if (!NT_SUCCESS(status))
         goto fail13;
 
-    status = CacheInitialize(Fdo, &Fdo->CacheContext);
+    status = GnttabInitialize(Fdo, &Fdo->GnttabContext);
     if (!NT_SUCCESS(status))
         goto fail14;
 
-    status = GnttabInitialize(Fdo, &Fdo->GnttabContext);
+    status = UnplugInitialize(Fdo, &Fdo->UnplugContext);
     if (!NT_SUCCESS(status))
         goto fail15;
 
@@ -4687,56 +4657,56 @@ done:
 fail16:
     Error("fail16\n");
 
-    GnttabTeardown(Fdo->GnttabContext);
-    Fdo->GnttabContext = NULL;
+    UnplugTeardown(Fdo->UnplugContext);
+    Fdo->UnplugContext = NULL;
 
 fail15:
     Error("fail15\n");
 
-    CacheTeardown(Fdo->CacheContext);
-    Fdo->CacheContext = NULL;
+    GnttabTeardown(Fdo->GnttabContext);
+    Fdo->GnttabContext = NULL;
 
 fail14:
     Error("fail14\n");
 
-    RangeSetTeardown(Fdo->RangeSetContext);
-    Fdo->RangeSetContext = NULL;
+    CacheTeardown(Fdo->CacheContext);
+    Fdo->CacheContext = NULL;
 
 fail13:
     Error("fail13\n");
 
-    StoreTeardown(Fdo->StoreContext);
-    Fdo->StoreContext = NULL;
+    RangeSetTeardown(Fdo->RangeSetContext);
+    Fdo->RangeSetContext = NULL;
 
 fail12:
     Error("fail12\n");
 
-    EvtchnTeardown(Fdo->EvtchnContext);
-    Fdo->EvtchnContext = NULL;
+    StoreTeardown(Fdo->StoreContext);
+    Fdo->StoreContext = NULL;
 
 fail11:
     Error("fail11\n");
 
-    SharedInfoTeardown(Fdo->SharedInfoContext);
-    Fdo->SharedInfoContext = NULL;
+    EvtchnTeardown(Fdo->EvtchnContext);
+    Fdo->EvtchnContext = NULL;
 
 fail10:
     Error("fail10\n");
 
-    SuspendTeardown(Fdo->SuspendContext);
-    Fdo->SuspendContext = NULL;
+    SharedInfoTeardown(Fdo->SharedInfoContext);
+    Fdo->SharedInfoContext = NULL;
 
 fail9:
     Error("fail9\n");
 
-    DebugTeardown(Fdo->DebugContext);
-    Fdo->DebugContext = NULL;
+    SuspendTeardown(Fdo->SuspendContext);
+    Fdo->SuspendContext = NULL;
 
 fail8:
     Error("fail8\n");
 
-    RtlZeroMemory(&Fdo->UnplugInterface,
-                  sizeof (XENFILT_UNPLUG_INTERFACE));
+    DebugTeardown(Fdo->DebugContext);
+    Fdo->DebugContext = NULL;
 
 fail7:
     Error("fail7\n");
@@ -4834,6 +4804,9 @@ FdoDestroy(
             Fdo->BalloonContext = NULL;
         }
 
+        UnplugTeardown(Fdo->UnplugContext);
+        Fdo->UnplugContext = NULL;
+
         GnttabTeardown(Fdo->GnttabContext);
         Fdo->GnttabContext = NULL;
 
@@ -4858,9 +4831,6 @@ FdoDestroy(
         DebugTeardown(Fdo->DebugContext);
         Fdo->DebugContext = NULL;
 
-        RtlZeroMemory(&Fdo->UnplugInterface,
-                      sizeof (XENFILT_UNPLUG_INTERFACE));
-
         __FdoSetActive(Fdo, FALSE);
     }
 
diff --git a/src/xenbus/fdo.h b/src/xenbus/fdo.h
index 4b99ba0..1feef17 100644
--- a/src/xenbus/fdo.h
+++ b/src/xenbus/fdo.h
@@ -33,7 +33,6 @@
 #define _XENBUS_FDO_H
 
 #include <ntddk.h>
-#include <unplug_interface.h>
 
 #include "driver.h"
 #include "types.h"
@@ -249,10 +248,11 @@ FdoGetGnttabContext(
     IN  PXENBUS_FDO Fdo
     );
 
-extern VOID
-FdoGetUnplugInterface(
-    IN  PXENBUS_FDO                 Fdo,
-    OUT PXENFILT_UNPLUG_INTERFACE   UnplugInterface
+#include "unplug.h"
+
+extern PXENBUS_UNPLUG_CONTEXT
+FdoGetUnplugContext(
+    IN  PXENBUS_FDO Fdo
     );
 
 extern NTSTATUS
diff --git a/src/xenbus/pdo.c b/src/xenbus/pdo.c
index f305bb7..8e7f90a 100644
--- a/src/xenbus/pdo.c
+++ b/src/xenbus/pdo.c
@@ -362,11 +362,12 @@ typedef struct _XENBUS_PDO_REVISION {
     ULONG   RangeSetInterfaceVersion;
     ULONG   CacheInterfaceVersion;
     ULONG   GnttabInterfaceVersion;
+    ULONG   UnplugInterfaceVersion;
     ULONG   EmulatedInterfaceVersion;
 } XENBUS_PDO_REVISION, *PXENBUS_PDO_REVISION;
 
-#define DEFINE_REVISION(_N, _S, _SI, _E, _D, _ST, _R, _C, _G, _EM) \
-    { (_N), (_S), (_SI), (_E), (_D), (_ST), (_R), (_C), (_G), (_EM) }
+#define DEFINE_REVISION(_N, _S, _SI, _E, _D, _ST, _R, _C, _G, _U, _EM) \
+    { (_N), (_S), (_SI), (_E), (_D), (_ST), (_R), (_C), (_G), (_U), (_EM) }
 
 static XENBUS_PDO_REVISION PdoRevision[] = {
     DEFINE_REVISION_TABLE
@@ -426,6 +427,11 @@ PdoDumpRevisions(
         ASSERT(IMPLY(Index == ARRAYSIZE(PdoRevision) - 1,
                      Revision->GnttabInterfaceVersion == 
XENBUS_GNTTAB_INTERFACE_VERSION_MAX));
 
+        ASSERT3U(Revision->UnplugInterfaceVersion, >=, 
XENBUS_UNPLUG_INTERFACE_VERSION_MIN);
+        ASSERT3U(Revision->UnplugInterfaceVersion, <=, 
XENBUS_UNPLUG_INTERFACE_VERSION_MAX);
+        ASSERT(IMPLY(Index == ARRAYSIZE(PdoRevision) - 1,
+                     Revision->UnplugInterfaceVersion == 
XENBUS_UNPLUG_INTERFACE_VERSION_MAX));
+
         ASSERT3U(Revision->EmulatedInterfaceVersion, >=, 
XENFILT_EMULATED_INTERFACE_VERSION_MIN);
         ASSERT3U(Revision->EmulatedInterfaceVersion, <=, 
XENFILT_EMULATED_INTERFACE_VERSION_MAX);
         ASSERT(IMPLY(Index == ARRAYSIZE(PdoRevision) - 1,
@@ -442,6 +448,7 @@ PdoDumpRevisions(
              "RANGE_SET v%u "
              "CACHE v%u "
              "GNTTAB v%u "
+             "UNPLUG v%u\n"
              "EMULATED v%u\n",
              Revision->Number,
              Revision->SuspendInterfaceVersion,
@@ -452,6 +459,7 @@ PdoDumpRevisions(
              Revision->RangeSetInterfaceVersion,
              Revision->CacheInterfaceVersion,
              Revision->GnttabInterfaceVersion,
+             Revision->UnplugInterfaceVersion,
              Revision->EmulatedInterfaceVersion);
     }
 }
@@ -1010,6 +1018,7 @@ DEFINE_PDO_QUERY_INTERFACE(Store)
 DEFINE_PDO_QUERY_INTERFACE(RangeSet)
 DEFINE_PDO_QUERY_INTERFACE(Cache)
 DEFINE_PDO_QUERY_INTERFACE(Gnttab)
+DEFINE_PDO_QUERY_INTERFACE(Unplug)
 
 struct _INTERFACE_ENTRY {
     const GUID  *Guid;
@@ -1027,6 +1036,7 @@ static struct _INTERFACE_ENTRY PdoInterfaceTable[] = {
     { &GUID_XENBUS_RANGE_SET_INTERFACE, "RANGE_SET_INTERFACE", 
PdoQueryRangeSetInterface },
     { &GUID_XENBUS_CACHE_INTERFACE, "CACHE_INTERFACE", PdoQueryCacheInterface 
},
     { &GUID_XENBUS_GNTTAB_INTERFACE, "GNTTAB_INTERFACE", 
PdoQueryGnttabInterface },
+    { &GUID_XENBUS_UNPLUG_INTERFACE, "UNPLUG_INTERFACE", 
PdoQueryUnplugInterface },
     { &GUID_XENFILT_EMULATED_INTERFACE, "EMULATED_INTERFACE", PdoDelegateIrp },
     { NULL, NULL, NULL }
 };
diff --git a/src/xenbus/suspend.c b/src/xenbus/suspend.c
index b826795..fad35e4 100644
--- a/src/xenbus/suspend.c
+++ b/src/xenbus/suspend.c
@@ -33,8 +33,6 @@
 #include <stdarg.h>
 #include <xen.h>
 
-#include <unplug_interface.h>
-
 #include "suspend.h"
 #include "thread.h"
 #include "fdo.h"
@@ -58,7 +56,6 @@ struct _XENBUS_SUSPEND_CONTEXT {
     LIST_ENTRY                  LateList;
     XENBUS_DEBUG_INTERFACE      DebugInterface;
     PXENBUS_DEBUG_CALLBACK      DebugCallback;
-    XENFILT_UNPLUG_INTERFACE    UnplugInterface;
 };
 
 #define XENBUS_SUSPEND_TAG  'PSUS'
@@ -153,10 +150,6 @@ SuspendTrigger(
     KIRQL                   Irql;
     NTSTATUS                status;
 
-    status = STATUS_NOT_SUPPORTED;
-    if (Context->UnplugInterface.Interface.Context == NULL)
-        goto fail1;
-
     KeRaiseIrql(DISPATCH_LEVEL, &Irql);
 
     LogPrintf(LOG_LEVEL_INFO,
@@ -179,7 +172,7 @@ SuspendTrigger(
 
         HypercallPopulate();
 
-        XENFILT_UNPLUG(Replay, &Context->UnplugInterface);
+        UnplugDevices();
 
         for (ListEntry = Context->EarlyList.Flink;
              ListEntry != &Context->EarlyList;
@@ -216,11 +209,6 @@ SuspendTrigger(
     KeLowerIrql(Irql);
 
     return STATUS_SUCCESS;
-
-fail1:
-    Error("fail1 (%08x)\n", status);
-
-    return status;
 }
 
 static ULONG
@@ -338,13 +326,6 @@ SuspendAcquire(
     if (!NT_SUCCESS(status))
         goto fail2;
 
-    if (Context->UnplugInterface.Interface.Context != NULL) {
-        status = XENFILT_UNPLUG(Acquire, &Context->UnplugInterface);
-
-        if (!NT_SUCCESS(status))
-            goto fail3;
-    }
-
     Trace("<====\n");
 
 done:
@@ -352,14 +333,6 @@ done:
 
     return STATUS_SUCCESS;
 
-fail3:
-    Error("fail3\n");
-
-    XENBUS_DEBUG(Deregister,
-                 &Context->DebugInterface,
-                 Context->DebugCallback);
-    Context->DebugCallback = NULL;
-
 fail2:
     Error("fail2\n");
 
@@ -396,9 +369,6 @@ SuspendRelease(
 
     Context->Count = 0;
 
-    if (Context->UnplugInterface.Interface.Context != NULL)
-        XENFILT_UNPLUG(Release, &Context->UnplugInterface);
-
     XENBUS_DEBUG(Deregister,
                  &Context->DebugInterface,
                  Context->DebugCallback);
@@ -444,8 +414,6 @@ SuspendInitialize(
                                sizeof ((*Context)->DebugInterface));
     ASSERT(NT_SUCCESS(status));
 
-    FdoGetUnplugInterface(Fdo, &(*Context)->UnplugInterface);
-
     InitializeListHead(&(*Context)->EarlyList);
     InitializeListHead(&(*Context)->LateList);
     KeInitializeSpinLock(&(*Context)->Lock);
@@ -509,9 +477,6 @@ SuspendTeardown(
 
     Context->Fdo = NULL;
 
-    RtlZeroMemory(&Context->UnplugInterface,
-                  sizeof (XENFILT_UNPLUG_INTERFACE));
-
     RtlZeroMemory(&Context->DebugInterface,
                   sizeof (XENBUS_DEBUG_INTERFACE));
 
diff --git a/src/xenbus/unplug.c b/src/xenbus/unplug.c
new file mode 100644
index 0000000..0a1b27a
--- /dev/null
+++ b/src/xenbus/unplug.c
@@ -0,0 +1,241 @@
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * *   Redistributions of source code must retain the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer.
+ * *   Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer in the documentation and/or other
+ *     materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <ntddk.h>
+#include <ntstrsafe.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <xen.h>
+
+#include "unplug.h"
+#include "fdo.h"
+#include "mutex.h"
+#include "dbg_print.h"
+#include "assert.h"
+#include "util.h"
+
+struct _XENBUS_UNPLUG_CONTEXT {
+    KSPIN_LOCK  Lock;
+    LONG        References;
+    MUTEX       Mutex;
+};
+
+#define XENBUS_UNPLUG_TAG    'LPNU'
+
+static FORCEINLINE PVOID
+__UnplugAllocate(
+    IN  ULONG   Length
+    )
+{
+    return __AllocatePoolWithTag(NonPagedPool, Length, XENBUS_UNPLUG_TAG);
+}
+
+static FORCEINLINE VOID
+__UnplugFree(
+    IN  PVOID   Buffer
+    )
+{
+    ExFreePoolWithTag(Buffer, XENBUS_UNPLUG_TAG);
+}
+
+static VOID
+UnplugRequest(
+    IN  PINTERFACE                  Interface,
+    IN  XENBUS_UNPLUG_DEVICE_TYPE   Type,
+    IN  BOOLEAN                     Make
+    )
+{
+    PXENBUS_UNPLUG_CONTEXT          Context = Interface->Context;
+
+    ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
+
+    AcquireMutex(&Context->Mutex);
+
+    switch (Type) {
+    case XENBUS_UNPLUG_DEVICE_TYPE_NICS:
+        Info("NICS (%s)\n", (Make) ? "MAKE" : "REVOKE");
+
+        if (Make)
+            (VOID) UnplugIncrementValue(UNPLUG_NICS);
+        else
+            (VOID) UnplugDecrementValue(UNPLUG_NICS);
+
+        break;
+
+    case XENBUS_UNPLUG_DEVICE_TYPE_DISKS:
+        Info("DISKS (%s)\n", (Make) ? "MAKE" : "REVOKE");
+
+        if (Make)
+            (VOID) UnplugIncrementValue(UNPLUG_DISKS);
+        else
+            (VOID) UnplugDecrementValue(UNPLUG_DISKS);
+
+        break;
+
+    default:
+        ASSERT(FALSE);
+        break;
+    }
+
+    ReleaseMutex(&Context->Mutex);
+}
+
+static NTSTATUS
+UnplugAcquire(
+    IN  PINTERFACE          Interface
+    )
+{
+    PXENBUS_UNPLUG_CONTEXT  Context = Interface->Context;
+    KIRQL                   Irql;
+
+    KeAcquireSpinLock(&Context->Lock, &Irql);
+
+    if (Context->References++ != 0)
+        goto done;
+
+    Trace("<===>\n");
+
+done:
+    KeReleaseSpinLock(&Context->Lock, Irql);
+
+    return STATUS_SUCCESS;
+}
+
+static VOID
+UnplugRelease(
+    IN  PINTERFACE          Interface
+    )
+{
+    PXENBUS_UNPLUG_CONTEXT  Context = Interface->Context;
+    KIRQL                   Irql;
+
+    KeAcquireSpinLock(&Context->Lock, &Irql);
+
+    if (--Context->References > 0)
+        goto done;
+
+    Trace("<===>\n");
+
+done:
+    KeReleaseSpinLock(&Context->Lock, Irql);
+}
+
+static struct _XENBUS_UNPLUG_INTERFACE_V1 UnplugInterfaceVersion1 = {
+    { sizeof (struct _XENBUS_UNPLUG_INTERFACE_V1), 1, NULL, NULL, NULL },
+    UnplugAcquire,
+    UnplugRelease,
+    UnplugRequest
+};
+
+NTSTATUS
+UnplugInitialize(
+    IN  PXENBUS_FDO             Fdo,
+    OUT PXENBUS_UNPLUG_CONTEXT  *Context
+    )
+{
+    NTSTATUS                    status;
+
+    UNREFERENCED_PARAMETER(Fdo);
+
+    Trace("====>\n");
+
+    *Context = __UnplugAllocate(sizeof (XENBUS_UNPLUG_CONTEXT));
+
+    status = STATUS_NO_MEMORY;
+    if (*Context == NULL)
+        goto fail1;
+
+    KeInitializeSpinLock(&(*Context)->Lock);
+    InitializeMutex(&(*Context)->Mutex);
+
+    Trace("<====\n");
+
+    return STATUS_SUCCESS;
+
+fail1:
+    Error("fail1 (%08x)\n", status);
+
+    return status;
+}
+
+NTSTATUS
+UnplugGetInterface(
+    IN      PXENBUS_UNPLUG_CONTEXT  Context,
+    IN      ULONG                   Version,
+    IN OUT  PINTERFACE              Interface,
+    IN      ULONG                   Size
+    )
+{
+    NTSTATUS                        status;
+
+    ASSERT(Context != NULL);
+
+    switch (Version) {
+    case 1: {
+        struct _XENBUS_UNPLUG_INTERFACE_V1   *UnplugInterface;
+
+        UnplugInterface = (struct _XENBUS_UNPLUG_INTERFACE_V1 *)Interface;
+
+        status = STATUS_BUFFER_OVERFLOW;
+        if (Size < sizeof (struct _XENBUS_UNPLUG_INTERFACE_V1))
+            break;
+
+        *UnplugInterface = UnplugInterfaceVersion1;
+
+        ASSERT3U(Interface->Version, ==, Version);
+        Interface->Context = Context;
+
+        status = STATUS_SUCCESS;
+        break;
+    }
+    default:
+        status = STATUS_NOT_SUPPORTED;
+        break;
+    }
+
+    return status;
+}
+
+VOID
+UnplugTeardown(
+    IN  PXENBUS_UNPLUG_CONTEXT  Context
+    )
+{
+    Trace("====>\n");
+
+    RtlZeroMemory(&Context->Mutex, sizeof (MUTEX));
+    RtlZeroMemory(&Context->Lock, sizeof (KSPIN_LOCK));
+
+    ASSERT(IsZeroMemory(Context, sizeof (XENBUS_UNPLUG_CONTEXT)));
+    __UnplugFree(Context);
+
+    Trace("<====\n");
+}
diff --git a/src/xenbus/unplug.h b/src/xenbus/unplug.h
new file mode 100644
index 0000000..416b2d4
--- /dev/null
+++ b/src/xenbus/unplug.h
@@ -0,0 +1,62 @@
+/* Copyright (c) Citrix Systems Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms,
+ * with or without modification, are permitted provided
+ * that the following conditions are met:
+ *
+ * *   Redistributions of source code must retain the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer.
+ * *   Redistributions in binary form must reproduce the above
+ *     copyright notice, this list of conditions and the
+ *     following disclaimer in the documentation and/or other
+ *     materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND
+ * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#ifndef _XENBUS_UNPLUG_H
+#define _XENBUS_UNPLUG_H
+
+#include <ntddk.h>
+#include <xen.h>
+#include <unplug_interface.h>
+
+typedef struct _XENBUS_UNPLUG_CONTEXT  XENBUS_UNPLUG_CONTEXT, 
*PXENBUS_UNPLUG_CONTEXT;
+
+#include "fdo.h"
+
+extern NTSTATUS
+UnplugInitialize(
+    IN  PXENBUS_FDO             Fdo,
+    OUT PXENBUS_UNPLUG_CONTEXT  *Context
+    );
+
+extern NTSTATUS
+UnplugGetInterface(
+    IN      PXENBUS_UNPLUG_CONTEXT  Context,
+    IN      ULONG                   Version,
+    IN OUT  PINTERFACE              Interface,
+    IN      ULONG                   Size
+    );
+
+extern VOID
+UnplugTeardown(
+    IN  PXENBUS_UNPLUG_CONTEXT   Context
+    );
+
+#endif  // _XENBUS_UNPLUG_H
diff --git a/src/xenfilt/driver.c b/src/xenfilt/driver.c
index 16ed6f7..f0ffac0 100644
--- a/src/xenfilt/driver.c
+++ b/src/xenfilt/driver.c
@@ -38,7 +38,6 @@
 #include "pdo.h"
 #include "driver.h"
 #include "emulated.h"
-#include "unplug.h"
 #include "mutex.h"
 #include "dbg_print.h"
 #include "assert.h"
@@ -50,7 +49,6 @@ extern PULONG       InitSafeBootMode;
 typedef struct _XENFILT_DRIVER {
     PDRIVER_OBJECT              DriverObject;
     HANDLE                      ParametersKey;
-    HANDLE                      UnplugKey;
 
     PCHAR                       ActiveDeviceID;
     PCHAR                       ActiveInstanceID;
@@ -61,12 +59,7 @@ typedef struct _XENFILT_DRIVER {
     XENFILT_FILTER_STATE        FilterState;
 
     PXENFILT_EMULATED_CONTEXT   EmulatedContext;
-    PXENFILT_UNPLUG_CONTEXT     UnplugContext;
-
     XENFILT_EMULATED_INTERFACE  EmulatedInterface;
-    XENFILT_UNPLUG_INTERFACE    UnplugInterface;
-
-    BOOLEAN                     UnplugAcquired;
 } XENFILT_DRIVER, *PXENFILT_DRIVER;
 
 static XENFILT_DRIVER   Driver;
@@ -138,27 +131,27 @@ DriverGetParametersKey(
 }
 
 static FORCEINLINE VOID
-__DriverSetUnplugKey(
-    IN  HANDLE  Key
+__DriverSetEmulatedContext(
+    IN  PXENFILT_EMULATED_CONTEXT   Context
     )
 {
-    Driver.UnplugKey = Key;
+    Driver.EmulatedContext = Context;
 }
 
-static FORCEINLINE HANDLE
-__DriverGetUnplugKey(
+static FORCEINLINE PXENFILT_EMULATED_CONTEXT
+__DriverGetEmulatedContext(
     VOID
     )
 {
-    return Driver.UnplugKey;
+    return Driver.EmulatedContext;
 }
 
-HANDLE
-DriverGetUnplugKey(
+PXENFILT_EMULATED_CONTEXT
+DriverGetEmulatedContext(
     VOID
     )
 {
-    return __DriverGetUnplugKey();
+    return __DriverGetEmulatedContext();
 }
 
 static FORCEINLINE VOID
@@ -226,26 +219,6 @@ DriverRemoveFunctionDeviceObject(
     --Driver.References;
 }
 
-#define DEFINE_DRIVER_GET_CONTEXT(_Interface, _Type)            \
-static FORCEINLINE _Type                                        \
-__DriverGet ## _Interface ## Context(                           \
-    VOID                                                        \
-    )                                                           \
-{                                                               \
-    return Driver. ## _Interface ## Context;                    \
-}                                                               \
-                                                                \
-_Type                                                           \
-DriverGet ## _Interface ## Context(                             \
-    VOID                                                        \
-    )                                                           \
-{                                                               \
-    return __DriverGet ## _Interface ## Context();              \
-}
-
-DEFINE_DRIVER_GET_CONTEXT(Emulated, PXENFILT_EMULATED_CONTEXT)
-DEFINE_DRIVER_GET_CONTEXT(Unplug, PXENFILT_UNPLUG_CONTEXT)
-
 #define SERVICES_KEY 
L"\\Registry\\Machine\\SYSTEM\\CurrentControlSet\\Services"
 
 #define SERVICE_KEY(_Driver)    \
@@ -387,7 +360,6 @@ DriverSetFilterState(
     case XENFILT_FILTER_ENABLED: {
         PLIST_ENTRY ListEntry;
         BOOLEAN     Present;
-        NTSTATUS    status;
 
         // Assume all FDOs have enumerated until we know otherwise
         Driver.FilterState = XENFILT_FILTER_PENDING;
@@ -414,10 +386,8 @@ DriverSetFilterState(
 
         Info("ACTIVE DEVICE %sPRESENT\n", (!Present) ? "NOT " : "");
 
-        if (Present) {
-            status = XENFILT_UNPLUG(Acquire, &Driver.UnplugInterface);
-            Driver.UnplugAcquired = NT_SUCCESS(status) ? TRUE : FALSE;
-        }
+        if (Present)
+            UnplugDevices();
 
         Info("PENDING\n");
         break;
@@ -461,7 +431,6 @@ DriverUnload(
     )
 {
     HANDLE              ParametersKey;
-    HANDLE              UnplugKey;
 
     ASSERT3P(DriverObject, ==, __DriverGetDriverObject());
 
@@ -477,23 +446,11 @@ DriverUnload(
     RtlZeroMemory(&Driver.List, sizeof (LIST_ENTRY));
     RtlZeroMemory(&Driver.Mutex, sizeof (MUTEX));
 
-    if (Driver.UnplugAcquired) {
-        XENFILT_UNPLUG(Release, &Driver.UnplugInterface);
-
-        Driver.UnplugAcquired = FALSE;
-    }
-
     XENFILT_EMULATED(Release, &Driver.EmulatedInterface);
 
-    RtlZeroMemory(&Driver.UnplugInterface,
-                  sizeof (XENFILT_UNPLUG_INTERFACE));
-
     RtlZeroMemory(&Driver.EmulatedInterface,
                   sizeof (XENFILT_EMULATED_INTERFACE));
 
-    UnplugTeardown(Driver.UnplugContext);
-    Driver.UnplugContext = NULL;
-
     EmulatedTeardown(Driver.EmulatedContext);
     Driver.EmulatedContext = NULL;
 
@@ -505,10 +462,6 @@ DriverUnload(
         Driver.ActiveInstanceID = NULL;
     }
 
-    UnplugKey = __DriverGetUnplugKey();
-    __DriverSetUnplugKey(NULL);
-    RegistryCloseKey(UnplugKey);
-
     ParametersKey = __DriverGetParametersKey();
     __DriverSetParametersKey(NULL);
     RegistryCloseKey(ParametersKey);
@@ -763,15 +716,15 @@ DRIVER_INITIALIZE   DriverEntry;
 
 NTSTATUS
 DriverEntry(
-    IN  PDRIVER_OBJECT  DriverObject,
-    IN  PUNICODE_STRING RegistryPath
+    IN  PDRIVER_OBJECT          DriverObject,
+    IN  PUNICODE_STRING         RegistryPath
     )
 {
-    HANDLE              ServiceKey;
-    HANDLE              ParametersKey;
-    HANDLE              UnplugKey;
-    ULONG               Index;
-    NTSTATUS            status;
+    HANDLE                      ServiceKey;
+    HANDLE                      ParametersKey;
+    PXENFILT_EMULATED_CONTEXT   EmulatedContext;
+    ULONG                       Index;
+    NTSTATUS                    status;
 
     ASSERT3P(__DriverGetDriverObject(), ==, NULL);
 
@@ -820,23 +773,15 @@ DriverEntry(
 
     __DriverSetParametersKey(ParametersKey);
 
-    status = RegistryOpenSubKey(ServiceKey, "Unplug", KEY_READ, &UnplugKey);
+    status = DriverSetActiveDeviceInstance();
     if (!NT_SUCCESS(status))
         goto fail4;
 
-    __DriverSetUnplugKey(UnplugKey);
-
-    status = DriverSetActiveDeviceInstance();
+    status = EmulatedInitialize(&EmulatedContext);
     if (!NT_SUCCESS(status))
         goto fail5;
 
-    status = EmulatedInitialize(&Driver.EmulatedContext);
-    if (!NT_SUCCESS(status))
-        goto fail6;
-
-    status = UnplugInitialize(&Driver.UnplugContext);
-    if (!NT_SUCCESS(status))
-        goto fail7;
+    __DriverSetEmulatedContext(EmulatedContext);
 
     status = EmulatedGetInterface(__DriverGetEmulatedContext(),
                                   XENFILT_EMULATED_INTERFACE_VERSION_MAX,
@@ -845,16 +790,9 @@ DriverEntry(
     ASSERT(NT_SUCCESS(status));
     ASSERT(Driver.EmulatedInterface.Interface.Context != NULL);
 
-    status = UnplugGetInterface(__DriverGetUnplugContext(),
-                                 XENFILT_UNPLUG_INTERFACE_VERSION_MAX,
-                                 (PINTERFACE)&Driver.UnplugInterface,
-                                 sizeof (Driver.UnplugInterface));
-    ASSERT(NT_SUCCESS(status));
-    ASSERT(Driver.UnplugInterface.Interface.Context != NULL);
-
     status = XENFILT_EMULATED(Acquire, &Driver.EmulatedInterface);
     if (!NT_SUCCESS(status))
-        goto fail8;
+        goto fail6;
 
     RegistryCloseKey(ServiceKey);
 
@@ -874,26 +812,14 @@ done:
     Trace("<====\n");
     return STATUS_SUCCESS;
 
-fail8:
-    Error("fail8\n");
-
-    RtlZeroMemory(&Driver.UnplugInterface,
-                  sizeof (XENFILT_UNPLUG_INTERFACE));
-
-    RtlZeroMemory(&Driver.EmulatedInterface,
-                  sizeof (XENFILT_EMULATED_INTERFACE));
-
-    UnplugTeardown(Driver.UnplugContext);
-    Driver.UnplugContext = NULL;
-
-fail7:
-    Error("fail7\n");
+fail6:
+    Error("fail6\n");
 
     EmulatedTeardown(Driver.EmulatedContext);
     Driver.EmulatedContext = NULL;
 
-fail6:
-    Error("fail6\n");
+fail5:
+    Error("fail5\n");
 
     if (Driver.ActiveDeviceID != NULL) {
         __DriverFree(Driver.ActiveDeviceID);
@@ -903,12 +829,6 @@ fail6:
         Driver.ActiveInstanceID = NULL;
     }
 
-fail5:
-    Error("fail5\n");
-
-    __DriverSetUnplugKey(NULL);
-    RegistryCloseKey(UnplugKey);
-
 fail4:
     Error("fail4\n");
 
diff --git a/src/xenfilt/driver.h b/src/xenfilt/driver.h
index 7079d27..f906d36 100644
--- a/src/xenfilt/driver.h
+++ b/src/xenfilt/driver.h
@@ -42,11 +42,6 @@ DriverGetParametersKey(
     VOID
     );
 
-extern HANDLE
-DriverGetUnplugKey(
-    VOID
-    );
-
 extern PCHAR
 DriverGetActiveDeviceID(
     VOID
@@ -90,13 +85,6 @@ DriverGetEmulatedContext(
     VOID
     );
 
-#include "unplug.h"
-
-PXENFILT_UNPLUG_CONTEXT
-DriverGetUnplugContext(
-    VOID
-    );
-
 typedef struct _XENFILT_FDO XENFILT_FDO, *PXENFILT_FDO;
 typedef struct _XENFILT_PDO XENFILT_PDO, *PXENFILT_PDO;
 
diff --git a/src/xenfilt/pdo.c b/src/xenfilt/pdo.c
index 230fdf0..6fab346 100644
--- a/src/xenfilt/pdo.c
+++ b/src/xenfilt/pdo.c
@@ -863,7 +863,6 @@ done:                                                       
        \
 }                                                                   \
 
 DEFINE_PDO_QUERY_INTERFACE(Emulated)
-DEFINE_PDO_QUERY_INTERFACE(Unplug)
 
 struct _INTERFACE_ENTRY {
     const GUID  *Guid;
@@ -876,7 +875,6 @@ struct _INTERFACE_ENTRY {
 
 struct _INTERFACE_ENTRY PdoInterfaceTable[] = {
     DEFINE_INTERFACE_ENTRY(EMULATED_INTERFACE, Emulated),
-    DEFINE_INTERFACE_ENTRY(UNPLUG_INTERFACE, Unplug),
     { NULL, NULL, NULL }
 };
 
diff --git a/src/xenfilt/unplug.c b/src/xenfilt/unplug.c
deleted file mode 100644
index 0c0948d..0000000
--- a/src/xenfilt/unplug.c
+++ /dev/null
@@ -1,467 +0,0 @@
-/* Copyright (c) Citrix Systems Inc.
- * All rights reserved.
- * 
- * Redistribution and use in source and binary forms, 
- * with or without modification, are permitted provided 
- * that the following conditions are met:
- * 
- * *   Redistributions of source code must retain the above 
- *     copyright notice, this list of conditions and the 
- *     following disclaimer.
- * *   Redistributions in binary form must reproduce the above 
- *     copyright notice, this list of conditions and the 
- *     following disclaimer in the documentation and/or other 
- *     materials provided with the distribution.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
- * SUCH DAMAGE.
- */
-
-#include <ntddk.h>
-#include <ntstrsafe.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <xen.h>
-#include <version.h>
-
-#include "driver.h"
-#include "high.h"
-#include "registry.h"
-#include "unplug.h"
-#include "dbg_print.h"
-#include "assert.h"
-#include "util.h"
-
-struct _XENFILT_UNPLUG_CONTEXT {
-    KSPIN_LOCK  Lock;
-    LONG        References;
-    HIGH_LOCK   UnplugLock;
-    BOOLEAN     BlackListed;
-    BOOLEAN     UnplugDisks;
-    BOOLEAN     UnplugNics;
-    BOOLEAN     BootEmulated;
-};
-
-typedef enum _XENFILT_UNPLUG_TYPE {
-    XENFILT_UNPLUG_DISKS = 0,
-    XENFILT_UNPLUG_NICS
-} XENFILT_UNPLUG_TYPE, *PXENFILT_UNPLUG_TYPE;
-
-#define XENFILT_UNPLUG_TAG  'LPNU'
-
-static FORCEINLINE PVOID
-__UnplugAllocate(
-    IN  ULONG   Length
-    )
-{
-    return __AllocatePoolWithTag(NonPagedPool, Length, XENFILT_UNPLUG_TAG);
-}
-
-static FORCEINLINE VOID
-__UnplugFree(
-    IN  PVOID   Buffer
-    )
-{
-    ExFreePoolWithTag(Buffer, XENFILT_UNPLUG_TAG);
-}
-
-static VOID
-UnplugGetFlags(
-    IN  PXENFILT_UNPLUG_CONTEXT Context
-    )
-{
-    HANDLE                      Key;
-    DWORD                       Value;
-    NTSTATUS                    status;
-
-    Context->BootEmulated = FALSE;
-
-    Key = DriverGetParametersKey();
-
-    status = RegistryQueryDwordValue(Key,
-                                     "BootEmulated",
-                                     &Value);
-    if (NT_SUCCESS(status)) {
-        LogPrintf(LOG_LEVEL_WARNING,
-                  "UNPLUG: BOOT_EMULATED %d\n",
-                  Value);
-
-        Context->BootEmulated = (Value == 1) ? TRUE : FALSE;
-    }
-}
-
-static VOID
-UnplugRequest(
-    IN  PXENFILT_UNPLUG_CONTEXT Context,
-    IN  XENFILT_UNPLUG_TYPE     Type
-    )
-{
-    switch (Type) {
-    case XENFILT_UNPLUG_DISKS:
-        if (Context->BootEmulated) {
-#pragma prefast(suppress:28138)
-            WRITE_PORT_USHORT((PUSHORT)0x10, 0x0004);
-
-            LogPrintf(LOG_LEVEL_WARNING, "UNPLUG: AUX DISKS\n");
-        } else {
-#pragma prefast(suppress:28138)
-            WRITE_PORT_USHORT((PUSHORT)0x10, 0x0001);
-
-            LogPrintf(LOG_LEVEL_WARNING, "UNPLUG: DISKS\n");
-        }
-        break;
-    case XENFILT_UNPLUG_NICS:
-#pragma prefast(suppress:28138)
-        WRITE_PORT_USHORT((PUSHORT)0x10, 0x0002);
-
-        LogPrintf(LOG_LEVEL_WARNING, "UNPLUG: NICS\n");
-        break;
-    default:
-        ASSERT(FALSE);
-    }
-}
-
-static NTSTATUS
-UnplugPreamble(
-    IN  PXENFILT_UNPLUG_CONTEXT Context
-    )
-{
-    USHORT                      Magic;
-    UCHAR                       Version;
-    NTSTATUS                    status;
-
-    // See docs/misc/hvm-emulated-unplug.markdown for details of the
-    // protocol in use here
-
-#pragma prefast(suppress:28138)
-    Magic = READ_PORT_USHORT((PUSHORT)0x10);
-    
-    if (Magic == 0xd249) {
-        Context->BlackListed = TRUE;
-        goto done;
-    }
-
-    status = STATUS_NOT_SUPPORTED;
-    if (Magic != 0x49d2)
-        goto fail1;
-
-#pragma prefast(suppress:28138)
-    Version = READ_PORT_UCHAR((PUCHAR)0x12);
-    if (Version != 0) {
-#pragma prefast(suppress:28138)
-        WRITE_PORT_USHORT((PUSHORT)0x12, 0xFFFF);   // FIXME
-
-#pragma prefast(suppress:28138)
-        WRITE_PORT_ULONG((PULONG)0x10, 
-                         (MAJOR_VERSION << 16) |
-                         (MINOR_VERSION << 8) |
-                         MICRO_VERSION);
-
-#pragma prefast(suppress:28138)
-        Magic = READ_PORT_USHORT((PUSHORT)0x10);
-        if (Magic == 0xd249)
-            Context->BlackListed = TRUE;
-    }
-
-done:
-    LogPrintf(LOG_LEVEL_WARNING,
-              "UNPLUG: PRE-AMBLE (DRIVERS %s)\n",
-              (Context->BlackListed) ? "BLACKLISTED" : "NOT BLACKLISTED");
-
-    return STATUS_SUCCESS;
-
-fail1:
-    return status;
-}
-
-#define HKEY_LOCAL_MACHINE  "\\Registry\\Machine"
-#define SERVICES_KEY        HKEY_LOCAL_MACHINE 
"\\SYSTEM\\CurrentControlSet\\Services"
-
-static VOID
-UnplugCheckForPVDisks(
-    IN  PXENFILT_UNPLUG_CONTEXT Context
-    )
-{
-    HANDLE                      UnplugKey;
-    PANSI_STRING                ServiceNames;
-    ULONG                       Count;
-    ULONG                       Index;
-    KIRQL                       Irql;
-    NTSTATUS                    status;
-
-    ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
-
-    UnplugKey = DriverGetUnplugKey();
-
-    ServiceNames = NULL;
-
-    status = RegistryQuerySzValue(UnplugKey,
-                                  "DISKS",
-                                  &ServiceNames);
-    if (!NT_SUCCESS(status))
-        goto done;
-
-    Count = 0;
-    for (Index = 0; ServiceNames[Index].Buffer != NULL; Index++)
-        if (_stricmp(ServiceNames[Index].Buffer, "XENVBD") == 0)
-            Count++;
-
-    if (Count < 1)
-        goto done;
-
-    AcquireHighLock(&Context->UnplugLock, &Irql);
-    Context->UnplugDisks = TRUE;
-    ReleaseHighLock(&Context->UnplugLock, Irql);
-
-done:
-    Info("%s\n", (Context->UnplugDisks) ? "PRESENT" : "NOT PRESENT");
-
-    if (ServiceNames != NULL)
-        RegistryFreeSzValue(ServiceNames);
-}
-
-static VOID
-UnplugCheckForPVNics(
-    IN  PXENFILT_UNPLUG_CONTEXT Context
-    )
-{
-    HANDLE                      UnplugKey;
-    PANSI_STRING                ServiceNames;
-    ULONG                       Count;
-    ULONG                       Index;
-    KIRQL                       Irql;
-    NTSTATUS                    status;
-
-    ASSERT3U(KeGetCurrentIrql(), ==, PASSIVE_LEVEL);
-
-    UnplugKey = DriverGetUnplugKey();
-
-    ServiceNames = NULL;
-
-    status = RegistryQuerySzValue(UnplugKey,
-                                  "NICS",
-                                  &ServiceNames);
-    if (!NT_SUCCESS(status))
-        goto done;
-
-    Count = 0;
-    for (Index = 0; ServiceNames[Index].Buffer != NULL; Index++)
-        if (_stricmp(ServiceNames[Index].Buffer, "XENVIF") == 0 ||
-            _stricmp(ServiceNames[Index].Buffer, "XENNET") == 0)
-            Count++;
-
-    if (Count < 2)
-        goto done;
-
-    AcquireHighLock(&Context->UnplugLock, &Irql);
-    Context->UnplugNics = TRUE;
-    ReleaseHighLock(&Context->UnplugLock, Irql);
-
-done:
-    Info("%s\n", (Context->UnplugNics) ? "PRESENT" : "NOT PRESENT");
-
-    if (ServiceNames != NULL)
-        RegistryFreeSzValue(ServiceNames);
-}
-
-static VOID
-UnplugReplay(
-    IN  PINTERFACE          Interface
-    )
-{
-    PXENFILT_UNPLUG_CONTEXT Context = Interface->Context;
-    KIRQL                   Irql;
-    NTSTATUS                status;
-
-    AcquireHighLock(&Context->UnplugLock, &Irql);
-
-    status = UnplugPreamble(Context);
-    ASSERT(NT_SUCCESS(status));
-
-    if (Context->UnplugDisks)
-        UnplugRequest(Context, XENFILT_UNPLUG_DISKS);
-
-    if (Context->UnplugNics)
-        UnplugRequest(Context, XENFILT_UNPLUG_NICS);
-    
-    ReleaseHighLock(&Context->UnplugLock, Irql);
-}
-
-NTSTATUS
-UnplugAcquire(
-    IN  PINTERFACE          Interface
-    )
-{
-    PXENFILT_UNPLUG_CONTEXT Context = Interface->Context;
-    KIRQL                   Irql;
-    NTSTATUS                status;
-
-    KeAcquireSpinLock(&Context->Lock, &Irql);
-
-    if (Context->References++ != 0)
-        goto done;
-
-    Trace("====>\n");
-
-    (VOID)__AcquireHighLock(&Context->UnplugLock);
-
-    status = UnplugPreamble(Context);
-    if (!NT_SUCCESS(status))
-        goto fail1;
-
-    if (Context->UnplugDisks)
-        UnplugRequest(Context, XENFILT_UNPLUG_DISKS);
-
-    if (Context->UnplugNics)
-        UnplugRequest(Context, XENFILT_UNPLUG_NICS);
-    
-    ReleaseHighLock(&Context->UnplugLock, DISPATCH_LEVEL);
-
-    Trace("<====\n");
-
-done:
-    KeReleaseSpinLock(&Context->Lock, Irql);
-
-    return STATUS_SUCCESS;
-
-fail1:
-    Error("fail1 (%08x)\n", status);
-
-    ReleaseHighLock(&Context->UnplugLock, DISPATCH_LEVEL);
-
-    KeReleaseSpinLock(&Context->Lock, Irql);
-
-    return status;
-}
-
-VOID
-UnplugRelease(
-    IN  PINTERFACE              Interface
-    )
-{
-    PXENFILT_UNPLUG_CONTEXT     Context = Interface->Context;
-    KIRQL                       Irql;
-
-    KeAcquireSpinLock(&Context->Lock, &Irql);
-
-    if (--Context->References > 0)
-        goto done;
-
-    Trace("====>\n");
-
-    Context->BlackListed = FALSE;
-
-    Trace("<====\n");
-
-done:
-    KeReleaseSpinLock(&Context->Lock, Irql);
-}
-
-static struct _XENFILT_UNPLUG_INTERFACE_V1 UnplugInterfaceVersion1 = {
-    { sizeof (struct _XENFILT_UNPLUG_INTERFACE_V1), 1, NULL, NULL, NULL },
-    UnplugAcquire,
-    UnplugRelease,
-    UnplugReplay
-};
-                     
-NTSTATUS
-UnplugInitialize(
-    OUT PXENFILT_UNPLUG_CONTEXT *Context
-    )
-{
-    NTSTATUS                    status;
-
-    Trace("====>\n");
-
-    *Context = __UnplugAllocate(sizeof (XENFILT_UNPLUG_CONTEXT));
-
-    status = STATUS_NO_MEMORY;
-    if (*Context == NULL)
-        goto fail1;
-
-    UnplugCheckForPVDisks(*Context);
-    UnplugCheckForPVNics(*Context);
-    UnplugGetFlags(*Context);
-
-    KeInitializeSpinLock(&(*Context)->Lock);
-    InitializeHighLock(&(*Context)->UnplugLock);
-
-    Trace("<====\n");
-
-    return STATUS_SUCCESS;
-
-fail1:
-    Error("fail1 (%08x)\n", status);
-
-    return status;
-}
-
-NTSTATUS
-UnplugGetInterface(
-    IN      PXENFILT_UNPLUG_CONTEXT Context,
-    IN      ULONG                   Version,
-    IN OUT  PINTERFACE              Interface,
-    IN      ULONG                   Size
-    )
-{
-    NTSTATUS                        status;
-
-    ASSERT(Context != NULL);
-
-    switch (Version) {
-    case 1: {
-        struct _XENFILT_UNPLUG_INTERFACE_V1 *UnplugInterface;
-
-        UnplugInterface = (struct _XENFILT_UNPLUG_INTERFACE_V1 *)Interface;
-
-        status = STATUS_BUFFER_OVERFLOW;
-        if (Size < sizeof (struct _XENFILT_UNPLUG_INTERFACE_V1))
-            break;
-
-        *UnplugInterface = UnplugInterfaceVersion1;
-
-        ASSERT3U(Interface->Version, ==, Version);
-        Interface->Context = Context;
-
-        status = STATUS_SUCCESS;
-        break;
-    }
-    default:
-        status = STATUS_NOT_SUPPORTED;
-        break;
-    }
-
-    return status;
-}   
-
-VOID
-UnplugTeardown(
-    IN  PXENFILT_UNPLUG_CONTEXT Context
-    )
-{
-    Trace("====>\n");
-
-    Context->BootEmulated = FALSE;
-    Context->UnplugNics = FALSE;
-    Context->UnplugDisks = FALSE;
-
-    RtlZeroMemory(&Context->UnplugLock, sizeof (HIGH_LOCK));
-    RtlZeroMemory(&Context->Lock, sizeof (KSPIN_LOCK));
-
-    ASSERT(IsZeroMemory(Context, sizeof (XENFILT_UNPLUG_CONTEXT)));
-    __UnplugFree(Context);
-
-    Trace("<====\n");
-}
diff --git a/src/xenfilt/unplug.h b/src/xenfilt/unplug.h
deleted file mode 100644
index 191d8e2..0000000
--- a/src/xenfilt/unplug.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/* Copyright (c) Citrix Systems Inc.
- * All rights reserved.
- * 
- * Redistribution and use in source and binary forms, 
- * with or without modification, are permitted provided 
- * that the following conditions are met:
- * 
- * *   Redistributions of source code must retain the above 
- *     copyright notice, this list of conditions and the 
- *     following disclaimer.
- * *   Redistributions in binary form must reproduce the above 
- *     copyright notice, this list of conditions and the 
- *     following disclaimer in the documentation and/or other 
- *     materials provided with the distribution.
- * 
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 
- * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, 
- * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 
- * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR 
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 
- * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
- * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 
- * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 
- * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 
- * SUCH DAMAGE.
- */
-
-#ifndef _XENFILT_UNPLUG_H
-#define _XENFILT_UNPLUG_H
-
-#include <ntddk.h>
-#include <xen.h>
-#include <unplug_interface.h>
-
-typedef struct _XENFILT_UNPLUG_CONTEXT  XENFILT_UNPLUG_CONTEXT, 
*PXENFILT_UNPLUG_CONTEXT;
-
-extern NTSTATUS
-UnplugInitialize(
-    OUT PXENFILT_UNPLUG_CONTEXT *Context
-    );
-
-extern NTSTATUS
-UnplugGetInterface(
-    IN      PXENFILT_UNPLUG_CONTEXT Context,
-    IN      ULONG                   Version,
-    IN OUT  PINTERFACE              Interface,
-    IN      ULONG                   Size
-    );
-
-extern VOID
-UnplugTeardown(
-    IN  PXENFILT_UNPLUG_CONTEXT Context
-    );
-
-#endif  // _XENFILT_UNPLUG_H
diff --git a/vs2012/xen/xen.vcxproj b/vs2012/xen/xen.vcxproj
index df966af..0ffb844 100644
--- a/vs2012/xen/xen.vcxproj
+++ b/vs2012/xen/xen.vcxproj
@@ -90,6 +90,7 @@
     <ClCompile Include="..\..\src\xen\process.c" />
     <ClCompile Include="..\..\src\xen\acpi.c" />
     <ClCompile Include="..\..\src\xen\system.c" />
+    <ClCompile Include="..\..\src\xen\unplug.c" />
   </ItemGroup>
   <ItemGroup>
     <MASM Include="..\..\src\xen\amd64\hypercall_thunk.asm">
diff --git a/vs2012/xenbus/xenbus.vcxproj b/vs2012/xenbus/xenbus.vcxproj
index ab78a02..82f0dbf 100644
--- a/vs2012/xenbus/xenbus.vcxproj
+++ b/vs2012/xenbus/xenbus.vcxproj
@@ -94,6 +94,7 @@
     <ClCompile Include="..\..\src\xenbus\balloon.c" />
     <ClCompile Include="..\..\src\xenbus\cache.c" />
     <ClCompile Include="..\..\src\xenbus\hash_table.c" />
+    <ClCompile Include="..\..\src\xenbus\unplug.c" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="..\..\src\xenbus\xenbus.rc" />
diff --git a/vs2012/xenfilt/xenfilt.vcxproj b/vs2012/xenfilt/xenfilt.vcxproj
index 34efda4..4d5747d 100644
--- a/vs2012/xenfilt/xenfilt.vcxproj
+++ b/vs2012/xenfilt/xenfilt.vcxproj
@@ -68,7 +68,6 @@
   <ItemGroup>
     <ClCompile Include="../../src/common/registry.c" />
     <ClCompile Include="../../src/xenfilt/driver.c" />
-    <ClCompile Include="../../src/xenfilt/unplug.c" />
     <ClCompile Include="../../src/xenfilt/emulated.c" />
     <ClCompile Include="../../src/xenfilt/fdo.c" />
     <ClCompile Include="../../src/xenfilt/pdo.c" />
diff --git a/vs2013/xen/xen.vcxproj b/vs2013/xen/xen.vcxproj
index cd40452..9330d8d 100644
--- a/vs2013/xen/xen.vcxproj
+++ b/vs2013/xen/xen.vcxproj
@@ -93,6 +93,7 @@
     <ClCompile Include="..\..\src\xen\process.c" />
     <ClCompile Include="..\..\src\xen\acpi.c" />
     <ClCompile Include="..\..\src\xen\system.c" />
+    <ClCompile Include="..\..\src\xen\unplug.c" />
   </ItemGroup>
   <ItemGroup>
     <MASM Include="..\..\src\xen\amd64\hypercall_thunk.asm">
diff --git a/vs2013/xenbus/xenbus.vcxproj b/vs2013/xenbus/xenbus.vcxproj
index ca486c9..fb0b0dd 100644
--- a/vs2013/xenbus/xenbus.vcxproj
+++ b/vs2013/xenbus/xenbus.vcxproj
@@ -97,6 +97,7 @@
     <ClCompile Include="..\..\src\xenbus\balloon.c" />
     <ClCompile Include="..\..\src\xenbus\cache.c" />
     <ClCompile Include="..\..\src\xenbus\hash_table.c" />
+    <ClCompile Include="..\..\src\xenbus\unplug.c" />
   </ItemGroup>
   <ItemGroup>
     <ResourceCompile Include="..\..\src\xenbus\xenbus.rc" />
diff --git a/vs2013/xenfilt/xenfilt.vcxproj b/vs2013/xenfilt/xenfilt.vcxproj
index db4a437..4f749b1 100644
--- a/vs2013/xenfilt/xenfilt.vcxproj
+++ b/vs2013/xenfilt/xenfilt.vcxproj
@@ -71,7 +71,6 @@
   <ItemGroup>
     <ClCompile Include="../../src/common/registry.c" />
     <ClCompile Include="../../src/xenfilt/driver.c" />
-    <ClCompile Include="../../src/xenfilt/unplug.c" />
     <ClCompile Include="../../src/xenfilt/emulated.c" />
     <ClCompile Include="../../src/xenfilt/fdo.c" />
     <ClCompile Include="../../src/xenfilt/pdo.c" />
-- 
2.1.1


_______________________________________________
win-pv-devel mailing list
win-pv-devel@xxxxxxxxxxxxxxxxxxxx
http://lists.xenproject.org/cgi-bin/mailman/listinfo/win-pv-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.