1 /** @file
2   Main file for DrvDiag 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 STATIC CONST EFI_GUID *DiagGuidList[] = {&gEfiDriverDiagnosticsProtocolGuid, &gEfiDriverDiagnostics2ProtocolGuid, NULL};
19 //
20 // We need 1 more item on the list...
21 //
22 typedef enum {
23   TestModeStandard      = EfiDriverDiagnosticTypeStandard,
24   TestModeExtended      = EfiDriverDiagnosticTypeExtended,
25   TestModeManufacturing = EfiDriverDiagnosticTypeManufacturing,
26   TestModeList,
27   TestModeMax
28 } DRV_DIAG_TEST_MODE;
29 
30 /**
31   Do the diagnostics call for some set of handles.
32 
33   @param[in] Mode               The type of diagnostic test to run.
34   @param[in] Lang               The language code to use.
35   @param[in] AllChilds          Should the test be on all children.
36   @param[in] DriverHandle       The driver handle to test with.
37   @param[in] ControllerHandle   The specific controller handle to test.
38   @param[in] ChildHandle        The specific child handle to test.
39 
40   @retval EFI_SUCCESS           The operation was successful.
41   @retval EFI_INVALID_PARAMETER A parameter had an invalid value.
42   @retval EFI_NOT_FOUND         No diagnostic handle could be found.
43 **/
44 EFI_STATUS
DoDiagnostics(IN CONST DRV_DIAG_TEST_MODE Mode,IN CONST CHAR8 * Lang,IN CONST BOOLEAN AllChilds,IN CONST EFI_HANDLE DriverHandle,IN CONST EFI_HANDLE ControllerHandle,IN CONST EFI_HANDLE ChildHandle)45 DoDiagnostics (
46   IN CONST DRV_DIAG_TEST_MODE Mode,
47   IN CONST CHAR8              *Lang,
48   IN CONST BOOLEAN            AllChilds,
49   IN CONST EFI_HANDLE         DriverHandle,
50   IN CONST EFI_HANDLE         ControllerHandle,
51   IN CONST EFI_HANDLE         ChildHandle
52   )
53 {
54   EFI_DRIVER_DIAGNOSTICS_PROTOCOL     *DriverDiagnostics;
55   EFI_DRIVER_DIAGNOSTICS2_PROTOCOL    *DriverDiagnostics2;
56   EFI_HANDLE                          *DriverHandleList;
57   EFI_HANDLE                          *ControllerHandleList;
58   EFI_HANDLE                          *ChildHandleList;
59   EFI_HANDLE                          *Walker;
60   UINTN                               DriverHandleListCount;
61   UINTN                               ControllerHandleListCount;
62   UINTN                               ChildHandleListCount;
63   UINTN                               DriverHandleListLoop;
64   UINTN                               ControllerHandleListLoop;
65   UINTN                               ChildHandleListLoop;
66   EFI_STATUS                          Status;
67   EFI_STATUS                          Status2;
68   EFI_GUID                            *ErrorType;
69   UINTN                               OutBufferSize;
70   CHAR16                              *OutBuffer;
71   UINTN                               HandleIndex1;
72   UINTN                               HandleIndex2;
73   CHAR8                               *Language;
74   BOOLEAN                             Found;
75 
76   if ((ChildHandle != NULL && AllChilds) || (Mode >= TestModeMax)){
77     return (EFI_INVALID_PARAMETER);
78   }
79 
80   DriverDiagnostics                   = NULL;
81   DriverDiagnostics2                  = NULL;
82   Status                              = EFI_SUCCESS;
83   Status2                             = EFI_SUCCESS;
84   DriverHandleList                    = NULL;
85   ControllerHandleList                = NULL;
86   ChildHandleList                     = NULL;
87   Language                            = NULL;
88   OutBuffer                           = NULL;
89   ErrorType                           = NULL;
90   DriverHandleListCount               = 0;
91   ControllerHandleListCount           = 0;
92   ChildHandleListCount                = 0;
93 
94   if (DriverHandle != NULL) {
95     DriverHandleList = AllocateZeroPool(2*sizeof(EFI_HANDLE));
96     if (DriverHandleList == NULL) {
97       return EFI_OUT_OF_RESOURCES;
98     }
99     DriverHandleList[0] = DriverHandle;
100     DriverHandleListCount = 1;
101   } else {
102     DriverHandleList = GetHandleListByProtocolList(DiagGuidList);
103     if (DriverHandleList == NULL) {
104       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROTOCOL_NF), gShellDriver1HiiHandle, L"drvdiag", L"gEfiDriverDiagnosticsProtocolGuid", &gEfiDriverDiagnosticsProtocolGuid);
105       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROTOCOL_NF), gShellDriver1HiiHandle, L"drvdiag", L"gEfiDriverDiagnostics2ProtocolGuid", &gEfiDriverDiagnostics2ProtocolGuid);
106       return (EFI_NOT_FOUND);
107     }
108     for (Walker = DriverHandleList ; Walker != NULL && *Walker != NULL ; DriverHandleListCount++, Walker++);
109   }
110 
111   if (ControllerHandle != NULL) {
112     ControllerHandleList = AllocateZeroPool(2*sizeof(EFI_HANDLE));
113     if (ControllerHandleList == NULL) {
114       SHELL_FREE_NON_NULL (DriverHandleList);
115       return EFI_OUT_OF_RESOURCES;
116     }
117     ControllerHandleList[0] = ControllerHandle;
118     ControllerHandleListCount = 1;
119   } else {
120     ControllerHandleList = NULL;
121   }
122 
123   if (ChildHandle != NULL) {
124     ChildHandleList = AllocateZeroPool(2*sizeof(EFI_HANDLE));
125     if (ChildHandleList == NULL) {
126       SHELL_FREE_NON_NULL (ControllerHandleList);
127       SHELL_FREE_NON_NULL (DriverHandleList);
128       return EFI_OUT_OF_RESOURCES;
129     }
130     ChildHandleList[0] = ChildHandle;
131     ChildHandleListCount = 1;
132   } else if (AllChilds) {
133     ChildHandleList = NULL;
134     //
135     // This gets handled in the loop below.
136     //
137   } else {
138     ChildHandleList = NULL;
139   }
140 
141   if (Mode == TestModeList) {
142     ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DRVDIAG_HEADER), gShellDriver1HiiHandle);
143   }
144   for (DriverHandleListLoop = 0
145     ;  DriverHandleListLoop < DriverHandleListCount
146     ;  DriverHandleListLoop++
147     ){
148     if (Mode == TestModeList) {
149       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DRVDIAG_DRIVER_HEADER), gShellDriver1HiiHandle, ConvertHandleToHandleIndex(DriverHandleList[DriverHandleListLoop]));
150     }
151     if (ControllerHandle == NULL) {
152       PARSE_HANDLE_DATABASE_DEVICES(DriverHandleList[DriverHandleListLoop], &ControllerHandleListCount, &ControllerHandleList);
153     }
154     if (ControllerHandleListCount == 0) {
155       if (Mode == TestModeList) {
156         ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_DRVDIAG_DRIVER_NO_HANDLES), gShellDriver1HiiHandle);
157       }
158     } else {
159       if (Mode == TestModeList) {
160         ShellPrintEx(-1, -1, L"\r\n");
161       }
162       for (ControllerHandleListLoop = 0
163         ;  ControllerHandleListLoop < ControllerHandleListCount
164         ;  ControllerHandleListLoop++
165         ){
166         if (AllChilds) {
167           ASSERT(ChildHandleList == NULL);
168           PARSE_HANDLE_DATABASE_MANAGED_CHILDREN(
169             DriverHandleList[DriverHandleListLoop],
170             ControllerHandleList[ControllerHandleListLoop],
171             &ChildHandleListCount,
172             &ChildHandleList);
173         }
174         for (ChildHandleListLoop = 0
175           ;  (ChildHandleListLoop < ChildHandleListCount || ChildHandleList == NULL)
176           ;  ChildHandleListLoop++
177           ){
178           Found = FALSE;
179           if (Mode != TestModeList) {
180             if (Lang == NULL || Lang[2] == '-') {
181               //
182               // Get the protocol pointer and call the function
183               //
184               Status = gBS->OpenProtocol(
185                 DriverHandleList[DriverHandleListLoop],
186                 &gEfiDriverDiagnostics2ProtocolGuid,
187                 (VOID**)&DriverDiagnostics2,
188                 gImageHandle,
189                 NULL,
190                 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
191               if (!EFI_ERROR(Status) && (DriverDiagnostics2 != NULL)) {
192                 Language = GetBestLanguageForDriver(DriverDiagnostics2->SupportedLanguages, Lang, FALSE);
193                 Found = TRUE;
194                 Status = DriverDiagnostics2->RunDiagnostics(
195                   DriverDiagnostics2,
196                   ControllerHandleList[ControllerHandleListLoop],
197                   ChildHandleList == NULL?NULL:ChildHandleList[ChildHandleListLoop],
198                   (EFI_DRIVER_DIAGNOSTIC_TYPE)Mode,
199                   Language,
200                   &ErrorType,
201                   &OutBufferSize,
202                   &OutBuffer);
203                 FreePool(Language);
204               }
205             }
206             if (!Found && (Lang == NULL||(Lang!=NULL&&(Lang[2]!='-')))){
207               Status = gBS->OpenProtocol(
208                 DriverHandleList[DriverHandleListLoop],
209                 &gEfiDriverDiagnosticsProtocolGuid,
210                 (VOID**)&DriverDiagnostics,
211                 gImageHandle,
212                 NULL,
213                 EFI_OPEN_PROTOCOL_GET_PROTOCOL);
214               if (!EFI_ERROR(Status)) {
215                 Language = GetBestLanguageForDriver(DriverDiagnostics->SupportedLanguages, Lang, FALSE);
216                 Status = DriverDiagnostics->RunDiagnostics(
217                   DriverDiagnostics,
218                   ControllerHandleList[ControllerHandleListLoop],
219                   ChildHandleList == NULL?NULL:ChildHandleList[ChildHandleListLoop],
220                   (EFI_DRIVER_DIAGNOSTIC_TYPE)Mode,
221                   Language,
222                   &ErrorType,
223                   &OutBufferSize,
224                   &OutBuffer);
225                 FreePool(Language);
226               }
227             }
228             if (EFI_ERROR(Status)) {
229               Status2 = Status;
230             }
231             HandleIndex1 = ConvertHandleToHandleIndex(DriverHandleList[DriverHandleListLoop]);
232             HandleIndex2 = ConvertHandleToHandleIndex(ControllerHandleList[ControllerHandleListLoop]);
233             ShellPrintHiiEx(
234               -1,
235               -1,
236               NULL,
237               STRING_TOKEN (STR_3P_RESULT),
238               gShellDriver1HiiHandle,
239               L"DrvDiag",
240               HandleIndex1,
241               HandleIndex2,
242               ChildHandleList == NULL?0:ConvertHandleToHandleIndex(ChildHandleList[ChildHandleListLoop]),
243               Status);
244             if (OutBuffer!=NULL) {
245               FreePool(OutBuffer);
246               OutBuffer = NULL;
247             }
248             if (ErrorType!=NULL) {
249               FreePool(ErrorType);
250               ErrorType = NULL;
251             }
252           } else {
253             HandleIndex1 = ConvertHandleToHandleIndex(DriverHandleList[DriverHandleListLoop]);
254             HandleIndex2 = ConvertHandleToHandleIndex(ControllerHandleList[ControllerHandleListLoop]);
255             //
256             // Print out the information that this set can be tested
257             //
258             ShellPrintHiiEx(
259               -1,
260               -1,
261               NULL,
262               STRING_TOKEN (STR_DRV_DIAG_ITEM_LINE),
263               gShellDriver1HiiHandle,
264               HandleIndex1,
265               HandleIndex2,
266               ChildHandleList == NULL?0:ConvertHandleToHandleIndex(ChildHandleList[ChildHandleListLoop])
267            );
268           }
269 
270           //
271           // If we are doing a single pass with NULL child jump out after a single loop
272           //
273           if (ChildHandleList == NULL) {
274             break;
275           }
276         }
277         if (AllChilds) {
278           SHELL_FREE_NON_NULL(ChildHandleList);
279           ChildHandleList       = NULL;
280           ChildHandleListCount  = 0;
281         }
282       }
283       if (ControllerHandle == NULL) {
284         SHELL_FREE_NON_NULL(ControllerHandleList);
285         ControllerHandleList      = NULL;
286         ControllerHandleListCount = 0;
287       }
288       }
289   }
290 
291   if (DriverHandleList != NULL) {
292     FreePool(DriverHandleList);
293   }
294   if (ControllerHandleList != NULL) {
295     FreePool(ControllerHandleList);
296   }
297   if (ChildHandleList != NULL) {
298     FreePool(ChildHandleList);
299   }
300   return (Status2);
301 }
302 
303 
304 STATIC CONST SHELL_PARAM_ITEM ParamList[] = {
305   {L"-c", TypeFlag},
306   {L"-s", TypeFlag},
307   {L"-e", TypeFlag},
308   {L"-m", TypeFlag},
309   {L"-l", TypeValue},
310   {NULL, TypeMax}
311   };
312 
313 /**
314   Function for 'drvdiag' command.
315 
316   @param[in] ImageHandle  Handle to the Image (NULL if Internal).
317   @param[in] SystemTable  Pointer to the System Table (NULL if Internal).
318 **/
319 SHELL_STATUS
320 EFIAPI
ShellCommandRunDrvDiag(IN EFI_HANDLE ImageHandle,IN EFI_SYSTEM_TABLE * SystemTable)321 ShellCommandRunDrvDiag (
322   IN EFI_HANDLE        ImageHandle,
323   IN EFI_SYSTEM_TABLE  *SystemTable
324   )
325 {
326   EFI_STATUS          Status;
327   LIST_ENTRY          *Package;
328   CHAR16              *ProblemParam;
329   SHELL_STATUS        ShellStatus;
330   DRV_DIAG_TEST_MODE  Mode;
331   CHAR8               *Language;
332   CONST CHAR16        *DriverHandleStr;
333   CONST CHAR16        *ControllerHandleStr;
334   CONST CHAR16        *ChildHandleStr;
335   CONST CHAR16        *Lang;
336   EFI_HANDLE          Handle1;
337   EFI_HANDLE          Handle2;
338   EFI_HANDLE          Handle3;
339   UINT64              Intermediate;
340 
341   ShellStatus         = SHELL_SUCCESS;
342   Mode                = TestModeMax;
343   Language            = NULL;
344 
345   //
346   // initialize the shell lib (we must be in non-auto-init...)
347   //
348   Status = ShellInitialize();
349   ASSERT_EFI_ERROR(Status);
350 
351   Status = CommandInit();
352   ASSERT_EFI_ERROR(Status);
353 
354   //
355   // parse the command line
356   //
357   Status = ShellCommandLineParse (ParamList, &Package, &ProblemParam, TRUE);
358   if (EFI_ERROR(Status)) {
359     if (Status == EFI_VOLUME_CORRUPTED && ProblemParam != NULL) {
360       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_PROBLEM), gShellDriver1HiiHandle, L"drvdiag", ProblemParam);
361       FreePool(ProblemParam);
362       ShellStatus = SHELL_INVALID_PARAMETER;
363     } else {
364       ASSERT(FALSE);
365     }
366   } else {
367     //
368     // if more than 3 'value' parameters (plus the name one) or we have any 2 mode flags
369     //
370     if ((ShellCommandLineGetCount(Package) > 4)
371       ||(ShellCommandLineGetFlag(Package, L"-s") && ShellCommandLineGetFlag(Package, L"-e"))
372       ||(ShellCommandLineGetFlag(Package, L"-s") && ShellCommandLineGetFlag(Package, L"-m"))
373       ||(ShellCommandLineGetFlag(Package, L"-e") && ShellCommandLineGetFlag(Package, L"-m"))
374      ){
375       //
376       // error for too many parameters
377       //
378       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_TOO_MANY), gShellDriver1HiiHandle, L"drvdiag");
379       ShellStatus = SHELL_INVALID_PARAMETER;
380     } else if ((ShellCommandLineGetFlag(Package, L"-s"))
381             || (ShellCommandLineGetFlag(Package, L"-e"))
382             || (ShellCommandLineGetFlag(Package, L"-m"))
383            ){
384       //
385       // Run the appropriate test
386       //
387       if        (ShellCommandLineGetFlag(Package, L"-s")) {
388         Mode =   TestModeStandard;
389       } else if (ShellCommandLineGetFlag(Package, L"-e")) {
390         Mode = TestModeExtended;
391       } else if (ShellCommandLineGetFlag(Package, L"-m")) {
392         Mode = TestModeManufacturing;
393       } else {
394         ASSERT(FALSE);
395       }
396     } else {
397       //
398       // Do a listing of what's available to test
399       //
400       Mode = TestModeList;
401     }
402 
403     Lang = ShellCommandLineGetValue(Package, L"-l");
404     if (ShellCommandLineGetFlag(Package, L"-l") && Lang == NULL) {
405       ASSERT(Language == NULL);
406       ShellPrintHiiEx(-1, -1, NULL, STRING_TOKEN (STR_GEN_NO_VALUE), gShellDriver1HiiHandle, L"drvdiag",  L"-l");
407       ShellCommandLineFreeVarList (Package);
408       return (SHELL_INVALID_PARAMETER);
409     } else if (Lang != NULL) {
410       Language = AllocateZeroPool(StrSize(Lang));
411       AsciiSPrint(Language, StrSize(Lang), "%S", Lang);
412     }
413 
414     DriverHandleStr     = ShellCommandLineGetRawValue(Package, 1);
415     ControllerHandleStr = ShellCommandLineGetRawValue(Package, 2);
416     ChildHandleStr      = ShellCommandLineGetRawValue(Package, 3);
417 
418     if (DriverHandleStr == NULL) {
419       Handle1 = NULL;
420     } else {
421       ShellConvertStringToUint64(DriverHandleStr, &Intermediate, TRUE, FALSE);
422       Handle1 = ConvertHandleIndexToHandle((UINTN)Intermediate);
423     }
424     if (ControllerHandleStr == NULL) {
425       Handle2 = NULL;
426     } else {
427       ShellConvertStringToUint64(ControllerHandleStr, &Intermediate, TRUE, FALSE);
428       Handle2 = ConvertHandleIndexToHandle((UINTN)Intermediate);
429     }
430     if (ChildHandleStr == NULL) {
431       Handle3 = NULL;
432     } else {
433       ShellConvertStringToUint64(ChildHandleStr, &Intermediate, TRUE, FALSE);
434       Handle3 = ConvertHandleIndexToHandle((UINTN)Intermediate);
435     }
436 
437     Status = DoDiagnostics (
438       Mode,
439       Language,
440       ShellCommandLineGetFlag(Package, L"-c"),
441       Handle1,
442       Handle2,
443       Handle3
444       );
445 
446     SHELL_FREE_NON_NULL(Language);
447     ShellCommandLineFreeVarList (Package);
448 
449   }
450   if (ShellStatus == SHELL_SUCCESS) {
451     if (Status == EFI_SECURITY_VIOLATION) {
452       ShellStatus = SHELL_SECURITY_VIOLATION;
453     } else if (Status == EFI_INVALID_PARAMETER) {
454       ShellStatus = SHELL_INVALID_PARAMETER;
455     } else if (Status == EFI_NOT_FOUND) {
456       ShellStatus = SHELL_NOT_FOUND;
457     } else if (EFI_ERROR(Status)) {
458       ShellStatus = SHELL_NOT_FOUND;
459     }
460   }
461 
462   return (ShellStatus);
463 }
464