Home | History | Annotate | Download | only in UefiShellDriver1CommandsLib
      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
     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
     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
    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
    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
    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
    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