Home | History | Annotate | Download | only in Dxe
      1 /** @file
      2     Help functions used by PCD DXE driver.
      3 
      4 Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>
      5 Copyright (c) 2006 - 2015, 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 "Service.h"
     17 #include <Library/DxeServicesLib.h>
     18 
     19 PCD_DATABASE   mPcdDatabase;
     20 
     21 UINT32         mPcdTotalTokenCount;
     22 UINT32         mPeiLocalTokenCount;
     23 UINT32         mDxeLocalTokenCount;
     24 UINT32         mPeiNexTokenCount;
     25 UINT32         mDxeNexTokenCount;
     26 UINT32         mPeiExMapppingTableSize;
     27 UINT32         mDxeExMapppingTableSize;
     28 UINT32         mPeiGuidTableSize;
     29 UINT32         mDxeGuidTableSize;
     30 
     31 BOOLEAN        mPeiExMapTableEmpty;
     32 BOOLEAN        mDxeExMapTableEmpty;
     33 BOOLEAN        mPeiDatabaseEmpty;
     34 
     35 LIST_ENTRY    *mCallbackFnTable;
     36 EFI_GUID     **TmpTokenSpaceBuffer;
     37 UINTN          TmpTokenSpaceBufferCount;
     38 
     39 /**
     40   Get Local Token Number by Token Number.
     41 
     42   @param[in]    IsPeiDb     If TRUE, the pcd entry is initialized in PEI phase,
     43                             If FALSE, the pcd entry is initialized in DXE phase.
     44   @param[in]    TokenNumber The PCD token number.
     45 
     46   @return       Local Token Number.
     47 **/
     48 UINT32
     49 GetLocalTokenNumber (
     50   IN BOOLEAN            IsPeiDb,
     51   IN UINTN              TokenNumber
     52   )
     53 {
     54   UINTN                 TmpTokenNumber;
     55   UINT32                *LocalTokenNumberTable;
     56   UINT32                LocalTokenNumber;
     57   UINTN                 Size;
     58   UINTN                 MaxSize;
     59 
     60   //
     61   // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
     62   // We have to decrement TokenNumber by 1 to make it usable
     63   // as the array index.
     64   //
     65   TokenNumber--;
     66 
     67   //
     68   // Backup the TokenNumber passed in as GetPtrTypeSize need the original TokenNumber
     69   //
     70   TmpTokenNumber = TokenNumber;
     71 
     72   LocalTokenNumberTable  = IsPeiDb ? (UINT32 *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->LocalTokenNumberTableOffset) :
     73                                      (UINT32 *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->LocalTokenNumberTableOffset);
     74   TokenNumber            = IsPeiDb ? TokenNumber : TokenNumber - mPeiLocalTokenCount;
     75 
     76   LocalTokenNumber = LocalTokenNumberTable[TokenNumber];
     77 
     78   Size = (LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) >> PCD_DATUM_TYPE_SHIFT;
     79 
     80   if ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == PCD_TYPE_SKU_ENABLED) {
     81     if (Size == 0) {
     82       GetPtrTypeSize (TmpTokenNumber, &MaxSize);
     83     } else {
     84       MaxSize = Size;
     85     }
     86     LocalTokenNumber = GetSkuEnabledTokenNumber (LocalTokenNumber & ~PCD_TYPE_SKU_ENABLED, MaxSize, IsPeiDb);
     87   }
     88 
     89   return LocalTokenNumber;
     90 }
     91 
     92 /**
     93   Get PCD type by Local Token Number.
     94 
     95   @param[in]    LocalTokenNumber The PCD local token number.
     96 
     97   @return       PCD type.
     98 **/
     99 EFI_PCD_TYPE
    100 GetPcdType (
    101   IN UINT32             LocalTokenNumber
    102   )
    103 {
    104   switch (LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) {
    105     case PCD_DATUM_TYPE_POINTER:
    106       return EFI_PCD_TYPE_PTR;
    107     case PCD_DATUM_TYPE_UINT8:
    108       if ((LocalTokenNumber & PCD_DATUM_TYPE_UINT8_BOOLEAN) == PCD_DATUM_TYPE_UINT8_BOOLEAN) {
    109         return EFI_PCD_TYPE_BOOL;
    110       } else {
    111         return EFI_PCD_TYPE_8;
    112       }
    113     case PCD_DATUM_TYPE_UINT16:
    114       return EFI_PCD_TYPE_16;
    115     case PCD_DATUM_TYPE_UINT32:
    116       return EFI_PCD_TYPE_32;
    117     case PCD_DATUM_TYPE_UINT64:
    118       return EFI_PCD_TYPE_64;
    119     default:
    120       ASSERT (FALSE);
    121       return EFI_PCD_TYPE_8;
    122   }
    123 }
    124 
    125 /**
    126   Get PCD name.
    127 
    128   @param[in]    OnlyTokenSpaceName  If TRUE, only need to get the TokenSpaceCName.
    129                                     If FALSE, need to get the full PCD name.
    130   @param[in]    IsPeiDb             If TRUE, the pcd entry is initialized in PEI phase,
    131                                     If FALSE, the pcd entry is initialized in DXE phase.
    132   @param[in]    TokenNumber         The PCD token number.
    133 
    134   @return       The TokenSpaceCName or full PCD name.
    135 **/
    136 CHAR8 *
    137 GetPcdName (
    138   IN BOOLEAN            OnlyTokenSpaceName,
    139   IN BOOLEAN            IsPeiDb,
    140   IN UINTN              TokenNumber
    141   )
    142 {
    143   PCD_DATABASE_INIT *Database;
    144   UINT8             *StringTable;
    145   UINTN             NameSize;
    146   PCD_NAME_INDEX    *PcdNameIndex;
    147   CHAR8             *TokenSpaceName;
    148   CHAR8             *PcdName;
    149   CHAR8             *Name;
    150 
    151   //
    152   // Return NULL when PCD name table is absent.
    153   //
    154   if (IsPeiDb) {
    155     if (mPcdDatabase.PeiDb->PcdNameTableOffset == 0) {
    156       return NULL;
    157     }
    158   } else {
    159     if (mPcdDatabase.DxeDb->PcdNameTableOffset == 0) {
    160       return NULL;
    161     }
    162   }
    163 
    164   //
    165   // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
    166   // We have to decrement TokenNumber by 1 to make it usable
    167   // as the array index.
    168   //
    169   TokenNumber--;
    170 
    171   Database = IsPeiDb ? mPcdDatabase.PeiDb: mPcdDatabase.DxeDb;
    172   TokenNumber = IsPeiDb ? TokenNumber : TokenNumber - mPeiLocalTokenCount;
    173 
    174   StringTable = (UINT8 *) Database + Database->StringTableOffset;
    175 
    176   //
    177   // Get the PCD name index.
    178   //
    179   PcdNameIndex = (PCD_NAME_INDEX *)((UINT8 *) Database + Database->PcdNameTableOffset) + TokenNumber;
    180   TokenSpaceName = (CHAR8 *)&StringTable[PcdNameIndex->TokenSpaceCNameIndex];
    181   PcdName = (CHAR8 *)&StringTable[PcdNameIndex->PcdCNameIndex];
    182 
    183   if (OnlyTokenSpaceName) {
    184     //
    185     // Only need to get the TokenSpaceCName.
    186     //
    187     Name = AllocateCopyPool (AsciiStrSize (TokenSpaceName), TokenSpaceName);
    188   } else {
    189     //
    190     // Need to get the full PCD name.
    191     //
    192     NameSize = AsciiStrSize (TokenSpaceName) + AsciiStrSize (PcdName);
    193     Name = AllocateZeroPool (NameSize);
    194     ASSERT (Name != NULL);
    195     //
    196     // Catenate TokenSpaceCName and PcdCName with a '.' to form the full PCD name.
    197     //
    198     AsciiStrCatS (Name, NameSize, TokenSpaceName);
    199     Name[AsciiStrSize (TokenSpaceName) - sizeof (CHAR8)] = '.';
    200     AsciiStrCatS (Name, NameSize, PcdName);
    201   }
    202 
    203   return Name;
    204 }
    205 
    206 /**
    207   Retrieve additional information associated with a PCD token.
    208 
    209   This includes information such as the type of value the TokenNumber is associated with as well as possible
    210   human readable name that is associated with the token.
    211 
    212   @param[in]    IsPeiDb     If TRUE, the pcd entry is initialized in PEI phase,
    213                             If FALSE, the pcd entry is initialized in DXE phase.
    214   @param[in]    Guid        The 128-bit unique value that designates the namespace from which to extract the value.
    215   @param[in]    TokenNumber The PCD token number.
    216   @param[out]   PcdInfo     The returned information associated with the requested TokenNumber.
    217                             The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
    218 
    219   @retval  EFI_SUCCESS      The PCD information was returned successfully
    220   @retval  EFI_NOT_FOUND    The PCD service could not find the requested token number.
    221 **/
    222 EFI_STATUS
    223 ExGetPcdInfo (
    224   IN        BOOLEAN             IsPeiDb,
    225   IN CONST  EFI_GUID            *Guid,
    226   IN        UINTN               TokenNumber,
    227   OUT       EFI_PCD_INFO        *PcdInfo
    228   )
    229 {
    230   PCD_DATABASE_INIT     *Database;
    231   UINTN                 GuidTableIdx;
    232   EFI_GUID              *MatchGuid;
    233   EFI_GUID              *GuidTable;
    234   DYNAMICEX_MAPPING     *ExMapTable;
    235   UINTN                 Index;
    236   UINT32                LocalTokenNumber;
    237 
    238   Database = IsPeiDb ? mPcdDatabase.PeiDb: mPcdDatabase.DxeDb;
    239 
    240   GuidTable = (EFI_GUID *)((UINT8 *)Database + Database->GuidTableOffset);
    241   MatchGuid = ScanGuid (GuidTable, Database->GuidTableCount * sizeof(EFI_GUID), Guid);
    242 
    243   if (MatchGuid == NULL) {
    244     return EFI_NOT_FOUND;
    245   }
    246 
    247   GuidTableIdx = MatchGuid - GuidTable;
    248 
    249   ExMapTable = (DYNAMICEX_MAPPING *)((UINT8 *)Database + Database->ExMapTableOffset);
    250 
    251   //
    252   // Find the PCD by GuidTableIdx and ExTokenNumber in ExMapTable.
    253   //
    254   for (Index = 0; Index < Database->ExTokenCount; Index++) {
    255     if (ExMapTable[Index].ExGuidIndex == GuidTableIdx) {
    256       if (TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
    257         //
    258         // TokenNumber is 0, follow spec to set PcdType to EFI_PCD_TYPE_8,
    259         // PcdSize to 0 and PcdName to the null-terminated ASCII string
    260         // associated with the token's namespace Guid.
    261         //
    262         PcdInfo->PcdType = EFI_PCD_TYPE_8;
    263         PcdInfo->PcdSize = 0;
    264         //
    265         // Here use one representative in the token space to get the TokenSpaceCName.
    266         //
    267         PcdInfo->PcdName = GetPcdName (TRUE, IsPeiDb, ExMapTable[Index].TokenNumber);
    268         return EFI_SUCCESS;
    269       } else if (ExMapTable[Index].ExTokenNumber == TokenNumber) {
    270         PcdInfo->PcdSize = DxePcdGetSize (ExMapTable[Index].TokenNumber);
    271         LocalTokenNumber = GetLocalTokenNumber (IsPeiDb, ExMapTable[Index].TokenNumber);
    272         PcdInfo->PcdType = GetPcdType (LocalTokenNumber);
    273         PcdInfo->PcdName = GetPcdName (FALSE, IsPeiDb, ExMapTable[Index].TokenNumber);
    274         return EFI_SUCCESS;
    275       }
    276     }
    277   }
    278 
    279   return EFI_NOT_FOUND;
    280 }
    281 
    282 /**
    283   Retrieve additional information associated with a PCD token.
    284 
    285   This includes information such as the type of value the TokenNumber is associated with as well as possible
    286   human readable name that is associated with the token.
    287 
    288   @param[in]    Guid        The 128-bit unique value that designates the namespace from which to extract the value.
    289   @param[in]    TokenNumber The PCD token number.
    290   @param[out]   PcdInfo     The returned information associated with the requested TokenNumber.
    291                             The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
    292 
    293   @retval  EFI_SUCCESS      The PCD information was returned successfully.
    294   @retval  EFI_NOT_FOUND    The PCD service could not find the requested token number.
    295 **/
    296 EFI_STATUS
    297 DxeGetPcdInfo (
    298   IN CONST  EFI_GUID        *Guid,
    299   IN        UINTN           TokenNumber,
    300   OUT       EFI_PCD_INFO    *PcdInfo
    301   )
    302 {
    303   EFI_STATUS            Status;
    304   BOOLEAN               PeiExMapTableEmpty;
    305   BOOLEAN               DxeExMapTableEmpty;
    306   UINT32                LocalTokenNumber;
    307   BOOLEAN               IsPeiDb;
    308 
    309   ASSERT (PcdInfo != NULL);
    310 
    311   Status = EFI_NOT_FOUND;
    312   PeiExMapTableEmpty = mPeiExMapTableEmpty;
    313   DxeExMapTableEmpty = mDxeExMapTableEmpty;
    314 
    315   if (Guid == NULL) {
    316     if (((TokenNumber + 1 > mPeiNexTokenCount + 1) && (TokenNumber + 1 <= mPeiLocalTokenCount + 1)) ||
    317         ((TokenNumber + 1 > (mPeiLocalTokenCount + mDxeNexTokenCount + 1)))) {
    318       return EFI_NOT_FOUND;
    319     } else if (TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
    320       //
    321       // TokenNumber is 0, follow spec to set PcdType to EFI_PCD_TYPE_8,
    322       // PcdSize to 0 and PcdName to NULL for default Token Space.
    323       //
    324       PcdInfo->PcdType = EFI_PCD_TYPE_8;
    325       PcdInfo->PcdSize = 0;
    326       PcdInfo->PcdName = NULL;
    327     } else {
    328       PcdInfo->PcdSize = DxePcdGetSize (TokenNumber);
    329       IsPeiDb = FALSE;
    330       if ((TokenNumber + 1 <= mPeiNexTokenCount + 1)) {
    331         IsPeiDb = TRUE;
    332       }
    333       LocalTokenNumber = GetLocalTokenNumber (IsPeiDb, TokenNumber);
    334       PcdInfo->PcdType = GetPcdType (LocalTokenNumber);
    335       PcdInfo->PcdName = GetPcdName (FALSE, IsPeiDb, TokenNumber);
    336     }
    337     return EFI_SUCCESS;
    338   }
    339 
    340   if (PeiExMapTableEmpty && DxeExMapTableEmpty) {
    341     return EFI_NOT_FOUND;
    342   }
    343 
    344   if (!PeiExMapTableEmpty) {
    345     Status = ExGetPcdInfo (
    346                TRUE,
    347                Guid,
    348                TokenNumber,
    349                PcdInfo
    350                );
    351   }
    352 
    353   if (Status == EFI_SUCCESS) {
    354     return Status;
    355   }
    356 
    357   if (!DxeExMapTableEmpty) {
    358     Status = ExGetPcdInfo (
    359                FALSE,
    360                Guid,
    361                TokenNumber,
    362                PcdInfo
    363                );
    364   }
    365 
    366   return Status;
    367 }
    368 
    369 /**
    370   Get the PCD entry pointer in PCD database.
    371 
    372   This routine will visit PCD database to find the PCD entry according to given
    373   token number. The given token number is autogened by build tools and it will be
    374   translated to local token number. Local token number contains PCD's type and
    375   offset of PCD entry in PCD database.
    376 
    377   @param TokenNumber     Token's number, it is autogened by build tools
    378   @param GetSize         The size of token's value
    379 
    380   @return PCD entry pointer in PCD database
    381 
    382 **/
    383 VOID *
    384 GetWorker (
    385   IN UINTN             TokenNumber,
    386   IN UINTN             GetSize
    387   )
    388 {
    389   EFI_GUID            *GuidTable;
    390   UINT8               *StringTable;
    391   EFI_GUID            *Guid;
    392   UINT16              *Name;
    393   VARIABLE_HEAD       *VariableHead;
    394   UINT8               *VaraiableDefaultBuffer;
    395   UINT8               *Data;
    396   VPD_HEAD            *VpdHead;
    397   UINT8               *PcdDb;
    398   VOID                *RetPtr;
    399   UINTN               TmpTokenNumber;
    400   UINTN               DataSize;
    401   EFI_STATUS          Status;
    402   UINT32              LocalTokenNumber;
    403   UINT32              Offset;
    404   STRING_HEAD         StringTableIdx;
    405   BOOLEAN             IsPeiDb;
    406 
    407   //
    408   // Aquire lock to prevent reentrance from TPL_CALLBACK level
    409   //
    410   EfiAcquireLock (&mPcdDatabaseLock);
    411 
    412   RetPtr = NULL;
    413 
    414   ASSERT (TokenNumber > 0);
    415   //
    416   // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
    417   // We have to decrement TokenNumber by 1 to make it usable
    418   // as the array index.
    419   //
    420   TokenNumber--;
    421 
    422   TmpTokenNumber = TokenNumber;
    423 
    424   //
    425   // EBC compiler is very choosy. It may report warning about comparison
    426   // between UINTN and 0 . So we add 1 in each size of the
    427   // comparison.
    428   //
    429   ASSERT (TokenNumber + 1 < mPcdTotalTokenCount + 1);
    430 
    431   ASSERT ((GetSize == DxePcdGetSize (TokenNumber + 1)) || (GetSize == 0));
    432 
    433   // EBC compiler is very choosy. It may report warning about comparison
    434   // between UINTN and 0 . So we add 1 in each size of the
    435   // comparison.
    436   IsPeiDb = (BOOLEAN) ((TokenNumber + 1 < mPeiLocalTokenCount + 1) ? TRUE : FALSE);
    437 
    438   LocalTokenNumber = GetLocalTokenNumber (IsPeiDb, TokenNumber + 1);
    439 
    440   PcdDb = IsPeiDb ? ((UINT8 *) mPcdDatabase.PeiDb) : ((UINT8 *) mPcdDatabase.DxeDb);
    441 
    442   if (IsPeiDb) {
    443     StringTable = (UINT8 *) ((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->StringTableOffset);
    444   } else {
    445     StringTable = (UINT8 *) ((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->StringTableOffset);
    446   }
    447 
    448 
    449   Offset     = LocalTokenNumber & PCD_DATABASE_OFFSET_MASK;
    450 
    451   switch (LocalTokenNumber & PCD_TYPE_ALL_SET) {
    452     case PCD_TYPE_VPD:
    453       VpdHead = (VPD_HEAD *) ((UINT8 *) PcdDb + Offset);
    454       RetPtr = (VOID *) (UINTN) (PcdGet32 (PcdVpdBaseAddress) + VpdHead->Offset);
    455 
    456       break;
    457 
    458     case PCD_TYPE_HII|PCD_TYPE_STRING:
    459     case PCD_TYPE_HII:
    460       if (IsPeiDb) {
    461         GuidTable = (EFI_GUID *) ((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->GuidTableOffset);
    462       } else {
    463         GuidTable = (EFI_GUID *) ((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->GuidTableOffset);
    464       }
    465 
    466       VariableHead = (VARIABLE_HEAD *) (PcdDb + Offset);
    467       Guid = GuidTable + VariableHead->GuidTableIndex;
    468       Name = (UINT16*)(StringTable + VariableHead->StringIndex);
    469 
    470       if ((LocalTokenNumber & PCD_TYPE_ALL_SET) == (PCD_TYPE_HII|PCD_TYPE_STRING)) {
    471         //
    472         // If a HII type PCD's datum type is VOID*, the DefaultValueOffset is the index of
    473         // string array in string table.
    474         //
    475         StringTableIdx = *(STRING_HEAD*)((UINT8 *) PcdDb + VariableHead->DefaultValueOffset);
    476         VaraiableDefaultBuffer = (UINT8 *) (StringTable + StringTableIdx);
    477       } else {
    478         VaraiableDefaultBuffer = (UINT8 *) PcdDb + VariableHead->DefaultValueOffset;
    479       }
    480       Status = GetHiiVariable (Guid, Name, &Data, &DataSize);
    481       if (Status == EFI_SUCCESS) {
    482         if (DataSize >= (VariableHead->Offset + GetSize)) {
    483           if (GetSize == 0) {
    484             //
    485             // It is a pointer type. So get the MaxSize reserved for
    486             // this PCD entry.
    487             //
    488             GetPtrTypeSize (TmpTokenNumber, &GetSize);
    489             if (GetSize > (DataSize - VariableHead->Offset)) {
    490               //
    491               // Use actual valid size.
    492               //
    493               GetSize = DataSize - VariableHead->Offset;
    494             }
    495           }
    496           //
    497           // If the operation is successful, we copy the data
    498           // to the default value buffer in the PCD Database.
    499           // So that we can free the Data allocated in GetHiiVariable.
    500           //
    501           CopyMem (VaraiableDefaultBuffer, Data + VariableHead->Offset, GetSize);
    502         }
    503         FreePool (Data);
    504       }
    505       RetPtr = (VOID *) VaraiableDefaultBuffer;
    506       break;
    507 
    508     case PCD_TYPE_STRING:
    509       StringTableIdx = *(STRING_HEAD*)((UINT8 *) PcdDb + Offset);
    510       RetPtr = (VOID *) (StringTable + StringTableIdx);
    511       break;
    512 
    513     case PCD_TYPE_DATA:
    514       RetPtr = (VOID *) ((UINT8 *) PcdDb + Offset);
    515       break;
    516 
    517     default:
    518       ASSERT (FALSE);
    519       break;
    520 
    521   }
    522 
    523   EfiReleaseLock (&mPcdDatabaseLock);
    524 
    525   return RetPtr;
    526 
    527 }
    528 
    529 /**
    530   Register the callback function for a PCD entry.
    531 
    532   This routine will register a callback function to a PCD entry by given token number
    533   and token space guid.
    534 
    535   @param TokenNumber        PCD token's number, it is autogened by build tools.
    536   @param Guid               PCD token space's guid,
    537                             if not NULL, this PCD is dynamicEx type PCD.
    538   @param CallBackFunction   Callback function pointer
    539 
    540   @return EFI_SUCCESS Always success for registering callback function.
    541 
    542 **/
    543 EFI_STATUS
    544 DxeRegisterCallBackWorker (
    545   IN  UINTN                   TokenNumber,
    546   IN  CONST EFI_GUID          *Guid, OPTIONAL
    547   IN  PCD_PROTOCOL_CALLBACK   CallBackFunction
    548 )
    549 {
    550   CALLBACK_FN_ENTRY       *FnTableEntry;
    551   LIST_ENTRY              *ListHead;
    552   LIST_ENTRY              *ListNode;
    553 
    554   if (Guid != NULL) {
    555     TokenNumber = GetExPcdTokenNumber (Guid, (UINT32) TokenNumber);
    556   }
    557 
    558   //
    559   // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
    560   // We have to decrement TokenNumber by 1 to make it usable
    561   // as the array index of mCallbackFnTable[].
    562   //
    563   ListHead = &mCallbackFnTable[TokenNumber - 1];
    564   ListNode = GetFirstNode (ListHead);
    565 
    566   while (ListNode != ListHead) {
    567     FnTableEntry = CR_FNENTRY_FROM_LISTNODE(ListNode, CALLBACK_FN_ENTRY, Node);
    568 
    569     if (FnTableEntry->CallbackFn == CallBackFunction) {
    570       //
    571       // We only allow a Callback function to be register once
    572       // for a TokenNumber. So just return EFI_SUCCESS
    573       //
    574       return EFI_SUCCESS;
    575     }
    576     ListNode = GetNextNode (ListHead, ListNode);
    577   }
    578 
    579   FnTableEntry = AllocatePool (sizeof(CALLBACK_FN_ENTRY));
    580   ASSERT (FnTableEntry != NULL);
    581 
    582   FnTableEntry->CallbackFn = CallBackFunction;
    583   InsertTailList (ListHead, &FnTableEntry->Node);
    584 
    585   return EFI_SUCCESS;
    586 }
    587 
    588 /**
    589   UnRegister the callback function for a PCD entry.
    590 
    591   This routine will unregister a callback function to a PCD entry by given token number
    592   and token space guid.
    593 
    594   @param TokenNumber        PCD token's number, it is autogened by build tools.
    595   @param Guid               PCD token space's guid.
    596                             if not NULL, this PCD is dynamicEx type PCD.
    597   @param CallBackFunction   Callback function pointer
    598 
    599   @retval EFI_SUCCESS               Callback function is success to be unregister.
    600   @retval EFI_INVALID_PARAMETER     Can not find the PCD entry by given token number.
    601 **/
    602 EFI_STATUS
    603 DxeUnRegisterCallBackWorker (
    604   IN  UINTN                   TokenNumber,
    605   IN  CONST EFI_GUID          *Guid, OPTIONAL
    606   IN  PCD_PROTOCOL_CALLBACK   CallBackFunction
    607 )
    608 {
    609   CALLBACK_FN_ENTRY       *FnTableEntry;
    610   LIST_ENTRY              *ListHead;
    611   LIST_ENTRY              *ListNode;
    612 
    613   if (Guid != NULL) {
    614     TokenNumber = GetExPcdTokenNumber (Guid, (UINT32) TokenNumber);
    615   }
    616 
    617   //
    618   // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
    619   // We have to decrement TokenNumber by 1 to make it usable
    620   // as the array index of mCallbackFnTable[].
    621   //
    622   ListHead = &mCallbackFnTable[TokenNumber - 1];
    623   ListNode = GetFirstNode (ListHead);
    624 
    625   while (ListNode != ListHead) {
    626     FnTableEntry = CR_FNENTRY_FROM_LISTNODE(ListNode, CALLBACK_FN_ENTRY, Node);
    627 
    628     if (FnTableEntry->CallbackFn == CallBackFunction) {
    629       //
    630       // We only allow a Callback function to be register once
    631       // for a TokenNumber. So we can safely remove the Node from
    632       // the Link List and return EFI_SUCCESS.
    633       //
    634       RemoveEntryList (ListNode);
    635       FreePool (FnTableEntry);
    636 
    637       return EFI_SUCCESS;
    638     }
    639     ListNode = GetNextNode (ListHead, ListNode);
    640   }
    641 
    642   return EFI_INVALID_PARAMETER;
    643 }
    644 
    645 /**
    646   Get next token number in given token space.
    647 
    648   This routine is used for dynamicEx type PCD. It will firstly scan token space
    649   table to get token space according to given token space guid. Then scan given
    650   token number in found token space, if found, then return next token number in
    651   this token space.
    652 
    653   @param Guid            Token space guid. Next token number will be scaned in
    654                          this token space.
    655   @param TokenNumber     Token number.
    656                          If PCD_INVALID_TOKEN_NUMBER, return first token number in
    657                          token space table.
    658                          If not PCD_INVALID_TOKEN_NUMBER, return next token number
    659                          in token space table.
    660   @param GuidTable       Token space guid table. It will be used for scan token space
    661                          by given token space guid.
    662   @param SizeOfGuidTable The size of guid table.
    663   @param ExMapTable      DynamicEx token number mapping table.
    664   @param SizeOfExMapTable The size of dynamicEx token number mapping table.
    665 
    666   @retval EFI_NOT_FOUND  Can not given token space or token number.
    667   @retval EFI_SUCCESS    Success to get next token number.
    668 
    669 **/
    670 EFI_STATUS
    671 ExGetNextTokeNumber (
    672   IN      CONST EFI_GUID         *Guid,
    673   IN OUT  UINTN                  *TokenNumber,
    674   IN      EFI_GUID               *GuidTable,
    675   IN      UINTN                  SizeOfGuidTable,
    676   IN      DYNAMICEX_MAPPING      *ExMapTable,
    677   IN      UINTN                  SizeOfExMapTable
    678   )
    679 {
    680   EFI_GUID         *MatchGuid;
    681   UINTN            Index;
    682   UINTN            GuidTableIdx;
    683   BOOLEAN          Found;
    684   UINTN            ExMapTableCount;
    685 
    686   //
    687   // Scan token space guid
    688   //
    689   MatchGuid = ScanGuid (GuidTable, SizeOfGuidTable, Guid);
    690   if (MatchGuid == NULL) {
    691     return EFI_NOT_FOUND;
    692   }
    693 
    694   //
    695   // Find the token space table in dynamicEx mapping table.
    696   //
    697   Found = FALSE;
    698   GuidTableIdx = MatchGuid - GuidTable;
    699   ExMapTableCount = SizeOfExMapTable / sizeof(ExMapTable[0]);
    700   for (Index = 0; Index < ExMapTableCount; Index++) {
    701     if (ExMapTable[Index].ExGuidIndex == GuidTableIdx) {
    702       Found = TRUE;
    703       break;
    704     }
    705   }
    706 
    707   if (Found) {
    708     //
    709     // If given token number is PCD_INVALID_TOKEN_NUMBER, then return the first
    710     // token number in found token space.
    711     //
    712     if (*TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
    713       *TokenNumber = ExMapTable[Index].ExTokenNumber;
    714       return EFI_SUCCESS;
    715     }
    716 
    717     for ( ; Index < ExMapTableCount; Index++) {
    718       if (ExMapTable[Index].ExTokenNumber == *TokenNumber) {
    719         break;
    720       }
    721     }
    722 
    723     while (Index < ExMapTableCount) {
    724       Index++;
    725       if (Index == ExMapTableCount) {
    726         //
    727         // Exceed the length of ExMap Table
    728         //
    729         *TokenNumber = PCD_INVALID_TOKEN_NUMBER;
    730         return EFI_NOT_FOUND;
    731       } else if (ExMapTable[Index].ExGuidIndex == GuidTableIdx) {
    732         //
    733         // Found the next match
    734         //
    735         *TokenNumber = ExMapTable[Index].ExTokenNumber;
    736         return EFI_SUCCESS;
    737       }
    738     }
    739   }
    740 
    741   return EFI_NOT_FOUND;
    742 }
    743 
    744 /**
    745   Find the PCD database.
    746 
    747   @retval The base address of external PCD database binary.
    748   @retval NULL         Return NULL if not find.
    749 **/
    750 DXE_PCD_DATABASE *
    751 LocateExPcdBinary (
    752   VOID
    753 )
    754 {
    755   DXE_PCD_DATABASE      *DxePcdDbBinary;
    756   UINTN                 DxePcdDbSize;
    757   EFI_STATUS            Status;
    758 
    759   DxePcdDbBinary = NULL;
    760   //
    761   // Search the External Pcd database from one section of current FFS,
    762   // and read it to memory
    763   //
    764   Status = GetSectionFromFfs (
    765              EFI_SECTION_RAW,
    766              0,
    767              (VOID **) &DxePcdDbBinary,
    768              &DxePcdDbSize
    769              );
    770   ASSERT_EFI_ERROR (Status);
    771 
    772   //
    773   // Check the first bytes (Header Signature Guid) and build version.
    774   //
    775   if (!CompareGuid ((VOID *)DxePcdDbBinary, &gPcdDataBaseSignatureGuid) ||
    776       (DxePcdDbBinary->BuildVersion != PCD_SERVICE_DXE_VERSION)) {
    777     ASSERT (FALSE);
    778   }
    779 
    780   return DxePcdDbBinary;
    781 }
    782 
    783 /**
    784   Initialize the PCD database in DXE phase.
    785 
    786   PCD database in DXE phase also contains PCD database in PEI phase which is copied
    787   from GUID Hob.
    788 
    789 **/
    790 VOID
    791 BuildPcdDxeDataBase (
    792   VOID
    793   )
    794 {
    795   PEI_PCD_DATABASE    *PeiDatabase;
    796   EFI_HOB_GUID_TYPE   *GuidHob;
    797   UINTN               Index;
    798   UINT32              PcdDxeDbLen;
    799   VOID                *PcdDxeDb;
    800 
    801   //
    802   // Assign PCD Entries with default value to PCD DATABASE
    803   //
    804   mPcdDatabase.DxeDb = LocateExPcdBinary ();
    805   ASSERT(mPcdDatabase.DxeDb != NULL);
    806   PcdDxeDbLen = mPcdDatabase.DxeDb->Length + mPcdDatabase.DxeDb->UninitDataBaseSize;
    807   PcdDxeDb = AllocateZeroPool (PcdDxeDbLen);
    808   ASSERT (PcdDxeDb != NULL);
    809   CopyMem (PcdDxeDb, mPcdDatabase.DxeDb, mPcdDatabase.DxeDb->Length);
    810   FreePool (mPcdDatabase.DxeDb);
    811   mPcdDatabase.DxeDb = PcdDxeDb;
    812 
    813   GuidHob = GetFirstGuidHob (&gPcdDataBaseHobGuid);
    814   if (GuidHob != NULL) {
    815 
    816     //
    817     // If no PEIMs use dynamic Pcd Entry, the Pcd Service PEIM
    818     // should not be included at all. So the GuidHob could
    819     // be NULL. If it is NULL, we just copy over the DXE Default
    820     // Value to PCD Database.
    821     //
    822 
    823     PeiDatabase = (PEI_PCD_DATABASE *) GET_GUID_HOB_DATA (GuidHob);
    824     //
    825     // Assign PCD Entries refereneced in PEI phase to PCD DATABASE
    826     //
    827     mPcdDatabase.PeiDb = PeiDatabase;
    828     //
    829     // Inherit the SystemSkuId from PEI phase.
    830     //
    831     mPcdDatabase.DxeDb->SystemSkuId = mPcdDatabase.PeiDb->SystemSkuId;
    832   } else {
    833     mPcdDatabase.PeiDb = AllocateZeroPool (sizeof (PEI_PCD_DATABASE));
    834     ASSERT(mPcdDatabase.PeiDb != NULL);
    835   }
    836 
    837   //
    838   // Initialized the external PCD database local variables
    839   //
    840   mPeiLocalTokenCount     = mPcdDatabase.PeiDb->LocalTokenCount;
    841   mDxeLocalTokenCount     = mPcdDatabase.DxeDb->LocalTokenCount;
    842 
    843   mPeiExMapppingTableSize = mPcdDatabase.PeiDb->ExTokenCount * sizeof (DYNAMICEX_MAPPING);
    844   mDxeExMapppingTableSize = mPcdDatabase.DxeDb->ExTokenCount * sizeof (DYNAMICEX_MAPPING);
    845   mPeiGuidTableSize       = mPcdDatabase.PeiDb->GuidTableCount * sizeof(GUID);
    846   mDxeGuidTableSize       = mPcdDatabase.DxeDb->GuidTableCount * sizeof (GUID);
    847 
    848   mPcdTotalTokenCount     = mPeiLocalTokenCount + mDxeLocalTokenCount;
    849   mPeiNexTokenCount       = mPeiLocalTokenCount - mPcdDatabase.PeiDb->ExTokenCount;
    850   mDxeNexTokenCount       = mDxeLocalTokenCount - mPcdDatabase.DxeDb->ExTokenCount;
    851 
    852   mPeiExMapTableEmpty     = (mPcdDatabase.PeiDb->ExTokenCount == 0) ? TRUE : FALSE;
    853   mDxeExMapTableEmpty     = (mPcdDatabase.DxeDb->ExTokenCount == 0) ? TRUE : FALSE;
    854   mPeiDatabaseEmpty       = (mPeiLocalTokenCount == 0) ? TRUE : FALSE;
    855 
    856   TmpTokenSpaceBufferCount = mPcdDatabase.PeiDb->ExTokenCount + mPcdDatabase.DxeDb->ExTokenCount;
    857   TmpTokenSpaceBuffer     = (EFI_GUID **)AllocateZeroPool(TmpTokenSpaceBufferCount * sizeof (EFI_GUID *));
    858 
    859   //
    860   // Initialized the Callback Function Table
    861   //
    862   mCallbackFnTable = AllocateZeroPool (mPcdTotalTokenCount * sizeof (LIST_ENTRY));
    863   ASSERT(mCallbackFnTable != NULL);
    864 
    865   //
    866   // EBC compiler is very choosy. It may report warning about comparison
    867   // between UINTN and 0 . So we add 1 in each size of the
    868   // comparison.
    869   //
    870   for (Index = 0; Index + 1 < mPcdTotalTokenCount + 1; Index++) {
    871     InitializeListHead (&mCallbackFnTable[Index]);
    872   }
    873 }
    874 
    875 /**
    876   Get Variable which contains HII type PCD entry.
    877 
    878   @param VariableGuid    Variable's guid
    879   @param VariableName    Variable's unicode name string
    880   @param VariableData    Variable's data pointer,
    881   @param VariableSize    Variable's size.
    882 
    883   @return the status of gRT->GetVariable
    884 **/
    885 EFI_STATUS
    886 GetHiiVariable (
    887   IN  EFI_GUID      *VariableGuid,
    888   IN  UINT16        *VariableName,
    889   OUT UINT8         **VariableData,
    890   OUT UINTN         *VariableSize
    891   )
    892 {
    893   UINTN      Size;
    894   EFI_STATUS Status;
    895   UINT8      *Buffer;
    896 
    897   Size = 0;
    898   Buffer = NULL;
    899 
    900   //
    901   // Firstly get the real size of HII variable
    902   //
    903   Status = gRT->GetVariable (
    904     (UINT16 *)VariableName,
    905     VariableGuid,
    906     NULL,
    907     &Size,
    908     Buffer
    909     );
    910 
    911   //
    912   // Allocate buffer to hold whole variable data according to variable size.
    913   //
    914   if (Status == EFI_BUFFER_TOO_SMALL) {
    915     Buffer = (UINT8 *) AllocatePool (Size);
    916 
    917     ASSERT (Buffer != NULL);
    918 
    919     Status = gRT->GetVariable (
    920       VariableName,
    921       VariableGuid,
    922       NULL,
    923       &Size,
    924       Buffer
    925       );
    926 
    927     ASSERT (Status == EFI_SUCCESS);
    928     *VariableData = Buffer;
    929     *VariableSize = Size;
    930   } else {
    931     //
    932     // Use Default Data only when variable is not found.
    933     // For other error status, correct data can't be got, and trig ASSERT().
    934     //
    935     ASSERT (Status == EFI_NOT_FOUND);
    936   }
    937 
    938   return Status;
    939 }
    940 
    941 /**
    942   Find the local token number according to system SKU ID.
    943 
    944   @param LocalTokenNumber PCD token number
    945   @param Size             The size of PCD entry.
    946   @param IsPeiDb          If TRUE, the PCD entry is initialized in PEI phase.
    947                           If False, the PCD entry is initialized in DXE phase.
    948 
    949   @return Token number according to system SKU ID.
    950 
    951 **/
    952 UINT32
    953 GetSkuEnabledTokenNumber (
    954   UINT32    LocalTokenNumber,
    955   UINTN     Size,
    956   BOOLEAN   IsPeiDb
    957   )
    958 {
    959   SKU_HEAD              *SkuHead;
    960   SKU_ID                *SkuIdTable;
    961   INTN                  Index;
    962   UINT8                 *Value;
    963   UINT8                 *PcdDb;
    964   BOOLEAN               FoundSku;
    965 
    966   ASSERT ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == 0);
    967 
    968   PcdDb = IsPeiDb ? (UINT8 *) mPcdDatabase.PeiDb : (UINT8 *) mPcdDatabase.DxeDb;
    969 
    970   SkuHead     = (SKU_HEAD *) (PcdDb + (LocalTokenNumber & PCD_DATABASE_OFFSET_MASK));
    971   Value       = (UINT8 *) (PcdDb + SkuHead->SkuDataStartOffset);
    972 
    973   SkuIdTable =  (SKU_ID *)(PcdDb + SkuHead->SkuIdTableOffset);
    974   //
    975   // Find the current system's SKU ID entry in SKU ID table.
    976   //
    977   FoundSku = FALSE;
    978   for (Index = 0; Index < SkuIdTable[0]; Index++) {
    979     if (mPcdDatabase.DxeDb->SystemSkuId == SkuIdTable[Index + 1]) {
    980       FoundSku = TRUE;
    981       break;
    982     }
    983   }
    984 
    985   //
    986   // Find the default SKU ID entry in SKU ID table.
    987   //
    988 
    989   if(!FoundSku) {
    990     for (Index = 0; Index < SkuIdTable[0]; Index++) {
    991       if (0 == SkuIdTable[Index + 1]) {
    992         break;
    993       }
    994     }
    995   }
    996   ASSERT (Index < SkuIdTable[0]);
    997 
    998   switch (LocalTokenNumber & PCD_TYPE_ALL_SET) {
    999     case PCD_TYPE_VPD:
   1000       Value = (UINT8 *) &(((VPD_HEAD *) Value)[Index]);
   1001       return (UINT32) ((Value - PcdDb) | PCD_TYPE_VPD);
   1002 
   1003     case PCD_TYPE_HII:
   1004       Value = (UINT8 *) &(((VARIABLE_HEAD *) Value)[Index]);
   1005       return (UINT32) ((Value - PcdDb) | PCD_TYPE_HII);
   1006 
   1007     case PCD_TYPE_HII|PCD_TYPE_STRING:
   1008       Value = (UINT8 *) &(((VARIABLE_HEAD *) Value)[Index]);
   1009       return (UINT32) ((Value - PcdDb) | PCD_TYPE_HII | PCD_TYPE_STRING);
   1010 
   1011     case PCD_TYPE_STRING:
   1012       Value = (UINT8 *) &(((STRING_HEAD *) Value)[Index]);
   1013       return (UINT32) ((Value - PcdDb) | PCD_TYPE_STRING);
   1014 
   1015     case PCD_TYPE_DATA:
   1016       Value += Size * Index;
   1017       return (UINT32) ((Value - PcdDb) | PCD_TYPE_DATA);
   1018 
   1019     default:
   1020       ASSERT (FALSE);
   1021   }
   1022 
   1023   ASSERT (FALSE);
   1024 
   1025   return 0;
   1026 
   1027 }
   1028 
   1029 /**
   1030   Invoke the callback function when dynamic PCD entry was set, if this PCD entry
   1031   has registered callback function.
   1032 
   1033   @param ExTokenNumber   DynamicEx PCD's token number, if this PCD entry is dyanmicEx
   1034                          type PCD.
   1035   @param Guid            DynamicEx PCD's guid, if this PCD entry is dynamicEx type
   1036                          PCD.
   1037   @param TokenNumber     PCD token number generated by build tools.
   1038   @param Data            Value want to be set for this PCD entry
   1039   @param Size            The size of value
   1040 
   1041 **/
   1042 VOID
   1043 InvokeCallbackOnSet (
   1044   UINT32            ExTokenNumber,
   1045   CONST EFI_GUID    *Guid, OPTIONAL
   1046   UINTN             TokenNumber,
   1047   VOID              *Data,
   1048   UINTN             Size
   1049   )
   1050 {
   1051   CALLBACK_FN_ENTRY       *FnTableEntry;
   1052   LIST_ENTRY              *ListHead;
   1053   LIST_ENTRY              *ListNode;
   1054 
   1055   //
   1056   // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
   1057   // We have to decrement TokenNumber by 1 to make it usable
   1058   // as the array index of mCallbackFnTable[].
   1059   //
   1060   ListHead = &mCallbackFnTable[TokenNumber - 1];
   1061   ListNode = GetFirstNode (ListHead);
   1062 
   1063   while (ListNode != ListHead) {
   1064     FnTableEntry = CR_FNENTRY_FROM_LISTNODE (ListNode, CALLBACK_FN_ENTRY, Node);
   1065 
   1066     FnTableEntry->CallbackFn(Guid,
   1067                     (Guid == NULL) ? TokenNumber : ExTokenNumber,
   1068                     Data,
   1069                     Size);
   1070 
   1071     ListNode = GetNextNode (ListHead, ListNode);
   1072   }
   1073 
   1074   return;
   1075 }
   1076 
   1077 
   1078 /**
   1079   Wrapper function for setting non-pointer type value for a PCD entry.
   1080 
   1081   @param TokenNumber     Pcd token number autogenerated by build tools.
   1082   @param Data            Value want to be set for PCD entry
   1083   @param Size            Size of value.
   1084 
   1085   @return status of SetWorker.
   1086 
   1087 **/
   1088 EFI_STATUS
   1089 SetValueWorker (
   1090   IN UINTN                   TokenNumber,
   1091   IN VOID                    *Data,
   1092   IN UINTN                   Size
   1093   )
   1094 {
   1095   return SetWorker (TokenNumber, Data, &Size, FALSE);
   1096 }
   1097 
   1098 
   1099 /**
   1100   Set value for an PCD entry
   1101 
   1102   @param TokenNumber     Pcd token number autogenerated by build tools.
   1103   @param Data            Value want to be set for PCD entry
   1104   @param Size            Size of value.
   1105   @param PtrType         If TRUE, the type of PCD entry's value is Pointer.
   1106                          If False, the type of PCD entry's value is not Pointer.
   1107 
   1108   @retval EFI_INVALID_PARAMETER  If this PCD type is VPD, VPD PCD can not be set.
   1109   @retval EFI_INVALID_PARAMETER  If Size can not be set to size table.
   1110   @retval EFI_INVALID_PARAMETER  If Size of non-Ptr type PCD does not match the size information in PCD database.
   1111   @retval EFI_NOT_FOUND          If value type of PCD entry is intergrate, but not in
   1112                                  range of UINT8, UINT16, UINT32, UINT64
   1113   @retval EFI_NOT_FOUND          Can not find the PCD type according to token number.
   1114 **/
   1115 EFI_STATUS
   1116 SetWorker (
   1117   IN          UINTN                   TokenNumber,
   1118   IN          VOID                    *Data,
   1119   IN OUT      UINTN                   *Size,
   1120   IN          BOOLEAN                 PtrType
   1121   )
   1122 {
   1123   BOOLEAN             IsPeiDb;
   1124   UINT32              LocalTokenNumber;
   1125   EFI_GUID            *GuidTable;
   1126   UINT8               *StringTable;
   1127   EFI_GUID            *Guid;
   1128   UINT16              *Name;
   1129   UINTN               VariableOffset;
   1130   UINT32              Attributes;
   1131   VOID                *InternalData;
   1132   VARIABLE_HEAD       *VariableHead;
   1133   UINTN               Offset;
   1134   UINT8               *PcdDb;
   1135   EFI_STATUS          Status;
   1136   UINTN               MaxSize;
   1137   UINTN               TmpTokenNumber;
   1138 
   1139   //
   1140   // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
   1141   // We have to decrement TokenNumber by 1 to make it usable
   1142   // as the array index.
   1143   //
   1144   TokenNumber--;
   1145 
   1146   TmpTokenNumber = TokenNumber;
   1147 
   1148   //
   1149   // EBC compiler is very choosy. It may report warning about comparison
   1150   // between UINTN and 0 . So we add 1 in each size of the
   1151   // comparison.
   1152   //
   1153   ASSERT (TokenNumber + 1 < mPcdTotalTokenCount + 1);
   1154 
   1155   if (PtrType) {
   1156     //
   1157     // Get MaxSize first, then check new size with max buffer size.
   1158     //
   1159     GetPtrTypeSize (TokenNumber, &MaxSize);
   1160     if (*Size > MaxSize) {
   1161       *Size = MaxSize;
   1162       return EFI_INVALID_PARAMETER;
   1163     }
   1164   } else {
   1165     if (*Size != DxePcdGetSize (TokenNumber + 1)) {
   1166       return EFI_INVALID_PARAMETER;
   1167     }
   1168   }
   1169 
   1170   //
   1171   // EBC compiler is very choosy. It may report warning about comparison
   1172   // between UINTN and 0 . So we add 1 in each size of the
   1173   // comparison.
   1174   //
   1175   if ((TokenNumber + 1 < mPeiNexTokenCount + 1) ||
   1176       (TokenNumber + 1 >= mPeiLocalTokenCount + 1 && TokenNumber + 1 < (mPeiLocalTokenCount + mDxeNexTokenCount + 1))) {
   1177     InvokeCallbackOnSet (0, NULL, TokenNumber + 1, Data, *Size);
   1178   }
   1179 
   1180   //
   1181   // Aquire lock to prevent reentrance from TPL_CALLBACK level
   1182   //
   1183   EfiAcquireLock (&mPcdDatabaseLock);
   1184 
   1185   //
   1186   // EBC compiler is very choosy. It may report warning about comparison
   1187   // between UINTN and 0 . So we add 1 in each size of the
   1188   // comparison.
   1189   //
   1190   IsPeiDb = (BOOLEAN) ((TokenNumber + 1 < mPeiLocalTokenCount + 1) ? TRUE : FALSE);
   1191 
   1192   LocalTokenNumber = GetLocalTokenNumber (IsPeiDb, TokenNumber + 1);
   1193 
   1194   Offset = LocalTokenNumber & PCD_DATABASE_OFFSET_MASK;
   1195 
   1196   PcdDb = IsPeiDb ? ((UINT8 *) mPcdDatabase.PeiDb) : ((UINT8 *) mPcdDatabase.DxeDb);
   1197 
   1198   if (IsPeiDb) {
   1199     StringTable = (UINT8 *) ((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->StringTableOffset);
   1200   } else {
   1201     StringTable = (UINT8 *) ((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->StringTableOffset);
   1202   }
   1203 
   1204 
   1205   InternalData = PcdDb + Offset;
   1206 
   1207   switch (LocalTokenNumber & PCD_TYPE_ALL_SET) {
   1208     case PCD_TYPE_VPD:
   1209       ASSERT (FALSE);
   1210       Status = EFI_INVALID_PARAMETER;
   1211       break;
   1212 
   1213     case PCD_TYPE_STRING:
   1214       if (SetPtrTypeSize (TmpTokenNumber, Size)) {
   1215         CopyMem (StringTable + *((STRING_HEAD *)InternalData), Data, *Size);
   1216         Status = EFI_SUCCESS;
   1217       } else {
   1218         Status = EFI_INVALID_PARAMETER;
   1219       }
   1220       break;
   1221 
   1222     case PCD_TYPE_HII|PCD_TYPE_STRING:
   1223     case PCD_TYPE_HII:
   1224       if (PtrType) {
   1225         if (!SetPtrTypeSize (TmpTokenNumber, Size)) {
   1226           Status = EFI_INVALID_PARAMETER;
   1227           break;
   1228         }
   1229       }
   1230 
   1231       if (IsPeiDb) {
   1232         GuidTable = (EFI_GUID *) ((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->GuidTableOffset);
   1233       } else {
   1234         GuidTable = (EFI_GUID *) ((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->GuidTableOffset);
   1235       }
   1236 
   1237       VariableHead = (VARIABLE_HEAD *) (PcdDb + Offset);
   1238 
   1239       Guid = GuidTable + VariableHead->GuidTableIndex;
   1240       Name = (UINT16*) (StringTable + VariableHead->StringIndex);
   1241       VariableOffset = VariableHead->Offset;
   1242       Attributes = VariableHead->Attributes;
   1243       Status = SetHiiVariable (Guid, Name, Attributes, Data, *Size, VariableOffset);
   1244       break;
   1245 
   1246     case PCD_TYPE_DATA:
   1247       if (PtrType) {
   1248         if (SetPtrTypeSize (TmpTokenNumber, Size)) {
   1249           CopyMem (InternalData, Data, *Size);
   1250           Status = EFI_SUCCESS;
   1251         } else {
   1252           Status = EFI_INVALID_PARAMETER;
   1253         }
   1254         break;
   1255       }
   1256 
   1257       Status = EFI_SUCCESS;
   1258       switch (*Size) {
   1259         case sizeof(UINT8):
   1260           *((UINT8 *) InternalData) = *((UINT8 *) Data);
   1261           break;
   1262 
   1263         case sizeof(UINT16):
   1264           *((UINT16 *) InternalData) = *((UINT16 *) Data);
   1265           break;
   1266 
   1267         case sizeof(UINT32):
   1268           *((UINT32 *) InternalData) = *((UINT32 *) Data);
   1269           break;
   1270 
   1271         case sizeof(UINT64):
   1272           *((UINT64 *) InternalData) = *((UINT64 *) Data);
   1273           break;
   1274 
   1275         default:
   1276           ASSERT (FALSE);
   1277           Status = EFI_NOT_FOUND;
   1278           break;
   1279       }
   1280       break;
   1281 
   1282     default:
   1283       ASSERT (FALSE);
   1284       Status = EFI_NOT_FOUND;
   1285       break;
   1286     }
   1287 
   1288   EfiReleaseLock (&mPcdDatabaseLock);
   1289 
   1290   return Status;
   1291 }
   1292 
   1293 /**
   1294   Wrapper function for get PCD value for dynamic-ex PCD.
   1295 
   1296   @param Guid            Token space guid for dynamic-ex PCD.
   1297   @param ExTokenNumber   Token number for dynamic-ex PCD.
   1298   @param GetSize         The size of dynamic-ex PCD value.
   1299 
   1300   @return PCD entry in PCD database.
   1301 
   1302 **/
   1303 VOID *
   1304 ExGetWorker (
   1305   IN CONST EFI_GUID         *Guid,
   1306   IN UINTN                  ExTokenNumber,
   1307   IN UINTN                  GetSize
   1308   )
   1309 {
   1310   return GetWorker(GetExPcdTokenNumber (Guid, (UINT32) ExTokenNumber), GetSize);
   1311 }
   1312 
   1313 /**
   1314   Wrapper function for set PCD value for non-Pointer type dynamic-ex PCD.
   1315 
   1316   @param ExTokenNumber   Token number for dynamic-ex PCD.
   1317   @param Guid            Token space guid for dynamic-ex PCD.
   1318   @param Data            Value want to be set.
   1319   @param SetSize         The size of value.
   1320 
   1321   @return status of ExSetWorker().
   1322 
   1323 **/
   1324 EFI_STATUS
   1325 ExSetValueWorker (
   1326   IN          UINTN                ExTokenNumber,
   1327   IN          CONST EFI_GUID       *Guid,
   1328   IN          VOID                 *Data,
   1329   IN          UINTN                SetSize
   1330   )
   1331 {
   1332   return ExSetWorker (ExTokenNumber, Guid, Data, &SetSize, FALSE);
   1333 }
   1334 
   1335 /**
   1336   Set value for a dynamic-ex PCD entry.
   1337 
   1338   This routine find the local token number according to dynamic-ex PCD's token
   1339   space guid and token number firstly, and invoke callback function if this PCD
   1340   entry registered callback function. Finally, invoken general SetWorker to set
   1341   PCD value.
   1342 
   1343   @param ExTokenNumber   Dynamic-ex PCD token number.
   1344   @param Guid            Token space guid for dynamic-ex PCD.
   1345   @param Data            PCD value want to be set
   1346   @param SetSize         Size of value.
   1347   @param PtrType         If TRUE, this PCD entry is pointer type.
   1348                          If FALSE, this PCD entry is not pointer type.
   1349 
   1350   @return status of SetWorker().
   1351 
   1352 **/
   1353 EFI_STATUS
   1354 ExSetWorker (
   1355   IN          UINTN                ExTokenNumber,
   1356   IN          CONST EFI_GUID       *Guid,
   1357   IN          VOID                 *Data,
   1358   IN OUT      UINTN                *SetSize,
   1359   IN          BOOLEAN              PtrType
   1360   )
   1361 {
   1362   UINTN                   TokenNumber;
   1363 
   1364   TokenNumber = GetExPcdTokenNumber (Guid, (UINT32) ExTokenNumber);
   1365 
   1366   InvokeCallbackOnSet ((UINT32) ExTokenNumber, Guid, TokenNumber, Data, *SetSize);
   1367 
   1368   return SetWorker (TokenNumber, Data, SetSize, PtrType);
   1369 
   1370 }
   1371 
   1372 /**
   1373   Set value for HII-type PCD.
   1374 
   1375   A HII-type PCD's value is stored in a variable. Setting/Getting the value of
   1376   HII-type PCD is to visit this variable.
   1377 
   1378   @param VariableGuid    Guid of variable which stored value of a HII-type PCD.
   1379   @param VariableName    Unicode name of variable which stored value of a HII-type PCD.
   1380   @param SetAttributes   Attributes bitmask to set for the variable.
   1381   @param Data            Value want to be set.
   1382   @param DataSize        Size of value
   1383   @param Offset          Value offset of HII-type PCD in variable.
   1384 
   1385   @return status of GetVariable()/SetVariable().
   1386 
   1387 **/
   1388 EFI_STATUS
   1389 SetHiiVariable (
   1390   IN  EFI_GUID     *VariableGuid,
   1391   IN  UINT16       *VariableName,
   1392   IN  UINT32       SetAttributes,
   1393   IN  CONST VOID   *Data,
   1394   IN  UINTN        DataSize,
   1395   IN  UINTN        Offset
   1396   )
   1397 {
   1398   UINTN       Size;
   1399   VOID        *Buffer;
   1400   EFI_STATUS  Status;
   1401   UINT32      Attribute;
   1402   UINTN       SetSize;
   1403 
   1404   Size = 0;
   1405   SetSize = 0;
   1406 
   1407   //
   1408   // Try to get original variable size information.
   1409   //
   1410   Status = gRT->GetVariable (
   1411     (UINT16 *)VariableName,
   1412     VariableGuid,
   1413     NULL,
   1414     &Size,
   1415     NULL
   1416     );
   1417 
   1418   if (Status == EFI_BUFFER_TOO_SMALL) {
   1419     //
   1420     // Patch new PCD's value to offset in given HII variable.
   1421     //
   1422     if (Size >= (DataSize + Offset)) {
   1423       SetSize = Size;
   1424     } else {
   1425       SetSize = DataSize + Offset;
   1426     }
   1427     Buffer = AllocatePool (SetSize);
   1428     ASSERT (Buffer != NULL);
   1429 
   1430     Status = gRT->GetVariable (
   1431       VariableName,
   1432       VariableGuid,
   1433       &Attribute,
   1434       &Size,
   1435       Buffer
   1436       );
   1437 
   1438     ASSERT_EFI_ERROR (Status);
   1439 
   1440     CopyMem ((UINT8 *)Buffer + Offset, Data, DataSize);
   1441 
   1442     if (SetAttributes == 0) {
   1443       SetAttributes = Attribute;
   1444     }
   1445 
   1446     Status = gRT->SetVariable (
   1447               VariableName,
   1448               VariableGuid,
   1449               SetAttributes,
   1450               SetSize,
   1451               Buffer
   1452               );
   1453 
   1454     FreePool (Buffer);
   1455     return Status;
   1456   } else if (Status == EFI_NOT_FOUND) {
   1457     //
   1458     // If variable does not exist, a new variable need to be created.
   1459     //
   1460 
   1461     Size = Offset + DataSize;
   1462 
   1463     Buffer = AllocateZeroPool (Size);
   1464     ASSERT (Buffer != NULL);
   1465 
   1466     CopyMem ((UINT8 *)Buffer + Offset, Data, DataSize);
   1467 
   1468     if (SetAttributes == 0) {
   1469       SetAttributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE;
   1470     }
   1471 
   1472     Status = gRT->SetVariable (
   1473               VariableName,
   1474               VariableGuid,
   1475               SetAttributes,
   1476               Size,
   1477               Buffer
   1478               );
   1479 
   1480     FreePool (Buffer);
   1481     return Status;
   1482   }
   1483 
   1484   //
   1485   // If we drop to here, the value is failed to be written in to variable area.
   1486   //
   1487   return Status;
   1488 }
   1489 
   1490 /**
   1491   Get Token Number according to dynamic-ex PCD's {token space guid:token number}
   1492 
   1493   A dynamic-ex type PCD, developer must provide pair of token space guid: token number
   1494   in DEC file. PCD database maintain a mapping table that translate pair of {token
   1495   space guid: token number} to Token Number.
   1496 
   1497   @param Guid            Token space guid for dynamic-ex PCD entry.
   1498   @param ExTokenNumber   Dynamic-ex PCD token number.
   1499 
   1500   @return Token Number for dynamic-ex PCD.
   1501 
   1502 **/
   1503 UINTN
   1504 GetExPcdTokenNumber (
   1505   IN CONST EFI_GUID             *Guid,
   1506   IN UINT32                     ExTokenNumber
   1507   )
   1508 {
   1509   UINT32              Index;
   1510   DYNAMICEX_MAPPING   *ExMap;
   1511   EFI_GUID            *GuidTable;
   1512   EFI_GUID            *MatchGuid;
   1513   UINTN               MatchGuidIdx;
   1514 
   1515   if (!mPeiDatabaseEmpty) {
   1516     ExMap       = (DYNAMICEX_MAPPING *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->ExMapTableOffset);
   1517     GuidTable   = (EFI_GUID *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->GuidTableOffset);
   1518 
   1519     MatchGuid   = ScanGuid (GuidTable, mPeiGuidTableSize, Guid);
   1520 
   1521     if (MatchGuid != NULL) {
   1522 
   1523       MatchGuidIdx = MatchGuid - GuidTable;
   1524 
   1525       for (Index = 0; Index < mPcdDatabase.PeiDb->ExTokenCount; Index++) {
   1526         if ((ExTokenNumber == ExMap[Index].ExTokenNumber) &&
   1527             (MatchGuidIdx == ExMap[Index].ExGuidIndex)) {
   1528             return ExMap[Index].TokenNumber;
   1529         }
   1530       }
   1531     }
   1532   }
   1533 
   1534   ExMap       = (DYNAMICEX_MAPPING *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->ExMapTableOffset);
   1535   GuidTable   = (EFI_GUID *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->GuidTableOffset);
   1536 
   1537   MatchGuid   = ScanGuid (GuidTable, mDxeGuidTableSize, Guid);
   1538   //
   1539   // We need to ASSERT here. If GUID can't be found in GuidTable, this is a
   1540   // error in the BUILD system.
   1541   //
   1542   ASSERT (MatchGuid != NULL);
   1543 
   1544   MatchGuidIdx = MatchGuid - GuidTable;
   1545 
   1546   for (Index = 0; Index < mPcdDatabase.DxeDb->ExTokenCount; Index++) {
   1547     if ((ExTokenNumber == ExMap[Index].ExTokenNumber) &&
   1548          (MatchGuidIdx == ExMap[Index].ExGuidIndex)) {
   1549         return ExMap[Index].TokenNumber;
   1550     }
   1551   }
   1552 
   1553   ASSERT (FALSE);
   1554 
   1555   return 0;
   1556 }
   1557 
   1558 /**
   1559   Get SKU ID table from PCD database.
   1560 
   1561   @param LocalTokenNumberTableIdx Index of local token number in token number table.
   1562   @param IsPeiDb                  If TRUE, the pcd entry is initialized in PEI phase,
   1563                                   If FALSE, the pcd entry is initialized in DXE phase.
   1564   @return Pointer to SKU ID array table
   1565 
   1566 **/
   1567 SKU_ID *
   1568 GetSkuIdArray (
   1569   IN    UINTN             LocalTokenNumberTableIdx,
   1570   IN    BOOLEAN           IsPeiDb
   1571   )
   1572 {
   1573   SKU_HEAD  *SkuHead;
   1574   UINTN     LocalTokenNumber;
   1575   UINT8     *Database;
   1576 
   1577   if (IsPeiDb) {
   1578     LocalTokenNumber = *((UINT32 *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->LocalTokenNumberTableOffset) + LocalTokenNumberTableIdx);
   1579     Database         = (UINT8 *) mPcdDatabase.PeiDb;
   1580   } else {
   1581     LocalTokenNumber = *((UINT32 *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->LocalTokenNumberTableOffset) + LocalTokenNumberTableIdx);
   1582     Database         = (UINT8 *) mPcdDatabase.DxeDb;
   1583   }
   1584 
   1585   ASSERT ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) != 0);
   1586 
   1587   SkuHead = (SKU_HEAD *) ((UINT8 *)Database + (LocalTokenNumber & PCD_DATABASE_OFFSET_MASK));
   1588 
   1589   return (SKU_ID *) (Database + SkuHead->SkuIdTableOffset);
   1590 
   1591 }
   1592 
   1593 /**
   1594   Wrapper function of getting index of PCD entry in size table.
   1595 
   1596   @param LocalTokenNumberTableIdx Index of this PCD in local token number table.
   1597   @param IsPeiDb                  If TRUE, the pcd entry is initialized in PEI phase,
   1598                                   If FALSE, the pcd entry is initialized in DXE phase.
   1599 
   1600   @return index of PCD entry in size table.
   1601 **/
   1602 UINTN
   1603 GetSizeTableIndex (
   1604   IN    UINTN             LocalTokenNumberTableIdx,
   1605   IN    BOOLEAN           IsPeiDb
   1606   )
   1607 {
   1608   UINT32 *LocalTokenNumberTable;
   1609   UINTN  LocalTokenNumber;
   1610   UINTN  Index;
   1611   UINTN  SizeTableIdx;
   1612   SKU_ID *SkuIdTable;
   1613 
   1614   if (IsPeiDb) {
   1615     LocalTokenNumberTable = (UINT32 *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->LocalTokenNumberTableOffset);
   1616   } else {
   1617     LocalTokenNumberTable = (UINT32 *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->LocalTokenNumberTableOffset);
   1618   }
   1619 
   1620   SizeTableIdx = 0;
   1621 
   1622   for (Index = 0; Index < LocalTokenNumberTableIdx; Index ++) {
   1623     LocalTokenNumber = LocalTokenNumberTable[Index];
   1624 
   1625     if ((LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) == PCD_DATUM_TYPE_POINTER) {
   1626       //
   1627       // SizeTable only contain record for PCD_DATUM_TYPE_POINTER type
   1628       // PCD entry.
   1629       //
   1630       if ((LocalTokenNumber & PCD_TYPE_VPD) != 0) {
   1631           //
   1632           // We have only two entry for VPD enabled PCD entry:
   1633           // 1) MAX Size.
   1634           // 2) Current Size
   1635           // Current size is equal to MAX size.
   1636           //
   1637           SizeTableIdx += 2;
   1638       } else {
   1639         if ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == 0) {
   1640           //
   1641           // We have only two entry for Non-Sku enabled PCD entry:
   1642           // 1) MAX SIZE
   1643           // 2) Current Size
   1644           //
   1645           SizeTableIdx += 2;
   1646         } else {
   1647           //
   1648           // We have these entry for SKU enabled PCD entry
   1649           // 1) MAX SIZE
   1650           // 2) Current Size for each SKU_ID (It is equal to MaxSku).
   1651           //
   1652           SkuIdTable = GetSkuIdArray (Index, IsPeiDb);
   1653           SizeTableIdx += (UINTN)*SkuIdTable + 1;
   1654         }
   1655       }
   1656     }
   1657 
   1658   }
   1659 
   1660   return SizeTableIdx;
   1661 }
   1662 
   1663 /**
   1664   Get size of POINTER type PCD value.
   1665 
   1666   @param LocalTokenNumberTableIdx Index of local token number in local token number table.
   1667   @param MaxSize                  Maxmium size of POINTER type PCD value.
   1668 
   1669   @return size of POINTER type PCD value.
   1670 
   1671 **/
   1672 UINTN
   1673 GetPtrTypeSize (
   1674   IN    UINTN             LocalTokenNumberTableIdx,
   1675   OUT   UINTN             *MaxSize
   1676   )
   1677 {
   1678   INTN        SizeTableIdx;
   1679   UINTN       LocalTokenNumber;
   1680   SKU_ID      *SkuIdTable;
   1681   SIZE_INFO   *SizeTable;
   1682   UINTN       Index;
   1683   BOOLEAN     IsPeiDb;
   1684   UINT32      *LocalTokenNumberTable;
   1685 
   1686   // EBC compiler is very choosy. It may report warning about comparison
   1687   // between UINTN and 0 . So we add 1 in each size of the
   1688   // comparison.
   1689   IsPeiDb = (BOOLEAN) (LocalTokenNumberTableIdx + 1 < mPeiLocalTokenCount + 1);
   1690 
   1691 
   1692   if (IsPeiDb) {
   1693     LocalTokenNumberTable = (UINT32 *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->LocalTokenNumberTableOffset);
   1694     SizeTable = (SIZE_INFO *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->SizeTableOffset);
   1695   } else {
   1696     LocalTokenNumberTableIdx -= mPeiLocalTokenCount;
   1697     LocalTokenNumberTable = (UINT32 *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->LocalTokenNumberTableOffset);
   1698     SizeTable = (SIZE_INFO *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->SizeTableOffset);
   1699   }
   1700 
   1701   LocalTokenNumber = LocalTokenNumberTable[LocalTokenNumberTableIdx];
   1702 
   1703   ASSERT ((LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) == PCD_DATUM_TYPE_POINTER);
   1704 
   1705   SizeTableIdx = GetSizeTableIndex (LocalTokenNumberTableIdx, IsPeiDb);
   1706 
   1707   *MaxSize = SizeTable[SizeTableIdx];
   1708   //
   1709   // SizeTable only contain record for PCD_DATUM_TYPE_POINTER type
   1710   // PCD entry.
   1711   //
   1712   if ((LocalTokenNumber & PCD_TYPE_VPD) != 0) {
   1713       //
   1714       // We have only two entry for VPD enabled PCD entry:
   1715       // 1) MAX Size.
   1716       // 2) Current Size
   1717       // We consider current size is equal to MAX size.
   1718       //
   1719       return *MaxSize;
   1720   } else {
   1721     if ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == 0) {
   1722       //
   1723       // We have only two entry for Non-Sku enabled PCD entry:
   1724       // 1) MAX SIZE
   1725       // 2) Current Size
   1726       //
   1727       return SizeTable[SizeTableIdx + 1];
   1728     } else {
   1729       //
   1730       // We have these entry for SKU enabled PCD entry
   1731       // 1) MAX SIZE
   1732       // 2) Current Size for each SKU_ID (It is equal to MaxSku).
   1733       //
   1734       SkuIdTable = GetSkuIdArray (LocalTokenNumberTableIdx, IsPeiDb);
   1735       for (Index = 0; Index < SkuIdTable[0]; Index++) {
   1736         if (SkuIdTable[1 + Index] == mPcdDatabase.DxeDb->SystemSkuId) {
   1737           return SizeTable[SizeTableIdx + 1 + Index];
   1738         }
   1739       }
   1740       return SizeTable[SizeTableIdx + 1];
   1741     }
   1742   }
   1743 }
   1744 
   1745 /**
   1746   Set size of POINTER type PCD value. The size should not exceed the maximum size
   1747   of this PCD value.
   1748 
   1749   @param LocalTokenNumberTableIdx Index of local token number in local token number table.
   1750   @param CurrentSize              Size of POINTER type PCD value.
   1751 
   1752   @retval TRUE  Success to set size of PCD value.
   1753   @retval FALSE Fail to set size of PCD value.
   1754 **/
   1755 BOOLEAN
   1756 SetPtrTypeSize (
   1757   IN          UINTN             LocalTokenNumberTableIdx,
   1758   IN    OUT   UINTN             *CurrentSize
   1759   )
   1760 {
   1761   INTN        SizeTableIdx;
   1762   UINTN       LocalTokenNumber;
   1763   SKU_ID      *SkuIdTable;
   1764   SIZE_INFO   *SizeTable;
   1765   UINTN       Index;
   1766   UINTN       MaxSize;
   1767   BOOLEAN     IsPeiDb;
   1768   UINT32      *LocalTokenNumberTable;
   1769 
   1770   //
   1771   // EBC compiler is very choosy. It may report warning about comparison
   1772   // between UINTN and 0 . So we add 1 in each size of the
   1773   // comparison.
   1774   //
   1775   IsPeiDb = (BOOLEAN) (LocalTokenNumberTableIdx + 1 < mPeiLocalTokenCount + 1);
   1776 
   1777   if (IsPeiDb) {
   1778     LocalTokenNumberTable = (UINT32 *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->LocalTokenNumberTableOffset);
   1779     SizeTable = (SIZE_INFO *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->SizeTableOffset);
   1780   } else {
   1781     LocalTokenNumberTableIdx -= mPeiLocalTokenCount;
   1782     LocalTokenNumberTable = (UINT32 *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->LocalTokenNumberTableOffset);
   1783     SizeTable = (SIZE_INFO *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->SizeTableOffset);
   1784   }
   1785 
   1786   LocalTokenNumber = LocalTokenNumberTable[LocalTokenNumberTableIdx];
   1787 
   1788   ASSERT ((LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) == PCD_DATUM_TYPE_POINTER);
   1789 
   1790   SizeTableIdx = GetSizeTableIndex (LocalTokenNumberTableIdx, IsPeiDb);
   1791 
   1792   MaxSize = SizeTable[SizeTableIdx];
   1793   //
   1794   // SizeTable only contain record for PCD_DATUM_TYPE_POINTER type
   1795   // PCD entry.
   1796   //
   1797   if ((LocalTokenNumber & PCD_TYPE_VPD) != 0) {
   1798       //
   1799       // We shouldn't come here as we don't support SET for VPD
   1800       //
   1801       ASSERT (FALSE);
   1802       return FALSE;
   1803   } else {
   1804     if ((*CurrentSize > MaxSize) ||
   1805       (*CurrentSize == MAX_ADDRESS)) {
   1806        *CurrentSize = MaxSize;
   1807        return FALSE;
   1808     }
   1809 
   1810     if ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == 0) {
   1811       //
   1812       // We have only two entry for Non-Sku enabled PCD entry:
   1813       // 1) MAX SIZE
   1814       // 2) Current Size
   1815       //
   1816       SizeTable[SizeTableIdx + 1] = (SIZE_INFO) *CurrentSize;
   1817       return TRUE;
   1818     } else {
   1819       //
   1820       // We have these entry for SKU enabled PCD entry
   1821       // 1) MAX SIZE
   1822       // 2) Current Size for each SKU_ID (It is equal to MaxSku).
   1823       //
   1824       SkuIdTable = GetSkuIdArray (LocalTokenNumberTableIdx, IsPeiDb);
   1825       for (Index = 0; Index < SkuIdTable[0]; Index++) {
   1826         if (SkuIdTable[1 + Index] == mPcdDatabase.DxeDb->SystemSkuId) {
   1827           SizeTable[SizeTableIdx + 1 + Index] = (SIZE_INFO) *CurrentSize;
   1828           return TRUE;
   1829         }
   1830       }
   1831       SizeTable[SizeTableIdx + 1] = (SIZE_INFO) *CurrentSize;
   1832       return TRUE;
   1833     }
   1834   }
   1835 }
   1836 
   1837 /**
   1838   VariableLock DynamicHiiPcd.
   1839 
   1840   @param[in] IsPeiDb        If TRUE, the pcd entry is initialized in PEI phase,
   1841                             If FALSE, the pcd entry is initialized in DXE phase.
   1842   @param[in] VariableLock   Pointer to VariableLockProtocol.
   1843 
   1844 **/
   1845 VOID
   1846 VariableLockDynamicHiiPcd (
   1847   IN BOOLEAN                        IsPeiDb,
   1848   IN EDKII_VARIABLE_LOCK_PROTOCOL   *VariableLock
   1849   )
   1850 {
   1851   EFI_STATUS                Status;
   1852   PCD_DATABASE_INIT         *Database;
   1853   UINT32                    LocalTokenCount;
   1854   UINTN                     TokenNumber;
   1855   UINT32                    LocalTokenNumber;
   1856   UINTN                     Offset;
   1857   EFI_GUID                  *GuidTable;
   1858   UINT8                     *StringTable;
   1859   VARIABLE_HEAD             *VariableHead;
   1860   EFI_GUID                  *Guid;
   1861   UINT16                    *Name;
   1862 
   1863   Database = IsPeiDb ? mPcdDatabase.PeiDb: mPcdDatabase.DxeDb;
   1864   LocalTokenCount = IsPeiDb ? mPeiLocalTokenCount: mDxeLocalTokenCount;
   1865 
   1866   //
   1867   // Go through PCD database to find out DynamicHii PCDs.
   1868   //
   1869   for (TokenNumber = 1; TokenNumber <= LocalTokenCount; TokenNumber++) {
   1870     if (IsPeiDb) {
   1871       LocalTokenNumber = GetLocalTokenNumber (TRUE, TokenNumber);
   1872     } else {
   1873       LocalTokenNumber = GetLocalTokenNumber (FALSE, TokenNumber + mPeiLocalTokenCount);
   1874     }
   1875     if ((LocalTokenNumber & PCD_TYPE_HII) != 0) {
   1876       Offset = LocalTokenNumber & PCD_DATABASE_OFFSET_MASK;
   1877       VariableHead = (VARIABLE_HEAD *) ((UINT8 *) Database + Offset);
   1878       //
   1879       // Why not to set property by VarCheckProtocol with Attributes and Property directly here?
   1880       // It is because that set property by VarCheckProtocol will indicate the variable to
   1881       // be a system variable, but the unknown max size of the variable is dangerous to
   1882       // the system variable region.
   1883       //
   1884       if ((VariableHead->Property & VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY) != 0) {
   1885         //
   1886         // DynamicHii PCD with RO property set in *.dsc.
   1887         //
   1888         StringTable = (UINT8 *) ((UINT8 *) Database + Database->StringTableOffset);
   1889         GuidTable = (EFI_GUID *) ((UINT8 *) Database + Database->GuidTableOffset);
   1890         Guid = GuidTable + VariableHead->GuidTableIndex;
   1891         Name = (UINT16*) (StringTable + VariableHead->StringIndex);
   1892         Status = VariableLock->RequestToLock (VariableLock, Name, Guid);
   1893         ASSERT_EFI_ERROR (Status);
   1894       }
   1895     }
   1896   }
   1897 }
   1898 
   1899 /**
   1900   VariableLockProtocol callback
   1901   to lock the variables referenced by DynamicHii PCDs with RO property set in *.dsc.
   1902 
   1903   @param[in] Event      Event whose notification function is being invoked.
   1904   @param[in] Context    Pointer to the notification function's context.
   1905 
   1906 **/
   1907 VOID
   1908 EFIAPI
   1909 VariableLockCallBack (
   1910   IN EFI_EVENT          Event,
   1911   IN VOID               *Context
   1912   )
   1913 {
   1914   EFI_STATUS                    Status;
   1915   EDKII_VARIABLE_LOCK_PROTOCOL  *VariableLock;
   1916 
   1917   Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
   1918   if (!EFI_ERROR (Status)) {
   1919     VariableLockDynamicHiiPcd (TRUE, VariableLock);
   1920     VariableLockDynamicHiiPcd (FALSE, VariableLock);
   1921   }
   1922 }
   1923 
   1924