Home | History | Annotate | Download | only in XenBusDxe
      1 /** @file
      2   This driver produces XenBus Protocol instances for each Xen PV devices.
      3 
      4   This XenBus bus driver will first initialize differente services in order to
      5   enumerate the ParaVirtualized devices available.
      6 
      7   Those services are:
      8     - HyperCall
      9     - Event Channel
     10     - Grant Table
     11     - XenStore
     12     - XenBus
     13 
     14   Copyright (C) 2014, Citrix Ltd.
     15 
     16   This program and the accompanying materials
     17   are licensed and made available under the terms and conditions of the BSD License
     18   which accompanies this distribution.  The full text of the license may be found at
     19   http://opensource.org/licenses/bsd-license.php
     20 
     21   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     22   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     23 
     24 **/
     25 
     26 #include <Library/DebugLib.h>
     27 #include <Library/XenHypercallLib.h>
     28 
     29 #include "XenBusDxe.h"
     30 
     31 #include "GrantTable.h"
     32 #include "XenStore.h"
     33 #include "XenBus.h"
     34 
     35 #include <IndustryStandard/Xen/hvm/params.h>
     36 #include <IndustryStandard/Xen/memory.h>
     37 
     38 ///
     39 /// Driver Binding Protocol instance
     40 ///
     41 EFI_DRIVER_BINDING_PROTOCOL gXenBusDxeDriverBinding = {
     42   XenBusDxeDriverBindingSupported,
     43   XenBusDxeDriverBindingStart,
     44   XenBusDxeDriverBindingStop,
     45   XENBUS_DXE_VERSION,
     46   NULL,
     47   NULL
     48 };
     49 
     50 
     51 STATIC EFI_LOCK       mMyDeviceLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_CALLBACK);
     52 STATIC XENBUS_DEVICE *mMyDevice = NULL;
     53 
     54 /**
     55   Map the shared_info_t page into memory.
     56 
     57   @param Dev    A XENBUS_DEVICE instance.
     58 
     59   @retval EFI_SUCCESS     Dev->SharedInfo whill contain a pointer to
     60                           the shared info page
     61   @retval EFI_LOAD_ERROR  The shared info page could not be mapped. The
     62                           hypercall returned an error.
     63 **/
     64 STATIC
     65 EFI_STATUS
     66 XenGetSharedInfoPage (
     67   IN OUT XENBUS_DEVICE *Dev
     68   )
     69 {
     70   xen_add_to_physmap_t Parameter;
     71 
     72   ASSERT (Dev->SharedInfo == NULL);
     73 
     74   Parameter.domid = DOMID_SELF;
     75   Parameter.space = XENMAPSPACE_shared_info;
     76   Parameter.idx = 0;
     77 
     78   //
     79   // using reserved page because the page is not released when Linux is
     80   // starting because of the add_to_physmap. QEMU might try to access the
     81   // page, and fail because it have no right to do so (segv).
     82   //
     83   Dev->SharedInfo = AllocateReservedPages (1);
     84   Parameter.gpfn = (UINTN) Dev->SharedInfo >> EFI_PAGE_SHIFT;
     85   if (XenHypercallMemoryOp (XENMEM_add_to_physmap, &Parameter) != 0) {
     86     FreePages (Dev->SharedInfo, 1);
     87     Dev->SharedInfo = NULL;
     88     return EFI_LOAD_ERROR;
     89   }
     90 
     91   return EFI_SUCCESS;
     92 }
     93 
     94 /**
     95   Unloads an image.
     96 
     97   @param  ImageHandle           Handle that identifies the image to be unloaded.
     98 
     99   @retval EFI_SUCCESS           The image has been unloaded.
    100   @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
    101 
    102 **/
    103 EFI_STATUS
    104 EFIAPI
    105 XenBusDxeUnload (
    106   IN EFI_HANDLE  ImageHandle
    107   )
    108 {
    109   EFI_STATUS  Status;
    110 
    111   EFI_HANDLE  *HandleBuffer;
    112   UINTN       HandleCount;
    113   UINTN       Index;
    114 
    115   //
    116   // Retrieve array of all handles in the handle database
    117   //
    118   Status = gBS->LocateHandleBuffer (
    119                   AllHandles,
    120                   NULL,
    121                   NULL,
    122                   &HandleCount,
    123                   &HandleBuffer
    124                   );
    125   if (EFI_ERROR (Status)) {
    126     return Status;
    127   }
    128 
    129   //
    130   // Disconnect the current driver from handles in the handle database
    131   //
    132   for (Index = 0; Index < HandleCount; Index++) {
    133     gBS->DisconnectController (HandleBuffer[Index], gImageHandle, NULL);
    134   }
    135 
    136   //
    137   // Free the array of handles
    138   //
    139   FreePool (HandleBuffer);
    140 
    141 
    142   //
    143   // Uninstall protocols installed in the driver entry point
    144   //
    145   Status = gBS->UninstallMultipleProtocolInterfaces (
    146                   ImageHandle,
    147                   &gEfiDriverBindingProtocolGuid, &gXenBusDxeDriverBinding,
    148                   &gEfiComponentNameProtocolGuid,  &gXenBusDxeComponentName,
    149                   &gEfiComponentName2ProtocolGuid, &gXenBusDxeComponentName2,
    150                   NULL
    151                   );
    152   if (EFI_ERROR (Status)) {
    153     return Status;
    154   }
    155 
    156   return EFI_SUCCESS;
    157 }
    158 
    159 /**
    160   This is the declaration of an EFI image entry point. This entry point is
    161   the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
    162   both device drivers and bus drivers.
    163 
    164   @param  ImageHandle           The firmware allocated handle for the UEFI image.
    165   @param  SystemTable           A pointer to the EFI System Table.
    166 
    167   @retval EFI_SUCCESS           The operation completed successfully.
    168   @retval EFI_ABORTED           Xen hypercalls are not available.
    169   @retval Others                An unexpected error occurred.
    170 **/
    171 EFI_STATUS
    172 EFIAPI
    173 XenBusDxeDriverEntryPoint (
    174   IN EFI_HANDLE        ImageHandle,
    175   IN EFI_SYSTEM_TABLE  *SystemTable
    176   )
    177 {
    178   EFI_STATUS  Status;
    179 
    180   if (! XenHypercallIsAvailable ()) {
    181     return EFI_ABORTED;
    182   }
    183 
    184   //
    185   // Install UEFI Driver Model protocol(s).
    186   //
    187   Status = EfiLibInstallDriverBindingComponentName2 (
    188              ImageHandle,
    189              SystemTable,
    190              &gXenBusDxeDriverBinding,
    191              ImageHandle,
    192              &gXenBusDxeComponentName,
    193              &gXenBusDxeComponentName2
    194              );
    195   ASSERT_EFI_ERROR (Status);
    196 
    197 
    198   return Status;
    199 }
    200 
    201 
    202 /**
    203   Tests to see if this driver supports a given controller. If a child device is provided,
    204   it further tests to see if this driver supports creating a handle for the specified child device.
    205 
    206   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    207   @param[in]  ControllerHandle     The handle of the controller to test. This handle
    208                                    must support a protocol interface that supplies
    209                                    an I/O abstraction to the driver.
    210   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
    211                                    parameter is ignored by device drivers, and is optional for bus
    212                                    drivers. For bus drivers, if this parameter is not NULL, then
    213                                    the bus driver must determine if the bus controller specified
    214                                    by ControllerHandle and the child controller specified
    215                                    by RemainingDevicePath are both supported by this
    216                                    bus driver.
    217 
    218   @retval EFI_SUCCESS              The device specified by ControllerHandle and
    219                                    RemainingDevicePath is supported by the driver specified by This.
    220   @retval EFI_ALREADY_STARTED      The device specified by ControllerHandle and
    221                                    RemainingDevicePath is already being managed by the driver
    222                                    specified by This.
    223   @retval EFI_ACCESS_DENIED        The device specified by ControllerHandle and
    224                                    RemainingDevicePath is already being managed by a different
    225                                    driver or an application that requires exclusive access.
    226                                    Currently not implemented.
    227   @retval EFI_UNSUPPORTED          The device specified by ControllerHandle and
    228                                    RemainingDevicePath is not supported by the driver specified by This.
    229 **/
    230 EFI_STATUS
    231 EFIAPI
    232 XenBusDxeDriverBindingSupported (
    233   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    234   IN EFI_HANDLE                   ControllerHandle,
    235   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
    236   )
    237 {
    238   EFI_STATUS          Status;
    239   XENIO_PROTOCOL      *XenIo;
    240 
    241   Status = gBS->OpenProtocol (
    242                      ControllerHandle,
    243                      &gXenIoProtocolGuid,
    244                      (VOID **)&XenIo,
    245                      This->DriverBindingHandle,
    246                      ControllerHandle,
    247                      EFI_OPEN_PROTOCOL_BY_DRIVER
    248                      );
    249 
    250   if (EFI_ERROR (Status)) {
    251     return Status;
    252   }
    253 
    254   gBS->CloseProtocol (ControllerHandle, &gXenIoProtocolGuid,
    255          This->DriverBindingHandle, ControllerHandle);
    256 
    257   return Status;
    258 }
    259 
    260 VOID
    261 EFIAPI
    262 NotifyExitBoot (
    263   IN EFI_EVENT Event,
    264   IN VOID *Context
    265   )
    266 {
    267   XENBUS_DEVICE *Dev = Context;
    268 
    269   gBS->DisconnectController(Dev->ControllerHandle,
    270                             Dev->This->DriverBindingHandle, NULL);
    271 }
    272 
    273 /**
    274   Starts a bus controller.
    275 
    276   The Start() function is designed to be invoked from the EFI boot service ConnectController().
    277   As a result, much of the error checking on the parameters to Start() has been moved into this
    278   common boot service. It is legal to call Start() from other locations,
    279   but the following calling restrictions must be followed, or the system behavior will not be deterministic.
    280   1. ControllerHandle must be a valid EFI_HANDLE.
    281   2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
    282      EFI_DEVICE_PATH_PROTOCOL.
    283   3. Prior to calling Start(), the Supported() function for the driver specified by This must
    284      have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
    285 
    286   @param[in]  This                 A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    287   @param[in]  ControllerHandle     The handle of the controller to start. This handle
    288                                    must support a protocol interface that supplies
    289                                    an I/O abstraction to the driver.
    290   @param[in]  RemainingDevicePath  A pointer to the remaining portion of a device path.  This
    291                                    parameter is ignored by device drivers, and is optional for bus
    292                                    drivers. For a bus driver, if this parameter is NULL, then handles
    293                                    for all the children of Controller are created by this driver.
    294                                    If this parameter is not NULL and the first Device Path Node is
    295                                    not the End of Device Path Node, then only the handle for the
    296                                    child device specified by the first Device Path Node of
    297                                    RemainingDevicePath is created by this driver.
    298                                    If the first Device Path Node of RemainingDevicePath is
    299                                    the End of Device Path Node, no child handle is created by this
    300                                    driver.
    301 
    302   @retval EFI_SUCCESS              The device was started.
    303   @retval EFI_DEVICE_ERROR         The device could not be started due to a device error.Currently not implemented.
    304   @retval EFI_OUT_OF_RESOURCES     The request could not be completed due to a lack of resources.
    305   @retval EFI_UNSUPPORTED          Something is missing on the system that
    306                                    prevent to start the edvice.
    307   @retval Others                   The driver failded to start the device.
    308 
    309 **/
    310 EFI_STATUS
    311 EFIAPI
    312 XenBusDxeDriverBindingStart (
    313   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    314   IN EFI_HANDLE                   ControllerHandle,
    315   IN EFI_DEVICE_PATH_PROTOCOL     *RemainingDevicePath OPTIONAL
    316   )
    317 {
    318   EFI_STATUS Status;
    319   XENBUS_DEVICE *Dev;
    320   XENIO_PROTOCOL *XenIo;
    321   EFI_DEVICE_PATH_PROTOCOL *DevicePath;
    322 
    323   Status = gBS->OpenProtocol (
    324                      ControllerHandle,
    325                      &gXenIoProtocolGuid,
    326                      (VOID**)&XenIo,
    327                      This->DriverBindingHandle,
    328                      ControllerHandle,
    329                      EFI_OPEN_PROTOCOL_BY_DRIVER
    330                      );
    331 
    332   if (EFI_ERROR (Status)) {
    333     return Status;
    334   }
    335 
    336   Status = gBS->OpenProtocol (
    337                   ControllerHandle,
    338                   &gEfiDevicePathProtocolGuid,
    339                   (VOID **) &DevicePath,
    340                   This->DriverBindingHandle,
    341                   ControllerHandle,
    342                   EFI_OPEN_PROTOCOL_BY_DRIVER
    343                   );
    344 
    345   if (EFI_ERROR (Status)) {
    346     goto ErrorOpenningProtocol;
    347   }
    348 
    349   Dev = AllocateZeroPool (sizeof (*Dev));
    350   Dev->Signature = XENBUS_DEVICE_SIGNATURE;
    351   Dev->This = This;
    352   Dev->ControllerHandle = ControllerHandle;
    353   Dev->XenIo = XenIo;
    354   Dev->DevicePath = DevicePath;
    355   InitializeListHead (&Dev->ChildList);
    356 
    357   EfiAcquireLock (&mMyDeviceLock);
    358   if (mMyDevice != NULL) {
    359     EfiReleaseLock (&mMyDeviceLock);
    360     //
    361     // There is already a XenBus running, only one can be used at a time.
    362     //
    363     Status = EFI_ALREADY_STARTED;
    364     goto ErrorAllocated;
    365   }
    366   mMyDevice = Dev;
    367   EfiReleaseLock (&mMyDeviceLock);
    368 
    369   Status = XenGetSharedInfoPage (Dev);
    370   if (EFI_ERROR (Status)) {
    371     DEBUG ((EFI_D_ERROR, "XenBus: Unable to get the shared info page.\n"));
    372     Status = EFI_UNSUPPORTED;
    373     goto ErrorAllocated;
    374   }
    375 
    376   XenGrantTableInit (Dev);
    377 
    378   Status = XenStoreInit (Dev);
    379   ASSERT_EFI_ERROR (Status);
    380 
    381   XenBusEnumerateBus (Dev);
    382 
    383   Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,
    384                              NotifyExitBoot,
    385                              (VOID*) Dev,
    386                              &Dev->ExitBootEvent);
    387   ASSERT_EFI_ERROR (Status);
    388 
    389   return EFI_SUCCESS;
    390 
    391 ErrorAllocated:
    392   FreePool (Dev);
    393   gBS->CloseProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid,
    394                       This->DriverBindingHandle, ControllerHandle);
    395 ErrorOpenningProtocol:
    396   gBS->CloseProtocol (ControllerHandle, &gXenIoProtocolGuid,
    397                       This->DriverBindingHandle, ControllerHandle);
    398   return Status;
    399 }
    400 
    401 /**
    402   Stops a bus controller.
    403 
    404   The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
    405   As a result, much of the error checking on the parameters to Stop() has been moved
    406   into this common boot service. It is legal to call Stop() from other locations,
    407   but the following calling restrictions must be followed, or the system behavior will not be deterministic.
    408   1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
    409      same driver's Start() function.
    410   2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
    411      EFI_HANDLE. In addition, all of these handles must have been created in this driver's
    412      Start() function, and the Start() function must have called OpenProtocol() on
    413      ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
    414 
    415   @param[in]  This              A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
    416   @param[in]  ControllerHandle  A handle to the device being stopped. The handle must
    417                                 support a bus specific I/O protocol for the driver
    418                                 to use to stop the device.
    419   @param[in]  NumberOfChildren  The number of child device handles in ChildHandleBuffer.
    420   @param[in]  ChildHandleBuffer An array of child handles to be freed. May be NULL
    421                                 if NumberOfChildren is 0.
    422 
    423   @retval EFI_SUCCESS           The device was stopped.
    424   @retval EFI_DEVICE_ERROR      The device could not be stopped due to a device error.
    425 
    426 **/
    427 EFI_STATUS
    428 EFIAPI
    429 XenBusDxeDriverBindingStop (
    430   IN EFI_DRIVER_BINDING_PROTOCOL  *This,
    431   IN EFI_HANDLE                   ControllerHandle,
    432   IN UINTN                        NumberOfChildren,
    433   IN EFI_HANDLE                   *ChildHandleBuffer OPTIONAL
    434   )
    435 {
    436   UINTN Index;
    437   XENBUS_PROTOCOL *XenBusIo;
    438   XENBUS_PRIVATE_DATA *ChildData;
    439   EFI_STATUS Status;
    440   XENBUS_DEVICE *Dev = mMyDevice;
    441 
    442   for (Index = 0; Index < NumberOfChildren; Index++) {
    443     Status = gBS->OpenProtocol (
    444                ChildHandleBuffer[Index],
    445                &gXenBusProtocolGuid,
    446                (VOID **) &XenBusIo,
    447                This->DriverBindingHandle,
    448                ControllerHandle,
    449                EFI_OPEN_PROTOCOL_GET_PROTOCOL);
    450     if (EFI_ERROR (Status)) {
    451       DEBUG ((EFI_D_ERROR, "XenBusDxe: get children protocol failed: %r\n", Status));
    452       continue;
    453     }
    454     ChildData = XENBUS_PRIVATE_DATA_FROM_THIS (XenBusIo);
    455     Status = gBS->DisconnectController (ChildData->Handle, NULL, NULL);
    456     if (EFI_ERROR (Status)) {
    457       DEBUG ((EFI_D_ERROR, "XenBusDxe: error disconnecting child: %r\n",
    458               Status));
    459       continue;
    460     }
    461 
    462     Status = gBS->UninstallMultipleProtocolInterfaces (
    463                ChildData->Handle,
    464                &gEfiDevicePathProtocolGuid, ChildData->DevicePath,
    465                &gXenBusProtocolGuid, &ChildData->XenBusIo,
    466                NULL);
    467     ASSERT_EFI_ERROR (Status);
    468 
    469     FreePool ((VOID*)ChildData->XenBusIo.Type);
    470     FreePool ((VOID*)ChildData->XenBusIo.Node);
    471     FreePool ((VOID*)ChildData->XenBusIo.Backend);
    472     FreePool (ChildData->DevicePath);
    473     RemoveEntryList (&ChildData->Link);
    474     FreePool (ChildData);
    475   }
    476   if (NumberOfChildren > 0) {
    477     return EFI_SUCCESS;
    478   }
    479 
    480   gBS->CloseEvent (Dev->ExitBootEvent);
    481   XenStoreDeinit (Dev);
    482   XenGrantTableDeinit (Dev);
    483 
    484   gBS->CloseProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid,
    485          This->DriverBindingHandle, ControllerHandle);
    486   gBS->CloseProtocol (ControllerHandle, &gXenIoProtocolGuid,
    487          This->DriverBindingHandle, ControllerHandle);
    488 
    489   mMyDevice = NULL;
    490   FreePool (Dev);
    491   return EFI_SUCCESS;
    492 }
    493