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