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 /**
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 *
XenBusDeviceInitialized(IN XENBUS_DEVICE * Dev,IN CONST CHAR8 * Node)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
XenBusReadDriverState(IN CONST CHAR8 * Path)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
XenBusAddDevice(XENBUS_DEVICE * Dev,CONST CHAR8 * Type,CONST CHAR8 * Id)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 ((DEBUG_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 ((DEBUG_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 ((DEBUG_ERROR, "open by child controller fail (%r)\n",
201               Status));
202       goto ErrorOpenProtocolByChild;
203     }
204   } else {
205     DEBUG ((DEBUG_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
XenBusEnumerateDeviceType(XENBUS_DEVICE * Dev,CONST CHAR8 * Type)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
XenBusEnumerateBus(XENBUS_DEVICE * Dev)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
XenBusSetState(IN XENBUS_PROTOCOL * This,IN CONST XENSTORE_TRANSACTION * Transaction,IN enum xenbus_state NewState)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 ((DEBUG_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 ((DEBUG_ERROR, "XenBus: failed to write new state\n"));
332     goto Out;
333   }
334   DEBUG ((DEBUG_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 };
371