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
GetLocalTokenNumber(IN BOOLEAN IsPeiDb,IN UINTN TokenNumber)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
GetPcdType(IN UINT32 LocalTokenNumber)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 *
GetPcdName(IN BOOLEAN OnlyTokenSpaceName,IN BOOLEAN IsPeiDb,IN UINTN TokenNumber)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
ExGetPcdInfo(IN BOOLEAN IsPeiDb,IN CONST EFI_GUID * Guid,IN UINTN TokenNumber,OUT EFI_PCD_INFO * PcdInfo)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
DxeGetPcdInfo(IN CONST EFI_GUID * Guid,IN UINTN TokenNumber,OUT EFI_PCD_INFO * PcdInfo)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 *
GetWorker(IN UINTN TokenNumber,IN UINTN GetSize)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
DxeRegisterCallBackWorker(IN UINTN TokenNumber,IN CONST EFI_GUID * Guid,OPTIONAL IN PCD_PROTOCOL_CALLBACK CallBackFunction)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
DxeUnRegisterCallBackWorker(IN UINTN TokenNumber,IN CONST EFI_GUID * Guid,OPTIONAL IN PCD_PROTOCOL_CALLBACK CallBackFunction)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
ExGetNextTokeNumber(IN CONST EFI_GUID * Guid,IN OUT UINTN * TokenNumber,IN EFI_GUID * GuidTable,IN UINTN SizeOfGuidTable,IN DYNAMICEX_MAPPING * ExMapTable,IN UINTN SizeOfExMapTable)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 *
LocateExPcdBinary(VOID)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
BuildPcdDxeDataBase(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
GetHiiVariable(IN EFI_GUID * VariableGuid,IN UINT16 * VariableName,OUT UINT8 ** VariableData,OUT UINTN * VariableSize)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
GetSkuEnabledTokenNumber(UINT32 LocalTokenNumber,UINTN Size,BOOLEAN IsPeiDb)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
InvokeCallbackOnSet(UINT32 ExTokenNumber,CONST EFI_GUID * Guid,OPTIONAL UINTN TokenNumber,VOID * Data,UINTN Size)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
SetValueWorker(IN UINTN TokenNumber,IN VOID * Data,IN UINTN Size)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
SetWorker(IN UINTN TokenNumber,IN VOID * Data,IN OUT UINTN * Size,IN BOOLEAN PtrType)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 *
ExGetWorker(IN CONST EFI_GUID * Guid,IN UINTN ExTokenNumber,IN UINTN GetSize)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
ExSetValueWorker(IN UINTN ExTokenNumber,IN CONST EFI_GUID * Guid,IN VOID * Data,IN UINTN SetSize)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
ExSetWorker(IN UINTN ExTokenNumber,IN CONST EFI_GUID * Guid,IN VOID * Data,IN OUT UINTN * SetSize,IN BOOLEAN PtrType)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
SetHiiVariable(IN EFI_GUID * VariableGuid,IN UINT16 * VariableName,IN UINT32 SetAttributes,IN CONST VOID * Data,IN UINTN DataSize,IN UINTN Offset)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
GetExPcdTokenNumber(IN CONST EFI_GUID * Guid,IN UINT32 ExTokenNumber)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 *
GetSkuIdArray(IN UINTN LocalTokenNumberTableIdx,IN BOOLEAN IsPeiDb)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
GetSizeTableIndex(IN UINTN LocalTokenNumberTableIdx,IN BOOLEAN IsPeiDb)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
GetPtrTypeSize(IN UINTN LocalTokenNumberTableIdx,OUT UINTN * MaxSize)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
SetPtrTypeSize(IN UINTN LocalTokenNumberTableIdx,IN OUT UINTN * CurrentSize)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
VariableLockDynamicHiiPcd(IN BOOLEAN IsPeiDb,IN EDKII_VARIABLE_LOCK_PROTOCOL * VariableLock)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
VariableLockCallBack(IN EFI_EVENT Event,IN VOID * Context)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