1/** @file
2  The driver internal functions are implmented here.
3  They build Pei PCD database, and provide access service to PCD database.
4
5Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
6This program and the accompanying materials
7are licensed and made available under the terms and conditions of the BSD License
8which accompanies this distribution.  The full text of the license may be found at
9http://opensource.org/licenses/bsd-license.php
10
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12WITHOUT 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**/
26UINT32
27GetLocalTokenNumber (
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**/
66EFI_PCD_TYPE
67GetPcdType (
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**/
102CHAR8 *
103GetPcdName (
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**/
177EFI_STATUS
178ExGetPcdInfo (
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**/
248EFI_STATUS
249PeiGetPcdInfo (
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**/
317EFI_STATUS
318PeiRegisterCallBackWorker (
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**/
406VOID *
407LocateExPcdBinary (
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**/
439PEI_PCD_DATABASE *
440BuildPcdDatabase (
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**/
486EFI_STATUS
487GetHiiVariable (
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**/
544UINT32
545GetSkuEnabledTokenNumber (
546  UINT32 LocalTokenNumber,
547  UINTN  Size
548  )
549{
550  PEI_PCD_DATABASE      *PeiPcdDb;
551  SKU_HEAD              *SkuHead;
552  SKU_ID                *SkuIdTable;
553  INTN                  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**/
631VOID
632InvokeCallbackOnSet (
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**/
691EFI_STATUS
692SetValueWorker (
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**/
717EFI_STATUS
718SetWorker (
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**/
852EFI_STATUS
853ExSetValueWorker (
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**/
881EFI_STATUS
882ExSetWorker (
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**/
917VOID *
918ExGetWorker (
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**/
941VOID *
942GetWorker (
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**/
1064UINTN
1065GetExPcdTokenNumber (
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**/
1107PEI_PCD_DATABASE *
1108GetPcdDatabase (
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**/
1129SKU_ID *
1130GetSkuIdArray (
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**/
1157UINTN
1158GetSizeTableIndex (
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