]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellDriver1CommandsLib/Connect.c
321c366697e3073534a9da962bae315552fe8192
[mirror_edk2.git] / ShellPkg / Library / UefiShellDriver1CommandsLib / Connect.c
1 /** @file
2 Main file for connect shell Driver1 function.
3
4 Copyright (c) 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