• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   Main file for connect shell Driver1 function.
3 
4   (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
5   Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
6   This program and the accompanying materials
7   are licensed and made available under the terms and conditions of the BSD License
8   which accompanies this distribution.  The full text of the license may be found at
9   http://opensource.org/licenses/bsd-license.php
10 
11   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13 
14 **/
15 
16 #include "UefiShellDriver1CommandsLib.h"
17 
18 /**
19   Create all handles associate with every device path node.
20 
21   @param  DevicePathToConnect           The device path which will be connected.
22 
23   @retval EFI_SUCCESS                   All handles associate with every device path node
24                                         have been created.
25   @retval EFI_INVALID_PARAMETER         DevicePathToConnect is NULL.
26   @retval EFI_NOT_FOUND                 Create the handle associate with one device path
27                                         node failed
28 
29 **/
30 EFI_STATUS
ShellConnectDevicePath(IN EFI_DEVICE_PATH_PROTOCOL * DevicePathToConnect)31 ShellConnectDevicePath (
32   IN EFI_DEVICE_PATH_PROTOCOL   *DevicePathToConnect
33   )
34 {
35   EFI_DEVICE_PATH_PROTOCOL  *RemainingDevicePath;
36   EFI_STATUS                Status;
37   EFI_HANDLE                Handle;
38   EFI_HANDLE                PreviousHandle;
39 
40   if (DevicePathToConnect == NULL) {
41     return EFI_INVALID_PARAMETER;
42   }
43 
44   PreviousHandle = NULL;
45   do{
46     RemainingDevicePath = DevicePathToConnect;
47     Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &Handle);
48 
49     if (!EFI_ERROR (Status) && (Handle != NULL)) {
50       if (PreviousHandle == Handle) {
51         Status = EFI_NOT_FOUND;
52       } else {
53         PreviousHandle = Handle;
54         Status = gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE);
55       }
56     }
57 
58   } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath) );
59 
60   return Status;
61 
62 }
63 
64 /**
65   Connect drivers for PCI root bridge.
66 
67   @retval EFI_SUCCESS                     Connect drivers successfully.
68   @retval EFI_NOT_FOUND                   Cannot find PCI root bridge device.
69 
70 **/
71 EFI_STATUS
ShellConnectPciRootBridge(VOID)72 ShellConnectPciRootBridge (
73   VOID
74   )
75 {
76   UINTN               RootBridgeHandleCount;
77   EFI_HANDLE          *RootBridgeHandleBuffer;
78   UINTN               RootBridgeIndex;
79   EFI_STATUS          Status;
80 
81   RootBridgeHandleCount = 0;
82 
83   Status = gBS->LocateHandleBuffer (
84               ByProtocol,
85               &gEfiPciRootBridgeIoProtocolGuid,
86               NULL,
87               &RootBridgeHandleCount,
88               &RootBridgeHandleBuffer
89               );
90   if (EFI_ERROR (Status)) {
91     return Status;
92   }
93 
94   for (RootBridgeIndex = 0; RootBridgeIndex < RootBridgeHandleCount; RootBridgeIndex++) {
95     gBS->ConnectController (RootBridgeHandleBuffer[RootBridgeIndex], NULL, NULL, FALSE);
96   }
97 
98   FreePool (RootBridgeHandleBuffer);
99 
100   return EFI_SUCCESS;
101 }
102 
103 
104 /**
105   Connect controller(s) and driver(s).
106 
107   @param[in] ControllerHandle     The handle to the controller. Should have driver binding on it.
108   @param[in] DriverHandle         The handle to the driver. Should have driver binding.
109   @param[in] Recursive            TRUE to connect recursively, FALSE otherwise.
110   @param[in] Output               TRUE to have info on the screen, FALSE otherwise.
111   @param[in] AlwaysOutput         Override Output for errors.
112 
113   @retval EFI_SUCCESS             The operation was successful.
114 **/
115 EFI_STATUS
116 EFIAPI
ConnectControllers(IN CONST EFI_HANDLE ControllerHandle OPTIONAL,IN CONST EFI_HANDLE DriverHandle OPTIONAL,IN CONST BOOLEAN Recursive,IN CONST BOOLEAN Output,IN CONST BOOLEAN AlwaysOutput)117 ConnectControllers (
118   IN CONST EFI_HANDLE ControllerHandle OPTIONAL,
119   IN CONST EFI_HANDLE DriverHandle OPTIONAL,
120   IN CONST BOOLEAN    Recursive,
121   IN CONST BOOLEAN    Output,
122   IN CONST BOOLEAN    AlwaysOutput
123   )
124 {
125   EFI_STATUS Status;
126   EFI_STATUS Status2;
127   EFI_HANDLE *ControllerHandleList;
128   EFI_HANDLE *DriverHandleList;
129   EFI_HANDLE *HandleWalker;
130 
131   ControllerHandleList  = NULL;
132   Status                = EFI_NOT_FOUND;
133   Status2               = EFI_NOT_FOUND;
134 
135   //
136   // If we have a single handle to connect make that a 'list'
137   //
138   if (DriverHandle == NULL) {
139     DriverHandleList = NULL;
140   } else {
141     DriverHandleList = AllocateZeroPool(2*sizeof(EFI_HANDLE));
142     if (DriverHandleList == NULL) {
143       return (EFI_OUT_OF_RESOURCES);
144     }
145     DriverHandleList[0] = DriverHandle;
146     DriverHandleList[1] = NULL;
147   }
148 
149   //
150   // do we connect all controllers (with a loop) or a single one...
151   // This is where we call the gBS->ConnectController function.
152   //
153   if (ControllerHandle == NULL) {
154     ControllerHandleList = GetHandleListByProtocol(&gEfiDevicePathProtocolGuid);
155     for (HandleWalker = ControllerHandleList
156       ;  HandleWalker != NULL && *HandleWalker != NULL
157       ;  HandleWalker++
158      ){
159       Status = gBS->ConnectController(*HandleWalker, DriverHandleList, NULL, Recursive);
160       if (!EFI_ERROR(Status)) {
161         Status2 = EFI_SUCCESS;
162       }
163       if ((Output && !EFI_ERROR(Status)) || AlwaysOutput) {
164         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_HANDLE_RESULT), gShellDriver1HiiHandle, L"Connect", ConvertHandleToHandleIndex(*HandleWalker), Status);
165       }
166     }
167   } else {
168     Status = gBS->ConnectController(ControllerHandle, DriverHandleList, NULL, Recursive);
169     if (!EFI_ERROR(Status)) {
170       Status2 = EFI_SUCCESS;
171     }
172     if ((Output && !EFI_ERROR(Status)) || AlwaysOutput) {
173       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_HANDLE_RESULT), gShellDriver1HiiHandle, L"Connect", ConvertHandleToHandleIndex(ControllerHandle), Status);
174     }
175   }
176 
177   //
178   // Free any memory we allocated.
179   //
180   if (ControllerHandleList != NULL) {
181     FreePool(ControllerHandleList);
182   }
183   if (DriverHandleList     != NULL) {
184     FreePool(DriverHandleList);
185   }
186   return (Status2);
187 }
188 
189 /**
190   Do a connect from an EFI variable via it's key name.
191 
192   @param[in] Key      The name of the EFI Variable.
193 
194   @retval EFI_SUCCESS   The operation was successful.
195 **/
196 EFI_STATUS
197 EFIAPI
ShellConnectFromDevPaths(IN CONST CHAR16 * Key)198 ShellConnectFromDevPaths (
199   IN CONST CHAR16 *Key
200   )
201 {
202   EFI_DEVICE_PATH_PROTOCOL  *DevPath;
203   EFI_DEVICE_PATH_PROTOCOL  *CopyOfDevPath;
204   EFI_DEVICE_PATH_PROTOCOL  *Instance;
205   EFI_DEVICE_PATH_PROTOCOL  *Next;
206   UINTN                     Length;
207   UINTN                     Index;
208   UINTN                     HandleArrayCount;
209   UINTN                     Size;
210   EFI_HANDLE                *HandleArray;
211   EFI_STATUS                Status;
212   BOOLEAN                   AtLeastOneConnected;
213   EFI_PCI_IO_PROTOCOL       *PciIo;
214   UINT8                     Class[3];
215 
216   DevPath = NULL;
217   Length  = 0;
218   AtLeastOneConnected = FALSE;
219 
220   //
221   // Get the DevicePath buffer from the variable...
222   //
223   Status = gRT->GetVariable((CHAR16*)Key, (EFI_GUID*)&gEfiGlobalVariableGuid, NULL, &Length, DevPath);
224   if (Status == EFI_BUFFER_TOO_SMALL) {
225     DevPath = AllocateZeroPool(Length);
226     if (DevPath == NULL) {
227       return EFI_OUT_OF_RESOURCES;
228     }
229     Status = gRT->GetVariable((CHAR16*)Key, (EFI_GUID*)&gEfiGlobalVariableGuid, NULL, &Length, DevPath);
230     if (EFI_ERROR (Status)) {
231       if (DevPath != NULL) {
232         FreePool (DevPath);
233       }
234       return Status;
235     }
236   } else if (EFI_ERROR (Status)) {
237     return Status;
238   }
239 
240   Status = EFI_NOT_FOUND;
241 
242   CopyOfDevPath = DevPath;
243   //
244   // walk the list of devices and connect them
245   //
246   do {
247     //
248     // Check every instance of the console variable
249     //
250     Instance = GetNextDevicePathInstance (&CopyOfDevPath, &Size);
251     if (Instance == NULL) {
252       if (DevPath != NULL) {
253         FreePool (DevPath);
254       }
255       return EFI_UNSUPPORTED;
256     }
257 
258     Next = Instance;
259     while (!IsDevicePathEndType (Next)) {
260       Next = NextDevicePathNode (Next);
261     }
262 
263     SetDevicePathEndNode (Next);
264     //
265     // connect short form device path
266     //
267     if ((DevicePathType (Instance) == MESSAGING_DEVICE_PATH) &&
268       ((DevicePathSubType (Instance) == MSG_USB_CLASS_DP)
269       || (DevicePathSubType (Instance) == MSG_USB_WWID_DP)
270       )) {
271 
272       Status = ShellConnectPciRootBridge ();
273       if (EFI_ERROR(Status)) {
274         FreePool(Instance);
275         FreePool(DevPath);
276         return Status;
277       }
278 
279       Status = gBS->LocateHandleBuffer (
280                   ByProtocol,
281                   &gEfiPciIoProtocolGuid,
282                   NULL,
283                   &HandleArrayCount,
284                   &HandleArray
285                   );
286 
287       if (!EFI_ERROR (Status)) {
288         for (Index = 0; Index < HandleArrayCount; Index++) {
289           Status = gBS->HandleProtocol (
290                       HandleArray[Index],
291                       &gEfiPciIoProtocolGuid,
292                       (VOID **)&PciIo
293                       );
294 
295           if (!EFI_ERROR (Status)) {
296             Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 3, &Class);
297             if (!EFI_ERROR (Status)) {
298               if ((PCI_CLASS_SERIAL == Class[2]) &&
299                   (PCI_CLASS_SERIAL_USB == Class[1])) {
300                 Status = gBS->ConnectController (
301                               HandleArray[Index],
302                               NULL,
303                               Instance,
304                               FALSE
305                               );
306                 if (!EFI_ERROR(Status)) {
307                   AtLeastOneConnected = TRUE;
308                 }
309               }
310             }
311           }
312         }
313       }
314 
315       if (HandleArray != NULL) {
316         FreePool (HandleArray);
317       }
318     } else {
319       //
320       // connect the entire device path
321       //
322       Status = ShellConnectDevicePath (Instance);
323       if (!EFI_ERROR (Status)) {
324         AtLeastOneConnected = TRUE;
325       }
326     }
327     FreePool (Instance);
328 
329   } while (CopyOfDevPath != NULL);
330 
331   if (DevPath != NULL) {
332     FreePool(DevPath);
333   }
334 
335   if (AtLeastOneConnected) {
336     return EFI_SUCCESS;
337   } else {
338     return EFI_NOT_FOUND;
339   }
340 
341 }
342 
343 /**
344   Convert the handle identifiers from strings and then connect them.
345 
346   One of them should have driver binding and either can be NULL.
347 
348   @param[in] Handle1            The first handle.
349   @param[in] Handle2            The second handle.
350   @param[in] Recursive          TRUE to do connect recursively. FALSE otherwise.
351   @param[in] Output             TRUE to have output to screen. FALSE otherwise.
352 
353   @retval EFI_SUCCESS           The operation was successful.
354 **/
355 EFI_STATUS
356 EFIAPI
ConvertAndConnectControllers(IN EFI_HANDLE * Handle1 OPTIONAL,IN EFI_HANDLE * Handle2 OPTIONAL,IN CONST BOOLEAN Recursive,IN CONST BOOLEAN Output)357 ConvertAndConnectControllers (
358   IN EFI_HANDLE     *Handle1 OPTIONAL,
359   IN EFI_HANDLE     *Handle2 OPTIONAL,
360   IN CONST BOOLEAN  Recursive,
361   IN CONST BOOLEAN  Output
362   )
363 {
364   //
365   // if only one is NULL verify it's the proper one...
366   //
367   if ( (Handle1 == NULL && Handle2 != NULL)
368     || (Handle1 != NULL && Handle2 == NULL)
369    ){
370     //
371     // Figure out which one should be NULL and move the handle to the right place.
372     // If Handle1 is NULL then test Handle2 and vise versa.
373     // The one that DOES has driver binding must be Handle2
374     //
375     if (Handle1 == NULL) {
376       if (EFI_ERROR(gBS->OpenProtocol(Handle2, &gEfiDriverBindingProtocolGuid, NULL, NULL, gImageHandle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) {
377         // swap
378         Handle1 = Handle2;
379         Handle2 = NULL;
380       } else {
381         // We're all good...
382       }
383     } else {
384       if (EFI_ERROR(gBS->OpenProtocol(Handle1, &gEfiDriverBindingProtocolGuid, NULL, NULL, gImageHandle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) {
385         // We're all good...
386       } else {
387         // swap
388         Handle2 = Handle1;
389         Handle1 = NULL;
390       }
391     }
392   }
393 
394   return (ConnectControllers(Handle1, Handle2, Recursive, Output, (BOOLEAN)(Handle2 != NULL && Handle1 != NULL)));
395 }
396 
397 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
398   {L"-c", TypeFlag},
399   {L"-r", TypeFlag},
400   {NULL, TypeMax}
401   };
402 
403 /**
404   Function for 'connect' command.
405 
406   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
407   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
408 **/
409 SHELL_STATUS
410 EFIAPI
ShellCommandRunConnect(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)411 ShellCommandRunConnect (
412   IN EFI_HANDLE        ImageHandle,
413   IN EFI_SYSTEM_TABLE  *SystemTable
414   )
415 {
416   EFI_STATUS          Status;
417   LIST_ENTRY          *Package;
418   CHAR16              *ProblemParam;
419   SHELL_STATUS        ShellStatus;
420   CONST CHAR16        *Param1;
421   CONST CHAR16        *Param2;
422   UINTN               Count;
423   EFI_HANDLE          Handle1;
424   EFI_HANDLE          Handle2;
425   UINT64              Intermediate;
426 
427   ShellStatus         = SHELL_SUCCESS;
428   //
429   // initialize the shell lib (we must be in non-auto-init...)
430   //
431   Status = ShellInitialize();
432   ASSERT_EFI_ERROR(Status);
433 
434   Status = CommandInit();
435   ASSERT_EFI_ERROR(Status);
436 
437   //
438   // parse the command line
439   //
440   Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
441   if (EFI_ERROR(Status)) {
442     if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
443       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDriver1HiiHandle, L"connect", ProblemParam);
444       FreePool(ProblemParam);
445       ShellStatus = SHELL_INVALID_PARAMETER;
446     } else {
447       ASSERT(FALSE);
448     }
449   } else {
450     //
451     // if more than 2 'value' parameters (plus the name one) or either -r or -c with any value parameters we have too many parameters
452     //
453     Count = (gInReconnect?0x4:0x3);
454     if ((ShellCommandLineGetCount(Package) > Count)
455       ||((ShellCommandLineGetFlag(Package, L"-r") || ShellCommandLineGetFlag(Package, L"-c")) && ShellCommandLineGetCount(Package)>1)
456       ||(ShellCommandLineGetFlag(Package, L"-r") && ShellCommandLineGetFlag(Package, L"-c") )
457      ){
458       //
459       // error for too many parameters
460       //
461       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDriver1HiiHandle, L"connect");
462       ShellStatus = SHELL_INVALID_PARAMETER;
463     } else if (ShellCommandLineGetFlag(Package, L"-c")) {
464       //
465       // do the conin and conout from EFI variables
466       // if the first fails dont 'loose' the error
467       //
468       Status = ShellConnectFromDevPaths(L"ConInDev");
469       if (EFI_ERROR(Status)) {
470         ShellConnectFromDevPaths(L"ConOutDev");
471       } else {
472         Status = ShellConnectFromDevPaths(L"ConOutDev");
473       }
474       if (EFI_ERROR(Status)) {
475         ShellConnectFromDevPaths(L"ErrOutDev");
476       } else {
477         Status = ShellConnectFromDevPaths(L"ErrOutDev");
478       }
479       if (EFI_ERROR(Status)) {
480         ShellConnectFromDevPaths(L"ErrOut");
481       } else {
482         Status = ShellConnectFromDevPaths(L"ErrOut");
483       }
484       if (EFI_ERROR(Status)) {
485         ShellConnectFromDevPaths(L"ConIn");
486       } else {
487         Status = ShellConnectFromDevPaths(L"ConIn");
488       }
489       if (EFI_ERROR(Status)) {
490         ShellConnectFromDevPaths(L"ConOut");
491       } else {
492         Status = ShellConnectFromDevPaths(L"ConOut");
493       }
494       if (EFI_ERROR(Status)) {
495         ShellStatus = SHELL_DEVICE_ERROR;
496       }
497     } else {
498       //
499       // 0, 1, or 2 specific handles and possibly recursive
500       //
501       Param1  = ShellCommandLineGetRawValue(Package, 1);
502       Param2  = ShellCommandLineGetRawValue(Package, 2);
503       Count   = ShellCommandLineGetCount(Package);
504 
505       if (Param1 != NULL) {
506         Status  = ShellConvertStringToUint64(Param1, &Intermediate, TRUE, FALSE);
507         Handle1 = ConvertHandleIndexToHandle((UINTN)Intermediate);
508         if (EFI_ERROR(Status)) {
509           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"connect", Param1);
510           ShellStatus = SHELL_INVALID_PARAMETER;
511         }
512       } else {
513         Handle1 = NULL;
514       }
515 
516       if (Param2 != NULL) {
517         Status  = ShellConvertStringToUint64(Param2, &Intermediate, TRUE, FALSE);
518         Handle2 = ConvertHandleIndexToHandle((UINTN)Intermediate);
519         if (EFI_ERROR(Status)) {
520           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"connect", Param2);
521           ShellStatus = SHELL_INVALID_PARAMETER;
522         }
523       } else {
524         Handle2 = NULL;
525       }
526 
527       if (ShellStatus == SHELL_SUCCESS) {
528         if (Param1 != NULL && Handle1 == NULL){
529           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"connect", Param1);
530           ShellStatus = SHELL_INVALID_PARAMETER;
531         } else if (Param2 != NULL && Handle2 == NULL) {
532           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"connect", Param2);
533           ShellStatus = SHELL_INVALID_PARAMETER;
534         } else if (Handle2 != NULL && Handle1 != NULL && EFI_ERROR(gBS->OpenProtocol(Handle2, &gEfiDriverBindingProtocolGuid, NULL, gImageHandle, NULL, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) {
535           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"connect", Param2);
536           ShellStatus = SHELL_INVALID_PARAMETER;
537         } else {
538           Status = ConvertAndConnectControllers(Handle1, Handle2, ShellCommandLineGetFlag(Package, L"-r"), (BOOLEAN)(Count!=0));
539           if (EFI_ERROR(Status)) {
540             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CONNECT_NONE), gShellDriver1HiiHandle);
541             ShellStatus = SHELL_DEVICE_ERROR;
542           }
543         }
544       }
545     }
546 
547     ShellCommandLineFreeVarList (Package);
548   }
549   return (ShellStatus);
550 }
551 
552