]> git.proxmox.com Git - mirror_edk2.git/commitdiff
OvmfPkg/XenBusDxe: Introduce XenBus support itself.
authorAnthony PERARD <anthony.perard@citrix.com>
Wed, 29 Oct 2014 06:51:18 +0000 (06:51 +0000)
committerjljusten <jljusten@Edk2>
Wed, 29 Oct 2014 06:51:18 +0000 (06:51 +0000)
This is a bus-like on top of XenStore. It will look for advertised
ParaVirtualized devices and initialize them by producing XenBus
protocol.

Change in V4:
- Replace the license by the commonly used file header text.
- Clean XenBus.h header (remove copyright that does not belong to the
  file anymore; and rewrite the brief description of the file)
- Fix description on the function

Change in V3:
- Insert to ChildList later, once populated.
- Remove XENBUS_XENSTORE_NODE macro.
- add comment to XenBusAddDevice and XenBusEnumerateBus about
  concurrency calls.
- Add a description to the introduced member to the protocol.

Change in V2:
- comment, file header
- Fix comment style
- Error handling in the main init function
- coding style
- Fix error path in add device.

Origin: FreeBSD 10.0
License: This patch adds XenBus.c which is under the MIT licence.
Contributed-under: TianoCore Contribution Agreement 1.0
Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Acked-by: Jordan Justen <jordan.l.justen@intel.com>
git-svn-id: https://svn.code.sf.net/p/edk2/code/trunk/edk2@16270 6f19259b-4bc3-4df7-8a09-765794883524

OvmfPkg/Include/Protocol/XenBus.h
OvmfPkg/XenBusDxe/XenBus.c [new file with mode: 0644]
OvmfPkg/XenBusDxe/XenBus.h [new file with mode: 0644]
OvmfPkg/XenBusDxe/XenBusDxe.c
OvmfPkg/XenBusDxe/XenBusDxe.h
OvmfPkg/XenBusDxe/XenBusDxe.inf

index 5693b3f28436846664093dc045a5bf8dbce4a6b6..8d1fb52c22a908fd08812008985280a21363ce1e 100644 (file)
@@ -198,6 +198,24 @@ XENSTORE_STATUS
   IN BOOLEAN                Abort\r
   );\r
 \r
