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