]> git.proxmox.com Git - mirror_edk2.git/blob - OvmfPkg/XenBusDxe/XenBusDxe.c
7a7fd82d559d1a1604d8b4fa4ddc82798c72840d
[mirror_edk2.git] / OvmfPkg / XenBusDxe / XenBusDxe.c
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 <IndustryStandard/Pci.h>
27 #include <IndustryStandard/Acpi.h>
28 #include <Library/DebugLib.h>
29
30 #include "XenBusDxe.h"
31
32 #include "XenHypercall.h"
33 #include "GrantTable.h"
34 #include "XenStore.h"
35 #include "XenBus.h"
36
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 Unloads an image.
56
57 @param ImageHandle Handle that identifies the image to be unloaded.
58
59 @retval EFI_SUCCESS The image has been unloaded.
60 @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.
61
62 **/
63 EFI_STATUS
64 EFIAPI
65 XenBusDxeUnload (
66 IN EFI_HANDLE ImageHandle
67 )
68 {
69 EFI_STATUS Status;
70
71 EFI_HANDLE *HandleBuffer;
72 UINTN HandleCount;
73 UINTN Index;
74
75 //
76 // Retrieve array of all handles in the handle database
77 //
78 Status = gBS->LocateHandleBuffer (
79 AllHandles,
80 NULL,
81 NULL,
82 &HandleCount,
83 &HandleBuffer
84 );
85 if (EFI_ERROR (Status)) {
86 return Status;
87 }
88
89 //
90 // Disconnect the current driver from handles in the handle database
91 //
92 for (Index = 0; Index < HandleCount; Index++) {
93 gBS->DisconnectController (HandleBuffer[Index], gImageHandle, NULL);
94 }
95
96 //
97 // Free the array of handles
98 //
99 FreePool (HandleBuffer);
100
101
102 //
103 // Uninstall protocols installed in the driver entry point
104 //
105 Status = gBS->UninstallMultipleProtocolInterfaces (
106 ImageHandle,
107 &gEfiDriverBindingProtocolGuid, &gXenBusDxeDriverBinding,
108 &gEfiComponentNameProtocolGuid, &gXenBusDxeComponentName,
109 &gEfiComponentName2ProtocolGuid, &gXenBusDxeComponentName2,
110 NULL
111 );
112 if (EFI_ERROR (Status)) {
113 return Status;
114 }
115
116 return EFI_SUCCESS;
117 }
118
119 /**
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.
123
124 @param ImageHandle The firmware allocated handle for the UEFI image.
125 @param SystemTable A pointer to the EFI System Table.
126
127 @retval EFI_SUCCESS The operation completed successfully.
128 @retval Others An unexpected error occurred.
129 **/
130 EFI_STATUS
131 EFIAPI
132 XenBusDxeDriverEntryPoint (
133 IN EFI_HANDLE ImageHandle,
134 IN EFI_SYSTEM_TABLE *SystemTable
135 )
136 {
137 EFI_STATUS Status;
138
139 //
140 // Install UEFI Driver Model protocol(s).
141 //
142 Status = EfiLibInstallDriverBindingComponentName2 (
143 ImageHandle,
144 SystemTable,
145 &gXenBusDxeDriverBinding,
146 ImageHandle,
147 &gXenBusDxeComponentName,
148 &gXenBusDxeComponentName2
149 );
150 ASSERT_EFI_ERROR (Status);
151
152
153 return Status;
154 }
155
156
157 /**
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.
160
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
171 bus driver.
172
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
177 specified by This.
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.
184 **/
185 EFI_STATUS
186 EFIAPI
187 XenBusDxeDriverBindingSupported (
188 IN EFI_DRIVER_BINDING_PROTOCOL *This,
189 IN EFI_HANDLE ControllerHandle,
190 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
191 )
192 {
193 EFI_STATUS Status;
194 EFI_PCI_IO_PROTOCOL *PciIo;
195 PCI_TYPE00 Pci;
196
197 Status = gBS->OpenProtocol (
198 ControllerHandle,
199 &gEfiPciIoProtocolGuid,
200 (VOID **)&PciIo,
201 This->DriverBindingHandle,
202 ControllerHandle,
203 EFI_OPEN_PROTOCOL_BY_DRIVER
204 );
205 if (EFI_ERROR (Status)) {
206 return Status;
207 }
208
209 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0,
210 sizeof Pci / sizeof (UINT32), &Pci);
211
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;
216 } else {
217 Status = EFI_UNSUPPORTED;
218 }
219 }
220
221 gBS->CloseProtocol (ControllerHandle, &gEfiPciIoProtocolGuid,
222 This->DriverBindingHandle, ControllerHandle);
223
224 return Status;
225 }
226
227 VOID
228 EFIAPI
229 NotifyExitBoot (
230 IN EFI_EVENT Event,
231 IN VOID *Context
232 )
233 {
234 XENBUS_DEVICE *Dev = Context;
235
236 gBS->DisconnectController(Dev->ControllerHandle,
237 Dev->This->DriverBindingHandle, NULL);
238 }
239
240 /**
241 Starts a bus controller.
242
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.
252
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
267 driver.
268
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.
275
276 **/
277 EFI_STATUS
278 EFIAPI
279 XenBusDxeDriverBindingStart (
280 IN EFI_DRIVER_BINDING_PROTOCOL *This,
281 IN EFI_HANDLE ControllerHandle,
282 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
283 )
284 {
285 EFI_STATUS Status;
286 XENBUS_DEVICE *Dev;
287 EFI_PCI_IO_PROTOCOL *PciIo;
288 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc;
289 UINT64 MmioAddr;
290 EFI_DEVICE_PATH_PROTOCOL *DevicePath;
291
292 Status = gBS->OpenProtocol (
293 ControllerHandle,
294 &gEfiPciIoProtocolGuid,
295 (VOID **) &PciIo,
296 This->DriverBindingHandle,
297 ControllerHandle,
298 EFI_OPEN_PROTOCOL_BY_DRIVER
299 );
300 if (EFI_ERROR (Status)) {
301 return Status;
302 }
303
304 Status = gBS->OpenProtocol (
305 ControllerHandle,
306 &gEfiDevicePathProtocolGuid,
307 (VOID **) &DevicePath,
308 This->DriverBindingHandle,
309 ControllerHandle,
310 EFI_OPEN_PROTOCOL_BY_DRIVER
311 );
312
313 if (EFI_ERROR (Status)) {
314 goto ErrorOpenningProtocol;
315 }
316
317 Dev = AllocateZeroPool (sizeof (*Dev));
318 Dev->Signature = XENBUS_DEVICE_SIGNATURE;
319 Dev->This = This;
320 Dev->ControllerHandle = ControllerHandle;
321 Dev->PciIo = PciIo;
322 Dev->DevicePath = DevicePath;
323 InitializeListHead (&Dev->ChildList);
324
325 EfiAcquireLock (&mMyDeviceLock);
326 if (mMyDevice != NULL) {
327 EfiReleaseLock (&mMyDeviceLock);
328 //
329 // There is already a XenBus running, only one can be used at a time.
330 //
331 Status = EFI_ALREADY_STARTED;
332 goto ErrorAllocated;
333 }
334 mMyDevice = Dev;
335 EfiReleaseLock (&mMyDeviceLock);
336
337 //
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
340 // Grant Table.
341 //
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);
345
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;
349 FreePool (BarDesc);
350
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;
355 goto ErrorAllocated;
356 }
357
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;
362 goto ErrorAllocated;
363 }
364
365 XenGrantTableInit (Dev, MmioAddr);
366
367 Status = XenStoreInit (Dev);
368 ASSERT_EFI_ERROR (Status);
369
370 XenBusEnumerateBus (Dev);
371
372 Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,
373 NotifyExitBoot,
374 (VOID*) Dev,
375 &Dev->ExitBootEvent);
376 ASSERT_EFI_ERROR (Status);
377
378 return EFI_SUCCESS;
379
380 ErrorAllocated:
381 FreePool (Dev);
382 gBS->CloseProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid,
383 This->DriverBindingHandle, ControllerHandle);
384 ErrorOpenningProtocol:
385 gBS->CloseProtocol (ControllerHandle, &gEfiPciIoProtocolGuid,
386 This->DriverBindingHandle, ControllerHandle);
387 return Status;
388 }
389
390 /**
391 Stops a bus controller.
392
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.
403
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.
411
412 @retval EFI_SUCCESS The device was stopped.
413 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
414
415 **/
416 EFI_STATUS
417 EFIAPI
418 XenBusDxeDriverBindingStop (
419 IN EFI_DRIVER_BINDING_PROTOCOL *This,
420 IN EFI_HANDLE ControllerHandle,
421 IN UINTN NumberOfChildren,
422 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
423 )
424 {
425 UINTN Index;
426 XENBUS_PROTOCOL *XenBusIo;
427 XENBUS_PRIVATE_DATA *ChildData;
428 EFI_STATUS Status;
429 XENBUS_DEVICE *Dev = mMyDevice;
430
431 for (Index = 0; Index < NumberOfChildren; Index++) {
432 Status = gBS->OpenProtocol (
433 ChildHandleBuffer[Index],
434 &gXenBusProtocolGuid,
435 (VOID **) &XenBusIo,
436 This->DriverBindingHandle,
437 ControllerHandle,
438 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
439 if (EFI_ERROR (Status)) {
440 DEBUG ((EFI_D_ERROR, "XenBusDxe: get children protocol failed: %r\n", Status));
441 continue;
442 }
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",
447 Status));
448 continue;
449 }
450
451 Status = gBS->UninstallMultipleProtocolInterfaces (
452 ChildData->Handle,
453 &gEfiDevicePathProtocolGuid, ChildData->DevicePath,
454 &gXenBusProtocolGuid, &ChildData->XenBusIo,
455 NULL);
456 ASSERT_EFI_ERROR (Status);
457
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);
464 }
465 if (NumberOfChildren > 0) {
466 return EFI_SUCCESS;
467 }
468
469 gBS->CloseEvent (Dev->ExitBootEvent);
470 XenStoreDeinit (Dev);
471 XenGrantTableDeinit (Dev);
472
473 gBS->CloseProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid,
474 This->DriverBindingHandle, ControllerHandle);
475 gBS->CloseProtocol (ControllerHandle, &gEfiPciIoProtocolGuid,
476 This->DriverBindingHandle, ControllerHandle);
477
478 mMyDevice = NULL;
479 FreePool (Dev);
480 return EFI_SUCCESS;
481 }