+/**\r
+  Set a new state for the frontend of the PV driver.\r
+\r
+  @param This         A pointer to XENBUS_PROTOCOL instance.\r
+  @param Transaction  The transaction to end/commit.\r
+  @param State        The new state to apply.\r
+\r
+  @return  On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value\r
+           indicating the type of failure.\r
+**/\r
+typedef\r
+XENSTORE_STATUS\r
+(EFIAPI *XENBUS_SET_STATE)(\r
+  IN XENBUS_PROTOCOL        *This,\r
+  IN XENSTORE_TRANSACTION   Transaction,\r
+  IN XenBusState            State\r
+  );\r
+\r
 /**\r
   Grant access to the page Frame to the domain DomainId.\r
 \r
@@ -322,6 +340,7 @@ struct _XENBUS_PROTOCOL {
   XENBUS_XS_REMOVE              XsRemove;\r
   XENBUS_XS_TRANSACTION_START   XsTransactionStart;\r
   XENBUS_XS_TRANSACTION_END     XsTransactionEnd;\r
+  XENBUS_SET_STATE              SetState;\r
 \r
   XENBUS_GRANT_ACCESS           GrantAccess;\r
   XENBUS_GRANT_END_ACCESS       GrantEndAccess;\r
diff --git a/OvmfPkg/XenBusDxe/XenBus.c b/OvmfPkg/XenBusDxe/XenBus.c
new file mode 100644 (file)
index 0000000..edd2d95
--- /dev/null
@@ -0,0 +1,372 @@
+/** @file\r
+  XenBus Bus driver implemtation.\r
+\r
+  This file implement the necessary to discover and enumerate Xen PV devices\r
+  through XenStore.\r
+\r
+  Copyright (C) 2010 Spectra Logic Corporation\r
+  Copyright (C) 2008 Doug Rabson\r
+  Copyright (C) 2005 Rusty Russell, IBM Corporation\r
+  Copyright (C) 2005 Mike Wray, Hewlett-Packard\r
+  Copyright (C) 2005 XenSource Ltd\r
+  Copyright (C) 2014, Citrix Ltd.\r
+\r
+  This file may be distributed separately from the Linux kernel, or\r
+  incorporated into other software packages, subject to the following license:\r
+\r
+  Permission is hereby granted, free of charge, to any person obtaining a copy\r
+  of this source file (the "Software"), to deal in the Software without\r
+  restriction, including without limitation the rights to use, copy, modify,\r
+  merge, publish, distribute, sublicense, and/or sell copies of the Software,\r
+  and to permit persons to whom the Software is furnished to do so, subject to\r
+  the following conditions:\r
+\r
+  The above copyright notice and this permission notice shall be included in\r
+  all copies or substantial portions of the Software.\r
+\r
+  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
+  IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
+  FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
+  AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
+  LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
+  FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\r
+  IN THE SOFTWARE.\r
+**/\r
+\r
+#include <Library/PrintLib.h>\r
+\r
+#include "XenBus.h"\r
+#include "GrantTable.h"\r
+#include "XenStore.h"\r
+#include "EventChannel.h"\r
+\r
+#include <IndustryStandard/Xen/io/xenbus.h>\r
+\r
+STATIC XENBUS_PRIVATE_DATA gXenBusPrivateData;\r
+\r
+STATIC XENBUS_DEVICE_PATH gXenBusDevicePathTemplate = {\r
+  .Vendor.Header.Type = HARDWARE_DEVICE_PATH,\r
+  .Vendor.Header.SubType = HW_VENDOR_DP,\r
+  .Vendor.Header.Length[0] = (UINT8) sizeof (XENBUS_DEVICE_PATH),\r
+  .Vendor.Header.Length[1] = (UINT8) (sizeof (XENBUS_DEVICE_PATH) >> 8),\r
+  .Vendor.Guid = XENBUS_PROTOCOL_GUID,\r
+  .Type = 0,\r
+  .DeviceId = 0\r
+};\r
+\r
+\r
+/**\r
+  Search our internal record of configured devices (not the XenStore) to\r
+  determine if the XenBus device indicated by Node is known to the system.\r
+\r
+  @param Dev   The XENBUS_DEVICE instance to search for device children.\r
+  @param Node  The XenStore node path for the device to find.\r
+\r
+  @return  The XENBUS_PRIVATE_DATA of the found device if any, or NULL.\r
+ */\r
+STATIC\r
+XENBUS_PRIVATE_DATA *\r
+XenBusDeviceInitialized (\r
+  IN XENBUS_DEVICE *Dev,\r
+  IN CONST CHAR8 *Node\r
+  )\r
+{\r
+  LIST_ENTRY *Entry;\r
+  XENBUS_PRIVATE_DATA *Child;\r
+  XENBUS_PRIVATE_DATA *Result;\r
+\r
+  if (IsListEmpty (&Dev->ChildList)) {\r
+    return NULL;\r
+  }\r
+\r
+  Result = NULL;\r
+  for (Entry = GetFirstNode (&Dev->ChildList);\r
+       !IsNodeAtEnd (&Dev->ChildList, Entry);\r
+       Entry = GetNextNode (&Dev->ChildList, Entry)) {\r
+    Child = XENBUS_PRIVATE_DATA_FROM_LINK (Entry);\r
+    if (!AsciiStrCmp (Child->XenBusIo.Node, Node)) {\r
+      Result = Child;\r
+      break;\r
+    }\r
+  }\r
+\r
+  return (Result);\r
+}\r
+\r
+STATIC\r
+XenbusState\r
+XenBusReadDriverState (\r
+  IN CONST CHAR8 *Path\r
+  )\r
+{\r
+  XenbusState State;\r
+  CHAR8 *Ptr = NULL;\r
+  XENSTORE_STATUS Status;\r
+\r
+  Status = XenStoreRead (XST_NIL, Path, "state", NULL, (VOID **)&Ptr);\r
+  if (Status != XENSTORE_STATUS_SUCCESS) {\r
+    State = XenbusStateClosed;\r
+  } else {\r
+    State = AsciiStrDecimalToUintn (Ptr);\r
+  }\r
+\r
+  if (Ptr != NULL) {\r
+    FreePool (Ptr);\r
+  }\r
+\r
+  return State;\r
+}\r
+\r
+//\r
+// Callers should ensure that they are only one calling XenBusAddDevice.\r
+//\r
+STATIC\r
+EFI_STATUS\r
+XenBusAddDevice (\r
+  XENBUS_DEVICE *Dev,\r
+  CONST CHAR8 *Type,\r
+  CONST CHAR8 *Id)\r
+{\r
+  CHAR8 DevicePath[XENSTORE_ABS_PATH_MAX];\r
+  XENSTORE_STATUS StatusXenStore;\r
+  XENBUS_PRIVATE_DATA *Private;\r
+  EFI_STATUS Status;\r
+  XENBUS_DEVICE_PATH *TempXenBusPath;\r
+  VOID *ChildPciIo;\r
+\r
+  AsciiSPrint (DevicePath, sizeof (DevicePath),\r
+               "device/%a/%a", Type, Id);\r
+\r
+  if (XenStorePathExists (XST_NIL, DevicePath, "")) {\r
+    XENBUS_PRIVATE_DATA *Child;\r
+    enum xenbus_state State;\r
+    CHAR8 *BackendPath;\r
+\r
+    Child = XenBusDeviceInitialized (Dev, DevicePath);\r
+    if (Child != NULL) {\r
+      /*\r
+       * We are already tracking this node\r
+       */\r
+      Status = EFI_SUCCESS;\r
+      goto out;\r
+    }\r
+\r
+    State = XenBusReadDriverState (DevicePath);\r
+    if (State != XenbusStateInitialising) {\r
+      /*\r
+       * Device is not new, so ignore it. This can\r
+       * happen if a device is going away after\r
+       * switching to Closed.\r
+       */\r
+      DEBUG ((EFI_D_INFO, "XenBus: Device %a ignored. "\r
+              "State %d\n", DevicePath, State));\r
+      Status = EFI_SUCCESS;\r
+      goto out;\r
+    }\r
+\r
+    StatusXenStore = XenStoreRead (XST_NIL, DevicePath, "backend",\r
+                                   NULL, (VOID **) &BackendPath);\r
+    if (StatusXenStore != XENSTORE_STATUS_SUCCESS) {\r
+      DEBUG ((EFI_D_ERROR, "xenbus: %a no backend path.\n", DevicePath));\r
+      Status = EFI_NOT_FOUND;\r
+      goto out;\r
+    }\r
+\r
+    Private = AllocateCopyPool (sizeof (*Private), &gXenBusPrivateData);\r
+    Private->XenBusIo.Type = AsciiStrDup (Type);\r
+    Private->XenBusIo.Node = AsciiStrDup (DevicePath);\r
+    Private->XenBusIo.Backend = BackendPath;\r
+    Private->XenBusIo.DeviceId = AsciiStrDecimalToUintn (Id);\r
+    Private->Dev = Dev;\r
+\r
+    TempXenBusPath = AllocateCopyPool (sizeof (XENBUS_DEVICE_PATH),\r
+                                       &gXenBusDevicePathTemplate);\r
+    if (!AsciiStrCmp (Private->XenBusIo.Type, "vbd")) {\r
+      TempXenBusPath->Type = XENBUS_DEVICE_PATH_TYPE_VBD;\r
+    }\r
+    TempXenBusPath->DeviceId = Private->XenBusIo.DeviceId;\r
+    Private->DevicePath = (XENBUS_DEVICE_PATH *)AppendDevicePathNode (\r
+                            Dev->DevicePath,\r
+                            &TempXenBusPath->Vendor.Header);\r
+    FreePool (TempXenBusPath);\r
+\r
+    InsertTailList (&Dev->ChildList, &Private->Link);\r
+\r
+    Status = gBS->InstallMultipleProtocolInterfaces (\r
+               &Private->Handle,\r
+               &gEfiDevicePathProtocolGuid, Private->DevicePath,\r
+               &gXenBusProtocolGuid, &Private->XenBusIo,\r
+               NULL);\r
+    if (EFI_ERROR (Status)) {\r
+      goto ErrorInstallProtocol;\r
+    }\r
+\r
+    Status = gBS->OpenProtocol (Dev->ControllerHandle,\r
+               &gEfiPciIoProtocolGuid,\r
+               &ChildPciIo, Dev->This->DriverBindingHandle,\r
+               Private->Handle,\r
+               EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "open by child controller fail (%r)\n",\r
+              Status));\r
+      goto ErrorOpenProtocolByChild;\r
+    }\r
+  } else {\r
+    DEBUG ((EFI_D_ERROR, "XenBus: does not exist: %a\n", DevicePath));\r
+    Status = EFI_NOT_FOUND;\r
+  }\r
+\r
+  return Status;\r
+\r
+ErrorOpenProtocolByChild:\r
+  gBS->UninstallMultipleProtocolInterfaces (\r
+    &Private->Handle,\r
+    &gEfiDevicePathProtocolGuid, Private->DevicePath,\r
+    &gXenBusProtocolGuid, &Private->XenBusIo,\r
+    NULL);\r
+ErrorInstallProtocol:\r
+  RemoveEntryList (&Private->Link);\r
+  FreePool (Private->DevicePath);\r
+  FreePool ((VOID *) Private->XenBusIo.Backend);\r
+  FreePool ((VOID *) Private->XenBusIo.Node);\r
+  FreePool ((VOID *) Private->XenBusIo.Type);\r
+  FreePool (Private);\r
+out:\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Enumerate all devices of the given type on this bus.\r
+\r
+  @param Dev   A XENBUS_DEVICE instance.\r
+  @param Type  String indicating the device sub-tree (e.g. "vfb", "vif")\r
+               to enumerate.\r
+\r
+  Devices that are found are been initialize via XenBusAddDevice ().\r
+  XenBusAddDevice () ignores duplicate detects and ignores duplicate devices,\r
+  so it can be called unconditionally for any device found in the XenStore.\r
+ */\r
+STATIC\r
+VOID\r
+XenBusEnumerateDeviceType (\r
+  XENBUS_DEVICE *Dev,\r
+  CONST CHAR8 *Type\r
+  )\r
+{\r
+  CONST CHAR8 **Directory;\r
+  UINTN Index;\r
+  UINT32 Count;\r
+  XENSTORE_STATUS Status;\r
+\r
+  Status = XenStoreListDirectory (XST_NIL,\r
+                                  "device", Type,\r
+                                  &Count, &Directory);\r
+  if (Status != XENSTORE_STATUS_SUCCESS) {\r
+    return;\r
+  }\r
+  for (Index = 0; Index < Count; Index++) {\r
+    XenBusAddDevice (Dev, Type, Directory[Index]);\r
+  }\r
+\r
+  FreePool (Directory);\r
+}\r
+\r
+\r
+/**\r
+  Enumerate the devices on a XenBus bus and install a XenBus Protocol instance.\r
+\r
+  Caller should ensure that it is the only one to call this function. This\r
+  function cannot be called concurrently.\r
+\r
+  @param Dev   A XENBUS_DEVICE instance.\r
+\r
+  @return  On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value\r
+           indicating the type of failure.\r
+ */\r
+XENSTORE_STATUS\r
+XenBusEnumerateBus (\r
+  XENBUS_DEVICE *Dev\r
+  )\r
+{\r
+  CONST CHAR8 **Types;\r
+  UINTN Index;\r
+  UINT32 Count;\r
+  XENSTORE_STATUS Status;\r
+\r
+  Status = XenStoreListDirectory (XST_NIL,\r
+                                  "device", "",\r
+                                  &Count, &Types);\r
+  if (Status != XENSTORE_STATUS_SUCCESS) {\r
+    return Status;\r
+  }\r
+\r
+  for (Index = 0; Index < Count; Index++) {\r
+    XenBusEnumerateDeviceType (Dev, Types[Index]);\r
+  }\r
+\r
+  FreePool (Types);\r
+\r
+  return XENSTORE_STATUS_SUCCESS;\r
+}\r
+\r
+STATIC\r
+XENSTORE_STATUS\r
+EFIAPI\r
+XenBusSetState (\r
+  IN XENBUS_PROTOCOL      *This,\r
+  IN XENSTORE_TRANSACTION Transaction,\r
+  IN enum xenbus_state    NewState\r
+  )\r
+{\r
+  enum xenbus_state CurrentState;\r
+  XENSTORE_STATUS Status;\r
+  CHAR8 *Temp;\r
+\r
+  DEBUG ((EFI_D_INFO, "XenBus: Set state to %d\n", NewState));\r
+\r
+  Status = XenStoreRead (Transaction, This->Node, "state", NULL, (VOID **)&Temp);\r
+  if (Status != XENSTORE_STATUS_SUCCESS) {\r
+    goto Out;\r
+  }\r
+  CurrentState = AsciiStrDecimalToUintn (Temp);\r
+  FreePool (Temp);\r
+  if (CurrentState == NewState) {\r
+    goto Out;\r
+  }\r
+\r
+  do {\r
+    Status = XenStoreSPrint (Transaction, This->Node, "state", "%d", NewState);\r
+  } while (Status == XENSTORE_STATUS_EAGAIN);\r
+  if (Status != XENSTORE_STATUS_SUCCESS) {\r
+    DEBUG ((EFI_D_ERROR, "XenBus: failed to write new state\n"));\r
+    goto Out;\r
+  }\r
+  DEBUG ((EFI_D_INFO, "XenBus: Set state to %d, done\n", NewState));\r
+\r
+Out:\r
+  return Status;\r
+}\r
+\r
+STATIC XENBUS_PRIVATE_DATA gXenBusPrivateData = {\r
+  .Signature = XENBUS_PRIVATE_DATA_SIGNATURE,\r
+\r
+  .XenBusIo.XsRead = XenBusXenStoreRead,\r
+  .XenBusIo.XsBackendRead = XenBusXenStoreBackendRead,\r
+  .XenBusIo.XsPrintf = XenBusXenStoreSPrint,\r
+  .XenBusIo.XsRemove = XenBusXenStoreRemove,\r
+  .XenBusIo.XsTransactionStart = XenBusXenStoreTransactionStart,\r
+  .XenBusIo.XsTransactionEnd = XenBusXenStoreTransactionEnd,\r
+  .XenBusIo.SetState = XenBusSetState,\r
+  .XenBusIo.GrantAccess = XenBusGrantAccess,\r
+  .XenBusIo.GrantEndAccess = XenBusGrantEndAccess,\r
+  .XenBusIo.RegisterWatch = XenBusRegisterWatch,\r
+  .XenBusIo.RegisterWatchBackend = XenBusRegisterWatchBackend,\r
+  .XenBusIo.UnregisterWatch = XenBusUnregisterWatch,\r
+  .XenBusIo.WaitForWatch = XenBusWaitForWatch,\r
+\r
+  .XenBusIo.Type = NULL,\r
+  .XenBusIo.Node = NULL,\r
+  .XenBusIo.Backend = NULL,\r
+\r
+  .Dev = NULL\r
+};\r
diff --git a/OvmfPkg/XenBusDxe/XenBus.h b/OvmfPkg/XenBusDxe/XenBus.h
new file mode 100644 (file)
index 0000000..e96439a
--- /dev/null
@@ -0,0 +1,44 @@
+/** @file\r
+  XenBus Bus driver declarations.\r
+\r
+  Copyright (C) 2014, Citrix Ltd.\r
+\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+#ifndef _XEN_XENBUS_XENBUSB_H\r
+#define _XEN_XENBUS_XENBUSB_H\r
+\r
+#include "XenBusDxe.h"\r
+\r
+#define XENBUS_DEVICE_PATH_TYPE_VBD 0x1\r
+struct _XENBUS_DEVICE_PATH {\r
+  VENDOR_DEVICE_PATH  Vendor;\r
+  UINT8               Type;\r
+  UINT16              DeviceId;\r
+};\r
+\r
+\r
+/**\r
+  Perform XenBus bus enumeration and install protocol for children.\r
+\r
+  Caller should ensure that it is the only one to call this function. This\r
+  function cannot be called concurrently.\r
+\r
+  @param Dev   A XENBUS_DEVICE instance.\r
+\r
+  @return      On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value\r
+               indicating the type of failure.\r
+**/\r
+XENSTORE_STATUS\r
+XenBusEnumerateBus (\r
+  XENBUS_DEVICE *Dev\r
+  );\r
+\r
+#endif /* _XEN_XENBUS_XENBUSB_H */\r
index 679fe3b592e5274d13d0a2aa2d954d50c3e4bf68..7a7fd82d559d1a1604d8b4fa4ddc82798c72840d 100644 (file)
@@ -32,6 +32,7 @@
 #include "XenHypercall.h"\r
 #include "GrantTable.h"\r
 #include "XenStore.h"\r
