• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 *
XenBusDeviceInitialized(IN XENBUS_DEVICE * Dev,IN CONST CHAR8 * Node)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
XenBusReadDriverState(IN CONST CHAR8 * Path)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
XenBusAddDevice(XENBUS_DEVICE * Dev,CONST CHAR8 * Type,CONST CHAR8 * Id)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 *ChildXenIo;
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 = (UINT16)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                &gXenIoProtocolGuid,
212                &ChildXenIo, 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
XenBusEnumerateDeviceType(XENBUS_DEVICE * Dev,CONST CHAR8 * Type)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 ((VOID*)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
XenBusEnumerateBus(XENBUS_DEVICE * Dev)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 ((VOID*)Types);
314 
315   return XENSTORE_STATUS_SUCCESS;
316 }
317 
318 STATIC
319 XENSTORE_STATUS
320 EFIAPI
XenBusSetState(IN XENBUS_PROTOCOL * This,IN CONST XENSTORE_TRANSACTION * Transaction,IN enum xenbus_state NewState)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 };
387