]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/XenBusDxe/XenBus.c
OvmfPkg/Xen*: Pass struct XENSTORE_TRANSACTION argument as a pointer
[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
17 Permission is hereby granted, free of charge, to any person obtaining a copy\r
18 of this source file (the "Software"), to deal in the Software without\r
19 restriction, including without limitation the rights to use, copy, modify,\r
20 merge, publish, distribute, sublicense, and/or sell copies of the Software,\r
21 and to permit persons to whom the Software is furnished to do so, subject to\r
22 the following conditions:\r
23\r
24 The above copyright notice and this permission notice shall be included in\r
25 all copies or substantial portions of the Software.\r
26\r
27 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\r
28 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\r
29 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\r
30 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\r
31 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING\r
32 FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS\r
33 IN THE SOFTWARE.\r
34**/\r
35\r
36#include <Library/PrintLib.h>\r
37\r
38#include "XenBus.h"\r
39#include "GrantTable.h"\r
40#include "XenStore.h"\r
41#include "EventChannel.h"\r
42\r
43#include <IndustryStandard/Xen/io/xenbus.h>\r
44\r
45STATIC XENBUS_PRIVATE_DATA gXenBusPrivateData;\r
46\r
47STATIC XENBUS_DEVICE_PATH gXenBusDevicePathTemplate = {\r
48 .Vendor.Header.Type = HARDWARE_DEVICE_PATH,\r
49 .Vendor.Header.SubType = HW_VENDOR_DP,\r
50 .Vendor.Header.Length[0] = (UINT8) sizeof (XENBUS_DEVICE_PATH),\r
51 .Vendor.Header.Length[1] = (UINT8) (sizeof (XENBUS_DEVICE_PATH) >> 8),\r
52 .Vendor.Guid = XENBUS_PROTOCOL_GUID,\r
53 .Type = 0,\r
54 .DeviceId = 0\r
55};\r
56\r
57\r
58/**\r
59 Search our internal record of configured devices (not the XenStore) to\r
60 determine if the XenBus device indicated by Node is known to the system.\r
61\r
62 @param Dev The XENBUS_DEVICE instance to search for device children.\r
63 @param Node The XenStore node path for the device to find.\r
64\r
65 @return The XENBUS_PRIVATE_DATA of the found device if any, or NULL.\r
66 */\r
67STATIC\r
68XENBUS_PRIVATE_DATA *\r
69XenBusDeviceInitialized (\r
70 IN XENBUS_DEVICE *Dev,\r
71 IN CONST CHAR8 *Node\r
72 )\r
73{\r
74 LIST_ENTRY *Entry;\r
75 XENBUS_PRIVATE_DATA *Child;\r
76 XENBUS_PRIVATE_DATA *Result;\r
77\r
78 if (IsListEmpty (&Dev->ChildList)) {\r
79 return NULL;\r
80 }\r
81\r
82 Result = NULL;\r
83 for (Entry = GetFirstNode (&Dev->ChildList);\r
84 !IsNodeAtEnd (&Dev->ChildList, Entry);\r
85 Entry = GetNextNode (&Dev->ChildList, Entry)) {\r
86 Child = XENBUS_PRIVATE_DATA_FROM_LINK (Entry);\r
87 if (!AsciiStrCmp (Child->XenBusIo.Node, Node)) {\r
88 Result = Child;\r
89 break;\r
90 }\r
91 }\r
92\r
93 return (Result);\r
94}\r
95\r
96STATIC\r
97XenbusState\r
98XenBusReadDriverState (\r
99 IN CONST CHAR8 *Path\r
100 )\r
101{\r
102 XenbusState State;\r
103 CHAR8 *Ptr = NULL;\r
104 XENSTORE_STATUS Status;\r
105\r
106 Status = XenStoreRead (XST_NIL, Path, "state", NULL, (VOID **)&Ptr);\r
107 if (Status != XENSTORE_STATUS_SUCCESS) {\r
108 State = XenbusStateClosed;\r
109 } else {\r
110 State = AsciiStrDecimalToUintn (Ptr);\r
111 }\r
112\r
113 if (Ptr != NULL) {\r
114 FreePool (Ptr);\r
115 }\r
116\r
117 return State;\r
118}\r
119\r
120//\r
121// Callers should ensure that they are only one calling XenBusAddDevice.\r
122//\r
123STATIC\r
124EFI_STATUS\r
125XenBusAddDevice (\r
126 XENBUS_DEVICE *Dev,\r
127 CONST CHAR8 *Type,\r
128 CONST CHAR8 *Id)\r
129{\r
130 CHAR8 DevicePath[XENSTORE_ABS_PATH_MAX];\r
131 XENSTORE_STATUS StatusXenStore;\r
132 XENBUS_PRIVATE_DATA *Private;\r
133 EFI_STATUS Status;\r
134 XENBUS_DEVICE_PATH *TempXenBusPath;\r
135 VOID *ChildPciIo;\r
136\r
137 AsciiSPrint (DevicePath, sizeof (DevicePath),\r
138 "device/%a/%a", Type, Id);\r
139\r
140 if (XenStorePathExists (XST_NIL, DevicePath, "")) {\r
141 XENBUS_PRIVATE_DATA *Child;\r
142 enum xenbus_state State;\r
143 CHAR8 *BackendPath;\r
144\r
145 Child = XenBusDeviceInitialized (Dev, DevicePath);\r
146 if (Child != NULL) {\r
147 /*\r
148 * We are already tracking this node\r
149 */\r
150 Status = EFI_SUCCESS;\r
151 goto out;\r
152 }\r
153\r
154 State = XenBusReadDriverState (DevicePath);\r
155 if (State != XenbusStateInitialising) {\r
156 /*\r
157 * Device is not new, so ignore it. This can\r
158 * happen if a device is going away after\r
159 * switching to Closed.\r
160 */\r
161 DEBUG ((EFI_D_INFO, "XenBus: Device %a ignored. "\r
162 "State %d\n", DevicePath, State));\r
163 Status = EFI_SUCCESS;\r
164 goto out;\r
165 }\r
166\r
167 StatusXenStore = XenStoreRead (XST_NIL, DevicePath, "backend",\r
168 NULL, (VOID **) &BackendPath);\r
169 if (StatusXenStore != XENSTORE_STATUS_SUCCESS) {\r
170 DEBUG ((EFI_D_ERROR, "xenbus: %a no backend path.\n", DevicePath));\r
171 Status = EFI_NOT_FOUND;\r
172 goto out;\r
173 }\r
174\r
175 Private = AllocateCopyPool (sizeof (*Private), &gXenBusPrivateData);\r
176 Private->XenBusIo.Type = AsciiStrDup (Type);\r
177 Private->XenBusIo.Node = AsciiStrDup (DevicePath);\r
178 Private->XenBusIo.Backend = BackendPath;\r
179 Private->XenBusIo.DeviceId = AsciiStrDecimalToUintn (Id);\r
180 Private->Dev = Dev;\r
181\r
182 TempXenBusPath = AllocateCopyPool (sizeof (XENBUS_DEVICE_PATH),\r
183 &gXenBusDevicePathTemplate);\r
184 if (!AsciiStrCmp (Private->XenBusIo.Type, "vbd")) {\r
185 TempXenBusPath->Type = XENBUS_DEVICE_PATH_TYPE_VBD;\r
186 }\r
187 TempXenBusPath->DeviceId = Private->XenBusIo.DeviceId;\r
188 Private->DevicePath = (XENBUS_DEVICE_PATH *)AppendDevicePathNode (\r
189 Dev->DevicePath,\r
190 &TempXenBusPath->Vendor.Header);\r
191 FreePool (TempXenBusPath);\r
192\r
193 InsertTailList (&Dev->ChildList, &Private->Link);\r
194\r
195 Status = gBS->InstallMultipleProtocolInterfaces (\r
196 &Private->Handle,\r
197 &gEfiDevicePathProtocolGuid, Private->DevicePath,\r
198 &gXenBusProtocolGuid, &Private->XenBusIo,\r
199 NULL);\r
200 if (EFI_ERROR (Status)) {\r
201 goto ErrorInstallProtocol;\r
202 }\r
203\r
204 Status = gBS->OpenProtocol (Dev->ControllerHandle,\r
205 &gEfiPciIoProtocolGuid,\r
206 &ChildPciIo, Dev->This->DriverBindingHandle,\r
207 Private->Handle,\r
208 EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER);\r
209 if (EFI_ERROR (Status)) {\r
210 DEBUG ((EFI_D_ERROR, "open by child controller fail (%r)\n",\r
211 Status));\r
212 goto ErrorOpenProtocolByChild;\r
213 }\r
214 } else {\r
215 DEBUG ((EFI_D_ERROR, "XenBus: does not exist: %a\n", DevicePath));\r
216 Status = EFI_NOT_FOUND;\r
217 }\r
218\r
219 return Status;\r
220\r
221ErrorOpenProtocolByChild:\r
222 gBS->UninstallMultipleProtocolInterfaces (\r
223 &Private->Handle,\r
224 &gEfiDevicePathProtocolGuid, Private->DevicePath,\r
225 &gXenBusProtocolGuid, &Private->XenBusIo,\r
226 NULL);\r
227ErrorInstallProtocol:\r
228 RemoveEntryList (&Private->Link);\r
229 FreePool (Private->DevicePath);\r
230 FreePool ((VOID *) Private->XenBusIo.Backend);\r
231 FreePool ((VOID *) Private->XenBusIo.Node);\r
232 FreePool ((VOID *) Private->XenBusIo.Type);\r
233 FreePool (Private);\r
234out:\r
235 return Status;\r
236}\r
237\r
238/**\r
239 Enumerate all devices of the given type on this bus.\r
240\r
241 @param Dev A XENBUS_DEVICE instance.\r
242 @param Type String indicating the device sub-tree (e.g. "vfb", "vif")\r
243 to enumerate.\r
244\r
245 Devices that are found are been initialize via XenBusAddDevice ().\r
246 XenBusAddDevice () ignores duplicate detects and ignores duplicate devices,\r
247 so it can be called unconditionally for any device found in the XenStore.\r
248 */\r
249STATIC\r
250VOID\r
251XenBusEnumerateDeviceType (\r
252 XENBUS_DEVICE *Dev,\r
253 CONST CHAR8 *Type\r
254 )\r
255{\r
256 CONST CHAR8 **Directory;\r
257 UINTN Index;\r
258 UINT32 Count;\r
259 XENSTORE_STATUS Status;\r
260\r
261 Status = XenStoreListDirectory (XST_NIL,\r
262 "device", Type,\r
263 &Count, &Directory);\r
264 if (Status != XENSTORE_STATUS_SUCCESS) {\r
265 return;\r
266 }\r
267 for (Index = 0; Index < Count; Index++) {\r
268 XenBusAddDevice (Dev, Type, Directory[Index]);\r
269 }\r
270\r
271 FreePool (Directory);\r
272}\r
273\r
274\r
275/**\r
276 Enumerate the devices on a XenBus bus and install a XenBus Protocol instance.\r
277\r
278 Caller should ensure that it is the only one to call this function. This\r
279 function cannot be called concurrently.\r
280\r
281 @param Dev A XENBUS_DEVICE instance.\r
282\r
283 @return On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value\r
284 indicating the type of failure.\r
285 */\r
286XENSTORE_STATUS\r
287XenBusEnumerateBus (\r
288 XENBUS_DEVICE *Dev\r
289 )\r
290{\r
291 CONST CHAR8 **Types;\r
292 UINTN Index;\r
293 UINT32 Count;\r
294 XENSTORE_STATUS Status;\r
295\r
296 Status = XenStoreListDirectory (XST_NIL,\r
297 "device", "",\r
298 &Count, &Types);\r
299 if (Status != XENSTORE_STATUS_SUCCESS) {\r
300 return Status;\r
301 }\r
302\r
303 for (Index = 0; Index < Count; Index++) {\r
304 XenBusEnumerateDeviceType (Dev, Types[Index]);\r
305 }\r
306\r
307 FreePool (Types);\r
308\r
309 return XENSTORE_STATUS_SUCCESS;\r
310}\r
311\r
312STATIC\r
313XENSTORE_STATUS\r
314EFIAPI\r
315XenBusSetState (\r
316 IN XENBUS_PROTOCOL *This,\r
e26a83cd 317 IN CONST XENSTORE_TRANSACTION *Transaction,\r
86d968e0
AP
318 IN enum xenbus_state NewState\r
319 )\r
320{\r
321 enum xenbus_state CurrentState;\r
322 XENSTORE_STATUS Status;\r
323 CHAR8 *Temp;\r
324\r
325 DEBUG ((EFI_D_INFO, "XenBus: Set state to %d\n", NewState));\r
326\r
327 Status = XenStoreRead (Transaction, This->Node, "state", NULL, (VOID **)&Temp);\r
328 if (Status != XENSTORE_STATUS_SUCCESS) {\r
329 goto Out;\r
330 }\r
331 CurrentState = AsciiStrDecimalToUintn (Temp);\r
332 FreePool (Temp);\r
333 if (CurrentState == NewState) {\r
334 goto Out;\r
335 }\r
336\r
337 do {\r
338 Status = XenStoreSPrint (Transaction, This->Node, "state", "%d", NewState);\r
339 } while (Status == XENSTORE_STATUS_EAGAIN);\r
340 if (Status != XENSTORE_STATUS_SUCCESS) {\r
341 DEBUG ((EFI_D_ERROR, "XenBus: failed to write new state\n"));\r
342 goto Out;\r
343 }\r
344 DEBUG ((EFI_D_INFO, "XenBus: Set state to %d, done\n", NewState));\r
345\r
346Out:\r
347 return Status;\r
348}\r
349\r
350STATIC XENBUS_PRIVATE_DATA gXenBusPrivateData = {\r
351 .Signature = XENBUS_PRIVATE_DATA_SIGNATURE,\r
352\r
353 .XenBusIo.XsRead = XenBusXenStoreRead,\r
354 .XenBusIo.XsBackendRead = XenBusXenStoreBackendRead,\r
355 .XenBusIo.XsPrintf = XenBusXenStoreSPrint,\r
356 .XenBusIo.XsRemove = XenBusXenStoreRemove,\r
357 .XenBusIo.XsTransactionStart = XenBusXenStoreTransactionStart,\r
358 .XenBusIo.XsTransactionEnd = XenBusXenStoreTransactionEnd,\r
359 .XenBusIo.SetState = XenBusSetState,\r
360 .XenBusIo.GrantAccess = XenBusGrantAccess,\r
361 .XenBusIo.GrantEndAccess = XenBusGrantEndAccess,\r
e86895d9
AP
362 .XenBusIo.EventChannelAllocate = XenBusEventChannelAllocate,\r
363 .XenBusIo.EventChannelNotify = XenBusEventChannelNotify,\r
364 .XenBusIo.EventChannelClose = XenBusEventChannelClose,\r
86d968e0
AP
365 .XenBusIo.RegisterWatch = XenBusRegisterWatch,\r
366 .XenBusIo.RegisterWatchBackend = XenBusRegisterWatchBackend,\r
367 .XenBusIo.UnregisterWatch = XenBusUnregisterWatch,\r
368 .XenBusIo.WaitForWatch = XenBusWaitForWatch,\r
369\r
370 .XenBusIo.Type = NULL,\r
371 .XenBusIo.Node = NULL,\r
372 .XenBusIo.Backend = NULL,\r
373\r
374 .Dev = NULL\r
375};\r