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