+#include "XenBus.h"\r
 \r
 \r
 ///\r
@@ -286,6 +287,7 @@ XenBusDxeDriverBindingStart (
   EFI_PCI_IO_PROTOCOL *PciIo;\r
   EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc;\r
   UINT64 MmioAddr;\r
+  EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
 \r
   Status = gBS->OpenProtocol (\r
                      ControllerHandle,\r
@@ -299,11 +301,26 @@ XenBusDxeDriverBindingStart (
     return Status;\r
   }\r
 \r
+  Status = gBS->OpenProtocol (\r
+                  ControllerHandle,\r
+                  &gEfiDevicePathProtocolGuid,\r
+                  (VOID **) &DevicePath,\r
+                  This->DriverBindingHandle,\r
+                  ControllerHandle,\r
+                  EFI_OPEN_PROTOCOL_BY_DRIVER\r
+                  );\r
+\r
+  if (EFI_ERROR (Status)) {\r
+    goto ErrorOpenningProtocol;\r
+  }\r
+\r
   Dev = AllocateZeroPool (sizeof (*Dev));\r
   Dev->Signature = XENBUS_DEVICE_SIGNATURE;\r
   Dev->This = This;\r
   Dev->ControllerHandle = ControllerHandle;\r
   Dev->PciIo = PciIo;\r
+  Dev->DevicePath = DevicePath;\r
+  InitializeListHead (&Dev->ChildList);\r
 \r
   EfiAcquireLock (&mMyDeviceLock);\r
   if (mMyDevice != NULL) {\r
@@ -350,6 +367,8 @@ XenBusDxeDriverBindingStart (
   Status = XenStoreInit (Dev);\r
   ASSERT_EFI_ERROR (Status);\r
 \r
+  XenBusEnumerateBus (Dev);\r
+\r
   Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,\r
                              NotifyExitBoot,\r
                              (VOID*) Dev,\r
@@ -360,6 +379,9 @@ XenBusDxeDriverBindingStart (
 \r
 ErrorAllocated:\r
   FreePool (Dev);\r
+  gBS->CloseProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid,\r
+                      This->DriverBindingHandle, ControllerHandle);\r
+ErrorOpenningProtocol:\r
   gBS->CloseProtocol (ControllerHandle, &gEfiPciIoProtocolGuid,\r
                       This->DriverBindingHandle, ControllerHandle);\r
   return Status;\r
@@ -400,12 +422,56 @@ XenBusDxeDriverBindingStop (
   IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL\r
   )\r
 {\r
+  UINTN Index;\r
+  XENBUS_PROTOCOL *XenBusIo;\r
+  XENBUS_PRIVATE_DATA *ChildData;\r
+  EFI_STATUS Status;\r
   XENBUS_DEVICE *Dev = mMyDevice;\r
 \r
+  for (Index = 0; Index < NumberOfChildren; Index++) {\r
+    Status = gBS->OpenProtocol (\r
+               ChildHandleBuffer[Index],\r
+               &gXenBusProtocolGuid,\r
+               (VOID **) &XenBusIo,\r
+               This->DriverBindingHandle,\r
+               ControllerHandle,\r
+               EFI_OPEN_PROTOCOL_GET_PROTOCOL);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "XenBusDxe: get children protocol failed: %r\n", Status));\r
+      continue;\r
+    }\r
+    ChildData = XENBUS_PRIVATE_DATA_FROM_THIS (XenBusIo);\r
+    Status = gBS->DisconnectController (ChildData->Handle, NULL, NULL);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "XenBusDxe: error disconnecting child: %r\n",\r
+              Status));\r
+      continue;\r
+    }\r
+\r
+    Status = gBS->UninstallMultipleProtocolInterfaces (\r
+               ChildData->Handle,\r
+               &gEfiDevicePathProtocolGuid, ChildData->DevicePath,\r
+               &gXenBusProtocolGuid, &ChildData->XenBusIo,\r
+               NULL);\r
+    ASSERT_EFI_ERROR (Status);\r
+\r
+    FreePool ((VOID*)ChildData->XenBusIo.Type);\r
+    FreePool ((VOID*)ChildData->XenBusIo.Node);\r
+    FreePool ((VOID*)ChildData->XenBusIo.Backend);\r
+    FreePool (ChildData->DevicePath);\r
+    RemoveEntryList (&ChildData->Link);\r
+    FreePool (ChildData);\r
+  }\r
+  if (NumberOfChildren > 0) {\r
+    return EFI_SUCCESS;\r
+  }\r
+\r
   gBS->CloseEvent (Dev->ExitBootEvent);\r
   XenStoreDeinit (Dev);\r
   XenGrantTableDeinit (Dev);\r
 \r
