]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/XenBusDxe/XenBusDxe.c
OvmfPkg/XenBusDxe: Add InterlockedCompareExchange16.
[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
AP
32#include "XenHypercall.h"\r
33\r
e65e8802
AP
34\r
35///\r
36/// Driver Binding Protocol instance\r
37///\r
38EFI_DRIVER_BINDING_PROTOCOL gXenBusDxeDriverBinding = {\r
39 XenBusDxeDriverBindingSupported,\r
40 XenBusDxeDriverBindingStart,\r
41 XenBusDxeDriverBindingStop,\r
42 XENBUS_DXE_VERSION,\r
43 NULL,\r
44 NULL\r
45};\r
46\r
47\r
a154f420
AP
48STATIC EFI_LOCK mMyDeviceLock = EFI_INITIALIZE_LOCK_VARIABLE (TPL_CALLBACK);\r
49STATIC XENBUS_DEVICE *mMyDevice = NULL;\r
50\r
e65e8802
AP
51/**\r
52 Unloads an image.\r
53\r
54 @param ImageHandle Handle that identifies the image to be unloaded.\r
55\r
56 @retval EFI_SUCCESS The image has been unloaded.\r
57 @retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle.\r
58\r
59**/\r
60EFI_STATUS\r
61EFIAPI\r
62XenBusDxeUnload (\r
63 IN EFI_HANDLE ImageHandle\r
64 )\r
65{\r
66 EFI_STATUS Status;\r
67\r
68 EFI_HANDLE *HandleBuffer;\r
69 UINTN HandleCount;\r
70 UINTN Index;\r
71\r
72 //\r
73 // Retrieve array of all handles in the handle database\r
74 //\r
75 Status = gBS->LocateHandleBuffer (\r
76 AllHandles,\r
77 NULL,\r
78 NULL,\r
79 &HandleCount,\r
80 &HandleBuffer\r
81 );\r
82 if (EFI_ERROR (Status)) {\r
83 return Status;\r
84 }\r
85\r
86 //\r
87 // Disconnect the current driver from handles in the handle database\r
88 //\r
89 for (Index = 0; Index < HandleCount; Index++) {\r
90 gBS->DisconnectController (HandleBuffer[Index], gImageHandle, NULL);\r
91 }\r
92\r
93 //\r
94 // Free the array of handles\r
95 //\r
96 FreePool (HandleBuffer);\r
97\r
98\r
99 //\r
100 // Uninstall protocols installed in the driver entry point\r
101 //\r
102 Status = gBS->UninstallMultipleProtocolInterfaces (\r
103 ImageHandle,\r
104 &gEfiDriverBindingProtocolGuid, &gXenBusDxeDriverBinding,\r
105 &gEfiComponentNameProtocolGuid, &gXenBusDxeComponentName,\r
106 &gEfiComponentName2ProtocolGuid, &gXenBusDxeComponentName2,\r
107 NULL\r
108 );\r
109 if (EFI_ERROR (Status)) {\r
110 return Status;\r
111 }\r
112\r
113 return EFI_SUCCESS;\r
114}\r
115\r
116/**\r
117 This is the declaration of an EFI image entry point. This entry point is\r
118 the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including\r
119 both device drivers and bus drivers.\r
120\r
121 @param ImageHandle The firmware allocated handle for the UEFI image.\r
122 @param SystemTable A pointer to the EFI System Table.\r
123\r
124 @retval EFI_SUCCESS The operation completed successfully.\r
125 @retval Others An unexpected error occurred.\r
126**/\r
127EFI_STATUS\r
128EFIAPI\r
129XenBusDxeDriverEntryPoint (\r
130 IN EFI_HANDLE ImageHandle,\r
131 IN EFI_SYSTEM_TABLE *SystemTable\r
132 )\r
133{\r
134 EFI_STATUS Status;\r
135\r
136 //\r
137 // Install UEFI Driver Model protocol(s).\r
138 //\r
139 Status = EfiLibInstallDriverBindingComponentName2 (\r
140 ImageHandle,\r
141 SystemTable,\r
142 &gXenBusDxeDriverBinding,\r
143 ImageHandle,\r
144 &gXenBusDxeComponentName,\r
145 &gXenBusDxeComponentName2\r
146 );\r
147 ASSERT_EFI_ERROR (Status);\r
148\r
149\r
150 return Status;\r
151}\r
152\r
153\r
154/**\r
155 Tests to see if this driver supports a given controller. If a child device is provided,\r
156 it further tests to see if this driver supports creating a handle for the specified child device.\r
157\r
158 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
159 @param[in] ControllerHandle The handle of the controller to test. This handle\r
160 must support a protocol interface that supplies\r
161 an I/O abstraction to the driver.\r
162 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
163 parameter is ignored by device drivers, and is optional for bus\r
164 drivers. For bus drivers, if this parameter is not NULL, then\r
165 the bus driver must determine if the bus controller specified\r
166 by ControllerHandle and the child controller specified\r
167 by RemainingDevicePath are both supported by this\r
168 bus driver.\r
169\r
170 @retval EFI_SUCCESS The device specified by ControllerHandle and\r
171 RemainingDevicePath is supported by the driver specified by This.\r
172 @retval EFI_ALREADY_STARTED The device specified by ControllerHandle and\r
173 RemainingDevicePath is already being managed by the driver\r
174 specified by This.\r
175 @retval EFI_ACCESS_DENIED The device specified by ControllerHandle and\r
176 RemainingDevicePath is already being managed by a different\r
177 driver or an application that requires exclusive access.\r
178 Currently not implemented.\r
179 @retval EFI_UNSUPPORTED The device specified by ControllerHandle and\r
180 RemainingDevicePath is not supported by the driver specified by This.\r
181**/\r
182EFI_STATUS\r
183EFIAPI\r
184XenBusDxeDriverBindingSupported (\r
185 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
186 IN EFI_HANDLE ControllerHandle,\r
187 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
188 )\r
189{\r
190 EFI_STATUS Status;\r
191 EFI_PCI_IO_PROTOCOL *PciIo;\r
192 PCI_TYPE00 Pci;\r
193\r
194 Status = gBS->OpenProtocol (\r
195 ControllerHandle,\r
196 &gEfiPciIoProtocolGuid,\r
197 (VOID **)&PciIo,\r
198 This->DriverBindingHandle,\r
199 ControllerHandle,\r
200 EFI_OPEN_PROTOCOL_BY_DRIVER\r
201 );\r
202 if (EFI_ERROR (Status)) {\r
203 return Status;\r
204 }\r
205\r
206 Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0,\r
207 sizeof Pci / sizeof (UINT32), &Pci);\r
208\r
209 if (Status == EFI_SUCCESS) {\r
210 if (Pci.Hdr.VendorId == PCI_VENDOR_ID_XEN &&\r
211 Pci.Hdr.DeviceId == PCI_DEVICE_ID_XEN_PLATFORM) {\r
212 Status = EFI_SUCCESS;\r
213 } else {\r
214 Status = EFI_UNSUPPORTED;\r
215 }\r
216 }\r
217\r
218 gBS->CloseProtocol (ControllerHandle, &gEfiPciIoProtocolGuid,\r
219 This->DriverBindingHandle, ControllerHandle);\r
220\r
221 return Status;\r
222}\r
223\r
a154f420
AP
224VOID\r
225EFIAPI\r
226NotifyExitBoot (\r
227 IN EFI_EVENT Event,\r
228 IN VOID *Context\r
229 )\r
230{\r
231 XENBUS_DEVICE *Dev = Context;\r
232\r
233 gBS->DisconnectController(Dev->ControllerHandle,\r
234 Dev->This->DriverBindingHandle, NULL);\r
235}\r
236\r
e65e8802
AP
237/**\r
238 Starts a bus controller.\r
239\r
240 The Start() function is designed to be invoked from the EFI boot service ConnectController().\r
241 As a result, much of the error checking on the parameters to Start() has been moved into this\r
242 common boot service. It is legal to call Start() from other locations,\r
243 but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
244 1. ControllerHandle must be a valid EFI_HANDLE.\r
245 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned\r
246 EFI_DEVICE_PATH_PROTOCOL.\r
247 3. Prior to calling Start(), the Supported() function for the driver specified by This must\r
248 have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.\r
249\r
250 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
251 @param[in] ControllerHandle The handle of the controller to start. This handle\r
252 must support a protocol interface that supplies\r
253 an I/O abstraction to the driver.\r
254 @param[in] RemainingDevicePath A pointer to the remaining portion of a device path. This\r
255 parameter is ignored by device drivers, and is optional for bus\r
256 drivers. For a bus driver, if this parameter is NULL, then handles\r
257 for all the children of Controller are created by this driver.\r
258 If this parameter is not NULL and the first Device Path Node is\r
259 not the End of Device Path Node, then only the handle for the\r
260 child device specified by the first Device Path Node of\r
261 RemainingDevicePath is created by this driver.\r
262 If the first Device Path Node of RemainingDevicePath is\r
263 the End of Device Path Node, no child handle is created by this\r
264 driver.\r
265\r
266 @retval EFI_SUCCESS The device was started.\r
267 @retval EFI_DEVICE_ERROR The device could not be started due to a device error.Currently not implemented.\r
268 @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.\r
abcbbb14
AP
269 @retval EFI_UNSUPPORTED Something is missing on the system that\r
270 prevent to start the edvice.\r
e65e8802
AP
271 @retval Others The driver failded to start the device.\r
272\r
273**/\r
274EFI_STATUS\r
275EFIAPI\r
276XenBusDxeDriverBindingStart (\r
277 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
278 IN EFI_HANDLE ControllerHandle,\r
279 IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL\r
280 )\r
281{\r
a154f420
AP
282 EFI_STATUS Status;\r
283 XENBUS_DEVICE *Dev;\r
956622c4
AP
284 EFI_PCI_IO_PROTOCOL *PciIo;\r
285\r
286 Status = gBS->OpenProtocol (\r
287 ControllerHandle,\r
288 &gEfiPciIoProtocolGuid,\r
289 (VOID **) &PciIo,\r
290 This->DriverBindingHandle,\r
291 ControllerHandle,\r
292 EFI_OPEN_PROTOCOL_BY_DRIVER\r
293 );\r
294 if (EFI_ERROR (Status)) {\r
295 return Status;\r
296 }\r
a154f420
AP
297\r
298 Dev = AllocateZeroPool (sizeof (*Dev));\r
299 Dev->Signature = XENBUS_DEVICE_SIGNATURE;\r
300 Dev->This = This;\r
301 Dev->ControllerHandle = ControllerHandle;\r
956622c4 302 Dev->PciIo = PciIo;\r
a154f420
AP
303\r
304 EfiAcquireLock (&mMyDeviceLock);\r
305 if (mMyDevice != NULL) {\r
306 EfiReleaseLock (&mMyDeviceLock);\r
307 //\r
308 // There is already a XenBus running, only one can be used at a time.\r
309 //\r
310 Status = EFI_ALREADY_STARTED;\r
311 goto ErrorAllocated;\r
312 }\r
313 mMyDevice = Dev;\r
314 EfiReleaseLock (&mMyDeviceLock);\r
315\r
abcbbb14
AP
316 Status = XenHyperpageInit (Dev);\r
317 if (EFI_ERROR (Status)) {\r
318 DEBUG ((EFI_D_ERROR, "XenBus: Unable to retrieve the hyperpage.\n"));\r
319 Status = EFI_UNSUPPORTED;\r
320 goto ErrorAllocated;\r
321 }\r
322\r
323 Status = XenGetSharedInfoPage (Dev);\r
324 if (EFI_ERROR (Status)) {\r
325 DEBUG ((EFI_D_ERROR, "XenBus: Unable to get the shared info page.\n"));\r
326 Status = EFI_UNSUPPORTED;\r
327 goto ErrorAllocated;\r
328 }\r
329\r
a154f420
AP
330 Status = gBS->CreateEvent (EVT_SIGNAL_EXIT_BOOT_SERVICES, TPL_CALLBACK,\r
331 NotifyExitBoot,\r
332 (VOID*) Dev,\r
333 &Dev->ExitBootEvent);\r
334 ASSERT_EFI_ERROR (Status);\r
335\r
336 return EFI_SUCCESS;\r
337\r
338ErrorAllocated:\r
339 FreePool (Dev);\r
956622c4
AP
340 gBS->CloseProtocol (ControllerHandle, &gEfiPciIoProtocolGuid,\r
341 This->DriverBindingHandle, ControllerHandle);\r
a154f420 342 return Status;\r
e65e8802
AP
343}\r
344\r
345/**\r
346 Stops a bus controller.\r
347\r
348 The Stop() function is designed to be invoked from the EFI boot service DisconnectController().\r
349 As a result, much of the error checking on the parameters to Stop() has been moved\r
350 into this common boot service. It is legal to call Stop() from other locations,\r
351 but the following calling restrictions must be followed, or the system behavior will not be deterministic.\r
352 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this\r
353 same driver's Start() function.\r
354 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid\r
355 EFI_HANDLE. In addition, all of these handles must have been created in this driver's\r
356 Start() function, and the Start() function must have called OpenProtocol() on\r
357 ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.\r
358\r
359 @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.\r
360 @param[in] ControllerHandle A handle to the device being stopped. The handle must\r
361 support a bus specific I/O protocol for the driver\r
362 to use to stop the device.\r
363 @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.\r
364 @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL\r
365 if NumberOfChildren is 0.\r
366\r
367 @retval EFI_SUCCESS The device was stopped.\r
368 @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.\r
369\r
370**/\r
371EFI_STATUS\r
372EFIAPI\r
373XenBusDxeDriverBindingStop (\r
374 IN EFI_DRIVER_BINDING_PROTOCOL *This,\r
375 IN EFI_HANDLE ControllerHandle,\r
376 IN UINTN NumberOfChildren,\r
377 IN EFI_HANDLE *ChildHandleBuffer OPTIONAL\r
378 )\r
379{\r
a154f420
AP
380 XENBUS_DEVICE *Dev = mMyDevice;\r
381\r
382 gBS->CloseEvent (Dev->ExitBootEvent);\r
383\r
956622c4
AP
384 gBS->CloseProtocol (ControllerHandle, &gEfiPciIoProtocolGuid,\r
385 This->DriverBindingHandle, ControllerHandle);\r
386\r
a154f420
AP
387 mMyDevice = NULL;\r
388 FreePool (Dev);\r
389 return EFI_SUCCESS;\r
e65e8802 390}\r