2 A shell application to dump dynamic PCD settings.
4 Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
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>
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>
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
35 GLOBAL_REMOVE_IF_UNREFERENCED EFI_STRING_ID mStrDumpDynPcdHelpTokenId
= STRING_TOKEN (STR_DUMP_DYN_PCD_HELP_INFORMATION
);
37 #define MAJOR_VERSION 1
38 #define MINOR_VERSION 0
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;
48 static CONST CHAR8 mHex
[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};
56 This function parse application ARG.
67 EFI_SHELL_PARAMETERS_PROTOCOL
*ShellParameters
;
69 Status
= gBS
->HandleProtocol (
71 &gEfiShellParametersProtocolGuid
,
72 (VOID
**)&ShellParameters
74 if (EFI_ERROR(Status
)) {
78 Argc
= ShellParameters
->Argc
;
79 Argv
= ShellParameters
->Argv
;
84 Display current version.
91 Print (L
"DumpDynPcd Version %d.%02d\n", MAJOR_VERSION
, MINOR_VERSION
);
95 Display Usage and Help information.
102 Print (L
"Dump dynamic[ex] PCD info.\n");
104 Print (L
"DumpDynPcd [PcdName]\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");
114 Dump some hexadecimal data to the screen.
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.
141 while (DataSize
!= 0) {
143 if (Size
> DataSize
) {
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
);
157 Print (L
"%*a%08X: %-48a *%a*\r\n", Indent
, "", Offset
, Val
, Str
);
167 Safely append with automatic string resizing given length of Destination and
168 desired length of copy from Source.
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
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.
181 If Source is NULL, there is nothing to append, just return the current buffer in
184 if Destination is NULL, then ASSERT()
185 if Destination's current length (including NULL terminator) is already more then
186 CurrentSize, then ASSERT()
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
194 @return Destination return the resultant string.
198 InternalStrnCatGrow (
199 IN OUT CHAR16
**Destination
,
200 IN OUT UINTN
*CurrentSize
,
201 IN CONST CHAR16
*Source
204 UINTN DestinationStartSize
;
208 SourceLen
= StrLen(Source
);
213 ASSERT(Destination
!= NULL
);
216 // If there's nothing to do then just return Destination
218 if (Source
== NULL
) {
219 return (*Destination
);
223 // allow for un-initialized pointers, based on size being 0
225 if (CurrentSize
!= NULL
&& *CurrentSize
== 0) {
230 // allow for NULL pointers address as Destination
232 if (*Destination
!= NULL
) {
233 ASSERT(CurrentSize
!= 0);
234 DestinationStartSize
= StrSize(*Destination
);
235 ASSERT(DestinationStartSize
<= *CurrentSize
);
237 DestinationStartSize
= 0;
241 // Test and grow if required
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
);
249 *Destination
= ReallocatePool(*CurrentSize
, NewSize
, *Destination
);
250 *CurrentSize
= NewSize
;
253 NewSize
= (SourceLen
+ 1)*sizeof(CHAR16
);
254 *Destination
= AllocateZeroPool(NewSize
);
258 // Now use standard StrnCat on a big enough buffer
260 if (*Destination
== NULL
) {
264 StrnCatS(*Destination
, NewSize
/sizeof(CHAR16
), Source
, SourceLen
);
269 Get PCD type string based on input PCD type.
271 @param[in] TokenSpace PCD Token Space.
272 @param[in] PcdType The input PCD type.
274 @return Pointer to PCD type string.
279 IN CONST EFI_GUID
*TokenSpace
,
280 IN EFI_PCD_TYPE PcdType
291 InternalStrnCatGrow (&RetString
, &BufLen
, L
"UINT8");
293 case EFI_PCD_TYPE_16
:
294 InternalStrnCatGrow (&RetString
, &BufLen
, L
"UINT16");
296 case EFI_PCD_TYPE_32
:
297 InternalStrnCatGrow (&RetString
, &BufLen
, L
"UINT32");
299 case EFI_PCD_TYPE_64
:
300 InternalStrnCatGrow (&RetString
, &BufLen
, L
"UINT64");
302 case EFI_PCD_TYPE_BOOL
:
303 InternalStrnCatGrow (&RetString
, &BufLen
, L
"BOOLEAN");
305 case EFI_PCD_TYPE_PTR
:
306 InternalStrnCatGrow (&RetString
, &BufLen
, L
"POINTER");
309 InternalStrnCatGrow (&RetString
, &BufLen
, L
"UNKNOWN");
313 if (TokenSpace
== NULL
) {
314 InternalStrnCatGrow (&RetString
, &BufLen
, L
":DYNAMIC");
316 InternalStrnCatGrow (&RetString
, &BufLen
, L
":DYNAMICEX");
325 @param[in] TokenSpace PCD Token Space.
326 @param[in] TokenNumber PCD Token Number.
327 @param[in] PcdInfo Pointer to PCD info.
332 IN CONST EFI_GUID
*TokenSpace
,
333 IN UINTN TokenNumber
,
334 IN EFI_PCD_INFO
*PcdInfo
347 if (PcdInfo
->PcdName
!= NULL
) {
348 Print (L
"%a\n", PcdInfo
->PcdName
);
350 if (TokenSpace
== NULL
) {
351 Print (L
"Default Token Space\n");
353 Print (L
"%g\n", TokenSpace
);
357 RetString
= GetPcdTypeString (TokenSpace
, PcdInfo
->PcdType
);
359 switch (PcdInfo
->PcdType
) {
361 if (TokenSpace
== NULL
) {
362 Uint8
= mPcd
->Get8 (TokenNumber
);
364 Uint8
= mPiPcd
->Get8 (TokenSpace
, TokenNumber
);
366 Print (L
" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = 0x%x\n", TokenNumber
, RetString
, PcdInfo
->PcdSize
, Uint8
);
368 case EFI_PCD_TYPE_16
:
369 if (TokenSpace
== NULL
) {
370 Uint16
= mPcd
->Get16 (TokenNumber
);
372 Uint16
= mPiPcd
->Get16 (TokenSpace
, TokenNumber
);
374 Print (L
" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = 0x%x\n", TokenNumber
, RetString
, PcdInfo
->PcdSize
, Uint16
);
376 case EFI_PCD_TYPE_32
:
377 if (TokenSpace
== NULL
) {
378 Uint32
= mPcd
->Get32 (TokenNumber
);
380 Uint32
= mPiPcd
->Get32 (TokenSpace
, TokenNumber
);
382 Print (L
" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = 0x%x\n", TokenNumber
, RetString
, PcdInfo
->PcdSize
, Uint32
);
384 case EFI_PCD_TYPE_64
:
385 if (TokenSpace
== NULL
) {
386 Uint64
= mPcd
->Get64 (TokenNumber
);
388 Uint64
= mPiPcd
->Get64 (TokenSpace
, TokenNumber
);
390 Print (L
" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = 0x%lx\n", TokenNumber
, RetString
, PcdInfo
->PcdSize
, Uint64
);
392 case EFI_PCD_TYPE_BOOL
:
393 if (TokenSpace
== NULL
) {
394 Boolean
= mPcd
->GetBool (TokenNumber
);
396 Boolean
= mPiPcd
->GetBool (TokenSpace
, TokenNumber
);
398 Print (L
" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = %a\n", TokenNumber
, RetString
, PcdInfo
->PcdSize
, Boolean
? "TRUE" : "FALSE");
400 case EFI_PCD_TYPE_PTR
:
401 if (TokenSpace
== NULL
) {
402 PcdData
= mPcd
->GetPtr (TokenNumber
);
404 PcdData
= mPiPcd
->GetPtr (TokenSpace
, TokenNumber
);
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
);
413 if (RetString
!= NULL
) {
414 FreePool (RetString
);
420 Show one or all PCDs' info.
422 @param[in] InputPcdName Pointer to PCD name to show. If NULL, show all PCDs' info.
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.
432 IN CHAR16
*InputPcdName
436 EFI_GUID
*TokenSpace
;
438 EFI_PCD_INFO PcdInfo
;
442 PcdInfo
.PcdName
= NULL
;
444 PcdInfo
.PcdType
= 0xFF;
447 Print (L
"Current system SKU ID: 0x%x\n\n", mPiPcdInfo
->GetSku ());
453 Status
= mPiPcd
->GetNextToken (TokenSpace
, &TokenNumber
);
454 if (!EFI_ERROR (Status
) && TokenNumber
!= 0) {
455 if (TokenSpace
== NULL
) {
457 // PCD in default Token Space.
459 mPcdInfo
->GetInfo (TokenNumber
, &PcdInfo
);
461 mPiPcdInfo
->GetInfo (TokenSpace
, TokenNumber
, &PcdInfo
);
463 if (InputPcdName
!= NULL
) {
464 if (PcdInfo
.PcdName
== NULL
) {
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
;
475 if (mTempPcdNameBuffer
== NULL
) {
476 return EFI_OUT_OF_RESOURCES
;
478 AsciiStrToUnicodeStrS (PcdInfo
.PcdName
, mTempPcdNameBuffer
, mTempPcdNameBufferSize
/ sizeof (CHAR16
));
480 // Compare the input PCD name with the PCD name in PCD database.
482 if ((StrStr (mTempPcdNameBuffer
, InputPcdName
) != NULL
) ||
483 (mUnicodeCollation
!= NULL
&& mUnicodeCollation
->MetaiMatch (mUnicodeCollation
, mTempPcdNameBuffer
, InputPcdName
))) {
485 // Found matched PCD.
487 DumpPcdInfo (TokenSpace
, TokenNumber
, &PcdInfo
);
491 DumpPcdInfo (TokenSpace
, TokenNumber
, &PcdInfo
);
494 } while (!EFI_ERROR (Status
) && TokenNumber
!= 0);
496 Status
= mPiPcd
->GetNextTokenSpace ((CONST EFI_GUID
**) &TokenSpace
);
497 } while (!EFI_ERROR (Status
) && TokenSpace
!= NULL
);
499 if ((InputPcdName
!= NULL
) && !Found
) {
501 // The specified PCD is not found, print error.
503 Print (L
"%EError. %NNo matching PCD found: %s.\n", InputPcdName
);
504 return EFI_NOT_FOUND
;
510 Main entrypoint for DumpDynPcd shell application.
512 @param[in] ImageHandle The image handle.
513 @param[in] SystemTable The system table.
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.
525 IN EFI_HANDLE ImageHandle
,
526 IN EFI_SYSTEM_TABLE
*SystemTable
530 CHAR16
*InputPcdName
;
534 Status
= gBS
->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid
, NULL
, (VOID
**) &mUnicodeCollation
);
535 if (EFI_ERROR (Status
)) {
536 mUnicodeCollation
= NULL
;
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");
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");
551 Status
= gBS
->LocateProtocol (&gPcdProtocolGuid
, NULL
, (VOID
**) &mPcd
);
552 if (EFI_ERROR (Status
)) {
553 Print (L
"DumpDynPcd: %EError. %NPCD protocol is not present.\n");
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");
564 // get the command line arguments
567 if (EFI_ERROR(Status
)){
568 Print (L
"DumpDynPcd: %EError. %NThe input parameters are not recognized.\n");
569 Status
= EFI_INVALID_PARAMETER
;
574 Print (L
"DumpDynPcd: %EError. %NToo many arguments specified.\n");
575 Status
= EFI_INVALID_PARAMETER
;
580 Status
= ProcessPcd (InputPcdName
);
584 if ((StrCmp(Argv
[1], L
"-?") == 0)||(StrCmp(Argv
[1], L
"-h") == 0)||(StrCmp(Argv
[1], L
"-H") == 0)){
588 if ((StrCmp(Argv
[1], L
"-v") == 0)||(StrCmp(Argv
[1], L
"-V") == 0)){
592 if (StrStr(Argv
[1], L
"-") != NULL
){
593 Print (L
"DumpDynPcd: %EError. %NThe argument '%B%s%N' is invalid.\n", Argv
[1]);
599 InputPcdName
= Argv
[1];
600 Status
= ProcessPcd (InputPcdName
);
604 if (mTempPcdNameBuffer
!= NULL
) {
605 FreePool (mTempPcdNameBuffer
);