]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Application/DumpDynPcd/DumpDynPcd.c
MdeModulePkg/DumpDynPcd: Add application to dump dynamic PCD settings
[mirror_edk2.git] / MdeModulePkg / Application / DumpDynPcd / DumpDynPcd.c
1 /** @file
2 A shell application to dump dynamic PCD settings.
3
4 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
6
7 **/
8
9 #include <Uefi.h>
10 #include <PiDxe.h>
11 #include <Library/BaseLib.h>
12 #include <Library/DebugLib.h>
13 #include <Library/MemoryAllocationLib.h>
14 #include <Library/UefiBootServicesTableLib.h>
15 #include <Library/UefiLib.h>
16
17
18 #include <Protocol/UnicodeCollation.h>
19 #include <Protocol/PiPcd.h>
20 #include <Protocol/Pcd.h>
21 #include <Protocol/PiPcdInfo.h>
22 #include <Protocol/PcdInfo.h>
23 #include <Protocol/ShellParameters.h>
24 #include <Protocol/Shell.h>
25
26
27 //
28 // String token ID of help message text.
29 // Shell supports to find help message in the resource section of an application image if
30 // .MAN file is not found. This global variable is added to make build tool recognizes
31 // that the help string is consumed by user and then build tool will add the string into
32 // the resource section. Thus the application can use '-?' option to show help message in
33 // Shell.
34 //
35 GLOBAL_REMOVE_IF_UNREFERENCED EFI_STRING_ID mStrDumpDynPcdHelpTokenId = STRING_TOKEN (STR_DUMP_DYN_PCD_HELP_INFORMATION);
36
37 #define MAJOR_VERSION 1
38 #define MINOR_VERSION 0
39
40 static EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL;
41 static EFI_PCD_PROTOCOL *mPiPcd = NULL;
42 static PCD_PROTOCOL *mPcd = NULL;
43 static EFI_GET_PCD_INFO_PROTOCOL *mPiPcdInfo = NULL;
44 static GET_PCD_INFO_PROTOCOL *mPcdInfo = NULL;
45 static CHAR16 *mTempPcdNameBuffer = NULL;
46 static UINTN mTempPcdNameBufferSize = 0;
47
48 static CONST CHAR8 mHex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
49
50 static UINTN Argc;
51 static CHAR16 **Argv;
52
53
54 /**
55
56 This function parse application ARG.
57
58 @return Status
59 **/
60 static
61 EFI_STATUS
62 GetArg (
63 VOID
64 )
65 {
66 EFI_STATUS Status;
67 EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters;
68
69 Status = gBS->HandleProtocol (
70 gImageHandle,
71 &gEfiShellParametersProtocolGuid,
72 (VOID**)&ShellParameters
73 );
74 if (EFI_ERROR(Status)) {
75 return Status;
76 }
77
78 Argc = ShellParameters->Argc;
79 Argv = ShellParameters->Argv;
80 return EFI_SUCCESS;
81 }
82
83 /**
84 Display current version.
85 **/
86 static
87 VOID
88 ShowVersion (
89 )
90 {
91 Print (L"DumpDynPcd Version %d.%02d\n", MAJOR_VERSION, MINOR_VERSION);
92 }
93
94 /**
95 Display Usage and Help information.
96 **/
97 static
98 VOID
99 ShowHelp (
100 )
101 {
102 Print (L"Dump dynamic[ex] PCD info.\n");
103 Print (L"\n");
104 Print (L"DumpDynPcd [PcdName]\n");
105 Print (L"\n");
106 Print (L" PcdName Specifies the name of PCD.\n");
107 Print (L" A literal[or partial] name or a pattern as specified in\n");
108 Print (L" the MetaiMatch() function of the EFI_UNICODE_COLLATION2_PROCOOL.\n");
109 Print (L" If it is absent, dump all PCDs' info.\n");
110 Print (L"The PCD data is printed as hexadecimal dump.\n");
111 }
112
113 /**
114 Dump some hexadecimal data to the screen.
115
116 @param[in] Indent How many spaces to indent the output.
117 @param[in] Offset The offset of the printing.
118 @param[in] DataSize The size in bytes of UserData.
119 @param[in] UserData The data to print out.
120 **/
121 static
122 VOID
123 DumpHex (
124 IN UINTN Indent,
125 IN UINTN Offset,
126 IN UINTN DataSize,
127 IN VOID *UserData
128 )
129 {
130 UINT8 *Data;
131
132 CHAR8 Val[50];
133
134 CHAR8 Str[20];
135
136 UINT8 TempByte;
137 UINTN Size;
138 UINTN Index;
139
140 Data = UserData;
141 while (DataSize != 0) {
142 Size = 16;
143 if (Size > DataSize) {
144 Size = DataSize;
145 }
146
147 for (Index = 0; Index < Size; Index += 1) {
148 TempByte = Data[Index];
149 Val[Index * 3 + 0] = mHex[TempByte >> 4];
150 Val[Index * 3 + 1] = mHex[TempByte & 0xF];
151 Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' ');
152 Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);
153 }
154
155 Val[Index * 3] = 0;
156 Str[Index] = 0;
157 Print (L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str);
158
159 Data += Size;
160 Offset += Size;
161 DataSize -= Size;
162 }
163 }
164
165
166 /**
167 Safely append with automatic string resizing given length of Destination and
168 desired length of copy from Source.
169
170 append the first D characters of Source to the end of Destination, where D is
171 the lesser of Count and the StrLen() of Source. If appending those D characters
172 will fit within Destination (whose Size is given as CurrentSize) and
173 still leave room for a NULL terminator, then those characters are appended,
174 starting at the original terminating NULL of Destination, and a new terminating
175 NULL is appended.
176
177 If appending D characters onto Destination will result in a overflow of the size
178 given in CurrentSize the string will be grown such that the copy can be performed
179 and CurrentSize will be updated to the new size.
180
181 If Source is NULL, there is nothing to append, just return the current buffer in
182 Destination.
183
184 if Destination is NULL, then ASSERT()
185 if Destination's current length (including NULL terminator) is already more then
186 CurrentSize, then ASSERT()
187
188 @param[in, out] Destination The String to append onto
189 @param[in, out] CurrentSize on call the number of bytes in Destination. On
190 return possibly the new size (still in bytes). if NULL
191 then allocate whatever is needed.
192 @param[in] Source The String to append from
193
194 @return Destination return the resultant string.
195 **/
196 static
197 CHAR16*
198 InternalStrnCatGrow (
199 IN OUT CHAR16 **Destination,
200 IN OUT UINTN *CurrentSize,
201 IN CONST CHAR16 *Source
202 )
203 {
204 UINTN DestinationStartSize;
205 UINTN NewSize;
206 UINTN SourceLen;
207
208 SourceLen = StrLen(Source);
209
210 //
211 // ASSERTs
212 //
213 ASSERT(Destination != NULL);
214
215 //
216 // If there's nothing to do then just return Destination
217 //
218 if (Source == NULL) {
219 return (*Destination);
220 }
221
222 //
223 // allow for un-initialized pointers, based on size being 0
224 //
225 if (CurrentSize != NULL && *CurrentSize == 0) {
226 *Destination = NULL;
227 }
228
229 //
230 // allow for NULL pointers address as Destination
231 //
232 if (*Destination != NULL) {
233 ASSERT(CurrentSize != 0);
234 DestinationStartSize = StrSize(*Destination);
235 ASSERT(DestinationStartSize <= *CurrentSize);
236 } else {
237 DestinationStartSize = 0;
238 }
239
240 //
241 // Test and grow if required
242 //
243 if (CurrentSize != NULL) {
244 NewSize = *CurrentSize;
245 if (NewSize < DestinationStartSize + (SourceLen * sizeof(CHAR16))) {
246 while (NewSize < (DestinationStartSize + (SourceLen*sizeof(CHAR16)))) {
247 NewSize += 2 * SourceLen * sizeof(CHAR16);
248 }
249 *Destination = ReallocatePool(*CurrentSize, NewSize, *Destination);
250 *CurrentSize = NewSize;
251 }
252 } else {
253 NewSize = (SourceLen + 1)*sizeof(CHAR16);
254 *Destination = AllocateZeroPool(NewSize);
255 }
256
257 //
258 // Now use standard StrnCat on a big enough buffer
259 //
260 if (*Destination == NULL) {
261 return (NULL);
262 }
263
264 StrnCatS(*Destination, NewSize/sizeof(CHAR16), Source, SourceLen);
265 return *Destination;
266 }
267
268 /**
269 Get PCD type string based on input PCD type.
270
271 @param[in] TokenSpace PCD Token Space.
272 @param[in] PcdType The input PCD type.
273
274 @return Pointer to PCD type string.
275 **/
276 static
277 CHAR16 *
278 GetPcdTypeString (
279 IN CONST EFI_GUID *TokenSpace,
280 IN EFI_PCD_TYPE PcdType
281 )
282 {
283 UINTN BufLen;
284 CHAR16 *RetString;
285
286 BufLen = 0;
287 RetString = NULL;
288
289 switch (PcdType) {
290 case EFI_PCD_TYPE_8:
291 InternalStrnCatGrow (&RetString, &BufLen, L"UINT8");
292 break;
293 case EFI_PCD_TYPE_16:
294 InternalStrnCatGrow (&RetString, &BufLen, L"UINT16");
295 break;
296 case EFI_PCD_TYPE_32:
297 InternalStrnCatGrow (&RetString, &BufLen, L"UINT32");
298 break;
299 case EFI_PCD_TYPE_64:
300 InternalStrnCatGrow (&RetString, &BufLen, L"UINT64");
301 break;
302 case EFI_PCD_TYPE_BOOL:
303 InternalStrnCatGrow (&RetString, &BufLen, L"BOOLEAN");
304 break;
305 case EFI_PCD_TYPE_PTR:
306 InternalStrnCatGrow (&RetString, &BufLen, L"POINTER");
307 break;
308 default:
309 InternalStrnCatGrow (&RetString, &BufLen, L"UNKNOWN");
310 break;
311 }
312
313 if (TokenSpace == NULL) {
314 InternalStrnCatGrow (&RetString, &BufLen, L":DYNAMIC");
315 } else {
316 InternalStrnCatGrow (&RetString, &BufLen, L":DYNAMICEX");
317 }
318
319 return RetString;
320 }
321
322 /**
323 Dump PCD info.
324
325 @param[in] TokenSpace PCD Token Space.
326 @param[in] TokenNumber PCD Token Number.
327 @param[in] PcdInfo Pointer to PCD info.
328 **/
329 static
330 VOID
331 DumpPcdInfo (
332 IN CONST EFI_GUID *TokenSpace,
333 IN UINTN TokenNumber,
334 IN EFI_PCD_INFO *PcdInfo
335 )
336 {
337 CHAR16 *RetString;
338 UINT8 Uint8;
339 UINT16 Uint16;
340 UINT32 Uint32;
341 UINT64 Uint64;
342 BOOLEAN Boolean;
343 VOID *PcdData;
344
345 RetString = NULL;
346
347 if (PcdInfo->PcdName != NULL) {
348 Print (L"%a\n", PcdInfo->PcdName);
349 } else {
350 if (TokenSpace == NULL) {
351 Print (L"Default Token Space\n");
352 } else {
353 Print (L"%g\n", TokenSpace);
354 }
355 }
356
357 RetString = GetPcdTypeString (TokenSpace, PcdInfo->PcdType);
358
359 switch (PcdInfo->PcdType) {
360 case EFI_PCD_TYPE_8:
361 if (TokenSpace == NULL) {
362 Uint8 = mPcd->Get8 (TokenNumber);
363 } else {
364 Uint8 = mPiPcd->Get8 (TokenSpace, TokenNumber);
365 }
366 Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = 0x%x\n", TokenNumber, RetString, PcdInfo->PcdSize, Uint8);
367 break;
368 case EFI_PCD_TYPE_16:
369 if (TokenSpace == NULL) {
370 Uint16 = mPcd->Get16 (TokenNumber);
371 } else {
372 Uint16 = mPiPcd->Get16 (TokenSpace, TokenNumber);
373 }
374 Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = 0x%x\n", TokenNumber, RetString, PcdInfo->PcdSize, Uint16);
375 break;
376 case EFI_PCD_TYPE_32:
377 if (TokenSpace == NULL) {
378 Uint32 = mPcd->Get32 (TokenNumber);
379 } else {
380 Uint32 = mPiPcd->Get32 (TokenSpace, TokenNumber);
381 }
382 Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = 0x%x\n", TokenNumber, RetString, PcdInfo->PcdSize, Uint32);
383 break;
384 case EFI_PCD_TYPE_64:
385 if (TokenSpace == NULL) {
386 Uint64 = mPcd->Get64 (TokenNumber);
387 } else {
388 Uint64 = mPiPcd->Get64 (TokenSpace, TokenNumber);
389 }
390 Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = 0x%lx\n", TokenNumber, RetString, PcdInfo->PcdSize, Uint64);
391 break;
392 case EFI_PCD_TYPE_BOOL:
393 if (TokenSpace == NULL) {
394 Boolean = mPcd->GetBool (TokenNumber);
395 } else {
396 Boolean = mPiPcd->GetBool (TokenSpace, TokenNumber);
397 }
398 Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = %a\n", TokenNumber, RetString, PcdInfo->PcdSize, Boolean ? "TRUE" : "FALSE");
399 break;
400 case EFI_PCD_TYPE_PTR:
401 if (TokenSpace == NULL) {
402 PcdData = mPcd->GetPtr (TokenNumber);
403 } else {
404 PcdData = mPiPcd->GetPtr (TokenSpace, TokenNumber);
405 }
406 Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x\n", TokenNumber, RetString, PcdInfo->PcdSize);
407 DumpHex (2, 0, PcdInfo->PcdSize, PcdData);
408 break;
409 default:
410 return;
411 }
412
413 if (RetString != NULL) {
414 FreePool (RetString);
415 }
416 Print (L"\n");
417 }
418
419 /**
420 Show one or all PCDs' info.
421
422 @param[in] InputPcdName Pointer to PCD name to show. If NULL, show all PCDs' info.
423
424 @retval EFI_SUCCESS Command completed successfully.
425 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to run the command.
426 @retval EFI_ABORTED Aborted by user.
427 @retval EFI_NOT_FOUND The specified PCD is not found.
428 **/
429 static
430 EFI_STATUS
431 ProcessPcd (
432 IN CHAR16 *InputPcdName
433 )
434 {
435 EFI_STATUS Status;
436 EFI_GUID *TokenSpace;
437 UINTN TokenNumber;
438 EFI_PCD_INFO PcdInfo;
439 BOOLEAN Found;
440 UINTN PcdNameSize;
441
442 PcdInfo.PcdName = NULL;
443 PcdInfo.PcdSize = 0;
444 PcdInfo.PcdType = 0xFF;
445 Found = FALSE;
446
447 Print (L"Current system SKU ID: 0x%x\n\n", mPiPcdInfo->GetSku ());
448
449 TokenSpace = NULL;
450 do {
451 TokenNumber = 0;
452 do {
453 Status = mPiPcd->GetNextToken (TokenSpace, &TokenNumber);
454 if (!EFI_ERROR (Status) && TokenNumber != 0) {
455 if (TokenSpace == NULL) {
456 //
457 // PCD in default Token Space.
458 //
459 mPcdInfo->GetInfo (TokenNumber, &PcdInfo);
460 } else {
461 mPiPcdInfo->GetInfo (TokenSpace, TokenNumber, &PcdInfo);
462 }
463 if (InputPcdName != NULL) {
464 if (PcdInfo.PcdName == NULL) {
465 continue;
466 }
467 PcdNameSize = AsciiStrSize (PcdInfo.PcdName) * sizeof (CHAR16);
468 if (mTempPcdNameBuffer == NULL) {
469 mTempPcdNameBufferSize = PcdNameSize;
470 mTempPcdNameBuffer = AllocatePool (mTempPcdNameBufferSize);
471 } else if (mTempPcdNameBufferSize < PcdNameSize) {
472 mTempPcdNameBuffer = ReallocatePool (mTempPcdNameBufferSize, PcdNameSize, mTempPcdNameBuffer);
473 mTempPcdNameBufferSize = PcdNameSize;
474 }
475 if (mTempPcdNameBuffer == NULL) {
476 return EFI_OUT_OF_RESOURCES;
477 }
478 AsciiStrToUnicodeStrS (PcdInfo.PcdName, mTempPcdNameBuffer, mTempPcdNameBufferSize / sizeof (CHAR16));
479 //
480 // Compare the input PCD name with the PCD name in PCD database.
481 //
482 if ((StrStr (mTempPcdNameBuffer, InputPcdName) != NULL) ||
483 (mUnicodeCollation != NULL && mUnicodeCollation->MetaiMatch (mUnicodeCollation, mTempPcdNameBuffer, InputPcdName))) {
484 //
485 // Found matched PCD.
486 //
487 DumpPcdInfo (TokenSpace, TokenNumber, &PcdInfo);
488 Found = TRUE;
489 }
490 } else {
491 DumpPcdInfo (TokenSpace, TokenNumber, &PcdInfo);
492 }
493 }
494 } while (!EFI_ERROR (Status) && TokenNumber != 0);
495
496 Status = mPiPcd->GetNextTokenSpace ((CONST EFI_GUID **) &TokenSpace);
497 } while (!EFI_ERROR (Status) && TokenSpace != NULL);
498
499 if ((InputPcdName != NULL) && !Found) {
500 //
501 // The specified PCD is not found, print error.
502 //
503 Print (L"%EError. %NNo matching PCD found: %s.\n", InputPcdName);
504 return EFI_NOT_FOUND;
505 }
506 return EFI_SUCCESS;
507 }
508
509 /**
510 Main entrypoint for DumpDynPcd shell application.
511
512 @param[in] ImageHandle The image handle.
513 @param[in] SystemTable The system table.
514
515 @retval EFI_SUCCESS Command completed successfully.
516 @retval EFI_INVALID_PARAMETER Command usage error.
517 @retval EFI_OUT_OF_RESOURCES Not enough resources were available to run the command.
518 @retval EFI_ABORTED Aborted by user.
519 @retval EFI_NOT_FOUND The specified PCD is not found.
520 @retval Others Error status returned from gBS->LocateProtocol.
521 **/
522 EFI_STATUS
523 EFIAPI
524 DumpDynPcdMain (
525 IN EFI_HANDLE ImageHandle,
526 IN EFI_SYSTEM_TABLE *SystemTable
527 )
528 {
529 EFI_STATUS Status;
530 CHAR16 *InputPcdName;
531
532 InputPcdName = NULL;
533
534 Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID **) &mUnicodeCollation);
535 if (EFI_ERROR (Status)) {
536 mUnicodeCollation = NULL;
537 }
538
539 Status = gBS->LocateProtocol (&gEfiPcdProtocolGuid, NULL, (VOID **) &mPiPcd);
540 if (EFI_ERROR (Status)) {
541 Print (L"DumpDynPcd: %EError. %NPI PCD protocol is not present.\n");
542 return Status;
543 }
544
545 Status = gBS->LocateProtocol (&gEfiGetPcdInfoProtocolGuid, NULL, (VOID **) &mPiPcdInfo);
546 if (EFI_ERROR (Status)) {
547 Print (L"DumpDynPcd: %EError. %NPI PCD info protocol is not present.\n");
548 return Status;
549 }
550
551 Status = gBS->LocateProtocol (&gPcdProtocolGuid, NULL, (VOID **) &mPcd);
552 if (EFI_ERROR (Status)) {
553 Print (L"DumpDynPcd: %EError. %NPCD protocol is not present.\n");
554 return Status;
555 }
556
557 Status = gBS->LocateProtocol (&gGetPcdInfoProtocolGuid, NULL, (VOID **) &mPcdInfo);
558 if (EFI_ERROR (Status)) {
559 Print (L"DumpDynPcd: %EError. %NPCD info protocol is not present.\n");
560 return Status;
561 }
562
563 //
564 // get the command line arguments
565 //
566 Status = GetArg();
567 if (EFI_ERROR(Status)){
568 Print (L"DumpDynPcd: %EError. %NThe input parameters are not recognized.\n");
569 Status = EFI_INVALID_PARAMETER;
570 return Status;
571 }
572
573 if (Argc > 2){
574 Print (L"DumpDynPcd: %EError. %NToo many arguments specified.\n");
575 Status = EFI_INVALID_PARAMETER;
576 return Status;
577 }
578
579 if (Argc == 1){
580 Status = ProcessPcd (InputPcdName);
581 goto Done;
582 }
583
584 if ((StrCmp(Argv[1], L"-?") == 0)||(StrCmp(Argv[1], L"-h") == 0)||(StrCmp(Argv[1], L"-H") == 0)){
585 ShowHelp ();
586 goto Done;
587 } else {
588 if ((StrCmp(Argv[1], L"-v") == 0)||(StrCmp(Argv[1], L"-V") == 0)){
589 ShowVersion ();
590 goto Done;
591 } else {
592 if (StrStr(Argv[1], L"-") != NULL){
593 Print (L"DumpDynPcd: %EError. %NThe argument '%B%s%N' is invalid.\n", Argv[1]);
594 goto Done;
595 }
596 }
597 }
598
599 InputPcdName = Argv[1];
600 Status = ProcessPcd (InputPcdName);
601
602 Done:
603
604 if (mTempPcdNameBuffer != NULL) {
605 FreePool (mTempPcdNameBuffer);
606 }
607
608 return Status;
609 }
610