Home | History | Annotate | Download | only in XenBusDxe
      1 /** @file
      2   XenBus Bus driver implemtation.
      3 
      4   This file implement the necessary to discover and enumerate Xen PV devices
      5   through XenStore.
      6 
      7   Copyright (C) 2010 Spectra Logic Corporation
      8   Copyright (C) 2008 Doug Rabson
      9   Copyright (C) 2005 Rusty Russell, IBM Corporation
     10   Copyright (C) 2005 Mike Wray, Hewlett-Packard
     11   Copyright (C) 2005 XenSource Ltd
     12   Copyright (C) 2014, Citrix Ltd.
     13 
     14   This file may be distributed separately from the Linux kernel, or
     15   incorporated into other software packages, subject to the following license:
     16 
     17   Permission is hereby granted, free of charge, to any person obtaining a copy
     18   of this source file (the "Software"), to deal in the Software without
     19   restriction, including without limitation the rights to use, copy, modify,
     20   merge, publish, distribute, sublicense, and/or sell copies of the Software,
     21   and to permit persons to whom the Software is furnished to do so, subject to
     22   the following conditions:
     23 
     24   The above copyright notice and this permission notice shall be included in
     25   all copies or substantial portions of the Software.
     26 
     27   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     28   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     29   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     30   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     31   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     32   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     33   IN THE SOFTWARE.
     34 **/
     35 
     36 #include <Library/PrintLib.h>
     37 
     38 #include "XenBus.h"
     39 #include "GrantTable.h"
     40 #include "XenStore.h"
     41 #include "EventChannel.h"
     42 
     43 #include <IndustryStandard/Xen/io/xenbus.h>
     44 
     45 STATIC XENBUS_PRIVATE_DATA gXenBusPrivateData;
     46 
     47 STATIC XENBUS_DEVICE_PATH gXenBusDevicePathTemplate = {
     48   {                                                 // Vendor
     49     {                                               // Vendor.Header
     50       HARDWARE_DEVICE_PATH,                         // Vendor.Header.Type
     51       HW_VENDOR_DP,                                 // Vendor.Header.SubType
     52       {
     53         (UINT8) (sizeof (XENBUS_DEVICE_PATH)),      // Vendor.Header.Length[0]
     54         (UINT8) (sizeof (XENBUS_DEVICE_PATH) >> 8), // Vendor.Header.Length[1]
     55       }
     56     },
     57     XENBUS_PROTOCOL_GUID,                           // Vendor.Guid
     58   },
     59   0,                                                // Type
     60   0                                                 // DeviceId
     61 };
     62 
     63 
     64 /**
     65   Search our internal record of configured devices (not the XenStore) to
     66   determine if the XenBus device indicated by Node is known to the system.
     67 
     68   @param Dev   The XENBUS_DEVICE instance to search for device children.
     69   @param Node  The XenStore node path for the device to find.
     70 
     71   @return  The XENBUS_PRIVATE_DATA of the found device if any, or NULL.
     72  */
     73 STATIC
     74 XENBUS_PRIVATE_DATA *
     75 XenBusDeviceInitialized (
     76   IN XENBUS_DEVICE *Dev,
     77   IN CONST CHAR8 *Node
     78   )
     79 {
     80   LIST_ENTRY *Entry;
     81   XENBUS_PRIVATE_DATA *Child;
     82   XENBUS_PRIVATE_DATA *Result;
     83 
     84   if (IsListEmpty (&Dev->ChildList)) {
     85     return NULL;
     86   }
     87 
     88   Result = NULL;
     89   for (Entry = GetFirstNode (&Dev->ChildList);
     90        !IsNodeAtEnd (&Dev->ChildList, Entry);
     91        Entry = GetNextNode (&Dev->ChildList, Entry)) {
     92     Child = XENBUS_PRIVATE_DATA_FROM_LINK (Entry);
     93     if (!AsciiStrCmp (Child->XenBusIo.Node, Node)) {
     94       Result = Child;
     95       break;
     96     }
     97   }
     98 
     99   return (Result);
    100 }
    101 
    102 STATIC
    103 XenbusState
    104 XenBusReadDriverState (
    105   IN CONST CHAR8 *Path
    106   )
    107 {
    108   XenbusState State;
    109   CHAR8 *Ptr = NULL;
    110   XENSTORE_STATUS Status;
    111 
    112   Status = XenStoreRead (XST_NIL, Path, "state", NULL, (VOID **)&Ptr);
    113   if (Status != XENSTORE_STATUS_SUCCESS) {
    114     State = XenbusStateClosed;
    115   } else {
    116     State = AsciiStrDecimalToUintn (Ptr);
    117   }
    118 
    119   if (Ptr != NULL) {
    120     FreePool (Ptr);
    121   }
    122 
    123   return State;
    124 }
    125 
    126 //
    127 // Callers should ensure that they are only one calling XenBusAddDevice.
    128 //
    129 STATIC
    130 EFI_STATUS
    131 XenBusAddDevice (
    132   XENBUS_DEVICE *Dev,
    133   CONST CHAR8 *Type,
    134   CONST CHAR8 *Id)
    135 {
    136   CHAR8 DevicePath[XENSTORE_ABS_PATH_MAX];
    137   XENSTORE_STATUS StatusXenStore;
    138   XENBUS_PRIVATE_DATA *Private;
    139   EFI_STATUS Status;
    140   XENBUS_DEVICE_PATH *TempXenBusPath;
    141   VOID *ChildXenIo;
    142 
    143   AsciiSPrint (DevicePath, sizeof (DevicePath),
    144                "device/%a/%a", Type, Id);
    145 
    146   if (XenStorePathExists (XST_NIL, DevicePath, "")) {
    147     XENBUS_PRIVATE_DATA *Child;
    148     enum xenbus_state State;
    149     CHAR8 *BackendPath;
    150 
    151     Child = XenBusDeviceInitialized (Dev, DevicePath);
    152     if (Child != NULL) {
    153       /*
    154        * We are already tracking this node
    155        */
    156       Status = EFI_SUCCESS;
    157       goto out;
    158     }
    159 
    160     State = XenBusReadDriverState (DevicePath);
    161     if (State != XenbusStateInitialising) {
    162       /*
    163        * Device is not new, so ignore it. This can
    164        * happen if a device is going away after
    165        * switching to Closed.
    166        */
    167       DEBUG ((EFI_D_INFO, "XenBus: Device %a ignored. "
    168               "State %d\n", DevicePath, State));
    169       Status = EFI_SUCCESS;
    170       goto out;
    171     }
    172 
    173     StatusXenStore = XenStoreRead (XST_NIL, DevicePath, "backend",
    174                                    NULL, (VOID **) &BackendPath);
    175     if (StatusXenStore != XENSTORE_STATUS_SUCCESS) {
    176       DEBUG ((EFI_D_ERROR, "xenbus: %a no backend path.\n", DevicePath));
    177       Status = EFI_NOT_FOUND;
    178       goto out;
    179     }
    180 
    181     Private = AllocateCopyPool (sizeof (*Private), &gXenBusPrivateData);
    182     Private->XenBusIo.Type = AsciiStrDup (Type);
    183     Private->XenBusIo.Node = AsciiStrDup (DevicePath);
    184     Private->XenBusIo.Backend = BackendPath;
    185     Private->XenBusIo.DeviceId = (UINT16)AsciiStrDecimalToUintn (Id);
    186     Private->Dev = Dev;
    187 
    188     TempXenBusPath = AllocateCopyPool (sizeof (XENBUS_DEVICE_PATH),
    189                                        &gXenBusDevicePathTemplate);
    190     if (!AsciiStrCmp (Private->XenBusIo.Type, "vbd")) {
    191       TempXenBusPath->Type = XENBUS_DEVICE_PATH_TYPE_VBD;
    192     }
    193     TempXenBusPath->DeviceId = Private->XenBusIo.DeviceId;
    194     Private->DevicePath = (XENBUS_DEVICE_PATH *)AppendDevicePathNode (
    195                             Dev->DevicePath,
    196                             &TempXenBusPath->Vendor.Header);
    197     FreePool (TempXenBusPath);
    198 
    199     InsertTailList (&Dev->ChildList, &Private->Link);
    200 
    201     Status = gBS->InstallMultipleProtocolInterfaces (
    202                &Private->Handle,
    203                &gEfiDevicePathProtocolGuid, Private->DevicePath,
    204                &gXenBusProtocolGuid, &Private->XenBusIo,
    205                NULL);
    206     if (EFI_ERROR (Status)) {
    207       goto ErrorInstallProtocol;
    208     }
    209 
    210     Status = gBS->OpenProtocol (Dev->ControllerHandle,
    211                &gXenIoProtocolGuid,
    212                &ChildXenIo, Dev->This->DriverBindingHandle,
    213                Private->Handle,
    214                EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);
    215     if (EFI_ERROR (Status)) {
    216       DEBUG ((EFI_D_ERROR, "open by child controller fail (%r)\n",
    217               Status));
    218       goto ErrorOpenProtocolByChild;
    219     }
    220   } else {
    221     DEBUG ((EFI_D_ERROR, "XenBus: does not exist: %a\n", DevicePath));
    222     Status = EFI_NOT_FOUND;
    223   }
    224 
    225   return Status;
    226 
    227 ErrorOpenProtocolByChild:
    228   gBS->UninstallMultipleProtocolInterfaces (
    229     &Private->Handle,
    230     &gEfiDevicePathProtocolGuid, Private->DevicePath,
    231     &gXenBusProtocolGuid, &Private->XenBusIo,
    232     NULL);
    233 ErrorInstallProtocol:
    234   RemoveEntryList (&Private->Link);
    235   FreePool (Private->DevicePath);
    236   FreePool ((VOID *) Private->XenBusIo.Backend);
    237   FreePool ((VOID *) Private->XenBusIo.Node);
    238   FreePool ((VOID *) Private->XenBusIo.Type);
    239   FreePool (Private);
    240 out:
    241   return Status;
    242 }
    243 
    244 /**
    245   Enumerate all devices of the given type on this bus.
    246 
    247   @param Dev   A XENBUS_DEVICE instance.
    248   @param Type  String indicating the device sub-tree (e.g. "vfb", "vif")
    249                to enumerate.
    250 
    251   Devices that are found are been initialize via XenBusAddDevice ().
    252   XenBusAddDevice () ignores duplicate detects and ignores duplicate devices,
    253   so it can be called unconditionally for any device found in the XenStore.
    254  */
    255 STATIC
    256 VOID
    257 XenBusEnumerateDeviceType (
    258   XENBUS_DEVICE *Dev,
    259   CONST CHAR8 *Type
    260   )
    261 {
    262   CONST CHAR8 **Directory;
    263   UINTN Index;
    264   UINT32 Count;
    265   XENSTORE_STATUS Status;
    266 
    267   Status = XenStoreListDirectory (XST_NIL,
    268                                   "device", Type,
    269                                   &Count, &Directory);
    270   if (Status != XENSTORE_STATUS_SUCCESS) {
    271     return;
    272   }
    273   for (Index = 0; Index < Count; Index++) {
    274     XenBusAddDevice (Dev, Type, Directory[Index]);
    275   }
    276 
    277   FreePool ((VOID*)Directory);
    278 }
    279 
    280 
    281 /**
    282   Enumerate the devices on a XenBus bus and install a XenBus Protocol instance.
    283 
    284   Caller should ensure that it is the only one to call this function. This
    285   function cannot be called concurrently.
    286 
    287   @param Dev   A XENBUS_DEVICE instance.
    288 
    289   @return  On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value
    290            indicating the type of failure.
    291  */
    292 XENSTORE_STATUS
    293 XenBusEnumerateBus (
    294   XENBUS_DEVICE *Dev
    295   )
    296 {
    297   CONST CHAR8 **Types;
    298   UINTN Index;
    299   UINT32 Count;
    300   XENSTORE_STATUS Status;
    301 
    302   Status = XenStoreListDirectory (XST_NIL,
    303                                   "device", "",
    304                                   &Count, &Types);
    305   if (Status != XENSTORE_STATUS_SUCCESS) {
    306     return Status;
    307   }
    308 
    309   for (Index = 0; Index < Count; Index++) {
    310     XenBusEnumerateDeviceType (Dev, Types[Index]);
    311   }
    312 
    313   FreePool ((VOID*)Types);
    314 
    315   return XENSTORE_STATUS_SUCCESS;
    316 }
    317 
    318 STATIC
    319 XENSTORE_STATUS
    320 EFIAPI
    321 XenBusSetState (
    322   IN XENBUS_PROTOCOL      *This,
    323   IN CONST XENSTORE_TRANSACTION *Transaction,
    324   IN enum xenbus_state    NewState
    325   )
    326 {
    327   enum xenbus_state CurrentState;
    328   XENSTORE_STATUS Status;
    329   CHAR8 *Temp;
    330 
    331   DEBUG ((EFI_D_INFO, "XenBus: Set state to %d\n", NewState));
    332 
    333   Status = XenStoreRead (Transaction, This->Node, "state", NULL, (VOID **)&Temp);
    334   if (Status != XENSTORE_STATUS_SUCCESS) {
    335     goto Out;
    336   }
    337   CurrentState = AsciiStrDecimalToUintn (Temp);
    338   FreePool (Temp);
    339   if (CurrentState == NewState) {
    340     goto Out;
    341   }
    342 
    343   do {
    344     Status = XenStoreSPrint (Transaction, This->Node, "state", "%d", NewState);
    345   } while (Status == XENSTORE_STATUS_EAGAIN);
    346   if (Status != XENSTORE_STATUS_SUCCESS) {
    347     DEBUG ((EFI_D_ERROR, "XenBus: failed to write new state\n"));
    348     goto Out;
    349   }
    350   DEBUG ((EFI_D_INFO, "XenBus: Set state to %d, done\n", NewState));
    351 
    352 Out:
    353   return Status;
    354 }
    355 
    356 STATIC XENBUS_PRIVATE_DATA gXenBusPrivateData = {
    357   XENBUS_PRIVATE_DATA_SIGNATURE,    // Signature
    358   { NULL, NULL },                   // Link
    359   NULL,                             // Handle
    360   {                                 // XenBusIo
    361     XenBusXenStoreRead,             // XenBusIo.XsRead
    362     XenBusXenStoreBackendRead,      // XenBusIo.XsBackendRead
    363     XenBusXenStoreSPrint,           // XenBusIo.XsPrintf
    364     XenBusXenStoreRemove,           // XenBusIo.XsRemove
    365     XenBusXenStoreTransactionStart, // XenBusIo.XsTransactionStart
    366     XenBusXenStoreTransactionEnd,   // XenBusIo.XsTransactionEnd
    367     XenBusSetState,                 // XenBusIo.SetState
    368     XenBusGrantAccess,              // XenBusIo.GrantAccess
    369     XenBusGrantEndAccess,           // XenBusIo.GrantEndAccess
    370     XenBusEventChannelAllocate,     // XenBusIo.EventChannelAllocate
    371     XenBusEventChannelNotify,       // XenBusIo.EventChannelNotify
    372     XenBusEventChannelClose,        // XenBusIo.EventChannelClose
    373     XenBusRegisterWatch,            // XenBusIo.RegisterWatch
    374     XenBusRegisterWatchBackend,     // XenBusIo.RegisterWatchBackend
    375     XenBusUnregisterWatch,          // XenBusIo.UnregisterWatch
    376     XenBusWaitForWatch,             // XenBusIo.WaitForWatch
    377 
    378     NULL,                           // XenBusIo.Type
    379     0,                              // XenBusIo.DeviceId
    380     NULL,                           // XenBusIo.Node
    381     NULL,                           // XenBusIo.Backend
    382   },
    383 
    384   NULL,                             // Dev
    385   NULL                              // DevicePath
    386 };
    387