• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /** @file
2   The driver internal functions are implmented here.
3   They build Pei PCD database, and provide access service to PCD database.
4 
5 Copyright (c) 2006 - 2016, 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 
18 /**
19   Get Local Token Number by Token Number.
20 
21   @param[in]    Database    PCD database.
22   @param[in]    TokenNumber The PCD token number.
23 
24   @return       Local Token Number.
25 **/
26 UINT32
GetLocalTokenNumber(IN PEI_PCD_DATABASE * Database,IN UINTN TokenNumber)27 GetLocalTokenNumber (
28   IN PEI_PCD_DATABASE   *Database,
29   IN UINTN              TokenNumber
30   )
31 {
32   UINT32                LocalTokenNumber;
33   UINTN                 Size;
34   UINTN                 MaxSize;
35 
36   //
37   // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
38   // We have to decrement TokenNumber by 1 to make it usable
39   // as the array index.
40   //
41   TokenNumber--;
42 
43   LocalTokenNumber = *((UINT32 *)((UINT8 *)Database + Database->LocalTokenNumberTableOffset) + TokenNumber);
44 
45   Size = (LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) >> PCD_DATUM_TYPE_SHIFT;
46 
47   if ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == PCD_TYPE_SKU_ENABLED) {
48     if (Size == 0) {
49       GetPtrTypeSize (TokenNumber, &MaxSize, Database);
50     } else {
51       MaxSize = Size;
52     }
53     LocalTokenNumber = GetSkuEnabledTokenNumber (LocalTokenNumber & ~PCD_TYPE_SKU_ENABLED, MaxSize);
54   }
55 
56   return LocalTokenNumber;
57 }
58 
59 /**
60   Get PCD type by Local Token Number.
61 
62   @param[in]    LocalTokenNumber The PCD local token number.
63 
64   @return       PCD type.
65 **/
66 EFI_PCD_TYPE
GetPcdType(IN UINT32 LocalTokenNumber)67 GetPcdType (
68   IN UINT32             LocalTokenNumber
69   )
70 {
71   switch (LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) {
72     case PCD_DATUM_TYPE_POINTER:
73       return EFI_PCD_TYPE_PTR;
74     case PCD_DATUM_TYPE_UINT8:
75       if ((LocalTokenNumber & PCD_DATUM_TYPE_UINT8_BOOLEAN) == PCD_DATUM_TYPE_UINT8_BOOLEAN) {
76         return EFI_PCD_TYPE_BOOL;
77       } else {
78         return EFI_PCD_TYPE_8;
79       }
80     case PCD_DATUM_TYPE_UINT16:
81       return EFI_PCD_TYPE_16;
82     case PCD_DATUM_TYPE_UINT32:
83       return EFI_PCD_TYPE_32;
84     case PCD_DATUM_TYPE_UINT64:
85       return EFI_PCD_TYPE_64;
86     default:
87       ASSERT (FALSE);
88       return EFI_PCD_TYPE_8;
89   }
90 }
91 
92 /**
93   Get PCD name.
94 
95   @param[in]    OnlyTokenSpaceName  If TRUE, only need to get the TokenSpaceCName.
96                                     If FALSE, need to get the full PCD name.
97   @param[in]    Database            PCD database.
98   @param[in]    TokenNumber         The PCD token number.
99 
100   @return       The TokenSpaceCName or full PCD name.
101 **/
102 CHAR8 *
GetPcdName(IN BOOLEAN OnlyTokenSpaceName,IN PEI_PCD_DATABASE * Database,IN UINTN TokenNumber)103 GetPcdName (
104   IN BOOLEAN            OnlyTokenSpaceName,
105   IN PEI_PCD_DATABASE   *Database,
106   IN UINTN              TokenNumber
107   )
108 {
109   UINT8             *StringTable;
110   UINTN             NameSize;
111   PCD_NAME_INDEX    *PcdNameIndex;
112   CHAR8             *TokenSpaceName;
113   CHAR8             *PcdName;
114   CHAR8             *Name;
115 
116   //
117   // Return NULL when PCD name table is absent.
118   //
119   if (Database->PcdNameTableOffset == 0) {
120     return NULL;
121   }
122 
123   //
124   // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
125   // We have to decrement TokenNumber by 1 to make it usable
126   // as the array index.
127   //
128   TokenNumber--;
129 
130   StringTable = (UINT8 *) Database + Database->StringTableOffset;
131 
132   //
133   // Get the PCD name index.
134   //
135   PcdNameIndex = (PCD_NAME_INDEX *)((UINT8 *) Database + Database->PcdNameTableOffset) + TokenNumber;
136   TokenSpaceName = (CHAR8 *)&StringTable[PcdNameIndex->TokenSpaceCNameIndex];
137   PcdName = (CHAR8 *)&StringTable[PcdNameIndex->PcdCNameIndex];
138 
139   if (OnlyTokenSpaceName) {
140     //
141     // Only need to get the TokenSpaceCName.
142     //
143     Name = AllocateCopyPool (AsciiStrSize (TokenSpaceName), TokenSpaceName);
144   } else {
145     //
146     // Need to get the full PCD name.
147     //
148     NameSize = AsciiStrSize (TokenSpaceName) + AsciiStrSize (PcdName);
149     Name = AllocateZeroPool (NameSize);
150     ASSERT (Name != NULL);
151     //
152     // Catenate TokenSpaceCName and PcdCName with a '.' to form the full PCD name.
153     //
154     AsciiStrCatS (Name, NameSize, TokenSpaceName);
155     Name[AsciiStrSize (TokenSpaceName) - sizeof (CHAR8)] = '.';
156     AsciiStrCatS (Name, NameSize, PcdName);
157   }
158 
159   return Name;
160 }
161 
162 /**
163   Retrieve additional information associated with a PCD token.
164 
165   This includes information such as the type of value the TokenNumber is associated with as well as possible
166   human readable name that is associated with the token.
167 
168   @param[in]    Database    PCD database.
169   @param[in]    Guid        The 128-bit unique value that designates the namespace from which to extract the value.
170   @param[in]    TokenNumber The PCD token number.
171   @param[out]   PcdInfo     The returned information associated with the requested TokenNumber.
172                             The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
173 
174   @retval  EFI_SUCCESS      The PCD information was returned successfully
175   @retval  EFI_NOT_FOUND    The PCD service could not find the requested token number.
176 **/
177 EFI_STATUS
ExGetPcdInfo(IN PEI_PCD_DATABASE * Database,IN CONST EFI_GUID * Guid,IN UINTN TokenNumber,OUT EFI_PCD_INFO * PcdInfo)178 ExGetPcdInfo (
179   IN        PEI_PCD_DATABASE    *Database,
180   IN CONST  EFI_GUID            *Guid,
181   IN        UINTN               TokenNumber,
182   OUT       EFI_PCD_INFO        *PcdInfo
183   )
184 {
185   UINTN                 GuidTableIdx;
186   EFI_GUID              *MatchGuid;
187   EFI_GUID              *GuidTable;
188   DYNAMICEX_MAPPING     *ExMapTable;
189   UINTN                 Index;
190   UINT32                LocalTokenNumber;
191 
192   GuidTable = (EFI_GUID *)((UINT8 *)Database + Database->GuidTableOffset);
193   MatchGuid = ScanGuid (GuidTable, Database->GuidTableCount * sizeof(EFI_GUID), Guid);
194 
195   if (MatchGuid == NULL) {
196     return EFI_NOT_FOUND;
197   }
198 
199   GuidTableIdx = MatchGuid - GuidTable;
200 
201   ExMapTable = (DYNAMICEX_MAPPING *)((UINT8 *)Database + Database->ExMapTableOffset);
202 
203   //
204   // Find the PCD by GuidTableIdx and ExTokenNumber in ExMapTable.
205   //
206   for (Index = 0; Index < Database->ExTokenCount; Index++) {
207     if (ExMapTable[Index].ExGuidIndex == GuidTableIdx) {
208       if (TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
209         //
210         // TokenNumber is 0, follow spec to set PcdType to EFI_PCD_TYPE_8,
211         // PcdSize to 0 and PcdName to the null-terminated ASCII string
212         // associated with the token's namespace Guid.
213         //
214         PcdInfo->PcdType = EFI_PCD_TYPE_8;
215         PcdInfo->PcdSize = 0;
216         //
217         // Here use one representative in the token space to get the TokenSpaceCName.
218         //
219         PcdInfo->PcdName = GetPcdName (TRUE, Database, ExMapTable[Index].TokenNumber);
220         return EFI_SUCCESS;
221       } else if (ExMapTable[Index].ExTokenNumber == TokenNumber) {
222         PcdInfo->PcdSize = PeiPcdGetSize (ExMapTable[Index].TokenNumber);
223         LocalTokenNumber = GetLocalTokenNumber (Database, ExMapTable[Index].TokenNumber);
224         PcdInfo->PcdType = GetPcdType (LocalTokenNumber);
225         PcdInfo->PcdName = GetPcdName (FALSE, Database, ExMapTable[Index].TokenNumber);
226         return EFI_SUCCESS;
227       }
228     }
229   }
230 
231   return EFI_NOT_FOUND;
232 }
233 
234 /**
235   Retrieve additional information associated with a PCD token.
236 
237   This includes information such as the type of value the TokenNumber is associated with as well as possible
238   human readable name that is associated with the token.
239 
240   @param[in]    Guid        The 128-bit unique value that designates the namespace from which to extract the value.
241   @param[in]    TokenNumber The PCD token number.
242   @param[out]   PcdInfo     The returned information associated with the requested TokenNumber.
243                             The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
244 
245   @retval  EFI_SUCCESS      The PCD information was returned successfully.
246   @retval  EFI_NOT_FOUND    The PCD service could not find the requested token number.
247 **/
248 EFI_STATUS
PeiGetPcdInfo(IN CONST EFI_GUID * Guid,IN UINTN TokenNumber,OUT EFI_PCD_INFO * PcdInfo)249 PeiGetPcdInfo (
250   IN CONST  EFI_GUID        *Guid,
251   IN        UINTN           TokenNumber,
252   OUT       EFI_PCD_INFO    *PcdInfo
253   )
254 {
255   PEI_PCD_DATABASE      *PeiPcdDb;
256   BOOLEAN               PeiExMapTableEmpty;
257   UINTN                 PeiNexTokenNumber;
258   UINT32                LocalTokenNumber;
259 
260   ASSERT (PcdInfo != NULL);
261 
262   PeiPcdDb          = GetPcdDatabase ();
263   PeiNexTokenNumber = PeiPcdDb->LocalTokenCount - PeiPcdDb->ExTokenCount;
264 
265   if (PeiPcdDb->ExTokenCount == 0) {
266     PeiExMapTableEmpty = TRUE;
267   } else {
268     PeiExMapTableEmpty = FALSE;
269   }
270 
271   if (Guid == NULL) {
272     if (TokenNumber > PeiNexTokenNumber) {
273       return EFI_NOT_FOUND;
274     } else if (TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
275       //
276       // TokenNumber is 0, follow spec to set PcdType to EFI_PCD_TYPE_8,
277       // PcdSize to 0 and PcdName to NULL for default Token Space.
278       //
279       PcdInfo->PcdType = EFI_PCD_TYPE_8;
280       PcdInfo->PcdSize = 0;
281       PcdInfo->PcdName = NULL;
282     } else {
283       PcdInfo->PcdSize = PeiPcdGetSize (TokenNumber);
284       LocalTokenNumber = GetLocalTokenNumber (PeiPcdDb, TokenNumber);
285       PcdInfo->PcdType = GetPcdType (LocalTokenNumber);
286       PcdInfo->PcdName = GetPcdName (FALSE, PeiPcdDb, TokenNumber);
287     }
288     return EFI_SUCCESS;
289   } else {
290     if (PeiExMapTableEmpty) {
291       return EFI_NOT_FOUND;
292     }
293     return ExGetPcdInfo (
294              PeiPcdDb,
295              Guid,
296              TokenNumber,
297              PcdInfo
298              );
299   }
300 }
301 
302 /**
303   The function registers the CallBackOnSet fucntion
304   according to TokenNumber and EFI_GUID space.
305 
306   @param  ExTokenNumber       The token number.
307   @param  Guid              The GUID space.
308   @param  CallBackFunction  The Callback function to be registered.
309   @param  Register          To register or unregister the callback function.
310 
311   @retval EFI_SUCCESS If the Callback function is registered.
312   @retval EFI_NOT_FOUND If the PCD Entry is not found according to Token Number and GUID space.
313   @retval EFI_OUT_OF_RESOURCES If the callback function can't be registered because there is not free
314                                 slot left in the CallbackFnTable.
315   @retval EFI_INVALID_PARAMETER If the callback function want to be de-registered can not be found.
316 **/
317 EFI_STATUS
PeiRegisterCallBackWorker(IN UINTN ExTokenNumber,IN CONST EFI_GUID * Guid,OPTIONAL IN PCD_PPI_CALLBACK CallBackFunction,IN BOOLEAN Register)318 PeiRegisterCallBackWorker (
319   IN  UINTN                       ExTokenNumber,
320   IN  CONST EFI_GUID              *Guid, OPTIONAL
321   IN  PCD_PPI_CALLBACK            CallBackFunction,
322   IN  BOOLEAN                     Register
323 )
324 {
325   EFI_HOB_GUID_TYPE       *GuidHob;
326   PCD_PPI_CALLBACK        *CallbackTable;
327   PCD_PPI_CALLBACK        Compare;
328   PCD_PPI_CALLBACK        Assign;
329   UINT32                  LocalTokenNumber;
330   UINT32                  LocalTokenCount;
331   UINTN                   PeiNexTokenNumber;
332   UINTN                   TokenNumber;
333   UINTN                   Idx;
334   PEI_PCD_DATABASE        *PeiPcdDb;
335 
336   PeiPcdDb          = GetPcdDatabase();
337   LocalTokenCount   = PeiPcdDb->LocalTokenCount;
338   PeiNexTokenNumber = PeiPcdDb->LocalTokenCount - PeiPcdDb->ExTokenCount;
339 
340   if (Guid == NULL) {
341     TokenNumber = ExTokenNumber;
342     //
343     // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
344     // We have to decrement TokenNumber by 1 to make it usable
345     // as the array index.
346     //
347     TokenNumber--;
348     ASSERT (TokenNumber + 1 < (PeiNexTokenNumber + 1));
349   } else {
350     TokenNumber = GetExPcdTokenNumber (Guid, ExTokenNumber);
351     if (TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
352       return EFI_NOT_FOUND;
353     }
354     //
355     // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
356     // We have to decrement TokenNumber by 1 to make it usable
357     // as the array index.
358     //
359     TokenNumber--;
360     // EBC compiler is very choosy. It may report warning about comparison
361     // between UINTN and 0 . So we add 1 in each size of the
362     // comparison.
363     ASSERT ((TokenNumber + 1) < (LocalTokenCount + 1));
364   }
365 
366 
367   LocalTokenNumber = *((UINT32 *)((UINT8 *)PeiPcdDb + PeiPcdDb->LocalTokenNumberTableOffset) + TokenNumber);
368 
369   //
370   // We don't support SET for HII and VPD type PCD entry in PEI phase.
371   // So we will assert if any register callback for such PCD entry.
372   //
373   ASSERT ((LocalTokenNumber & PCD_TYPE_HII) == 0);
374   ASSERT ((LocalTokenNumber & PCD_TYPE_VPD) == 0);
375 
376   GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
377   ASSERT (GuidHob != NULL);
378 
379   CallbackTable = GET_GUID_HOB_DATA (GuidHob);
380   CallbackTable = CallbackTable + (TokenNumber * PcdGet32 (PcdMaxPeiPcdCallBackNumberPerPcdEntry));
381 
382   Compare = Register? NULL: CallBackFunction;
383   Assign  = Register? CallBackFunction: NULL;
384 
385 
386   for (Idx = 0; Idx < PcdGet32 (PcdMaxPeiPcdCallBackNumberPerPcdEntry); Idx++) {
387     if (CallbackTable[Idx] == Compare) {
388       CallbackTable[Idx] = Assign;
389       return EFI_SUCCESS;
390     }
391   }
392 
393   return Register? EFI_OUT_OF_RESOURCES : EFI_INVALID_PARAMETER;
394 
395 }
396 
397 
398 /**
399   Find the Pcd database.
400 
401   @param  FileHandle  Handle of the file the external PCD database binary located.
402 
403   @retval The base address of external PCD database binary.
404   @retval NULL         Return NULL if not find.
405 **/
406 VOID *
LocateExPcdBinary(IN EFI_PEI_FILE_HANDLE FileHandle)407 LocateExPcdBinary (
408   IN EFI_PEI_FILE_HANDLE    FileHandle
409   )
410 {
411   EFI_STATUS            Status;
412   VOID                  *PcdDb;
413 
414   PcdDb       = NULL;
415 
416   ASSERT (FileHandle != NULL);
417 
418   Status = PeiServicesFfsFindSectionData (EFI_SECTION_RAW, FileHandle, &PcdDb);
419   ASSERT_EFI_ERROR (Status);
420 
421   //
422   // Check the first bytes (Header Signature Guid) and build version.
423   //
424   if (!CompareGuid (PcdDb, &gPcdDataBaseSignatureGuid) ||
425       (((PEI_PCD_DATABASE *) PcdDb)->BuildVersion != PCD_SERVICE_PEIM_VERSION)) {
426     ASSERT (FALSE);
427   }
428   return PcdDb;
429 }
430 
431 
432 /**
433   The function builds the PCD database.
434 
435   @param  FileHandle  Handle of the file the external PCD database binary located.
436 
437   @return Pointer to PCD database.
438 **/
439 PEI_PCD_DATABASE *
BuildPcdDatabase(IN EFI_PEI_FILE_HANDLE FileHandle)440 BuildPcdDatabase (
441   IN EFI_PEI_FILE_HANDLE    FileHandle
442   )
443 {
444   PEI_PCD_DATABASE       *Database;
445   PEI_PCD_DATABASE       *PeiPcdDbBinary;
446   VOID                   *CallbackFnTable;
447   UINTN                  SizeOfCallbackFnTable;
448 
449   //
450   // Locate the external PCD database binary for one section of current FFS
451   //
452   PeiPcdDbBinary = LocateExPcdBinary (FileHandle);
453 
454   ASSERT(PeiPcdDbBinary != NULL);
455 
456   Database = BuildGuidHob (&gPcdDataBaseHobGuid, PeiPcdDbBinary->Length + PeiPcdDbBinary->UninitDataBaseSize);
457 
458   ZeroMem (Database, PeiPcdDbBinary->Length  + PeiPcdDbBinary->UninitDataBaseSize);
459 
460   //
461   // PeiPcdDbBinary is smaller than Database
462   //
463   CopyMem (Database, PeiPcdDbBinary, PeiPcdDbBinary->Length);
464 
465   SizeOfCallbackFnTable = Database->LocalTokenCount * sizeof (PCD_PPI_CALLBACK) * PcdGet32 (PcdMaxPeiPcdCallBackNumberPerPcdEntry);
466 
467   CallbackFnTable = BuildGuidHob (&gEfiCallerIdGuid, SizeOfCallbackFnTable);
468 
469   ZeroMem (CallbackFnTable, SizeOfCallbackFnTable);
470 
471   return Database;
472 }
473 
474 /**
475   The function is provided by PCD PEIM and PCD DXE driver to
476   do the work of reading a HII variable from variable service.
477 
478   @param VariableGuid     The Variable GUID.
479   @param VariableName     The Variable Name.
480   @param VariableData    The output data.
481   @param VariableSize    The size of the variable.
482 
483   @retval EFI_SUCCESS         Operation successful.
484   @retval EFI_NOT_FOUND         Variablel not found.
485 **/
486 EFI_STATUS
GetHiiVariable(IN CONST EFI_GUID * VariableGuid,IN UINT16 * VariableName,OUT VOID ** VariableData,OUT UINTN * VariableSize)487 GetHiiVariable (
488   IN  CONST EFI_GUID      *VariableGuid,
489   IN  UINT16              *VariableName,
490   OUT VOID                **VariableData,
491   OUT UINTN               *VariableSize
492   )
493 {
494   UINTN      Size;
495   EFI_STATUS Status;
496   VOID       *Buffer;
497   EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariablePpi;
498 
499   Status = PeiServicesLocatePpi (&gEfiPeiReadOnlyVariable2PpiGuid, 0, NULL, (VOID **) &VariablePpi);
500   ASSERT_EFI_ERROR (Status);
501 
502   Size = 0;
503   Status = VariablePpi->GetVariable (
504                           VariablePpi,
505                           VariableName,
506                           (EFI_GUID *) VariableGuid,
507                           NULL,
508                           &Size,
509                           NULL
510                           );
511 
512   if (Status == EFI_BUFFER_TOO_SMALL) {
513     Status = PeiServicesAllocatePool (Size, &Buffer);
514     ASSERT_EFI_ERROR (Status);
515 
516     Status = VariablePpi->GetVariable (
517                               VariablePpi,
518                               (UINT16 *) VariableName,
519                               (EFI_GUID *) VariableGuid,
520                               NULL,
521                               &Size,
522                               Buffer
523                               );
524     ASSERT_EFI_ERROR (Status);
525 
526     *VariableSize = Size;
527     *VariableData = Buffer;
528 
529     return EFI_SUCCESS;
530   }
531 
532   return EFI_NOT_FOUND;
533 }
534 
535 /**
536   Find the local token number according to system SKU ID.
537 
538   @param LocalTokenNumber PCD token number
539   @param Size             The size of PCD entry.
540 
541   @return Token number according to system SKU ID.
542 
543 **/
544 UINT32
GetSkuEnabledTokenNumber(UINT32 LocalTokenNumber,UINTN Size)545 GetSkuEnabledTokenNumber (
546   UINT32 LocalTokenNumber,
547   UINTN  Size
548   )
549 {
550   PEI_PCD_DATABASE      *PeiPcdDb;
551   SKU_HEAD              *SkuHead;
552   SKU_ID                *SkuIdTable;
553   UINTN                 Index;
554   UINT8                 *Value;
555   BOOLEAN               FoundSku;
556 
557   PeiPcdDb = GetPcdDatabase ();
558 
559   ASSERT ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == 0);
560 
561   SkuHead     = (SKU_HEAD *) ((UINT8 *)PeiPcdDb + (LocalTokenNumber & PCD_DATABASE_OFFSET_MASK));
562   Value       = (UINT8 *) ((UINT8 *)PeiPcdDb + (SkuHead->SkuDataStartOffset));
563   SkuIdTable  = (SKU_ID *) ((UINT8 *)PeiPcdDb + (SkuHead->SkuIdTableOffset));
564 
565   //
566   // Find the current system's SKU ID entry in SKU ID table.
567   //
568   FoundSku = FALSE;
569   for (Index = 0; Index < SkuIdTable[0]; Index++) {
570     if (PeiPcdDb->SystemSkuId == SkuIdTable[Index + 1]) {
571       FoundSku = TRUE;
572       break;
573     }
574   }
575 
576   //
577   // Find the default SKU ID entry in SKU ID table.
578   //
579   if(!FoundSku) {
580     for (Index = 0; Index < SkuIdTable[0]; Index++) {
581       if (0 == SkuIdTable[Index + 1]) {
582         break;
583       }
584     }
585   }
586   ASSERT (Index < SkuIdTable[0]);
587 
588   switch (LocalTokenNumber & PCD_TYPE_ALL_SET) {
589     case PCD_TYPE_VPD:
590       Value = (UINT8 *) &(((VPD_HEAD *) Value)[Index]);
591       return (UINT32) ((Value - (UINT8 *) PeiPcdDb) | PCD_TYPE_VPD);
592 
593     case PCD_TYPE_HII:
594       Value = (UINT8 *) &(((VARIABLE_HEAD *) Value)[Index]);
595       return (UINT32) ((Value - (UINT8 *) PeiPcdDb) | PCD_TYPE_HII);
596 
597     case PCD_TYPE_HII|PCD_TYPE_STRING:
598       Value = (UINT8 *) &(((VARIABLE_HEAD *) Value)[Index]);
599       return (UINT32) ((Value - (UINT8 *) PeiPcdDb) | PCD_TYPE_HII | PCD_TYPE_STRING);
600 
601     case PCD_TYPE_STRING:
602       Value = (UINT8 *) &(((STRING_HEAD *) Value)[Index]);
603       return (UINT32) ((Value - (UINT8 *) PeiPcdDb) | PCD_TYPE_STRING);
604 
605     case PCD_TYPE_DATA:
606       Value += Size * Index;
607       return (UINT32) ((Value - (UINT8 *) PeiPcdDb) | PCD_TYPE_DATA);
608 
609     default:
610       ASSERT (FALSE);
611   }
612 
613   ASSERT (FALSE);
614 
615   return 0;
616 }
617 
618 /**
619   Invoke the callback function when dynamic PCD entry was set, if this PCD entry
620   has registered callback function.
621 
622   @param ExTokenNumber   DynamicEx PCD's token number, if this PCD entry is dyanmicEx
623                          type PCD.
624   @param Guid            DynamicEx PCD's guid, if this PCD entry is dynamicEx type
625                          PCD.
626   @param TokenNumber     PCD token number generated by build tools.
627   @param Data            Value want to be set for this PCD entry
628   @param Size            The size of value
629 
630 **/
631 VOID
InvokeCallbackOnSet(UINTN ExTokenNumber,CONST EFI_GUID * Guid,OPTIONAL UINTN TokenNumber,VOID * Data,UINTN Size)632 InvokeCallbackOnSet (
633   UINTN             ExTokenNumber,
634   CONST EFI_GUID    *Guid, OPTIONAL
635   UINTN             TokenNumber,
636   VOID              *Data,
637   UINTN             Size
638   )
639 {
640   EFI_HOB_GUID_TYPE   *GuidHob;
641   PCD_PPI_CALLBACK    *CallbackTable;
642   UINTN               Idx;
643   PEI_PCD_DATABASE    *PeiPcdDb;
644   UINT32              LocalTokenCount;
645 
646   //
647   // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
648   // We have to decrement TokenNumber by 1 to make it usable
649   // as the array index.
650   //
651   TokenNumber--;
652 
653   PeiPcdDb        = GetPcdDatabase ();
654   LocalTokenCount = PeiPcdDb->LocalTokenCount;
655 
656   if (Guid == NULL) {
657     // EBC compiler is very choosy. It may report warning about comparison
658     // between UINTN and 0 . So we add 1 in each size of the
659     // comparison.
660     ASSERT (TokenNumber + 1 < (LocalTokenCount + 1));
661   }
662 
663   GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);
664   ASSERT (GuidHob != NULL);
665 
666   CallbackTable = GET_GUID_HOB_DATA (GuidHob);
667 
668   CallbackTable += (TokenNumber * PcdGet32 (PcdMaxPeiPcdCallBackNumberPerPcdEntry));
669 
670   for (Idx = 0; Idx < PcdGet32 (PcdMaxPeiPcdCallBackNumberPerPcdEntry); Idx++) {
671     if (CallbackTable[Idx] != NULL) {
672       CallbackTable[Idx] (Guid,
673                           (Guid == NULL) ? (TokenNumber + 1) : ExTokenNumber,
674                           Data,
675                           Size
676                           );
677     }
678   }
679 }
680 
681 /**
682   Wrapper function for setting non-pointer type value for a PCD entry.
683 
684   @param TokenNumber     Pcd token number autogenerated by build tools.
685   @param Data            Value want to be set for PCD entry
686   @param Size            Size of value.
687 
688   @return status of SetWorker.
689 
690 **/
691 EFI_STATUS
SetValueWorker(IN UINTN TokenNumber,IN VOID * Data,IN UINTN Size)692 SetValueWorker (
693   IN          UINTN              TokenNumber,
694   IN          VOID               *Data,
695   IN          UINTN              Size
696   )
697 {
698   return SetWorker (TokenNumber, Data, &Size, FALSE);
699 }
700 
701 /**
702   Set value for an PCD entry
703 
704   @param TokenNumber     Pcd token number autogenerated by build tools.
705   @param Data            Value want to be set for PCD entry
706   @param Size            Size of value.
707   @param PtrType         If TRUE, the type of PCD entry's value is Pointer.
708                          If False, the type of PCD entry's value is not Pointer.
709 
710   @retval EFI_INVALID_PARAMETER  If this PCD type is VPD, VPD PCD can not be set.
711   @retval EFI_INVALID_PARAMETER  If Size can not be set to size table.
712   @retval EFI_INVALID_PARAMETER  If Size of non-Ptr type PCD does not match the size information in PCD database.
713   @retval EFI_NOT_FOUND          If value type of PCD entry is intergrate, but not in
714                                  range of UINT8, UINT16, UINT32, UINT64
715   @retval EFI_NOT_FOUND          Can not find the PCD type according to token number.
716 **/
717 EFI_STATUS
SetWorker(IN UINTN TokenNumber,IN VOID * Data,IN OUT UINTN * Size,IN BOOLEAN PtrType)718 SetWorker (
719   IN          UINTN               TokenNumber,
720   IN          VOID                *Data,
721   IN OUT      UINTN               *Size,
722   IN          BOOLEAN             PtrType
723   )
724 {
725   UINT32              LocalTokenNumber;
726   UINTN               PeiNexTokenNumber;
727   PEI_PCD_DATABASE    *PeiPcdDb;
728   STRING_HEAD         StringTableIdx;
729   UINTN               Offset;
730   VOID                *InternalData;
731   UINTN               MaxSize;
732   UINT32              LocalTokenCount;
733 
734   if (!FeaturePcdGet(PcdPeiFullPcdDatabaseEnable)) {
735     return EFI_UNSUPPORTED;
736   }
737 
738   //
739   // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
740   // We have to decrement TokenNumber by 1 to make it usable
741   // as the array index.
742   //
743   TokenNumber--;
744   PeiPcdDb        = GetPcdDatabase ();
745   LocalTokenCount = PeiPcdDb->LocalTokenCount;
746 
747   // EBC compiler is very choosy. It may report warning about comparison
748   // between UINTN and 0 . So we add 1 in each size of the
749   // comparison.
750   ASSERT (TokenNumber + 1 < (LocalTokenCount + 1));
751 
752   if (PtrType) {
753     //
754     // Get MaxSize first, then check new size with max buffer size.
755     //
756     GetPtrTypeSize (TokenNumber, &MaxSize, PeiPcdDb);
757     if (*Size > MaxSize) {
758       *Size = MaxSize;
759       return EFI_INVALID_PARAMETER;
760     }
761   } else {
762     if (*Size != PeiPcdGetSize (TokenNumber + 1)) {
763       return EFI_INVALID_PARAMETER;
764     }
765   }
766 
767   //
768   // We only invoke the callback function for Dynamic Type PCD Entry.
769   // For Dynamic EX PCD entry, we have invoked the callback function for Dynamic EX
770   // type PCD entry in ExSetWorker.
771   //
772   PeiNexTokenNumber = PeiPcdDb->LocalTokenCount - PeiPcdDb->ExTokenCount;
773   if (TokenNumber + 1 < PeiNexTokenNumber + 1) {
774     InvokeCallbackOnSet (0, NULL, TokenNumber + 1, Data, *Size);
775   }
776 
777   LocalTokenNumber = GetLocalTokenNumber (PeiPcdDb, TokenNumber + 1);
778 
779   Offset          = LocalTokenNumber & PCD_DATABASE_OFFSET_MASK;
780   InternalData    = (VOID *) ((UINT8 *) PeiPcdDb + Offset);
781 
782   switch (LocalTokenNumber & PCD_TYPE_ALL_SET) {
783     case PCD_TYPE_VPD:
784     case PCD_TYPE_HII:
785     case PCD_TYPE_HII|PCD_TYPE_STRING:
786     {
787       ASSERT (FALSE);
788       return EFI_INVALID_PARAMETER;
789     }
790 
791     case PCD_TYPE_STRING:
792       if (SetPtrTypeSize (TokenNumber, Size, PeiPcdDb)) {
793         StringTableIdx = *((STRING_HEAD *)InternalData);
794         CopyMem ((UINT8 *)PeiPcdDb + PeiPcdDb->StringTableOffset + StringTableIdx, Data, *Size);
795         return EFI_SUCCESS;
796       } else {
797         return EFI_INVALID_PARAMETER;
798       }
799 
800     case PCD_TYPE_DATA:
801     {
802       if (PtrType) {
803         if (SetPtrTypeSize (TokenNumber, Size, PeiPcdDb)) {
804           CopyMem (InternalData, Data, *Size);
805           return EFI_SUCCESS;
806         } else {
807           return EFI_INVALID_PARAMETER;
808         }
809       }
810 
811       switch (*Size) {
812         case sizeof(UINT8):
813           *((UINT8 *) InternalData) = *((UINT8 *) Data);
814           return EFI_SUCCESS;
815 
816         case sizeof(UINT16):
817           *((UINT16 *) InternalData) = *((UINT16 *) Data);
818           return EFI_SUCCESS;
819 
820         case sizeof(UINT32):
821           *((UINT32 *) InternalData) = *((UINT32 *) Data);
822           return EFI_SUCCESS;
823 
824         case sizeof(UINT64):
825           *((UINT64 *) InternalData) = *((UINT64 *) Data);
826           return EFI_SUCCESS;
827 
828         default:
829           ASSERT (FALSE);
830           return EFI_NOT_FOUND;
831       }
832     }
833 
834   }
835 
836   ASSERT (FALSE);
837   return EFI_NOT_FOUND;
838 
839 }
840 
841 /**
842   Wrapper function for set PCD value for non-Pointer type dynamic-ex PCD.
843 
844   @param ExTokenNumber   Token number for dynamic-ex PCD.
845   @param Guid            Token space guid for dynamic-ex PCD.
846   @param Data            Value want to be set.
847   @param SetSize         The size of value.
848 
849   @return status of ExSetWorker().
850 
851 **/
852 EFI_STATUS
ExSetValueWorker(IN UINTN ExTokenNumber,IN CONST EFI_GUID * Guid,IN VOID * Data,IN UINTN Size)853 ExSetValueWorker (
854   IN          UINTN                ExTokenNumber,
855   IN          CONST EFI_GUID       *Guid,
856   IN          VOID                 *Data,
857   IN          UINTN                Size
858   )
859 {
860   return ExSetWorker (ExTokenNumber, Guid, Data, &Size, FALSE);
861 }
862 
863 /**
864   Set value for a dynamic-ex PCD entry.
865 
866   This routine find the local token number according to dynamic-ex PCD's token
867   space guid and token number firstly, and invoke callback function if this PCD
868   entry registered callback function. Finally, invoken general SetWorker to set
869   PCD value.
870 
871   @param ExTokenNumber   Dynamic-ex PCD token number.
872   @param Guid            Token space guid for dynamic-ex PCD.
873   @param Data            PCD value want to be set
874   @param SetSize         Size of value.
875   @param PtrType         If TRUE, this PCD entry is pointer type.
876                          If FALSE, this PCD entry is not pointer type.
877 
878   @return status of SetWorker().
879 
880 **/
881 EFI_STATUS
ExSetWorker(IN UINTN ExTokenNumber,IN CONST EFI_GUID * Guid,IN VOID * Data,IN OUT UINTN * Size,IN BOOLEAN PtrType)882 ExSetWorker (
883   IN            UINTN                ExTokenNumber,
884   IN            CONST EFI_GUID       *Guid,
885   IN            VOID                 *Data,
886   IN OUT        UINTN                *Size,
887   IN            BOOLEAN              PtrType
888   )
889 {
890   UINTN                     TokenNumber;
891 
892   if (!FeaturePcdGet(PcdPeiFullPcdDatabaseEnable)) {
893     return EFI_UNSUPPORTED;
894   }
895 
896   TokenNumber = GetExPcdTokenNumber (Guid, ExTokenNumber);
897   if (TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
898     return EFI_NOT_FOUND;
899   }
900 
901   InvokeCallbackOnSet (ExTokenNumber, Guid, TokenNumber, Data, *Size);
902 
903   return SetWorker (TokenNumber, Data, Size, PtrType);
904 
905 }
906 
907 /**
908   Wrapper function for get PCD value for dynamic-ex PCD.
909 
910   @param Guid            Token space guid for dynamic-ex PCD.
911   @param ExTokenNumber   Token number for dyanmic-ex PCD.
912   @param GetSize         The size of dynamic-ex PCD value.
913 
914   @return PCD entry in PCD database.
915 
916 **/
917 VOID *
ExGetWorker(IN CONST EFI_GUID * Guid,IN UINTN ExTokenNumber,IN UINTN GetSize)918 ExGetWorker (
919   IN CONST  EFI_GUID  *Guid,
920   IN UINTN            ExTokenNumber,
921   IN UINTN            GetSize
922   )
923 {
924   return GetWorker (GetExPcdTokenNumber (Guid, ExTokenNumber), GetSize);
925 }
926 
927 /**
928   Get the PCD entry pointer in PCD database.
929 
930   This routine will visit PCD database to find the PCD entry according to given
931   token number. The given token number is autogened by build tools and it will be
932   translated to local token number. Local token number contains PCD's type and
933   offset of PCD entry in PCD database.
934 
935   @param TokenNumber     Token's number, it is autogened by build tools
936   @param GetSize         The size of token's value
937 
938   @return PCD entry pointer in PCD database
939 
940 **/
941 VOID *
GetWorker(IN UINTN TokenNumber,IN UINTN GetSize)942 GetWorker (
943   IN UINTN               TokenNumber,
944   IN UINTN               GetSize
945   )
946 {
947   UINT32              Offset;
948   EFI_GUID            *Guid;
949   UINT16              *Name;
950   VARIABLE_HEAD       *VariableHead;
951   EFI_STATUS          Status;
952   UINTN               DataSize;
953   VOID                *Data;
954   UINT8               *StringTable;
955   STRING_HEAD         StringTableIdx;
956   PEI_PCD_DATABASE    *PeiPcdDb;
957   UINT32              LocalTokenNumber;
958   UINT32              LocalTokenCount;
959   UINT8               *VaraiableDefaultBuffer;
960 
961   //
962   // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
963   // We have to decrement TokenNumber by 1 to make it usable
964   // as the array index.
965   //
966   TokenNumber--;
967 
968   PeiPcdDb        = GetPcdDatabase ();
969   LocalTokenCount = PeiPcdDb->LocalTokenCount;
970 
971   // EBC compiler is very choosy. It may report warning about comparison
972   // between UINTN and 0 . So we add 1 in each size of the
973   // comparison.
974   ASSERT (TokenNumber + 1 < (LocalTokenCount + 1));
975 
976   ASSERT ((GetSize == PeiPcdGetSize(TokenNumber + 1)) || (GetSize == 0));
977 
978   LocalTokenNumber = GetLocalTokenNumber (PeiPcdDb, TokenNumber + 1);
979 
980   Offset      = LocalTokenNumber & PCD_DATABASE_OFFSET_MASK;
981   StringTable = (UINT8 *)PeiPcdDb + PeiPcdDb->StringTableOffset;
982 
983   switch (LocalTokenNumber & PCD_TYPE_ALL_SET) {
984     case PCD_TYPE_VPD:
985     {
986       VPD_HEAD *VpdHead;
987       VpdHead = (VPD_HEAD *) ((UINT8 *)PeiPcdDb + Offset);
988       return (VOID *) (UINTN) (PcdGet32 (PcdVpdBaseAddress) + VpdHead->Offset);
989     }
990 
991     case PCD_TYPE_HII|PCD_TYPE_STRING:
992     case PCD_TYPE_HII:
993     {
994       VariableHead = (VARIABLE_HEAD *) ((UINT8 *)PeiPcdDb + Offset);
995 
996       Guid = (EFI_GUID *) ((UINT8 *)PeiPcdDb + PeiPcdDb->GuidTableOffset) + VariableHead->GuidTableIndex;
997       Name = (UINT16*)&StringTable[VariableHead->StringIndex];
998 
999       if ((LocalTokenNumber & PCD_TYPE_ALL_SET) == (PCD_TYPE_HII|PCD_TYPE_STRING)) {
1000         //
1001         // If a HII type PCD's datum type is VOID*, the DefaultValueOffset is the index of
1002         // string array in string table.
1003         //
1004         VaraiableDefaultBuffer = (UINT8 *) &StringTable[*(STRING_HEAD*)((UINT8*) PeiPcdDb + VariableHead->DefaultValueOffset)];
1005       } else {
1006         VaraiableDefaultBuffer = (UINT8 *) PeiPcdDb + VariableHead->DefaultValueOffset;
1007       }
1008       Status = GetHiiVariable (Guid, Name, &Data, &DataSize);
1009       if ((Status == EFI_SUCCESS) && (DataSize >= (VariableHead->Offset + GetSize))) {
1010         if (GetSize == 0) {
1011           //
1012           // It is a pointer type. So get the MaxSize reserved for
1013           // this PCD entry.
1014           //
1015           GetPtrTypeSize (TokenNumber, &GetSize, PeiPcdDb);
1016           if (GetSize > (DataSize - VariableHead->Offset)) {
1017             //
1018             // Use actual valid size.
1019             //
1020             GetSize = DataSize - VariableHead->Offset;
1021           }
1022         }
1023         //
1024         // If the operation is successful, we copy the data
1025         // to the default value buffer in the PCD Database.
1026         //
1027         CopyMem (VaraiableDefaultBuffer, (UINT8 *) Data + VariableHead->Offset, GetSize);
1028       }
1029       return (VOID *) VaraiableDefaultBuffer;
1030     }
1031 
1032     case PCD_TYPE_DATA:
1033       return (VOID *) ((UINT8 *)PeiPcdDb + Offset);
1034 
1035     case PCD_TYPE_STRING:
1036       StringTableIdx = * (STRING_HEAD*) ((UINT8 *) PeiPcdDb + Offset);
1037       return (VOID *) (&StringTable[StringTableIdx]);
1038 
1039     default:
1040       ASSERT (FALSE);
1041       break;
1042 
1043   }
1044 
1045   ASSERT (FALSE);
1046 
1047   return NULL;
1048 
1049 }
1050 
1051 /**
1052   Get Token Number according to dynamic-ex PCD's {token space guid:token number}
1053 
1054   A dynamic-ex type PCD, developer must provide pair of token space guid: token number
1055   in DEC file. PCD database maintain a mapping table that translate pair of {token
1056   space guid: token number} to Token Number.
1057 
1058   @param Guid            Token space guid for dynamic-ex PCD entry.
1059   @param ExTokenNumber   Dynamic-ex PCD token number.
1060 
1061   @return Token Number for dynamic-ex PCD.
1062 
1063 **/
1064 UINTN
GetExPcdTokenNumber(IN CONST EFI_GUID * Guid,IN UINTN ExTokenNumber)1065 GetExPcdTokenNumber (
1066   IN CONST EFI_GUID             *Guid,
1067   IN UINTN                      ExTokenNumber
1068   )
1069 {
1070   UINT32              Index;
1071   DYNAMICEX_MAPPING   *ExMap;
1072   EFI_GUID            *GuidTable;
1073   EFI_GUID            *MatchGuid;
1074   UINTN               MatchGuidIdx;
1075   PEI_PCD_DATABASE    *PeiPcdDb;
1076 
1077   PeiPcdDb    = GetPcdDatabase();
1078 
1079   ExMap       = (DYNAMICEX_MAPPING *)((UINT8 *)PeiPcdDb + PeiPcdDb->ExMapTableOffset);
1080   GuidTable   = (EFI_GUID *)((UINT8 *)PeiPcdDb + PeiPcdDb->GuidTableOffset);
1081 
1082   MatchGuid = ScanGuid (GuidTable, PeiPcdDb->GuidTableCount * sizeof(EFI_GUID), Guid);
1083   //
1084   // We need to ASSERT here. If GUID can't be found in GuidTable, this is a
1085   // error in the BUILD system.
1086   //
1087   ASSERT (MatchGuid != NULL);
1088 
1089   MatchGuidIdx = MatchGuid - GuidTable;
1090 
1091   for (Index = 0; Index < PeiPcdDb->ExTokenCount; Index++) {
1092     if ((ExTokenNumber == ExMap[Index].ExTokenNumber) &&
1093         (MatchGuidIdx == ExMap[Index].ExGuidIndex)) {
1094       return ExMap[Index].TokenNumber;
1095     }
1096   }
1097 
1098   return PCD_INVALID_TOKEN_NUMBER;
1099 }
1100 
1101 /**
1102   Get PCD database from GUID HOB in PEI phase.
1103 
1104   @return Pointer to PCD database.
1105 
1106 **/
1107 PEI_PCD_DATABASE *
GetPcdDatabase(VOID)1108 GetPcdDatabase (
1109   VOID
1110   )
1111 {
1112   EFI_HOB_GUID_TYPE *GuidHob;
1113 
1114   GuidHob = GetFirstGuidHob (&gPcdDataBaseHobGuid);
1115   ASSERT (GuidHob != NULL);
1116 
1117   return (PEI_PCD_DATABASE *) GET_GUID_HOB_DATA (GuidHob);
1118 }
1119 
1120 /**
1121   Get SKU ID table from PCD database.
1122 
1123   @param LocalTokenNumberTableIdx Index of local token number in token number table.
1124   @param Database                 PCD database.
1125 
1126   @return Pointer to SKU ID array table
1127 
1128 **/
1129 SKU_ID *
GetSkuIdArray(IN UINTN LocalTokenNumberTableIdx,IN PEI_PCD_DATABASE * Database)1130 GetSkuIdArray (
1131   IN    UINTN             LocalTokenNumberTableIdx,
1132   IN    PEI_PCD_DATABASE  *Database
1133   )
1134 {
1135   SKU_HEAD *SkuHead;
1136   UINTN     LocalTokenNumber;
1137 
1138   LocalTokenNumber = *((UINT32 *)((UINT8 *)Database + Database->LocalTokenNumberTableOffset) + LocalTokenNumberTableIdx);
1139 
1140   ASSERT ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) != 0);
1141 
1142   SkuHead = (SKU_HEAD *) ((UINT8 *)Database + (LocalTokenNumber & PCD_DATABASE_OFFSET_MASK));
1143 
1144   return (SKU_ID *) ((UINT8 *)Database + SkuHead->SkuIdTableOffset);
1145 
1146 }
1147 
1148 /**
1149   Get index of PCD entry in size table.
1150 
1151   @param LocalTokenNumberTableIdx Index of this PCD in local token number table.
1152   @param Database                 Pointer to PCD database in PEI phase.
1153 
1154   @return index of PCD entry in size table.
1155 
1156 **/
1157 UINTN
GetSizeTableIndex(IN UINTN LocalTokenNumberTableIdx,IN PEI_PCD_DATABASE * Database)1158 GetSizeTableIndex (
1159   IN    UINTN             LocalTokenNumberTableIdx,
1160   IN    PEI_PCD_DATABASE  *Database
1161   )
1162 {
1163   UINTN       Index;
1164   UINTN       SizeTableIdx;
1165   UINTN       LocalTokenNumber;
1166   SKU_ID      *SkuIdTable;
1167 
1168   SizeTableIdx = 0;
1169 
1170   for (Index = 0; Index < LocalTokenNumberTableIdx; Index++) {
1171     LocalTokenNumber = *((UINT32 *)((UINT8 *)Database + Database->LocalTokenNumberTableOffset) + Index);
1172 
1173     if ((LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) == PCD_DATUM_TYPE_POINTER) {
1174       //
1175       // SizeTable only contain record for PCD_DATUM_TYPE_POINTER type
1176       // PCD entry.
1177       //
1178       if ((LocalTokenNumber & PCD_TYPE_VPD) != 0) {
1179           //
1180           // We have only two entry for VPD enabled PCD entry:
1181           // 1) MAX Size.
1182           // 2) Current Size
1183           // Current size is equal to MAX size.
1184           //
1185           SizeTableIdx += 2;
1186       } else {
1187         if ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == 0) {
1188           //
1189           // We have only two entry for Non-Sku enabled PCD entry:
1190           // 1) MAX SIZE
1191           // 2) Current Size
1192           //
1193           SizeTableIdx += 2;
1194         } else {
1195           //
1196           // We have these entry for SKU enabled PCD entry
1197           // 1) MAX SIZE
1198           // 2) Current Size for each SKU_ID (It is equal to MaxSku).
1199           //
1200           SkuIdTable = GetSkuIdArray (Index, Database);
1201           SizeTableIdx += (UINTN)*SkuIdTable + 1;
1202         }
1203       }
1204     }
1205 
1206   }
1207 
1208   return SizeTableIdx;
1209 }
1210