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