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