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