+/** @file\r
+ A shell application to dump dynamic PCD settings.\r
+\r
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>\r
+ SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <Uefi.h>\r
+#include <PiDxe.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+\r
+\r
+#include <Protocol/UnicodeCollation.h>\r
+#include <Protocol/PiPcd.h>\r
+#include <Protocol/Pcd.h>\r
+#include <Protocol/PiPcdInfo.h>\r
+#include <Protocol/PcdInfo.h>\r
+#include <Protocol/ShellParameters.h>\r
+#include <Protocol/Shell.h>\r
+\r
+\r
+//\r
+// String token ID of help message text.\r
+// Shell supports to find help message in the resource section of an application image if\r
+// .MAN file is not found. This global variable is added to make build tool recognizes\r
+// that the help string is consumed by user and then build tool will add the string into\r
+// the resource section. Thus the application can use '-?' option to show help message in\r
+// Shell.\r
+//\r
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_STRING_ID mStrDumpDynPcdHelpTokenId = STRING_TOKEN (STR_DUMP_DYN_PCD_HELP_INFORMATION);\r
+\r
+#define MAJOR_VERSION 1\r
+#define MINOR_VERSION 0\r
+\r
+static EFI_UNICODE_COLLATION_PROTOCOL *mUnicodeCollation = NULL;\r
+static EFI_PCD_PROTOCOL *mPiPcd = NULL;\r
+static PCD_PROTOCOL *mPcd = NULL;\r
+static EFI_GET_PCD_INFO_PROTOCOL *mPiPcdInfo = NULL;\r
+static GET_PCD_INFO_PROTOCOL *mPcdInfo = NULL;\r
+static CHAR16 *mTempPcdNameBuffer = NULL;\r
+static UINTN mTempPcdNameBufferSize = 0;\r
+\r
+static CONST CHAR8 mHex[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};\r
+\r
+static UINTN Argc;\r
+static CHAR16 **Argv;\r
+\r
+\r
+/**\r
+\r
+ This function parse application ARG.\r
+\r
+ @return Status\r
+**/\r
+static\r
+EFI_STATUS\r
+GetArg (\r
+ VOID\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_SHELL_PARAMETERS_PROTOCOL *ShellParameters;\r
+\r
+ Status = gBS->HandleProtocol (\r
+ gImageHandle,\r
+ &gEfiShellParametersProtocolGuid,\r
+ (VOID**)&ShellParameters\r
+ );\r
+ if (EFI_ERROR(Status)) {\r
+ return Status;\r
+ }\r
+\r
+ Argc = ShellParameters->Argc;\r
+ Argv = ShellParameters->Argv;\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Display current version.\r
+**/\r
+static\r
+VOID\r
+ShowVersion (\r
+ )\r
+{\r
+ Print (L"DumpDynPcd Version %d.%02d\n", MAJOR_VERSION, MINOR_VERSION);\r
+}\r
+\r
+/**\r
+ Display Usage and Help information.\r
+**/\r
+static\r
+VOID\r
+ShowHelp (\r
+ )\r
+{\r
+ Print (L"Dump dynamic[ex] PCD info.\n");\r
+ Print (L"\n");\r
+ Print (L"DumpDynPcd [PcdName]\n");\r
+ Print (L"\n");\r
+ Print (L" PcdName Specifies the name of PCD.\n");\r
+ Print (L" A literal[or partial] name or a pattern as specified in\n");\r
+ Print (L" the MetaiMatch() function of the EFI_UNICODE_COLLATION2_PROCOOL.\n");\r
+ Print (L" If it is absent, dump all PCDs' info.\n");\r
+ Print (L"The PCD data is printed as hexadecimal dump.\n");\r
+}\r
+\r
+/**\r
+ Dump some hexadecimal data to the screen.\r
+\r
+ @param[in] Indent How many spaces to indent the output.\r
+ @param[in] Offset The offset of the printing.\r
+ @param[in] DataSize The size in bytes of UserData.\r
+ @param[in] UserData The data to print out.\r
+**/\r
+static\r
+VOID\r
+DumpHex (\r
+ IN UINTN Indent,\r
+ IN UINTN Offset,\r
+ IN UINTN DataSize,\r
+ IN VOID *UserData\r
+ )\r
+{\r
+ UINT8 *Data;\r
+\r
+ CHAR8 Val[50];\r
+\r
+ CHAR8 Str[20];\r
+\r
+ UINT8 TempByte;\r
+ UINTN Size;\r
+ UINTN Index;\r
+\r
+ Data = UserData;\r
+ while (DataSize != 0) {\r
+ Size = 16;\r
+ if (Size > DataSize) {\r
+ Size = DataSize;\r
+ }\r
+\r
+ for (Index = 0; Index < Size; Index += 1) {\r
+ TempByte = Data[Index];\r
+ Val[Index * 3 + 0] = mHex[TempByte >> 4];\r
+ Val[Index * 3 + 1] = mHex[TempByte & 0xF];\r
+ Val[Index * 3 + 2] = (CHAR8) ((Index == 7) ? '-' : ' ');\r
+ Str[Index] = (CHAR8) ((TempByte < ' ' || TempByte > 'z') ? '.' : TempByte);\r
+ }\r
+\r
+ Val[Index * 3] = 0;\r
+ Str[Index] = 0;\r
+ Print (L"%*a%08X: %-48a *%a*\r\n", Indent, "", Offset, Val, Str);\r
+\r
+ Data += Size;\r
+ Offset += Size;\r
+ DataSize -= Size;\r
+ }\r
+}\r
+\r
+\r
+/**\r
+ Safely append with automatic string resizing given length of Destination and\r
+ desired length of copy from Source.\r
+\r
+ append the first D characters of Source to the end of Destination, where D is\r
+ the lesser of Count and the StrLen() of Source. If appending those D characters\r
+ will fit within Destination (whose Size is given as CurrentSize) and\r
+ still leave room for a NULL terminator, then those characters are appended,\r
+ starting at the original terminating NULL of Destination, and a new terminating\r
+ NULL is appended.\r
+\r
+ If appending D characters onto Destination will result in a overflow of the size\r
+ given in CurrentSize the string will be grown such that the copy can be performed\r
+ and CurrentSize will be updated to the new size.\r
+\r
+ If Source is NULL, there is nothing to append, just return the current buffer in\r
+ Destination.\r
+\r
+ if Destination is NULL, then ASSERT()\r
+ if Destination's current length (including NULL terminator) is already more then\r
+ CurrentSize, then ASSERT()\r
+\r
+ @param[in, out] Destination The String to append onto\r
+ @param[in, out] CurrentSize on call the number of bytes in Destination. On\r
+ return possibly the new size (still in bytes). if NULL\r
+ then allocate whatever is needed.\r
+ @param[in] Source The String to append from\r
+\r
+ @return Destination return the resultant string.\r
+**/\r
+static\r
+CHAR16*\r
+InternalStrnCatGrow (\r
+ IN OUT CHAR16 **Destination,\r
+ IN OUT UINTN *CurrentSize,\r
+ IN CONST CHAR16 *Source\r
+ )\r
+{\r
+ UINTN DestinationStartSize;\r
+ UINTN NewSize;\r
+ UINTN SourceLen;\r
+\r
+ SourceLen = StrLen(Source);\r
+\r
+ //\r
+ // ASSERTs\r
+ //\r
+ ASSERT(Destination != NULL);\r
+\r
+ //\r
+ // If there's nothing to do then just return Destination\r
+ //\r
+ if (Source == NULL) {\r
+ return (*Destination);\r
+ }\r
+\r
+ //\r
+ // allow for un-initialized pointers, based on size being 0\r
+ //\r
+ if (CurrentSize != NULL && *CurrentSize == 0) {\r
+ *Destination = NULL;\r
+ }\r
+\r
+ //\r
+ // allow for NULL pointers address as Destination\r
+ //\r
+ if (*Destination != NULL) {\r
+ ASSERT(CurrentSize != 0);\r
+ DestinationStartSize = StrSize(*Destination);\r
+ ASSERT(DestinationStartSize <= *CurrentSize);\r
+ } else {\r
+ DestinationStartSize = 0;\r
+ }\r
+\r
+ //\r
+ // Test and grow if required\r
+ //\r
+ if (CurrentSize != NULL) {\r
+ NewSize = *CurrentSize;\r
+ if (NewSize < DestinationStartSize + (SourceLen * sizeof(CHAR16))) {\r
+ while (NewSize < (DestinationStartSize + (SourceLen*sizeof(CHAR16)))) {\r
+ NewSize += 2 * SourceLen * sizeof(CHAR16);\r
+ }\r
+ *Destination = ReallocatePool(*CurrentSize, NewSize, *Destination);\r
+ *CurrentSize = NewSize;\r
+ }\r
+ } else {\r
+ NewSize = (SourceLen + 1)*sizeof(CHAR16);\r
+ *Destination = AllocateZeroPool(NewSize);\r
+ }\r
+\r
+ //\r
+ // Now use standard StrnCat on a big enough buffer\r
+ //\r
+ if (*Destination == NULL) {\r
+ return (NULL);\r
+ }\r
+\r
+ StrnCatS(*Destination, NewSize/sizeof(CHAR16), Source, SourceLen);\r
+ return *Destination;\r
+}\r
+\r
+/**\r
+ Get PCD type string based on input PCD type.\r
+\r
+ @param[in] TokenSpace PCD Token Space.\r
+ @param[in] PcdType The input PCD type.\r
+\r
+ @return Pointer to PCD type string.\r
+**/\r
+static\r
+CHAR16 *\r
+GetPcdTypeString (\r
+ IN CONST EFI_GUID *TokenSpace,\r
+ IN EFI_PCD_TYPE PcdType\r
+ )\r
+{\r
+ UINTN BufLen;\r
+ CHAR16 *RetString;\r
+\r
+ BufLen = 0;\r
+ RetString = NULL;\r
+\r
+ switch (PcdType) {\r
+ case EFI_PCD_TYPE_8:\r
+ InternalStrnCatGrow (&RetString, &BufLen, L"UINT8");\r
+ break;\r
+ case EFI_PCD_TYPE_16:\r
+ InternalStrnCatGrow (&RetString, &BufLen, L"UINT16");\r
+ break;\r
+ case EFI_PCD_TYPE_32:\r
+ InternalStrnCatGrow (&RetString, &BufLen, L"UINT32");\r
+ break;\r
+ case EFI_PCD_TYPE_64:\r
+ InternalStrnCatGrow (&RetString, &BufLen, L"UINT64");\r
+ break;\r
+ case EFI_PCD_TYPE_BOOL:\r
+ InternalStrnCatGrow (&RetString, &BufLen, L"BOOLEAN");\r
+ break;\r
+ case EFI_PCD_TYPE_PTR:\r
+ InternalStrnCatGrow (&RetString, &BufLen, L"POINTER");\r
+ break;\r
+ default:\r
+ InternalStrnCatGrow (&RetString, &BufLen, L"UNKNOWN");\r
+ break;\r
+ }\r
+\r
+ if (TokenSpace == NULL) {\r
+ InternalStrnCatGrow (&RetString, &BufLen, L":DYNAMIC");\r
+ } else {\r
+ InternalStrnCatGrow (&RetString, &BufLen, L":DYNAMICEX");\r
+ }\r
+\r
+ return RetString;\r
+}\r
+\r
+/**\r
+ Dump PCD info.\r
+\r
+ @param[in] TokenSpace PCD Token Space.\r
+ @param[in] TokenNumber PCD Token Number.\r
+ @param[in] PcdInfo Pointer to PCD info.\r
+**/\r
+static\r
+VOID\r
+DumpPcdInfo (\r
+ IN CONST EFI_GUID *TokenSpace,\r
+ IN UINTN TokenNumber,\r
+ IN EFI_PCD_INFO *PcdInfo\r
+ )\r
+{\r
+ CHAR16 *RetString;\r
+ UINT8 Uint8;\r
+ UINT16 Uint16;\r
+ UINT32 Uint32;\r
+ UINT64 Uint64;\r
+ BOOLEAN Boolean;\r
+ VOID *PcdData;\r
+\r
+ RetString = NULL;\r
+\r
+ if (PcdInfo->PcdName != NULL) {\r
+ Print (L"%a\n", PcdInfo->PcdName);\r
+ } else {\r
+ if (TokenSpace == NULL) {\r
+ Print (L"Default Token Space\n");\r
+ } else {\r
+ Print (L"%g\n", TokenSpace);\r
+ }\r
+ }\r
+\r
+ RetString = GetPcdTypeString (TokenSpace, PcdInfo->PcdType);\r
+\r
+ switch (PcdInfo->PcdType) {\r
+ case EFI_PCD_TYPE_8:\r
+ if (TokenSpace == NULL) {\r
+ Uint8 = mPcd->Get8 (TokenNumber);\r
+ } else {\r
+ Uint8 = mPiPcd->Get8 (TokenSpace, TokenNumber);\r
+ }\r
+ Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = 0x%x\n", TokenNumber, RetString, PcdInfo->PcdSize, Uint8);\r
+ break;\r
+ case EFI_PCD_TYPE_16:\r
+ if (TokenSpace == NULL) {\r
+ Uint16 = mPcd->Get16 (TokenNumber);\r
+ } else {\r
+ Uint16 = mPiPcd->Get16 (TokenSpace, TokenNumber);\r
+ }\r
+ Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = 0x%x\n", TokenNumber, RetString, PcdInfo->PcdSize, Uint16);\r
+ break;\r
+ case EFI_PCD_TYPE_32:\r
+ if (TokenSpace == NULL) {\r
+ Uint32 = mPcd->Get32 (TokenNumber);\r
+ } else {\r
+ Uint32 = mPiPcd->Get32 (TokenSpace, TokenNumber);\r
+ }\r
+ Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = 0x%x\n", TokenNumber, RetString, PcdInfo->PcdSize, Uint32);\r
+ break;\r
+ case EFI_PCD_TYPE_64:\r
+ if (TokenSpace == NULL) {\r
+ Uint64 = mPcd->Get64 (TokenNumber);\r
+ } else {\r
+ Uint64 = mPiPcd->Get64 (TokenSpace, TokenNumber);\r
+ }\r
+ Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = 0x%lx\n", TokenNumber, RetString, PcdInfo->PcdSize, Uint64);\r
+ break;\r
+ case EFI_PCD_TYPE_BOOL:\r
+ if (TokenSpace == NULL) {\r
+ Boolean = mPcd->GetBool (TokenNumber);\r
+ } else {\r
+ Boolean = mPiPcd->GetBool (TokenSpace, TokenNumber);\r
+ }\r
+ Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x - Value = %a\n", TokenNumber, RetString, PcdInfo->PcdSize, Boolean ? "TRUE" : "FALSE");\r
+ break;\r
+ case EFI_PCD_TYPE_PTR:\r
+ if (TokenSpace == NULL) {\r
+ PcdData = mPcd->GetPtr (TokenNumber);\r
+ } else {\r
+ PcdData = mPiPcd->GetPtr (TokenSpace, TokenNumber);\r
+ }\r
+ Print (L" Token = 0x%08x - Type = %H%-17s%N - Size = 0x%x\n", TokenNumber, RetString, PcdInfo->PcdSize);\r
+ DumpHex (2, 0, PcdInfo->PcdSize, PcdData);\r
+ break;\r
+ default:\r
+ return;\r
+ }\r
+\r
+ if (RetString != NULL) {\r
+ FreePool (RetString);\r
+ }\r
+ Print (L"\n");\r
+}\r
+\r
+/**\r
+ Show one or all PCDs' info.\r
+\r
+ @param[in] InputPcdName Pointer to PCD name to show. If NULL, show all PCDs' info.\r
+\r
+ @retval EFI_SUCCESS Command completed successfully.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to run the command.\r
+ @retval EFI_ABORTED Aborted by user.\r
+ @retval EFI_NOT_FOUND The specified PCD is not found.\r
+**/\r
+static\r
+EFI_STATUS\r
+ProcessPcd (\r
+ IN CHAR16 *InputPcdName\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ EFI_GUID *TokenSpace;\r
+ UINTN TokenNumber;\r
+ EFI_PCD_INFO PcdInfo;\r
+ BOOLEAN Found;\r
+ UINTN PcdNameSize;\r
+\r
+ PcdInfo.PcdName = NULL;\r
+ PcdInfo.PcdSize = 0;\r
+ PcdInfo.PcdType = 0xFF;\r
+ Found = FALSE;\r
+\r
+ Print (L"Current system SKU ID: 0x%x\n\n", mPiPcdInfo->GetSku ());\r
+\r
+ TokenSpace = NULL;\r
+ do {\r
+ TokenNumber = 0;\r
+ do {\r
+ Status = mPiPcd->GetNextToken (TokenSpace, &TokenNumber);\r
+ if (!EFI_ERROR (Status) && TokenNumber != 0) {\r
+ if (TokenSpace == NULL) {\r
+ //\r
+ // PCD in default Token Space.\r
+ //\r
+ mPcdInfo->GetInfo (TokenNumber, &PcdInfo);\r
+ } else {\r
+ mPiPcdInfo->GetInfo (TokenSpace, TokenNumber, &PcdInfo);\r
+ }\r
+ if (InputPcdName != NULL) {\r
+ if (PcdInfo.PcdName == NULL) {\r
+ continue;\r
+ }\r
+ PcdNameSize = AsciiStrSize (PcdInfo.PcdName) * sizeof (CHAR16);\r
+ if (mTempPcdNameBuffer == NULL) {\r
+ mTempPcdNameBufferSize = PcdNameSize;\r
+ mTempPcdNameBuffer = AllocatePool (mTempPcdNameBufferSize);\r
+ } else if (mTempPcdNameBufferSize < PcdNameSize) {\r
+ mTempPcdNameBuffer = ReallocatePool (mTempPcdNameBufferSize, PcdNameSize, mTempPcdNameBuffer);\r
+ mTempPcdNameBufferSize = PcdNameSize;\r
+ }\r
+ if (mTempPcdNameBuffer == NULL) {\r
+ return EFI_OUT_OF_RESOURCES;\r
+ }\r
+ AsciiStrToUnicodeStrS (PcdInfo.PcdName, mTempPcdNameBuffer, mTempPcdNameBufferSize / sizeof (CHAR16));\r
+ //\r
+ // Compare the input PCD name with the PCD name in PCD database.\r
+ //\r
+ if ((StrStr (mTempPcdNameBuffer, InputPcdName) != NULL) ||\r
+ (mUnicodeCollation != NULL && mUnicodeCollation->MetaiMatch (mUnicodeCollation, mTempPcdNameBuffer, InputPcdName))) {\r
+ //\r
+ // Found matched PCD.\r
+ //\r
+ DumpPcdInfo (TokenSpace, TokenNumber, &PcdInfo);\r
+ Found = TRUE;\r
+ }\r
+ } else {\r
+ DumpPcdInfo (TokenSpace, TokenNumber, &PcdInfo);\r
+ }\r
+ }\r
+ } while (!EFI_ERROR (Status) && TokenNumber != 0);\r
+\r
+ Status = mPiPcd->GetNextTokenSpace ((CONST EFI_GUID **) &TokenSpace);\r
+ } while (!EFI_ERROR (Status) && TokenSpace != NULL);\r
+\r
+ if ((InputPcdName != NULL) && !Found) {\r
+ //\r
+ // The specified PCD is not found, print error.\r
+ //\r
+ Print (L"%EError. %NNo matching PCD found: %s.\n", InputPcdName);\r
+ return EFI_NOT_FOUND;\r
+ }\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Main entrypoint for DumpDynPcd shell application.\r
+\r
+ @param[in] ImageHandle The image handle.\r
+ @param[in] SystemTable The system table.\r
+\r
+ @retval EFI_SUCCESS Command completed successfully.\r
+ @retval EFI_INVALID_PARAMETER Command usage error.\r
+ @retval EFI_OUT_OF_RESOURCES Not enough resources were available to run the command.\r
+ @retval EFI_ABORTED Aborted by user.\r
+ @retval EFI_NOT_FOUND The specified PCD is not found.\r
+ @retval Others Error status returned from gBS->LocateProtocol.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+DumpDynPcdMain (\r
+ IN EFI_HANDLE ImageHandle,\r
+ IN EFI_SYSTEM_TABLE *SystemTable\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+ CHAR16 *InputPcdName;\r
+\r
+ InputPcdName = NULL;\r
+\r
+ Status = gBS->LocateProtocol(&gEfiUnicodeCollation2ProtocolGuid, NULL, (VOID **) &mUnicodeCollation);\r
+ if (EFI_ERROR (Status)) {\r
+ mUnicodeCollation = NULL;\r
+ }\r
+\r
+ Status = gBS->LocateProtocol (&gEfiPcdProtocolGuid, NULL, (VOID **) &mPiPcd);\r
+ if (EFI_ERROR (Status)) {\r
+ Print (L"DumpDynPcd: %EError. %NPI PCD protocol is not present.\n");\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->LocateProtocol (&gEfiGetPcdInfoProtocolGuid, NULL, (VOID **) &mPiPcdInfo);\r
+ if (EFI_ERROR (Status)) {\r
+ Print (L"DumpDynPcd: %EError. %NPI PCD info protocol is not present.\n");\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->LocateProtocol (&gPcdProtocolGuid, NULL, (VOID **) &mPcd);\r
+ if (EFI_ERROR (Status)) {\r
+ Print (L"DumpDynPcd: %EError. %NPCD protocol is not present.\n");\r
+ return Status;\r
+ }\r
+\r
+ Status = gBS->LocateProtocol (&gGetPcdInfoProtocolGuid, NULL, (VOID **) &mPcdInfo);\r
+ if (EFI_ERROR (Status)) {\r
+ Print (L"DumpDynPcd: %EError. %NPCD info protocol is not present.\n");\r
+ return Status;\r
+ }\r
+\r
+ //\r
+ // get the command line arguments\r
+ //\r
+ Status = GetArg();\r
+ if (EFI_ERROR(Status)){\r
+ Print (L"DumpDynPcd: %EError. %NThe input parameters are not recognized.\n");\r
+ Status = EFI_INVALID_PARAMETER;\r
+ return Status;\r
+ }\r
+\r
+ if (Argc > 2){\r
+ Print (L"DumpDynPcd: %EError. %NToo many arguments specified.\n");\r
+ Status = EFI_INVALID_PARAMETER;\r
+ return Status;\r
+ }\r
+\r
+ if (Argc == 1){\r
+ Status = ProcessPcd (InputPcdName);\r
+ goto Done;\r
+ }\r
+\r
+ if ((StrCmp(Argv[1], L"-?") == 0)||(StrCmp(Argv[1], L"-h") == 0)||(StrCmp(Argv[1], L"-H") == 0)){\r
+ ShowHelp ();\r
+ goto Done;\r
+ } else {\r
+ if ((StrCmp(Argv[1], L"-v") == 0)||(StrCmp(Argv[1], L"-V") == 0)){\r
+ ShowVersion ();\r
+ goto Done;\r
+ } else {\r
+ if (StrStr(Argv[1], L"-") != NULL){\r
+ Print (L"DumpDynPcd: %EError. %NThe argument '%B%s%N' is invalid.\n", Argv[1]);\r
+ goto Done;\r
+ }\r
+ }\r
+ }\r
+\r
+ InputPcdName = Argv[1];\r
+ Status = ProcessPcd (InputPcdName);\r
+\r
+ Done:\r
+\r
+ if (mTempPcdNameBuffer != NULL) {\r
+ FreePool (mTempPcdNameBuffer);\r
+ }\r
+\r
+ return Status;\r
+}\r
+\r