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