]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/XenBusDxe/XenBusDxe.c
OvmfPkg/XenBusDxe: Introduce XenBus support itself.
[mirror_edk2.git] / OvmfPkg / XenBusDxe / XenBusDxe.c
CommitLineData
e65e8802
AP
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
abcbbb14 32#include "XenHypercall.h"\r
0fd14246 33#include "GrantTable.h"\r
a9090a94 34#include "XenStore.h"\r
86d968e0 35#include "XenBus.h"\r
abcbbb14 36\r
e65e8802
AP
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
a154f420
AP
51STATIC EFI_LOCK mMyDeviceLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_CALLBACK);\r
52STATIC XENBUS_DEVICE *mMyDevice = NULL;\r
53\r
e65e8802
AP
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
a154f420
AP
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
e65e8802
AP
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
abcbbb14
AP
272 @retval EFI_UNSUPPORTED Something is missing on the system that\r
273 prevent to start the edvice.\r
e65e8802
AP
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
a154f420
AP
285 EFI_STATUS Status;\r
286 XENBUS_DEVICE *Dev;\r
956622c4 287 EFI_PCI_IO_PROTOCOL *PciIo;\r
0fd14246
SS
288 EFI_ACPI_ADDRESS_SPACE_DESCRIPTOR *BarDesc;\r
289 UINT64 MmioAddr;\r
86d968e0 290 EFI_DEVICE_PATH_PROTOCOL *DevicePath;\r
956622c4
AP
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
a154f420 303\r
86d968e0
AP
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
a154f420
AP
317 Dev = AllocateZeroPool (sizeof (*Dev));\r
318 Dev->Signature = XENBUS_DEVICE_SIGNATURE;\r
319 Dev->This = This;\r
320 Dev->ControllerHandle = ControllerHandle;\r
956622c4 321 Dev->PciIo = PciIo;\r
86d968e0
AP
322 Dev->DevicePath = DevicePath;\r
323 InitializeListHead (&Dev->ChildList);\r
a154f420
AP
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
0fd14246
SS
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
abcbbb14
AP
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
0fd14246
SS
365 XenGrantTableInit (Dev, MmioAddr);\r
366\r
a9090a94
AP
367 Status = XenStoreInit (Dev);\r
368 ASSERT_EFI_ERROR (Status);\r
369\r
86d968e0
AP
370 XenBusEnumerateBus (Dev);\r
371\r
a154f420
AP
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
86d968e0
AP
382 gBS->CloseProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid,\r
383 This->DriverBindingHandle, ControllerHandle);\r
384ErrorOpenningProtocol:\r
956622c4
AP
385 gBS->CloseProtocol (ControllerHandle, &gEfiPciIoProtocolGuid,\r
386 This->DriverBindingHandle, ControllerHandle);\r
a154f420 387 return Status;\r
e65e8802
AP
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
86d968e0
AP
425 UINTN Index;\r
426 XENBUS_PROTOCOL *XenBusIo;\r
427 XENBUS_PRIVATE_DATA *ChildData;\r
428 EFI_STATUS Status;\r
a154f420
AP
429 XENBUS_DEVICE *Dev = mMyDevice;\r
430\r
86d968e0
AP
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
a154f420 469 gBS->CloseEvent (Dev->ExitBootEvent);\r
a9090a94 470 XenStoreDeinit (Dev);\r
0fd14246 471 XenGrantTableDeinit (Dev);\r
a154f420 472\r
86d968e0
AP
473 gBS->CloseProtocol (ControllerHandle, &gEfiDevicePathProtocolGuid,\r
474 This->DriverBindingHandle, ControllerHandle);\r
956622c4
AP
475 gBS->CloseProtocol (ControllerHandle, &gEfiPciIoProtocolGuid,\r
476 This->DriverBindingHandle, ControllerHandle);\r
477\r
a154f420
AP
478 mMyDevice = NULL;\r
479 FreePool (Dev);\r
480 return EFI_SUCCESS;\r
e65e8802 481}\r