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