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 - 2016, 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 ConnectControllers (
    117   IN CONST EFI_HANDLE ControllerHandle OPTIONAL,
    118   IN CONST EFI_HANDLE DriverHandle OPTIONAL,
    119   IN CONST BOOLEAN    Recursive,
    120   IN CONST BOOLEAN    Output,
    121   IN CONST BOOLEAN    AlwaysOutput
    122   )
    123 {
    124   EFI_STATUS Status;
    125   EFI_STATUS Status2;
    126   EFI_HANDLE *ControllerHandleList;
    127   EFI_HANDLE *DriverHandleList;
    128   EFI_HANDLE *HandleWalker;
    129 
    130   ControllerHandleList  = NULL;
    131   Status                = EFI_NOT_FOUND;
    132   Status2               = EFI_NOT_FOUND;
    133 
    134   //
    135   // If we have a single handle to connect make that a 'list'
    136   //
    137   if (DriverHandle == NULL) {
    138     DriverHandleList = NULL;
    139   } else {
    140     DriverHandleList = AllocateZeroPool(2*sizeof(EFI_HANDLE));
    141     if (DriverHandleList == NULL) {
    142       return (EFI_OUT_OF_RESOURCES);
    143     }
    144     DriverHandleList[0] = DriverHandle;
    145     DriverHandleList[1] = NULL;
    146   }
    147 
    148   //
    149   // do we connect all controllers (with a loop) or a single one...
    150   // This is where we call the gBS->ConnectController function.
    151   //
    152   if (ControllerHandle == NULL) {
    153     ControllerHandleList = GetHandleListByProtocol(&gEfiDevicePathProtocolGuid);
    154     for (HandleWalker = ControllerHandleList
    155       ;  HandleWalker != NULL && *HandleWalker != NULL
    156       ;  HandleWalker++
    157      ){
    158       Status = gBS->ConnectController(*HandleWalker, DriverHandleList, NULL, Recursive);
    159       if (!EFI_ERROR(Status)) {
    160         Status2 = EFI_SUCCESS;
    161       }
    162       if ((Output && !EFI_ERROR(Status)) || AlwaysOutput) {
    163         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_HANDLE_RESULT), gShellDriver1HiiHandle, L"Connect", ConvertHandleToHandleIndex(*HandleWalker), Status);
    164       }
    165     }
    166   } else {
    167     Status = gBS->ConnectController(ControllerHandle, DriverHandleList, NULL, Recursive);
    168     if (!EFI_ERROR(Status)) {
    169       Status2 = EFI_SUCCESS;
    170     }
    171     if ((Output && !EFI_ERROR(Status)) || AlwaysOutput) {
    172       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN(STR_HANDLE_RESULT), gShellDriver1HiiHandle, L"Connect", ConvertHandleToHandleIndex(ControllerHandle), Status);
    173     }
    174   }
    175 
    176   //
    177   // Free any memory we allocated.
    178   //
    179   if (ControllerHandleList != NULL) {
    180     FreePool(ControllerHandleList);
    181   }
    182   if (DriverHandleList     != NULL) {
    183     FreePool(DriverHandleList);
    184   }
    185   return (Status2);
    186 }
    187 
    188 /**
    189   Do a connect from an EFI variable via it's key name.
    190 
    191   @param[in] Key      The name of the EFI Variable.
    192 
    193   @retval EFI_SUCCESS   The operation was successful.
    194 **/
    195 EFI_STATUS
    196 ShellConnectFromDevPaths (
    197   IN CONST CHAR16 *Key
    198   )
    199 {
    200   EFI_DEVICE_PATH_PROTOCOL  *DevPath;
    201   EFI_DEVICE_PATH_PROTOCOL  *CopyOfDevPath;
    202   EFI_DEVICE_PATH_PROTOCOL  *Instance;
    203   EFI_DEVICE_PATH_PROTOCOL  *Next;
    204   UINTN                     Length;
    205   UINTN                     Index;
    206   UINTN                     HandleArrayCount;
    207   UINTN                     Size;
    208   EFI_HANDLE                *HandleArray;
    209   EFI_STATUS                Status;
    210   BOOLEAN                   AtLeastOneConnected;
    211   EFI_PCI_IO_PROTOCOL       *PciIo;
    212   UINT8                     Class[3];
    213 
    214   DevPath = NULL;
    215   Length  = 0;
    216   AtLeastOneConnected = FALSE;
    217 
    218   //
    219   // Get the DevicePath buffer from the variable...
    220   //
    221   Status = gRT->GetVariable((CHAR16*)Key, (EFI_GUID*)&gEfiGlobalVariableGuid, NULL, &Length, DevPath);
    222   if (Status == EFI_BUFFER_TOO_SMALL) {
    223     DevPath = AllocateZeroPool(Length);
    224     if (DevPath == NULL) {
    225       return EFI_OUT_OF_RESOURCES;
    226     }
    227     Status = gRT->GetVariable((CHAR16*)Key, (EFI_GUID*)&gEfiGlobalVariableGuid, NULL, &Length, DevPath);
    228     if (EFI_ERROR (Status)) {
    229       if (DevPath != NULL) {
    230         FreePool (DevPath);
    231       }
    232       return Status;
    233     }
    234   } else if (EFI_ERROR (Status)) {
    235     return Status;
    236   }
    237 
    238   Status = EFI_NOT_FOUND;
    239 
    240   CopyOfDevPath = DevPath;
    241   //
    242   // walk the list of devices and connect them
    243   //
    244   do {
    245     //
    246     // Check every instance of the console variable
    247     //
    248     Instance = GetNextDevicePathInstance (&CopyOfDevPath, &Size);
    249     if (Instance == NULL) {
    250       if (DevPath != NULL) {
    251         FreePool (DevPath);
    252       }
    253       return EFI_UNSUPPORTED;
    254     }
    255 
    256     Next = Instance;
    257     while (!IsDevicePathEndType (Next)) {
    258       Next = NextDevicePathNode (Next);
    259     }
    260 
    261     SetDevicePathEndNode (Next);
    262     //
    263     // connect short form device path
    264     //
    265     if ((DevicePathType (Instance) == MESSAGING_DEVICE_PATH) &&
    266       ((DevicePathSubType (Instance) == MSG_USB_CLASS_DP)
    267       || (DevicePathSubType (Instance) == MSG_USB_WWID_DP)
    268       )) {
    269 
    270       Status = ShellConnectPciRootBridge ();
    271       if (EFI_ERROR(Status)) {
    272         FreePool(Instance);
    273         FreePool(DevPath);
    274         return Status;
    275       }
    276 
    277       Status = gBS->LocateHandleBuffer (
    278                   ByProtocol,
    279                   &gEfiPciIoProtocolGuid,
    280                   NULL,
    281                   &HandleArrayCount,
    282                   &HandleArray
    283                   );
    284 
    285       if (!EFI_ERROR (Status)) {
    286         for (Index = 0; Index < HandleArrayCount; Index++) {
    287           Status = gBS->HandleProtocol (
    288                       HandleArray[Index],
    289                       &gEfiPciIoProtocolGuid,
    290                       (VOID **)&PciIo
    291                       );
    292 
    293           if (!EFI_ERROR (Status)) {
    294             Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 3, &Class);
    295             if (!EFI_ERROR (Status)) {
    296               if ((PCI_CLASS_SERIAL == Class[2]) &&
    297                   (PCI_CLASS_SERIAL_USB == Class[1])) {
    298                 Status = gBS->ConnectController (
    299                               HandleArray[Index],
    300                               NULL,
    301                               Instance,
    302                               FALSE
    303                               );
    304                 if (!EFI_ERROR(Status)) {
    305                   AtLeastOneConnected = TRUE;
    306                 }
    307               }
    308             }
    309           }
    310         }
    311       }
    312 
    313       if (HandleArray != NULL) {
    314         FreePool (HandleArray);
    315       }
    316     } else {
    317       //
    318       // connect the entire device path
    319       //
    320       Status = ShellConnectDevicePath (Instance);
    321       if (!EFI_ERROR (Status)) {
    322         AtLeastOneConnected = TRUE;
    323       }
    324     }
    325     FreePool (Instance);
    326 
    327   } while (CopyOfDevPath != NULL);
    328 
    329   if (DevPath != NULL) {
    330     FreePool(DevPath);
    331   }
    332 
    333   if (AtLeastOneConnected) {
    334     return EFI_SUCCESS;
    335   } else {
    336     return EFI_NOT_FOUND;
    337   }
    338 
    339 }
    340 
    341 /**
    342   Convert the handle identifiers from strings and then connect them.
    343 
    344   One of them should have driver binding and either can be NULL.
    345 
    346   @param[in] Handle1            The first handle.
    347   @param[in] Handle2            The second handle.
    348   @param[in] Recursive          TRUE to do connect recursively. FALSE otherwise.
    349   @param[in] Output             TRUE to have output to screen. FALSE otherwise.
    350 
    351   @retval EFI_SUCCESS           The operation was successful.
    352 **/
    353 EFI_STATUS
    354 ConvertAndConnectControllers (
    355   IN EFI_HANDLE     *Handle1 OPTIONAL,
    356   IN EFI_HANDLE     *Handle2 OPTIONAL,
    357   IN CONST BOOLEAN  Recursive,
    358   IN CONST BOOLEAN  Output
    359   )
    360 {
    361   //
    362   // if only one is NULL verify it's the proper one...
    363   //
    364   if ( (Handle1 == NULL && Handle2 != NULL)
    365     || (Handle1 != NULL && Handle2 == NULL)
    366    ){
    367     //
    368     // Figure out which one should be NULL and move the handle to the right place.
    369     // If Handle1 is NULL then test Handle2 and vise versa.
    370     // The one that DOES has driver binding must be Handle2
    371     //
    372     if (Handle1 == NULL) {
    373       if (EFI_ERROR(gBS->OpenProtocol(Handle2, &gEfiDriverBindingProtocolGuid, NULL, NULL, gImageHandle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) {
    374         // swap
    375         Handle1 = Handle2;
    376         Handle2 = NULL;
    377       } else {
    378         // We're all good...
    379       }
    380     } else {
    381       if (EFI_ERROR(gBS->OpenProtocol(Handle1, &gEfiDriverBindingProtocolGuid, NULL, NULL, gImageHandle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) {
    382         // We're all good...
    383       } else {
    384         // swap
    385         Handle2 = Handle1;
    386         Handle1 = NULL;
    387       }
    388     }
    389   }
    390 
    391   return (ConnectControllers(Handle1, Handle2, Recursive, Output, (BOOLEAN)(Handle2 != NULL && Handle1 != NULL)));
    392 }
    393 
    394 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
    395   {L"-c", TypeFlag},
    396   {L"-r", TypeFlag},
    397   {NULL, TypeMax}
    398   };
    399 
    400 /**
    401   Function for 'connect' command.
    402 
    403   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
    404   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
    405 **/
    406 SHELL_STATUS
    407 EFIAPI
    408 ShellCommandRunConnect (
    409   IN EFI_HANDLE        ImageHandle,
    410   IN EFI_SYSTEM_TABLE  *SystemTable
    411   )
    412 {
    413   EFI_STATUS          Status;
    414   LIST_ENTRY          *Package;
    415   CHAR16              *ProblemParam;
    416   SHELL_STATUS        ShellStatus;
    417   CONST CHAR16        *Param1;
    418   CONST CHAR16        *Param2;
    419   UINTN               Count;
    420   EFI_HANDLE          Handle1;
    421   EFI_HANDLE          Handle2;
    422   UINT64              Intermediate;
    423 
    424   ShellStatus         = SHELL_SUCCESS;
    425   //
    426   // initialize the shell lib (we must be in non-auto-init...)
    427   //
    428   Status = ShellInitialize();
    429   ASSERT_EFI_ERROR(Status);
    430 
    431   Status = CommandInit();
    432   ASSERT_EFI_ERROR(Status);
    433 
    434   //
    435   // parse the command line
    436   //
    437   Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
    438   if (EFI_ERROR(Status)) {
    439     if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
    440       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDriver1HiiHandle, L"connect", ProblemParam);
    441       FreePool(ProblemParam);
    442       ShellStatus = SHELL_INVALID_PARAMETER;
    443     } else {
    444       ASSERT(FALSE);
    445     }
    446   } else {
    447     //
    448     // if more than 2 'value' parameters (plus the name one) or either -r or -c with any value parameters we have too many parameters
    449     //
    450     Count = (gInReconnect?0x4:0x3);
    451     if ((ShellCommandLineGetCount(Package) > Count)
    452       ||(ShellCommandLineGetFlag(Package, L"-c") && ShellCommandLineGetCount(Package)>1)
    453       ||(ShellCommandLineGetFlag(Package, L"-r") && ShellCommandLineGetCount(Package)>2)
    454       ||(ShellCommandLineGetFlag(Package, L"-r") && ShellCommandLineGetFlag(Package, L"-c") )
    455     ){
    456       //
    457       // error for too many parameters
    458       //
    459       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDriver1HiiHandle, L"connect");
    460       ShellStatus = SHELL_INVALID_PARAMETER;
    461     } else if (ShellCommandLineGetFlag(Package, L"-c")) {
    462       //
    463       // do the conin and conout from EFI variables
    464       // if the first fails dont 'loose' the error
    465       //
    466       Status = ShellConnectFromDevPaths(L"ConInDev");
    467       if (EFI_ERROR(Status)) {
    468         ShellConnectFromDevPaths(L"ConOutDev");
    469       } else {
    470         Status = ShellConnectFromDevPaths(L"ConOutDev");
    471       }
    472       if (EFI_ERROR(Status)) {
    473         ShellConnectFromDevPaths(L"ErrOutDev");
    474       } else {
    475         Status = ShellConnectFromDevPaths(L"ErrOutDev");
    476       }
    477       if (EFI_ERROR(Status)) {
    478         ShellConnectFromDevPaths(L"ErrOut");
    479       } else {
    480         Status = ShellConnectFromDevPaths(L"ErrOut");
    481       }
    482       if (EFI_ERROR(Status)) {
    483         ShellConnectFromDevPaths(L"ConIn");
    484       } else {
    485         Status = ShellConnectFromDevPaths(L"ConIn");
    486       }
    487       if (EFI_ERROR(Status)) {
    488         ShellConnectFromDevPaths(L"ConOut");
    489       } else {
    490         Status = ShellConnectFromDevPaths(L"ConOut");
    491       }
    492       if (EFI_ERROR(Status)) {
    493         ShellStatus = SHELL_DEVICE_ERROR;
    494       }
    495     } else {
    496       //
    497       // 0, 1, or 2 specific handles and possibly recursive
    498       //
    499       Param1  = ShellCommandLineGetRawValue(Package, 1);
    500       Param2  = ShellCommandLineGetRawValue(Package, 2);
    501       Count   = ShellCommandLineGetCount(Package);
    502 
    503       if (Param1 != NULL) {
    504         Status  = ShellConvertStringToUint64(Param1, &Intermediate, TRUE, FALSE);
    505         Handle1 = ConvertHandleIndexToHandle((UINTN)Intermediate);
    506         if (EFI_ERROR(Status)) {
    507           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"connect", Param1);
    508           ShellStatus = SHELL_INVALID_PARAMETER;
    509         }
    510       } else {
    511         Handle1 = NULL;
    512       }
    513 
    514       if (Param2 != NULL) {
    515         Status  = ShellConvertStringToUint64(Param2, &Intermediate, TRUE, FALSE);
    516         Handle2 = ConvertHandleIndexToHandle((UINTN)Intermediate);
    517         if (EFI_ERROR(Status)) {
    518           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"connect", Param2);
    519           ShellStatus = SHELL_INVALID_PARAMETER;
    520         }
    521       } else {
    522         Handle2 = NULL;
    523       }
    524 
    525       if (ShellStatus == SHELL_SUCCESS) {
    526         if (Param1 != NULL && Handle1 == NULL){
    527           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"connect", Param1);
    528           ShellStatus = SHELL_INVALID_PARAMETER;
    529         } else if (Param2 != NULL && Handle2 == NULL) {
    530           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"connect", Param2);
    531           ShellStatus = SHELL_INVALID_PARAMETER;
    532         } else if (Handle2 != NULL && Handle1 != NULL && EFI_ERROR(gBS->OpenProtocol(Handle2, &gEfiDriverBindingProtocolGuid, NULL, gImageHandle, NULL, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) {
    533           ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"connect", Param2);
    534           ShellStatus = SHELL_INVALID_PARAMETER;
    535         } else {
    536           Status = ConvertAndConnectControllers(Handle1, Handle2, ShellCommandLineGetFlag(Package, L"-r"), (BOOLEAN)(Count!=0));
    537           if (EFI_ERROR(Status)) {
    538             ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_CONNECT_NONE), gShellDriver1HiiHandle);
    539             ShellStatus = SHELL_DEVICE_ERROR;
    540           }
    541         }
    542       }
    543     }
    544 
    545     ShellCommandLineFreeVarList (Package);
    546   }
    547   return (ShellStatus);
    548 }
    549 
    550