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