--- /dev/null
+/** @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
#include "XenHypercall.h"\r
#include "GrantTable.h"\r
#include "XenStore.h"\r
+#include "XenBus.h"\r
\r
\r
///\r
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
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
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
\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
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