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