]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/XenBusDxe/XenBus.c
IntelFsp2Pkg/SplitFspBin.py: Support rebasing 1.x binary.
[mirror_edk2.git] / OvmfPkg / XenBusDxe / XenBus.c
CommitLineData
86d968e0
AP
1/** @file\r
2 XenBus Bus driver implemtation.\r
3\r
4 This file implement the necessary to discover and enumerate Xen PV devices\r
5 through XenStore.\r
6\r
7 Copyright (C) 2010 Spectra Logic Corporation\r
8 Copyright (C) 2008 Doug Rabson\r
9 Copyright (C) 2005 Rusty Russell, IBM Corporation\r
10 Copyright (C) 2005 Mike Wray, Hewlett-Packard\r
11 Copyright (C) 2005 XenSource Ltd\r
12 Copyright (C) 2014, Citrix Ltd.\r
13\r
14 This file may be distributed separately from the Linux kernel, or\r
15 incorporated into other software packages, subject to the following license:\r
16\r
34131e1b 17 SPDX-License-Identifier: MIT\r
86d968e0
AP
18**/\r
19\r
20#include <Library/PrintLib.h>\r
21\r
22#include "XenBus.h"\r
23#include "GrantTable.h"\r
24#include "XenStore.h"\r
25#include "EventChannel.h"\r
26\r
27#include <IndustryStandard/Xen/io/xenbus.h>\r
28\r
29STATIC XENBUS_PRIVATE_DATA gXenBusPrivateData;\r
30\r
31STATIC XENBUS_DEVICE_PATH gXenBusDevicePathTemplate = {\r
489c5c67
AP
32 { // Vendor\r
33 { // Vendor.Header\r
34 HARDWARE_DEVICE_PATH, // Vendor.Header.Type\r
35 HW_VENDOR_DP, // Vendor.Header.SubType\r
36 {\r
37 (UINT8) (sizeof (XENBUS_DEVICE_PATH)), // Vendor.Header.Length[0]\r
38 (UINT8) (sizeof (XENBUS_DEVICE_PATH) >> 8), // Vendor.Header.Length[1]\r
39 }\r
40 },\r
41 XENBUS_PROTOCOL_GUID, // Vendor.Guid\r
42 },\r
43 0, // Type\r
44 0 // DeviceId\r
86d968e0
AP
45};\r
46\r
47\r
48/**\r
49 Search our internal record of configured devices (not the XenStore) to\r
50 determine if the XenBus device indicated by Node is known to the system.\r
51\r
52 @param Dev The XENBUS_DEVICE instance to search for device children.\r
53 @param Node The XenStore node path for the device to find.\r
54\r
55 @return The XENBUS_PRIVATE_DATA of the found device if any, or NULL.\r
56 */\r
57STATIC\r
58XENBUS_PRIVATE_DATA *\r
59XenBusDeviceInitialized (\r
60 IN XENBUS_DEVICE *Dev,\r
61 IN CONST CHAR8 *Node\r
62 )\r
63{\r
64 LIST_ENTRY *Entry;\r
65 XENBUS_PRIVATE_DATA *Child;\r
66 XENBUS_PRIVATE_DATA *Result;\r
67\r
68 if (IsListEmpty (&Dev->ChildList)) {\r
69 return NULL;\r
70 }\r
71\r
72 Result = NULL;\r
73 for (Entry = GetFirstNode (&Dev->ChildList);\r
74 !IsNodeAtEnd (&Dev->ChildList, Entry);\r
75 Entry = GetNextNode (&Dev->ChildList, Entry)) {\r
76 Child = XENBUS_PRIVATE_DATA_FROM_LINK (Entry);\r
77 if (!AsciiStrCmp (Child->XenBusIo.Node, Node)) {\r
78 Result = Child;\r
79 break;\r
80 }\r
81 }\r
82\r
83 return (Result);\r
84}\r
85\r
86STATIC\r
87XenbusState\r
88XenBusReadDriverState (\r
89 IN CONST CHAR8 *Path\r
90 )\r
91{\r
92 XenbusState State;\r
93 CHAR8 *Ptr = NULL;\r
94 XENSTORE_STATUS Status;\r
95\r
96 Status = XenStoreRead (XST_NIL, Path, "state", NULL, (VOID **)&Ptr);\r
97 if (Status != XENSTORE_STATUS_SUCCESS) {\r
98 State = XenbusStateClosed;\r
99 } else {\r
100 State = AsciiStrDecimalToUintn (Ptr);\r
101 }\r
102\r
103 if (Ptr != NULL) {\r
104 FreePool (Ptr);\r
105 }\r
106\r
107 return State;\r
108}\r
109\r
110//\r
111// Callers should ensure that they are only one calling XenBusAddDevice.\r
112//\r
113STATIC\r
114EFI_STATUS\r
115XenBusAddDevice (\r
116 XENBUS_DEVICE *Dev,\r
117 CONST CHAR8 *Type,\r
118 CONST CHAR8 *Id)\r
119{\r
120 CHAR8 DevicePath[XENSTORE_ABS_PATH_MAX];\r
121 XENSTORE_STATUS StatusXenStore;\r
122 XENBUS_PRIVATE_DATA *Private;\r
123 EFI_STATUS Status;\r
124 XENBUS_DEVICE_PATH *TempXenBusPath;\r
d9fdfd85 125 VOID *ChildXenIo;\r
86d968e0
AP
126\r
127 AsciiSPrint (DevicePath, sizeof (DevicePath),\r
128 "device/%a/%a", Type, Id);\r
129\r
130 if (XenStorePathExists (XST_NIL, DevicePath, "")) {\r
131 XENBUS_PRIVATE_DATA *Child;\r
132 enum xenbus_state State;\r
133 CHAR8 *BackendPath;\r
134\r
135 Child = XenBusDeviceInitialized (Dev, DevicePath);\r
136 if (Child != NULL) {\r
137 /*\r
138 * We are already tracking this node\r
139 */\r
140 Status = EFI_SUCCESS;\r
141 goto out;\r
142 }\r
143\r
144 State = XenBusReadDriverState (DevicePath);\r
145 if (State != XenbusStateInitialising) {\r
146 /*\r
147 * Device is not new, so ignore it. This can\r
148 * happen if a device is going away after\r
149 * switching to Closed.\r
150 */\r
151 DEBUG ((EFI_D_INFO, "XenBus: Device %a ignored. "\r
152 "State %d\n", DevicePath, State));\r
153 Status = EFI_SUCCESS;\r
154 goto out;\r
155 }\r
156\r
157 StatusXenStore = XenStoreRead (XST_NIL, DevicePath, "backend",\r
158 NULL, (VOID **) &BackendPath);\r
159 if (StatusXenStore != XENSTORE_STATUS_SUCCESS) {\r
160 DEBUG ((EFI_D_ERROR, "xenbus: %a no backend path.\n", DevicePath));\r
161 Status = EFI_NOT_FOUND;\r
162 goto out;\r
163 }\r
164\r
165 Private = AllocateCopyPool (sizeof (*Private), &gXenBusPrivateData);\r
166 Private->XenBusIo.Type = AsciiStrDup (Type);\r
167 Private->XenBusIo.Node = AsciiStrDup (DevicePath);\r
168 Private->XenBusIo.Backend = BackendPath;\r
017a4866 169 Private->XenBusIo.DeviceId = (UINT16)AsciiStrDecimalToUintn (Id);\r
86d968e0
AP
170 Private->Dev = Dev;\r
171\r
172 TempXenBusPath = AllocateCopyPool (sizeof (XENBUS_DEVICE_PATH),\r
173 &gXenBusDevicePathTemplate);\r
174 if (!AsciiStrCmp (Private->XenBusIo.Type, "vbd")) {\r
175 TempXenBusPath->Type = XENBUS_DEVICE_PATH_TYPE_VBD;\r
176 }\r
177 TempXenBusPath->DeviceId = Private->XenBusIo.DeviceId;\r
178 Private->DevicePath = (XENBUS_DEVICE_PATH *)AppendDevicePathNode (\r
179 Dev->DevicePath,\r
180 &TempXenBusPath->Vendor.Header);\r
181 FreePool (TempXenBusPath);\r
182\r
183 InsertTailList (&Dev->ChildList, &Private->Link);\r
184\r
185 Status = gBS->InstallMultipleProtocolInterfaces (\r
186 &Private->Handle,\r
187 &gEfiDevicePathProtocolGuid, Private->DevicePath,\r
188 &gXenBusProtocolGuid, &Private->XenBusIo,\r
189 NULL);\r
190 if (EFI_ERROR (Status)) {\r
191 goto ErrorInstallProtocol;\r
192 }\r
193\r
194 Status = gBS->OpenProtocol (Dev->ControllerHandle,\r
d9fdfd85
AB
195 &gXenIoProtocolGuid,\r
196 &ChildXenIo, Dev->This->DriverBindingHandle,\r
86d968e0
AP
197 Private->Handle,\r
198 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);\r
199 if (EFI_ERROR (Status)) {\r
200 DEBUG ((EFI_D_ERROR, "open by child controller fail (%r)\n",\r
201 Status));\r
202 goto ErrorOpenProtocolByChild;\r
203 }\r
204 } else {\r
205 DEBUG ((EFI_D_ERROR, "XenBus: does not exist: %a\n", DevicePath));\r
206 Status = EFI_NOT_FOUND;\r
207 }\r
208\r
209 return Status;\r
210\r
211ErrorOpenProtocolByChild:\r
212 gBS->UninstallMultipleProtocolInterfaces (\r
213 &Private->Handle,\r
214 &gEfiDevicePathProtocolGuid, Private->DevicePath,\r
215 &gXenBusProtocolGuid, &Private->XenBusIo,\r
216 NULL);\r
217ErrorInstallProtocol:\r
218 RemoveEntryList (&Private->Link);\r
219 FreePool (Private->DevicePath);\r
220 FreePool ((VOID *) Private->XenBusIo.Backend);\r
221 FreePool ((VOID *) Private->XenBusIo.Node);\r
222 FreePool ((VOID *) Private->XenBusIo.Type);\r
223 FreePool (Private);\r
224out:\r
225 return Status;\r
226}\r
227\r
228/**\r
229 Enumerate all devices of the given type on this bus.\r
230\r
231 @param Dev A XENBUS_DEVICE instance.\r
232 @param Type String indicating the device sub-tree (e.g. "vfb", "vif")\r
233 to enumerate.\r
234\r
235 Devices that are found are been initialize via XenBusAddDevice ().\r
236 XenBusAddDevice () ignores duplicate detects and ignores duplicate devices,\r
237 so it can be called unconditionally for any device found in the XenStore.\r
238 */\r
239STATIC\r
240VOID\r
241XenBusEnumerateDeviceType (\r
242 XENBUS_DEVICE *Dev,\r
243 CONST CHAR8 *Type\r
244 )\r
245{\r
246 CONST CHAR8 **Directory;\r
247 UINTN Index;\r
248 UINT32 Count;\r
249 XENSTORE_STATUS Status;\r
250\r
251 Status = XenStoreListDirectory (XST_NIL,\r
252 "device", Type,\r
253 &Count, &Directory);\r
254 if (Status != XENSTORE_STATUS_SUCCESS) {\r
255 return;\r
256 }\r
257 for (Index = 0; Index < Count; Index++) {\r
258 XenBusAddDevice (Dev, Type, Directory[Index]);\r
259 }\r
260\r
017a4866 261 FreePool ((VOID*)Directory);\r
86d968e0
AP
262}\r
263\r
264\r
265/**\r
266 Enumerate the devices on a XenBus bus and install a XenBus Protocol instance.\r
267\r
268 Caller should ensure that it is the only one to call this function. This\r
269 function cannot be called concurrently.\r
270\r
271 @param Dev A XENBUS_DEVICE instance.\r
272\r
273 @return On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value\r
274 indicating the type of failure.\r
275 */\r
276XENSTORE_STATUS\r
277XenBusEnumerateBus (\r
278 XENBUS_DEVICE *Dev\r
279 )\r
280{\r
281 CONST CHAR8 **Types;\r
282 UINTN Index;\r
283 UINT32 Count;\r
284 XENSTORE_STATUS Status;\r
285\r
286 Status = XenStoreListDirectory (XST_NIL,\r
287 "device", "",\r
288 &Count, &Types);\r
289 if (Status != XENSTORE_STATUS_SUCCESS) {\r
290 return Status;\r
291 }\r
292\r
293 for (Index = 0; Index < Count; Index++) {\r
294 XenBusEnumerateDeviceType (Dev, Types[Index]);\r
295 }\r
296\r
017a4866 297 FreePool ((VOID*)Types);\r
86d968e0
AP
298\r
299 return XENSTORE_STATUS_SUCCESS;\r
300}\r
301\r
302STATIC\r
303XENSTORE_STATUS\r
304EFIAPI\r
305XenBusSetState (\r
306 IN XENBUS_PROTOCOL *This,\r
e26a83cd 307 IN CONST XENSTORE_TRANSACTION *Transaction,\r
86d968e0
AP
308 IN enum xenbus_state NewState\r
309 )\r
310{\r
311 enum xenbus_state CurrentState;\r
312 XENSTORE_STATUS Status;\r
313 CHAR8 *Temp;\r
314\r
315 DEBUG ((EFI_D_INFO, "XenBus: Set state to %d\n", NewState));\r
316\r
317 Status = XenStoreRead (Transaction, This->Node, "state", NULL, (VOID **)&Temp);\r
318 if (Status != XENSTORE_STATUS_SUCCESS) {\r
319 goto Out;\r
320 }\r
321 CurrentState = AsciiStrDecimalToUintn (Temp);\r
322 FreePool (Temp);\r
323 if (CurrentState == NewState) {\r
324 goto Out;\r
325 }\r
326\r
327 do {\r
328 Status = XenStoreSPrint (Transaction, This->Node, "state", "%d", NewState);\r
329 } while (Status == XENSTORE_STATUS_EAGAIN);\r
330 if (Status != XENSTORE_STATUS_SUCCESS) {\r
331 DEBUG ((EFI_D_ERROR, "XenBus: failed to write new state\n"));\r
332 goto Out;\r
333 }\r
334 DEBUG ((EFI_D_INFO, "XenBus: Set state to %d, done\n", NewState));\r
335\r
336Out:\r
337 return Status;\r
338}\r
339\r
340STATIC XENBUS_PRIVATE_DATA gXenBusPrivateData = {\r
43be9f4c
AP
341 XENBUS_PRIVATE_DATA_SIGNATURE, // Signature\r
342 { NULL, NULL }, // Link\r
343 NULL, // Handle\r
344 { // XenBusIo\r
345 XenBusXenStoreRead, // XenBusIo.XsRead\r
346 XenBusXenStoreBackendRead, // XenBusIo.XsBackendRead\r
347 XenBusXenStoreSPrint, // XenBusIo.XsPrintf\r
348 XenBusXenStoreRemove, // XenBusIo.XsRemove\r
349 XenBusXenStoreTransactionStart, // XenBusIo.XsTransactionStart\r
350 XenBusXenStoreTransactionEnd, // XenBusIo.XsTransactionEnd\r
351 XenBusSetState, // XenBusIo.SetState\r
352 XenBusGrantAccess, // XenBusIo.GrantAccess\r
353 XenBusGrantEndAccess, // XenBusIo.GrantEndAccess\r
354 XenBusEventChannelAllocate, // XenBusIo.EventChannelAllocate\r
355 XenBusEventChannelNotify, // XenBusIo.EventChannelNotify\r
356 XenBusEventChannelClose, // XenBusIo.EventChannelClose\r
357 XenBusRegisterWatch, // XenBusIo.RegisterWatch\r
358 XenBusRegisterWatchBackend, // XenBusIo.RegisterWatchBackend\r
359 XenBusUnregisterWatch, // XenBusIo.UnregisterWatch\r
360 XenBusWaitForWatch, // XenBusIo.WaitForWatch\r
361\r
362 NULL, // XenBusIo.Type\r
363 0, // XenBusIo.DeviceId\r
364 NULL, // XenBusIo.Node\r
365 NULL, // XenBusIo.Backend\r
366 },\r
367\r
368 NULL, // Dev\r
369 NULL // DevicePath\r
86d968e0 370};\r