]>
Commit | Line | Data |
---|---|---|
1 | /** @file\r | |
2 | XenBus Bus driver implementation.\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 | SPDX-License-Identifier: MIT\r | |
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 | |
29 | STATIC XENBUS_PRIVATE_DATA gXenBusPrivateData;\r | |
30 | \r | |
31 | STATIC XENBUS_DEVICE_PATH gXenBusDevicePathTemplate = {\r | |
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 | |
45 | };\r | |
46 | \r | |
47 | /**\r | |
48 | Search our internal record of configured devices (not the XenStore) to\r | |
49 | determine if the XenBus device indicated by Node is known to the system.\r | |
50 | \r | |
51 | @param Dev The XENBUS_DEVICE instance to search for device children.\r | |
52 | @param Node The XenStore node path for the device to find.\r | |
53 | \r | |
54 | @return The XENBUS_PRIVATE_DATA of the found device if any, or NULL.\r | |
55 | */\r | |
56 | STATIC\r | |
57 | XENBUS_PRIVATE_DATA *\r | |
58 | XenBusDeviceInitialized (\r | |
59 | IN XENBUS_DEVICE *Dev,\r | |
60 | IN CONST CHAR8 *Node\r | |
61 | )\r | |
62 | {\r | |
63 | LIST_ENTRY *Entry;\r | |
64 | XENBUS_PRIVATE_DATA *Child;\r | |
65 | XENBUS_PRIVATE_DATA *Result;\r | |
66 | \r | |
67 | if (IsListEmpty (&Dev->ChildList)) {\r | |
68 | return NULL;\r | |
69 | }\r | |
70 | \r | |
71 | Result = NULL;\r | |
72 | for (Entry = GetFirstNode (&Dev->ChildList);\r | |
73 | !IsNodeAtEnd (&Dev->ChildList, Entry);\r | |
74 | Entry = GetNextNode (&Dev->ChildList, Entry))\r | |
75 | {\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 | |
86 | STATIC\r | |
87 | XenbusState\r | |
88 | XenBusReadDriverState (\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 | |
113 | STATIC\r | |
114 | EFI_STATUS\r | |
115 | XenBusAddDevice (\r | |
116 | XENBUS_DEVICE *Dev,\r | |
117 | CONST CHAR8 *Type,\r | |
118 | CONST CHAR8 *Id\r | |
119 | )\r | |
120 | {\r | |
121 | CHAR8 DevicePath[XENSTORE_ABS_PATH_MAX];\r | |
122 | XENSTORE_STATUS StatusXenStore;\r | |
123 | XENBUS_PRIVATE_DATA *Private;\r | |
124 | EFI_STATUS Status;\r | |
125 | XENBUS_DEVICE_PATH *TempXenBusPath;\r | |
126 | VOID *ChildXenIo;\r | |
127 | \r | |
128 | AsciiSPrint (\r | |
129 | DevicePath,\r | |
130 | sizeof (DevicePath),\r | |
131 | "device/%a/%a",\r | |
132 | Type,\r | |
133 | Id\r | |
134 | );\r | |
135 | \r | |
136 | if (XenStorePathExists (XST_NIL, DevicePath, "")) {\r | |
137 | XENBUS_PRIVATE_DATA *Child;\r | |
138 | enum xenbus_state State;\r | |
139 | CHAR8 *BackendPath;\r | |
140 | \r | |
141 | Child = XenBusDeviceInitialized (Dev, DevicePath);\r | |
142 | if (Child != NULL) {\r | |
143 | /*\r | |
144 | * We are already tracking this node\r | |
145 | */\r | |
146 | Status = EFI_SUCCESS;\r | |
147 | goto out;\r | |
148 | }\r | |
149 | \r | |
150 | State = XenBusReadDriverState (DevicePath);\r | |
151 | if (State != XenbusStateInitialising) {\r | |
152 | /*\r | |
153 | * Device is not new, so ignore it. This can\r | |
154 | * happen if a device is going away after\r | |
155 | * switching to Closed.\r | |
156 | */\r | |
157 | DEBUG ((\r | |
158 | DEBUG_INFO,\r | |
159 | "XenBus: Device %a ignored. "\r | |
160 | "State %d\n",\r | |
161 | DevicePath,\r | |
162 | State\r | |
163 | ));\r | |
164 | Status = EFI_SUCCESS;\r | |
165 | goto out;\r | |
166 | }\r | |
167 | \r | |
168 | StatusXenStore = XenStoreRead (\r | |
169 | XST_NIL,\r | |
170 | DevicePath,\r | |
171 | "backend",\r | |
172 | NULL,\r | |
173 | (VOID **)&BackendPath\r | |
174 | );\r | |
175 | if (StatusXenStore != XENSTORE_STATUS_SUCCESS) {\r | |
176 | DEBUG ((DEBUG_ERROR, "xenbus: %a no backend path.\n", DevicePath));\r | |
177 | Status = EFI_NOT_FOUND;\r | |
178 | goto out;\r | |
179 | }\r | |
180 | \r | |
181 | Private = AllocateCopyPool (sizeof (*Private), &gXenBusPrivateData);\r | |
182 | Private->XenBusIo.Type = AsciiStrDup (Type);\r | |
183 | Private->XenBusIo.Node = AsciiStrDup (DevicePath);\r | |
184 | Private->XenBusIo.Backend = BackendPath;\r | |
185 | Private->XenBusIo.DeviceId = (UINT16)AsciiStrDecimalToUintn (Id);\r | |
186 | Private->Dev = Dev;\r | |
187 | \r | |
188 | TempXenBusPath = AllocateCopyPool (\r | |
189 | sizeof (XENBUS_DEVICE_PATH),\r | |
190 | &gXenBusDevicePathTemplate\r | |
191 | );\r | |
192 | if (!AsciiStrCmp (Private->XenBusIo.Type, "vbd")) {\r | |
193 | TempXenBusPath->Type = XENBUS_DEVICE_PATH_TYPE_VBD;\r | |
194 | }\r | |
195 | \r | |
196 | TempXenBusPath->DeviceId = Private->XenBusIo.DeviceId;\r | |
197 | Private->DevicePath = (XENBUS_DEVICE_PATH *)AppendDevicePathNode (\r | |
198 | Dev->DevicePath,\r | |
199 | &TempXenBusPath->Vendor.Header\r | |
200 | );\r | |
201 | FreePool (TempXenBusPath);\r | |
202 | \r | |
203 | InsertTailList (&Dev->ChildList, &Private->Link);\r | |
204 | \r | |
205 | Status = gBS->InstallMultipleProtocolInterfaces (\r | |
206 | &Private->Handle,\r | |
207 | &gEfiDevicePathProtocolGuid,\r | |
208 | Private->DevicePath,\r | |
209 | &gXenBusProtocolGuid,\r | |
210 | &Private->XenBusIo,\r | |
211 | NULL\r | |
212 | );\r | |
213 | if (EFI_ERROR (Status)) {\r | |
214 | goto ErrorInstallProtocol;\r | |
215 | }\r | |
216 | \r | |
217 | Status = gBS->OpenProtocol (\r | |
218 | Dev->ControllerHandle,\r | |
219 | &gXenIoProtocolGuid,\r | |
220 | &ChildXenIo,\r | |
221 | Dev->This->DriverBindingHandle,\r | |
222 | Private->Handle,\r | |
223 | EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER\r | |
224 | );\r | |
225 | if (EFI_ERROR (Status)) {\r | |
226 | DEBUG ((\r | |
227 | DEBUG_ERROR,\r | |
228 | "open by child controller fail (%r)\n",\r | |
229 | Status\r | |
230 | ));\r | |
231 | goto ErrorOpenProtocolByChild;\r | |
232 | }\r | |
233 | } else {\r | |
234 | DEBUG ((DEBUG_ERROR, "XenBus: does not exist: %a\n", DevicePath));\r | |
235 | Status = EFI_NOT_FOUND;\r | |
236 | }\r | |
237 | \r | |
238 | return Status;\r | |
239 | \r | |
240 | ErrorOpenProtocolByChild:\r | |
241 | gBS->UninstallMultipleProtocolInterfaces (\r | |
242 | Private->Handle,\r | |
243 | &gEfiDevicePathProtocolGuid,\r | |
244 | Private->DevicePath,\r | |
245 | &gXenBusProtocolGuid,\r | |
246 | &Private->XenBusIo,\r | |
247 | NULL\r | |
248 | );\r | |
249 | ErrorInstallProtocol:\r | |
250 | RemoveEntryList (&Private->Link);\r | |
251 | FreePool (Private->DevicePath);\r | |
252 | FreePool ((VOID *)Private->XenBusIo.Backend);\r | |
253 | FreePool ((VOID *)Private->XenBusIo.Node);\r | |
254 | FreePool ((VOID *)Private->XenBusIo.Type);\r | |
255 | FreePool (Private);\r | |
256 | out:\r | |
257 | return Status;\r | |
258 | }\r | |
259 | \r | |
260 | /**\r | |
261 | Enumerate all devices of the given type on this bus.\r | |
262 | \r | |
263 | @param Dev A XENBUS_DEVICE instance.\r | |
264 | @param Type String indicating the device sub-tree (e.g. "vfb", "vif")\r | |
265 | to enumerate.\r | |
266 | \r | |
267 | Devices that are found are been initialize via XenBusAddDevice ().\r | |
268 | XenBusAddDevice () ignores duplicate detects and ignores duplicate devices,\r | |
269 | so it can be called unconditionally for any device found in the XenStore.\r | |
270 | */\r | |
271 | STATIC\r | |
272 | VOID\r | |
273 | XenBusEnumerateDeviceType (\r | |
274 | XENBUS_DEVICE *Dev,\r | |
275 | CONST CHAR8 *Type\r | |
276 | )\r | |
277 | {\r | |
278 | CONST CHAR8 **Directory;\r | |
279 | UINTN Index;\r | |
280 | UINT32 Count;\r | |
281 | XENSTORE_STATUS Status;\r | |
282 | \r | |
283 | Status = XenStoreListDirectory (\r | |
284 | XST_NIL,\r | |
285 | "device",\r | |
286 | Type,\r | |
287 | &Count,\r | |
288 | &Directory\r | |
289 | );\r | |
290 | if (Status != XENSTORE_STATUS_SUCCESS) {\r | |
291 | return;\r | |
292 | }\r | |
293 | \r | |
294 | for (Index = 0; Index < Count; Index++) {\r | |
295 | XenBusAddDevice (Dev, Type, Directory[Index]);\r | |
296 | }\r | |
297 | \r | |
298 | FreePool ((VOID *)Directory);\r | |
299 | }\r | |
300 | \r | |
301 | /**\r | |
302 | Enumerate the devices on a XenBus bus and install a XenBus Protocol instance.\r | |
303 | \r | |
304 | Caller should ensure that it is the only one to call this function. This\r | |
305 | function cannot be called concurrently.\r | |
306 | \r | |
307 | @param Dev A XENBUS_DEVICE instance.\r | |
308 | \r | |
309 | @return On success, XENSTORE_STATUS_SUCCESS. Otherwise an errno value\r | |
310 | indicating the type of failure.\r | |
311 | */\r | |
312 | XENSTORE_STATUS\r | |
313 | XenBusEnumerateBus (\r | |
314 | XENBUS_DEVICE *Dev\r | |
315 | )\r | |
316 | {\r | |
317 | CONST CHAR8 **Types;\r | |
318 | UINTN Index;\r | |
319 | UINT32 Count;\r | |
320 | XENSTORE_STATUS Status;\r | |
321 | \r | |
322 | Status = XenStoreListDirectory (\r | |
323 | XST_NIL,\r | |
324 | "device",\r | |
325 | "",\r | |
326 | &Count,\r | |
327 | &Types\r | |
328 | );\r | |
329 | if (Status != XENSTORE_STATUS_SUCCESS) {\r | |
330 | return Status;\r | |
331 | }\r | |
332 | \r | |
333 | for (Index = 0; Index < Count; Index++) {\r | |
334 | XenBusEnumerateDeviceType (Dev, Types[Index]);\r | |
335 | }\r | |
336 | \r | |
337 | FreePool ((VOID *)Types);\r | |
338 | \r | |
339 | return XENSTORE_STATUS_SUCCESS;\r | |
340 | }\r | |
341 | \r | |
342 | STATIC\r | |
343 | XENSTORE_STATUS\r | |
344 | EFIAPI\r | |
345 | XenBusSetState (\r | |
346 | IN XENBUS_PROTOCOL *This,\r | |
347 | IN CONST XENSTORE_TRANSACTION *Transaction,\r | |
348 | IN enum xenbus_state NewState\r | |
349 | )\r | |
350 | {\r | |
351 | enum xenbus_state CurrentState;\r | |
352 | XENSTORE_STATUS Status;\r | |
353 | CHAR8 *Temp;\r | |
354 | \r | |
355 | DEBUG ((DEBUG_INFO, "XenBus: Set state to %d\n", NewState));\r | |
356 | \r | |
357 | Status = XenStoreRead (Transaction, This->Node, "state", NULL, (VOID **)&Temp);\r | |
358 | if (Status != XENSTORE_STATUS_SUCCESS) {\r | |
359 | goto Out;\r | |
360 | }\r | |
361 | \r | |
362 | CurrentState = AsciiStrDecimalToUintn (Temp);\r | |
363 | FreePool (Temp);\r | |
364 | if (CurrentState == NewState) {\r | |
365 | goto Out;\r | |
366 | }\r | |
367 | \r | |
368 | do {\r | |
369 | Status = XenStoreSPrint (Transaction, This->Node, "state", "%d", NewState);\r | |
370 | } while (Status == XENSTORE_STATUS_EAGAIN);\r | |
371 | \r | |
372 | if (Status != XENSTORE_STATUS_SUCCESS) {\r | |
373 | DEBUG ((DEBUG_ERROR, "XenBus: failed to write new state\n"));\r | |
374 | goto Out;\r | |
375 | }\r | |
376 | \r | |
377 | DEBUG ((DEBUG_INFO, "XenBus: Set state to %d, done\n", NewState));\r | |
378 | \r | |
379 | Out:\r | |
380 | return Status;\r | |
381 | }\r | |
382 | \r | |
383 | STATIC XENBUS_PRIVATE_DATA gXenBusPrivateData = {\r | |
384 | XENBUS_PRIVATE_DATA_SIGNATURE, // Signature\r | |
385 | { NULL, NULL }, // Link\r | |
386 | NULL, // Handle\r | |
387 | { // XenBusIo\r | |
388 | XenBusXenStoreRead, // XenBusIo.XsRead\r | |
389 | XenBusXenStoreBackendRead, // XenBusIo.XsBackendRead\r | |
390 | XenBusXenStoreSPrint, // XenBusIo.XsPrintf\r | |
391 | XenBusXenStoreRemove, // XenBusIo.XsRemove\r | |
392 | XenBusXenStoreTransactionStart, // XenBusIo.XsTransactionStart\r | |
393 | XenBusXenStoreTransactionEnd, // XenBusIo.XsTransactionEnd\r | |
394 | XenBusSetState, // XenBusIo.SetState\r | |
395 | XenBusGrantAccess, // XenBusIo.GrantAccess\r | |
396 | XenBusGrantEndAccess, // XenBusIo.GrantEndAccess\r | |
397 | XenBusEventChannelAllocate, // XenBusIo.EventChannelAllocate\r | |
398 | XenBusEventChannelNotify, // XenBusIo.EventChannelNotify\r | |
399 | XenBusEventChannelClose, // XenBusIo.EventChannelClose\r | |
400 | XenBusRegisterWatch, // XenBusIo.RegisterWatch\r | |
401 | XenBusRegisterWatchBackend, // XenBusIo.RegisterWatchBackend\r | |
402 | XenBusUnregisterWatch, // XenBusIo.UnregisterWatch\r | |
403 | XenBusWaitForWatch, // XenBusIo.WaitForWatch\r | |
404 | \r | |
405 | NULL, // XenBusIo.Type\r | |
406 | 0, // XenBusIo.DeviceId\r | |
407 | NULL, // XenBusIo.Node\r | |
408 | NULL, // XenBusIo.Backend\r | |
409 | },\r | |
410 | \r | |
411 | NULL, // Dev\r | |
412 | NULL // DevicePath\r | |
413 | };\r |