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