• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
XenGetSharedInfoPage(IN OUT XENBUS_DEVICE * Dev)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
XenBusDxeUnload(IN EFI_HANDLE ImageHandle)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
XenBusDxeDriverEntryPoint(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)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
XenBusDxeDriverBindingSupported(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)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
NotifyExitBoot(IN EFI_EVENT Event,IN VOID * Context)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
XenBusDxeDriverBindingStart(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN EFI_DEVICE_PATH_PROTOCOL * RemainingDevicePath OPTIONAL)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
XenBusDxeDriverBindingStop(IN EFI_DRIVER_BINDING_PROTOCOL * This,IN EFI_HANDLE ControllerHandle,IN UINTN NumberOfChildren,IN EFI_HANDLE * ChildHandleBuffer OPTIONAL)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