+  gBS->CloseProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid,\r
+         This->DriverBindingHandle, ControllerHandle);\r
   gBS->CloseProtocol (ControllerHandle, &gEfiPciIoProtocolGuid,\r
          This->DriverBindingHandle, ControllerHandle);\r
 \r
index 6be5c58d920f11b065a72359afeedefbacf995d1..11640223ebf4dba90cf9817be67d0cd1497640aa 100644 (file)
@@ -82,6 +82,7 @@ extern EFI_COMPONENT_NAME_PROTOCOL  gXenBusDxeComponentName;
 #define PCI_DEVICE_ID_XEN_PLATFORM       0x0001\r
 \r
 \r
+typedef struct _XENBUS_DEVICE_PATH XENBUS_DEVICE_PATH;\r
 typedef struct _XENBUS_DEVICE XENBUS_DEVICE;\r
 \r
 // Have the state of the driver.\r
@@ -92,11 +93,29 @@ struct _XENBUS_DEVICE {
   EFI_HANDLE                    ControllerHandle;\r
   EFI_PCI_IO_PROTOCOL           *PciIo;\r
   EFI_EVENT                     ExitBootEvent;\r
+  EFI_DEVICE_PATH_PROTOCOL      *DevicePath;\r
+  LIST_ENTRY                    ChildList;\r
 \r
   VOID                          *Hyperpage;\r
   shared_info_t                 *SharedInfo;\r
 };\r
 \r
