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