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