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