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