]> git.proxmox.com Git - mirror_edk2.git/blob - ShellPkg/Library/UefiShellDriver1CommandsLib/Connect.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[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 } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath));
52
53 return Status;
54 }
55
56 /**
57 Connect drivers for PCI root bridge.
58
59 @retval EFI_SUCCESS Connect drivers successfully.
60 @retval EFI_NOT_FOUND Cannot find PCI root bridge device.
61
62 **/
63 EFI_STATUS
64 ShellConnectPciRootBridge (
65 VOID
66 )
67 {
68 UINTN RootBridgeHandleCount;
69 EFI_HANDLE *RootBridgeHandleBuffer;
70 UINTN RootBridgeIndex;
71 EFI_STATUS Status;
72
73 RootBridgeHandleCount = 0;
74
75 Status = gBS->LocateHandleBuffer (
76 ByProtocol,
77 &gEfiPciRootBridgeIoProtocolGuid,
78 NULL,
79 &RootBridgeHandleCount,
80 &RootBridgeHandleBuffer
81 );
82 if (EFI_ERROR (Status)) {
83 return Status;
84 }
85
86 for (RootBridgeIndex = 0; RootBridgeIndex < RootBridgeHandleCount; RootBridgeIndex++) {
87 gBS->ConnectController (RootBridgeHandleBuffer[RootBridgeIndex], NULL, NULL, FALSE);
88 }
89
90 FreePool (RootBridgeHandleBuffer);
91
92 return EFI_SUCCESS;
93 }
94
95 /**
96 Connect controller(s) and driver(s).
97
98 @param[in] ControllerHandle The handle to the controller. Should have driver binding on it.
99 @param[in] DriverHandle The handle to the driver. Should have driver binding.
100 @param[in] Recursive TRUE to connect recursively, FALSE otherwise.
101 @param[in] Output TRUE to have info on the screen, FALSE otherwise.
102 @param[in] AlwaysOutput Override Output for errors.
103
104 @retval EFI_SUCCESS The operation was successful.
105 **/
106 EFI_STATUS
107 ConnectControllers (
108 IN CONST EFI_HANDLE ControllerHandle OPTIONAL,
109 IN CONST EFI_HANDLE DriverHandle OPTIONAL,
110 IN CONST BOOLEAN Recursive,
111 IN CONST BOOLEAN Output,
112 IN CONST BOOLEAN AlwaysOutput
113 )
114 {
115 EFI_STATUS Status;
116 EFI_STATUS Status2;
117 EFI_HANDLE *ControllerHandleList;
118 EFI_HANDLE *DriverHandleList;
119 EFI_HANDLE *HandleWalker;
120
121 ControllerHandleList = NULL;
122 Status = EFI_NOT_FOUND;
123 Status2 = EFI_NOT_FOUND;
124
125 //
126 // If we have a single handle to connect make that a 'list'
127 //
128 if (DriverHandle == NULL) {
129 DriverHandleList = NULL;
130 } else {
131 DriverHandleList = AllocateZeroPool (2*sizeof (EFI_HANDLE));
132 if (DriverHandleList == NULL) {
133 return (EFI_OUT_OF_RESOURCES);
134 }
135
136 DriverHandleList[0] = DriverHandle;
137 DriverHandleList[1] = NULL;
138 }
139
140 //
141 // do we connect all controllers (with a loop) or a single one...
142 // This is where we call the gBS->ConnectController function.
143 //
144 if (ControllerHandle == NULL) {
145 ControllerHandleList = GetHandleListByProtocol (&gEfiDevicePathProtocolGuid);
146 for (HandleWalker = ControllerHandleList
147 ; HandleWalker != NULL && *HandleWalker != NULL
148 ; HandleWalker++
149 )
150 {
151 Status = gBS->ConnectController (*HandleWalker, DriverHandleList, NULL, Recursive);
152 if (!EFI_ERROR (Status)) {
153 Status2 = EFI_SUCCESS;
154 }
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
166 if ((Output && !EFI_ERROR (Status)) || AlwaysOutput) {
167 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_HANDLE_RESULT), gShellDriver1HiiHandle, L"Connect", ConvertHandleToHandleIndex (ControllerHandle), Status);
168 }
169 }
170
171 //
172 // Free any memory we allocated.
173 //
174 if (ControllerHandleList != NULL) {
175 FreePool (ControllerHandleList);
176 }
177
178 if (DriverHandleList != NULL) {
179 FreePool (DriverHandleList);
180 }
181
182 return (Status2);
183 }
184
185 /**
186 Do a connect from an EFI variable via it's key name.
187
188 @param[in] Key The name of the EFI Variable.
189
190 @retval EFI_SUCCESS The operation was successful.
191 **/
192 EFI_STATUS
193 ShellConnectFromDevPaths (
194 IN CONST CHAR16 *Key
195 )
196 {
197 EFI_DEVICE_PATH_PROTOCOL *DevPath;
198 EFI_DEVICE_PATH_PROTOCOL *CopyOfDevPath;
199 EFI_DEVICE_PATH_PROTOCOL *Instance;
200 EFI_DEVICE_PATH_PROTOCOL *Next;
201 UINTN Length;
202 UINTN Index;
203 UINTN HandleArrayCount;
204 UINTN Size;
205 EFI_HANDLE *HandleArray;
206 EFI_STATUS Status;
207 BOOLEAN AtLeastOneConnected;
208 EFI_PCI_IO_PROTOCOL *PciIo;
209 UINT8 Class[3];
210
211 DevPath = NULL;
212 Length = 0;
213 AtLeastOneConnected = FALSE;
214
215 //
216 // Get the DevicePath buffer from the variable...
217 //
218 Status = gRT->GetVariable ((CHAR16 *)Key, (EFI_GUID *)&gEfiGlobalVariableGuid, NULL, &Length, DevPath);
219 if (Status == EFI_BUFFER_TOO_SMALL) {
220 DevPath = AllocateZeroPool (Length);
221 if (DevPath == NULL) {
222 return EFI_OUT_OF_RESOURCES;
223 }
224
225 Status = gRT->GetVariable ((CHAR16 *)Key, (EFI_GUID *)&gEfiGlobalVariableGuid, NULL, &Length, DevPath);
226 if (EFI_ERROR (Status)) {
227 if (DevPath != NULL) {
228 FreePool (DevPath);
229 }
230
231 return Status;
232 }
233 } else if (EFI_ERROR (Status)) {
234 return Status;
235 }
236
237 Status = EFI_NOT_FOUND;
238
239 CopyOfDevPath = DevPath;
240 //
241 // walk the list of devices and connect them
242 //
243 do {
244 //
245 // Check every instance of the console variable
246 //
247 Instance = GetNextDevicePathInstance (&CopyOfDevPath, &Size);
248 if (Instance == NULL) {
249 if (DevPath != NULL) {
250 FreePool (DevPath);
251 }
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 {
299 Status = gBS->ConnectController (
300 HandleArray[Index],
301 NULL,
302 Instance,
303 FALSE
304 );
305 if (!EFI_ERROR (Status)) {
306 AtLeastOneConnected = TRUE;
307 }
308 }
309 }
310 }
311 }
312 }
313
314 if (HandleArray != NULL) {
315 FreePool (HandleArray);
316 }
317 } else {
318 //
319 // connect the entire device path
320 //
321 Status = ShellConnectDevicePath (Instance);
322 if (!EFI_ERROR (Status)) {
323 AtLeastOneConnected = TRUE;
324 }
325 }
326
327 FreePool (Instance);
328 } while (CopyOfDevPath != NULL);
329
330 if (DevPath != NULL) {
331 FreePool (DevPath);
332 }
333
334 if (AtLeastOneConnected) {
335 return EFI_SUCCESS;
336 } else {
337 return EFI_NOT_FOUND;
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 //
369 // Figure out which one should be NULL and move the handle to the right place.
370 // If Handle1 is NULL then test Handle2 and vise versa.
371 // The one that DOES has driver binding must be Handle2
372 //
373 if (Handle1 == NULL) {
374 if (EFI_ERROR (gBS->OpenProtocol (Handle2, &gEfiDriverBindingProtocolGuid, NULL, NULL, gImageHandle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) {
375 // swap
376 Handle1 = Handle2;
377 Handle2 = NULL;
378 } else {
379 // We're all good...
380 }
381 } else {
382 if (EFI_ERROR (gBS->OpenProtocol (Handle1, &gEfiDriverBindingProtocolGuid, NULL, NULL, gImageHandle, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) {
383 // We're all good...
384 } else {
385 // swap
386 Handle2 = Handle1;
387 Handle1 = NULL;
388 }
389 }
390 }
391
392 return (ConnectControllers (Handle1, Handle2, Recursive, Output, (BOOLEAN)(Handle2 != NULL && Handle1 != NULL)));
393 }
394
395 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
396 { L"-c", TypeFlag },
397 { L"-r", TypeFlag },
398 { NULL, TypeMax }
399 };
400
401 /**
402 Function for 'connect' command.
403
404 @param[in] ImageHandle Handle to the Image (NULL if Internal).
405 @param[in] SystemTable Pointer to the System Table (NULL if Internal).
406 **/
407 SHELL_STATUS
408 EFIAPI
409 ShellCommandRunConnect (
410 IN EFI_HANDLE ImageHandle,
411 IN EFI_SYSTEM_TABLE *SystemTable
412 )
413 {
414 EFI_STATUS Status;
415 LIST_ENTRY *Package;
416 CHAR16 *ProblemParam;
417 SHELL_STATUS ShellStatus;
418 CONST CHAR16 *Param1;
419 CONST CHAR16 *Param2;
420 UINTN Count;
421 EFI_HANDLE Handle1;
422 EFI_HANDLE Handle2;
423 UINT64 Intermediate;
424
425 ShellStatus = SHELL_SUCCESS;
426 //
427 // initialize the shell lib (we must be in non-auto-init...)
428 //
429 Status = ShellInitialize ();
430 ASSERT_EFI_ERROR (Status);
431
432 Status = CommandInit ();
433 ASSERT_EFI_ERROR (Status);
434
435 //
436 // parse the command line
437 //
438 Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
439 if (EFI_ERROR (Status)) {
440 if ((Status == EFI_VOLUME_CORRUPTED) && (ProblemParam != NULL)) {
441 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDriver1HiiHandle, L"connect", ProblemParam);
442 FreePool (ProblemParam);
443 ShellStatus = SHELL_INVALID_PARAMETER;
444 } else {
445 ASSERT (FALSE);
446 }
447 } else {
448 //
449 // if more than 2 'value' parameters (plus the name one) or either -r or -c with any value parameters we have too many parameters
450 //
451 Count = (gInReconnect ? 0x4 : 0x3);
452 if ( (ShellCommandLineGetCount (Package) > Count)
453 || (ShellCommandLineGetFlag (Package, L"-c") && (ShellCommandLineGetCount (Package) > 1))
454 || (ShellCommandLineGetFlag (Package, L"-r") && (ShellCommandLineGetCount (Package) > 2))
455 || (ShellCommandLineGetFlag (Package, L"-r") && ShellCommandLineGetFlag (Package, L"-c"))
456 )
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
475 if (EFI_ERROR (Status)) {
476 ShellConnectFromDevPaths (L"ErrOutDev");
477 } else {
478 Status = ShellConnectFromDevPaths (L"ErrOutDev");
479 }
480
481 if (EFI_ERROR (Status)) {
482 ShellConnectFromDevPaths (L"ErrOut");
483 } else {
484 Status = ShellConnectFromDevPaths (L"ErrOut");
485 }
486
487 if (EFI_ERROR (Status)) {
488 ShellConnectFromDevPaths (L"ConIn");
489 } else {
490 Status = ShellConnectFromDevPaths (L"ConIn");
491 }
492
493 if (EFI_ERROR (Status)) {
494 ShellConnectFromDevPaths (L"ConOut");
495 } else {
496 Status = ShellConnectFromDevPaths (L"ConOut");
497 }
498
499 if (EFI_ERROR (Status)) {
500 ShellStatus = SHELL_DEVICE_ERROR;
501 }
502 } else {
503 //
504 // 0, 1, or 2 specific handles and possibly recursive
505 //
506 Param1 = ShellCommandLineGetRawValue (Package, 1);
507 Param2 = ShellCommandLineGetRawValue (Package, 2);
508 Count = ShellCommandLineGetCount (Package);
509
510 if (Param1 != NULL) {
511 Status = ShellConvertStringToUint64 (Param1, &Intermediate, TRUE, FALSE);
512 Handle1 = ConvertHandleIndexToHandle ((UINTN)Intermediate);
513 if (EFI_ERROR (Status)) {
514 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"connect", Param1);
515 ShellStatus = SHELL_INVALID_PARAMETER;
516 }
517 } else {
518 Handle1 = NULL;
519 }
520
521 if (Param2 != NULL) {
522 Status = ShellConvertStringToUint64 (Param2, &Intermediate, TRUE, FALSE);
523 Handle2 = ConvertHandleIndexToHandle ((UINTN)Intermediate);
524 if (EFI_ERROR (Status)) {
525 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"connect", Param2);
526 ShellStatus = SHELL_INVALID_PARAMETER;
527 }
528 } else {
529 Handle2 = NULL;
530 }
531
532 if (ShellStatus == SHELL_SUCCESS) {
533 if ((Param1 != NULL) && (Handle1 == NULL)) {
534 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"connect", Param1);
535 ShellStatus = SHELL_INVALID_PARAMETER;
536 } else if ((Param2 != NULL) && (Handle2 == NULL)) {
537 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"connect", Param2);
538 ShellStatus = SHELL_INVALID_PARAMETER;
539 } else if ((Handle2 != NULL) && (Handle1 != NULL) && EFI_ERROR (gBS->OpenProtocol (Handle2, &gEfiDriverBindingProtocolGuid, NULL, gImageHandle, NULL, EFI_OPEN_PROTOCOL_TEST_PROTOCOL))) {
540 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_GEN_INV_HANDLE), gShellDriver1HiiHandle, L"connect", Param2);
541 ShellStatus = SHELL_INVALID_PARAMETER;
542 } else {
543 Status = ConvertAndConnectControllers (Handle1, Handle2, ShellCommandLineGetFlag (Package, L"-r"), (BOOLEAN)(Count != 0));
544 if (EFI_ERROR (Status)) {
545 ShellPrintHiiEx (-1, -1, NULL, STRING_TOKEN (STR_CONNECT_NONE), gShellDriver1HiiHandle);
546 ShellStatus = SHELL_DEVICE_ERROR;
547 }
548 }
549 }
550 }
551
552 ShellCommandLineFreeVarList (Package);
553 }
554
555 return (ShellStatus);
556 }