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

[Xen-devel] [PATCH 09/11] OvmfPkg/XenBusDxe: Fix NotifyExitBoot to avoid Memory Allocation Services



This patch fix the EVT_SIGNAL_EXIT_BOOT_SERVICES handler to avoid
using the Memory Allocation Services.

This comes with a new interface named RegisterExitCallback so that PV
drivers can disconnect from the backend before XenBusDxe is teared
down.

Instead of using Disconnect() to tear down the XenBus driver and the
children drivers, we are going to ask every driver using
XENBUS_PROTOCOL to disconnect from the hardware via the callback set
with RegisterExitCallback, then reset the xenstore shared ring and
the grant table.

Since there are no driver using RegisterExitCallback yet, no driver are
going to be disconnected. Linux can deal with that. And that will be
fixed by the next patch with a change for XenPvBlkDxe.

Ref: https://bugzilla.tianocore.org/show_bug.cgi?id=2190
Signed-off-by: Anthony PERARD <anthony.perard@xxxxxxxxxx>
---
 OvmfPkg/Include/Protocol/XenBus.h | 35 +++++++++++++++++++++++++++++++
 OvmfPkg/XenBusDxe/XenBus.c        | 18 ++++++++++++++++
 OvmfPkg/XenBusDxe/XenBusDxe.c     | 27 +++++++++++++++++++++---
 OvmfPkg/XenBusDxe/XenBusDxe.h     |  2 ++
 OvmfPkg/XenBusDxe/XenStore.c      | 22 ++++++++++++++++++-
 OvmfPkg/XenBusDxe/XenStore.h      | 21 +++++++++++++++++++
 6 files changed, 121 insertions(+), 4 deletions(-)

diff --git a/OvmfPkg/Include/Protocol/XenBus.h 
b/OvmfPkg/Include/Protocol/XenBus.h
index c22bdfb368..04986747c8 100644
--- a/OvmfPkg/Include/Protocol/XenBus.h
+++ b/OvmfPkg/Include/Protocol/XenBus.h
@@ -373,6 +373,38 @@ XENSTORE_STATUS
   IN VOID             *Token
   );
 
+typedef
+VOID
+(EFIAPI *XENBUS_EXIT_CALLBACK)(
+  IN  VOID                     *Context
+  );
+
+/**
+  Register a function to be called during the ExitBootServices event.
+
+  NotifyFunction will be called when XenBusDxe is notified of
+  EVT_SIGNAL_EXIT_BOOT_SERVICES. The function should follow the same
+  requirements as if it as registered an event on
+  EVT_SIGNAL_EXIT_BOOT_SERVICES, i.e. no use of the Memory Allocation
+  Services.
+
+  To unregister the function, call RegisterExitCallback with
+  NotifyFunction=NULL.
+
+  @note There can only be one callback per driver.
+
+  @param This             A pointer to the XENBUS_PROTOCOL.
+  @param NotifyFunction   The function to be called.
+  @param NotifyContext    A context.
+**/
+typedef
+VOID
+(EFIAPI *XENBUS_SET_EXIT_CALLBACK) (
+  IN XENBUS_PROTOCOL       *This,
+  IN XENBUS_EXIT_CALLBACK  NotifyFunction,
+  IN VOID                  *NotifyContext
+  );
+
 
 ///
 /// Protocol structure
