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