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