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