2 This driver produces XenBus Protocol instances for each Xen PV devices.
4 This XenBus bus driver will first initialize differente services in order to
5 enumerate the ParaVirtualized devices available.
14 Copyright (C) 2014, Citrix Ltd.
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
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.
26 #include <IndustryStandard/Pci.h>
27 #include <IndustryStandard/Acpi.h>
28 #include <Library/DebugLib.h>
30 #include "XenBusDxe.h"
32 #include "XenHypercall.h"
33 #include "GrantTable.h"
39 /// Driver Binding Protocol instance
41 EFI_DRIVER_BINDING_PROTOCOL gXenBusDxeDriverBinding
= {
42 XenBusDxeDriverBindingSupported
,
43 XenBusDxeDriverBindingStart
,
44 XenBusDxeDriverBindingStop
,
51 STATIC EFI_LOCK mMyDeviceLock
= EFI_INITIALIZE_LOCK_VARIABLE (TPL_CALLBACK
);
52 STATIC XENBUS_DEVICE
*mMyDevice
= NULL
;
57 @param ImageHandle Handle that identifies the image to be unloaded.
59 @retval EFI_SUCCESS The image has been unloaded.
60 @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
66 IN EFI_HANDLE ImageHandle
71 EFI_HANDLE
*HandleBuffer
;
76 // Retrieve array of all handles in the handle database
78 Status
= gBS
->LocateHandleBuffer (
85 if (EFI_ERROR (Status
)) {
90 // Disconnect the current driver from handles in the handle database
92 for (Index
= 0; Index
< HandleCount
; Index
++) {
93 gBS
->DisconnectController (HandleBuffer
[Index
], gImageHandle
, NULL
);
97 // Free the array of handles
99 FreePool (HandleBuffer
);
103 // Uninstall protocols installed in the driver entry point
105 Status
= gBS
->UninstallMultipleProtocolInterfaces (
107 &gEfiDriverBindingProtocolGuid
, &gXenBusDxeDriverBinding
,
108 &gEfiComponentNameProtocolGuid
, &gXenBusDxeComponentName
,
109 &gEfiComponentName2ProtocolGuid
, &gXenBusDxeComponentName2
,
112 if (EFI_ERROR (Status
)) {
120 This is the declaration of an EFI image entry point. This entry point is
121 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including
122 both device drivers and bus drivers.
124 @param ImageHandle The firmware allocated handle for the UEFI image.
125 @param SystemTable A pointer to the EFI System Table.
127 @retval EFI_SUCCESS The operation completed successfully.
128 @retval Others An unexpected error occurred.
132 XenBusDxeDriverEntryPoint (
133 IN EFI_HANDLE ImageHandle
,
134 IN EFI_SYSTEM_TABLE
*SystemTable
140 // Install UEFI Driver Model protocol(s).
142 Status
= EfiLibInstallDriverBindingComponentName2 (
145 &gXenBusDxeDriverBinding
,
147 &gXenBusDxeComponentName
,
148 &gXenBusDxeComponentName2
150 ASSERT_EFI_ERROR (Status
);
158 Tests to see if this driver supports a given controller. If a child device is provided,
159 it further tests to see if this driver supports creating a handle for the specified child device.
161 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
162 @param[in] ControllerHandle The handle of the controller to test. This handle
163 must support a protocol interface that supplies
164 an I/O abstraction to the driver.
165 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
166 parameter is ignored by device drivers, and is optional for bus
167 drivers. For bus drivers, if this parameter is not NULL, then
168 the bus driver must determine if the bus controller specified
169 by ControllerHandle and the child controller specified
170 by RemainingDevicePath are both supported by this
173 @retval EFI_SUCCESS The device specified by ControllerHandle and
174 RemainingDevicePath is supported by the driver specified by This.
175 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and
176 RemainingDevicePath is already being managed by the driver
178 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and
179 RemainingDevicePath is already being managed by a different
180 driver or an application that requires exclusive access.
181 Currently not implemented.
182 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and
183 RemainingDevicePath is not supported by the driver specified by This.
187 XenBusDxeDriverBindingSupported (
188 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
189 IN EFI_HANDLE ControllerHandle
,
190 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
194 EFI_PCI_IO_PROTOCOL
*PciIo
;
197 Status
= gBS
->OpenProtocol (
199 &gEfiPciIoProtocolGuid
,
201 This
->DriverBindingHandle
,
203 EFI_OPEN_PROTOCOL_BY_DRIVER
205 if (EFI_ERROR (Status
)) {
209 Status
= PciIo
->Pci
.Read (PciIo
, EfiPciIoWidthUint32
, 0,
210 sizeof Pci
/ sizeof (UINT32
), &Pci
);
212 if (Status
== EFI_SUCCESS
) {
213 if (Pci
.Hdr
.VendorId
== PCI_VENDOR_ID_XEN
&&
214 Pci
.Hdr
.DeviceId
== PCI_DEVICE_ID_XEN_PLATFORM
) {
215 Status
= EFI_SUCCESS
;
217 Status
= EFI_UNSUPPORTED
;
221 gBS
->CloseProtocol (ControllerHandle
, &gEfiPciIoProtocolGuid
,
222 This
->DriverBindingHandle
, ControllerHandle
);
234 XENBUS_DEVICE
*Dev
= Context
;
236 gBS
->DisconnectController(Dev
->ControllerHandle
,
237 Dev
->This
->DriverBindingHandle
, NULL
);
241 Starts a bus controller.
243 The Start() function is designed to be invoked from the EFI boot service ConnectController().
244 As a result, much of the error checking on the parameters to Start() has been moved into this
245 common boot service. It is legal to call Start() from other locations,
246 but the following calling restrictions must be followed, or the system behavior will not be deterministic.
247 1. ControllerHandle must be a valid EFI_HANDLE.
248 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
249 EFI_DEVICE_PATH_PROTOCOL.
250 3. Prior to calling Start(), the Supported() function for the driver specified by This must
251 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
253 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
254 @param[in] ControllerHandle The handle of the controller to start. This handle
255 must support a protocol interface that supplies
256 an I/O abstraction to the driver.
257 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This
258 parameter is ignored by device drivers, and is optional for bus
259 drivers. For a bus driver, if this parameter is NULL, then handles
260 for all the children of Controller are created by this driver.
261 If this parameter is not NULL and the first Device Path Node is
262 not the End of Device Path Node, then only the handle for the
263 child device specified by the first Device Path Node of
264 RemainingDevicePath is created by this driver.
265 If the first Device Path Node of RemainingDevicePath is
266 the End of Device Path Node, no child handle is created by this
269 @retval EFI_SUCCESS The device was started.
270 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.
271 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
272 @retval EFI_UNSUPPORTED Something is missing on the system that
273 prevent to start the edvice.
274 @retval Others The driver failded to start the device.
279 XenBusDxeDriverBindingStart (
280 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
281 IN EFI_HANDLE ControllerHandle
,
282 IN EFI_DEVICE_PATH_PROTOCOL
*RemainingDevicePath OPTIONAL
287 EFI_PCI_IO_PROTOCOL
*PciIo
;
288 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR
*BarDesc
;
290 EFI_DEVICE_PATH_PROTOCOL
*DevicePath
;
292 Status
= gBS
->OpenProtocol (
294 &gEfiPciIoProtocolGuid
,
296 This
->DriverBindingHandle
,
298 EFI_OPEN_PROTOCOL_BY_DRIVER
300 if (EFI_ERROR (Status
)) {
304 Status
= gBS
->OpenProtocol (
306 &gEfiDevicePathProtocolGuid
,
307 (VOID
**) &DevicePath
,
308 This
->DriverBindingHandle
,
310 EFI_OPEN_PROTOCOL_BY_DRIVER
313 if (EFI_ERROR (Status
)) {
314 goto ErrorOpenningProtocol
;
317 Dev
= AllocateZeroPool (sizeof (*Dev
));
318 Dev
->Signature
= XENBUS_DEVICE_SIGNATURE
;
320 Dev
->ControllerHandle
= ControllerHandle
;
322 Dev
->DevicePath
= DevicePath
;
323 InitializeListHead (&Dev
->ChildList
);
325 EfiAcquireLock (&mMyDeviceLock
);
326 if (mMyDevice
!= NULL
) {
327 EfiReleaseLock (&mMyDeviceLock
);
329 // There is already a XenBus running, only one can be used at a time.
331 Status
= EFI_ALREADY_STARTED
;
335 EfiReleaseLock (&mMyDeviceLock
);
338 // The BAR1 of this PCI device is used for shared memory and is supposed to
339 // look like MMIO. The address space of the BAR1 will be used to map the
342 Status
= PciIo
->GetBarAttributes (PciIo
, PCI_BAR_IDX1
, NULL
, (VOID
**) &BarDesc
);
343 ASSERT_EFI_ERROR (Status
);
344 ASSERT (BarDesc
->ResType
== ACPI_ADDRESS_SPACE_TYPE_MEM
);
346 /* Get a Memory address for mapping the Grant Table. */
347 DEBUG ((EFI_D_INFO
, "XenBus: BAR at %LX\n", BarDesc
->AddrRangeMin
));
348 MmioAddr
= BarDesc
->AddrRangeMin
;
351 Status
= XenHyperpageInit (Dev
);
352 if (EFI_ERROR (Status
)) {
353 DEBUG ((EFI_D_ERROR
, "XenBus: Unable to retrieve the hyperpage.\n"));
354 Status
= EFI_UNSUPPORTED
;
358 Status
= XenGetSharedInfoPage (Dev
);
359 if (EFI_ERROR (Status
)) {
360 DEBUG ((EFI_D_ERROR
, "XenBus: Unable to get the shared info page.\n"));
361 Status
= EFI_UNSUPPORTED
;
365 XenGrantTableInit (Dev
, MmioAddr
);
367 Status
= XenStoreInit (Dev
);
368 ASSERT_EFI_ERROR (Status
);
370 XenBusEnumerateBus (Dev
);
372 Status
= gBS
->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES
, TPL_CALLBACK
,
375 &Dev
->ExitBootEvent
);
376 ASSERT_EFI_ERROR (Status
);
382 gBS
->CloseProtocol (ControllerHandle
, &gEfiDevicePathProtocolGuid
,
383 This
->DriverBindingHandle
, ControllerHandle
);
384 ErrorOpenningProtocol
:
385 gBS
->CloseProtocol (ControllerHandle
, &gEfiPciIoProtocolGuid
,
386 This
->DriverBindingHandle
, ControllerHandle
);
391 Stops a bus controller.
393 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
394 As a result, much of the error checking on the parameters to Stop() has been moved
395 into this common boot service. It is legal to call Stop() from other locations,
396 but the following calling restrictions must be followed, or the system behavior will not be deterministic.
397 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
398 same driver's Start() function.
399 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
400 EFI_HANDLE. In addition, all of these handles must have been created in this driver's
401 Start() function, and the Start() function must have called OpenProtocol() on
402 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
404 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
405 @param[in] ControllerHandle A handle to the device being stopped. The handle must
406 support a bus specific I/O protocol for the driver
407 to use to stop the device.
408 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
409 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
410 if NumberOfChildren is 0.
412 @retval EFI_SUCCESS The device was stopped.
413 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
418 XenBusDxeDriverBindingStop (
419 IN EFI_DRIVER_BINDING_PROTOCOL
*This
,
420 IN EFI_HANDLE ControllerHandle
,
421 IN UINTN NumberOfChildren
,
422 IN EFI_HANDLE
*ChildHandleBuffer OPTIONAL
426 XENBUS_PROTOCOL
*XenBusIo
;
427 XENBUS_PRIVATE_DATA
*ChildData
;
429 XENBUS_DEVICE
*Dev
= mMyDevice
;
431 for (Index
= 0; Index
< NumberOfChildren
; Index
++) {
432 Status
= gBS
->OpenProtocol (
433 ChildHandleBuffer
[Index
],
434 &gXenBusProtocolGuid
,
436 This
->DriverBindingHandle
,
438 EFI_OPEN_PROTOCOL_GET_PROTOCOL
);
439 if (EFI_ERROR (Status
)) {
440 DEBUG ((EFI_D_ERROR
, "XenBusDxe: get children protocol failed: %r\n", Status
));
443 ChildData
= XENBUS_PRIVATE_DATA_FROM_THIS (XenBusIo
);
444 Status
= gBS
->DisconnectController (ChildData
->Handle
, NULL
, NULL
);
445 if (EFI_ERROR (Status
)) {
446 DEBUG ((EFI_D_ERROR
, "XenBusDxe: error disconnecting child: %r\n",
451 Status
= gBS
->UninstallMultipleProtocolInterfaces (
453 &gEfiDevicePathProtocolGuid
, ChildData
->DevicePath
,
454 &gXenBusProtocolGuid
, &ChildData
->XenBusIo
,
456 ASSERT_EFI_ERROR (Status
);
458 FreePool ((VOID
*)ChildData
->XenBusIo
.Type
);
459 FreePool ((VOID
*)ChildData
->XenBusIo
.Node
);
460 FreePool ((VOID
*)ChildData
->XenBusIo
.Backend
);
461 FreePool (ChildData
->DevicePath
);
462 RemoveEntryList (&ChildData
->Link
);
463 FreePool (ChildData
);
465 if (NumberOfChildren
> 0) {
469 gBS
->CloseEvent (Dev
->ExitBootEvent
);
470 XenStoreDeinit (Dev
);
471 XenGrantTableDeinit (Dev
);
473 gBS
->CloseProtocol (ControllerHandle
, &gEfiDevicePathProtocolGuid
,
474 This
->DriverBindingHandle
, ControllerHandle
);
475 gBS
->CloseProtocol (ControllerHandle
, &gEfiPciIoProtocolGuid
,
476 This
->DriverBindingHandle
, ControllerHandle
);