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