+// There is one of this struct allocated for every child.\r
+#define XENBUS_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('X', 'B', 'p', 'd')\r
+typedef struct {\r
+    UINTN Signature;\r
+    LIST_ENTRY Link;\r
+    EFI_HANDLE Handle;\r
+    XENBUS_PROTOCOL XenBusIo;\r
+    XENBUS_DEVICE *Dev;\r
+    XENBUS_DEVICE_PATH *DevicePath;\r
+} XENBUS_PRIVATE_DATA;\r
+\r
+#define XENBUS_PRIVATE_DATA_FROM_THIS(a) \\r
+  CR (a, XENBUS_PRIVATE_DATA, XenBusIo, XENBUS_PRIVATE_DATA_SIGNATURE)\r
+#define XENBUS_PRIVATE_DATA_FROM_LINK(a) \\r
+  CR (a, XENBUS_PRIVATE_DATA, Link, XENBUS_PRIVATE_DATA_SIGNATURE)\r
+\r
 /*\r
  * Helpers\r
  */\r
index 1343808ae3d884850b38775ee24b5693bcc0c27a..17a5a9073a58080172a2c446e475b6690717bece 100644 (file)
@@ -44,6 +44,9 @@
   EventChannel.h\r
   XenStore.c\r
   XenStore.h\r
+  XenBus.c\r
+  XenBus.h\r
+  Helpers.c\r
 \r
 [Sources.IA32]\r
   Ia32/hypercall.S\r