@@ -400,6 +432,9 @@ struct _XENBUS_PROTOCOL {
   XENBUS_REGISTER_WATCH_BACKEND RegisterWatchBackend;
   XENBUS_UNREGISTER_WATCH       UnregisterWatch;
   XENBUS_WAIT_FOR_WATCH         WaitForWatch;
+
+  XENBUS_SET_EXIT_CALLBACK      RegisterExitCallback;
+
   //
   // Protocol data fields
   //
diff --git a/OvmfPkg/XenBusDxe/XenBus.c b/OvmfPkg/XenBusDxe/XenBus.c
index 78835ec7b3..54166505d2 100644
--- a/OvmfPkg/XenBusDxe/XenBus.c
+++ b/OvmfPkg/XenBusDxe/XenBus.c
@@ -343,6 +343,23 @@ XenBusSetState (
   return Status;
 }
 
+STATIC
+VOID
+EFIAPI
+XenBusRegisterExitCallback (
+  IN XENBUS_PROTOCOL       *This,
+  IN XENBUS_EXIT_CALLBACK  NotifyFunction,
+  IN VOID                  *NotifyContext
+  )
+{
+  XENBUS_PRIVATE_DATA *Dev;
+
+  Dev = XENBUS_PRIVATE_DATA_FROM_THIS (This);
+
+  Dev->ExitCallback = NotifyFunction;
+  Dev->ExitCallbackContext = NotifyContext;
+}
+
 STATIC XENBUS_PRIVATE_DATA gXenBusPrivateData = {
   XENBUS_PRIVATE_DATA_SIGNATURE,    // Signature
   { NULL, NULL },                   // Link
@@ -364,6 +381,7 @@ STATIC XENBUS_PRIVATE_DATA gXenBusPrivateData = {
     XenBusRegisterWatchBackend,     // XenBusIo.RegisterWatchBackend
     XenBusUnregisterWatch,          // XenBusIo.UnregisterWatch
     XenBusWaitForWatch,             // XenBusIo.WaitForWatch
+    XenBusRegisterExitCallback,     // XenBusIo.RegisterExitCallback
 
     NULL,                           // XenBusIo.Type
     0,                              // XenBusIo.DeviceId
diff --git a/OvmfPkg/XenBusDxe/XenBusDxe.c b/OvmfPkg/XenBusDxe/XenBusDxe.c
index 634c7b71eb..c71966a666 100644
--- a/OvmfPkg/XenBusDxe/XenBusDxe.c
+++ b/OvmfPkg/XenBusDxe/XenBusDxe.c
@@ -258,10 +258,31 @@ NotifyExitBoot (
   IN VOID *Context
   )
 {
-  XENBUS_DEVICE *Dev = Context;
+  XENBUS_DEVICE       *Dev;
+  LIST_ENTRY          *Entry;
+  XENBUS_PRIVATE_DATA *Child;
 
-  gBS->DisconnectController(Dev->ControllerHandle,
-                            Dev->This->DriverBindingHandle, NULL);
+  Dev = Context;
+
+  //
+  // First, ask every driver using xenbus to disconnect without
+  // deallocating memory.
+  //
+  for (Entry = GetFirstNode (&Dev->ChildList);
+       !IsNodeAtEnd (&Dev->ChildList, Entry);
+       Entry = GetNextNode (&Dev->ChildList, Entry)) {
+    Child = XENBUS_PRIVATE_DATA_FROM_LINK (Entry);
+    if (Child->ExitCallback != NULL) {
+      Child->ExitCallback (Child->ExitCallbackContext);
+    }
+  }
+
+  //
+  // Now, we can reset the devices used by XenBusDxe.
+  //
+  XenStoreResetWatches ();
+  XenStoreResetRing (Dev);
+  XenGrantTableDeinit (Dev);
 }
 
 /**
diff --git a/OvmfPkg/XenBusDxe/XenBusDxe.h b/OvmfPkg/XenBusDxe/XenBusDxe.h
index b1dcc3549c..0e91c24338 100644
--- a/OvmfPkg/XenBusDxe/XenBusDxe.h
+++ b/OvmfPkg/XenBusDxe/XenBusDxe.h
@@ -94,6 +94,8 @@ typedef struct {
     XENBUS_PROTOCOL XenBusIo;
     XENBUS_DEVICE *Dev;
     XENBUS_DEVICE_PATH *DevicePath;
+    XENBUS_EXIT_CALLBACK ExitCallback;
+    VOID *ExitCallbackContext;
 } XENBUS_PRIVATE_DATA;
 
 #define XENBUS_PRIVATE_DATA_FROM_THIS(a) \
diff --git a/OvmfPkg/XenBusDxe/XenStore.c b/OvmfPkg/XenBusDxe/XenStore.c
index cb2d9e1215..4026c8a829 100644
--- a/OvmfPkg/XenBusDxe/XenStore.c
+++ b/OvmfPkg/XenBusDxe/XenStore.c
@@ -1054,8 +1054,18 @@ XenStoreDeinit (
     }
   }
 
+  XenStoreResetRing (Dev);
+
   gBS->CloseEvent (xs.EventChannelEvent);
 
+  xs.XenStore = NULL;
+}
+
+VOID
+XenStoreResetRing (
+  IN XENBUS_DEVICE *Dev
+  )
+{
   if (xs.XenStore->server_features & XENSTORE_SERVER_FEATURE_RECONNECTION) {
     xs.XenStore->connection = XENSTORE_RECONNECT;
     XenEventChannelNotify (xs.Dev, xs.EventChannel);
@@ -1072,7 +1082,17 @@ XenStoreDeinit (
     xs.XenStore->req_cons = xs.XenStore->req_prod = 0;
     xs.XenStore->rsp_cons = xs.XenStore->rsp_prod = 0;
   }
-  xs.XenStore = NULL;
+}
+
+VOID
+XenStoreResetWatches (
+  VOID
+  )
+{
+  XENSTORE_STATUS     Status;
+
+  Status = XenStoreSingle (XST_NIL, XS_RESET_WATCHES, "", NULL, NULL, NULL);
+  ASSERT (Status == XENSTORE_STATUS_SUCCESS);
 }
 
 //
diff --git a/OvmfPkg/XenBusDxe/XenStore.h b/OvmfPkg/XenBusDxe/XenStore.h
index ca8c080433..62cd5e97bf 100644
--- a/OvmfPkg/XenBusDxe/XenStore.h
+++ b/OvmfPkg/XenBusDxe/XenStore.h
@@ -271,6 +271,27 @@ XenStoreDeinit (
   IN XENBUS_DEVICE *Dev
   );
 
+/**
+  Effectively reset all watches registered with xenstore.
+
+  To be used by ExitBootServices
+**/
+VOID
+XenStoreResetWatches (
+  VOID
+  );
+
+/**
+  Reset the xenstore shared ring before handing it over to the next
+  operating system.
+
+  To be used by ExitBootServices
+**/
+VOID
+XenStoreResetRing (
+  IN XENBUS_DEVICE *Dev
+  );
+
 
 //
 // XENBUS protocol
-- 
Anthony PERARD

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxxx
https://lists.xenproject.org/mailman/listinfo/xen-devel

 


Rackspace

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