]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/PCD/Dxe/Service.c
43a3bda7760d45ecc165da430164a5d63321f24f
[mirror_edk2.git] / MdeModulePkg / Universal / PCD / Dxe / Service.c
1 /** @file
2 Help functions used by PCD DXE driver.
3
4 Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "Service.h"
16 #include <Library/DxeServicesLib.h>
17
18 PCD_DATABASE mPcdDatabase;
19
20 UINT32 mPcdTotalTokenCount;
21 UINT32 mPeiLocalTokenCount;
22 UINT32 mDxeLocalTokenCount;
23 UINT32 mPeiNexTokenCount;
24 UINT32 mDxeNexTokenCount;
25 UINT32 mPeiExMapppingTableSize;
26 UINT32 mDxeExMapppingTableSize;
27 UINT32 mPeiGuidTableSize;
28 UINT32 mDxeGuidTableSize;
29
30 BOOLEAN mPeiExMapTableEmpty;
31 BOOLEAN mDxeExMapTableEmpty;
32 BOOLEAN mPeiDatabaseEmpty;
33
34 LIST_ENTRY *mCallbackFnTable;
35 EFI_GUID **TmpTokenSpaceBuffer;
36 UINTN TmpTokenSpaceBufferCount;
37
38 /**
39 Get Local Token Number by Token Number.
40
41 @param[in] IsPeiDb If TRUE, the pcd entry is initialized in PEI phase,
42 If FALSE, the pcd entry is initialized in DXE phase.
43 @param[in] TokenNumber The PCD token number.
44
45 @return Local Token Number.
46 **/
47 UINT32
48 GetLocalTokenNumber (
49 IN BOOLEAN IsPeiDb,
50 IN UINTN TokenNumber
51 )
52 {
53 UINT32 *LocalTokenNumberTable;
54 UINT32 LocalTokenNumber;
55 UINTN Size;
56 UINTN MaxSize;
57
58 //
59 // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
60 // We have to decrement TokenNumber by 1 to make it usable
61 // as the array index.
62 //
63 TokenNumber--;
64
65 LocalTokenNumberTable = IsPeiDb ? (UINT32 *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->LocalTokenNumberTableOffset) :
66 (UINT32 *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->LocalTokenNumberTableOffset);
67 TokenNumber = IsPeiDb ? TokenNumber : TokenNumber - mPeiLocalTokenCount;
68
69 LocalTokenNumber = LocalTokenNumberTable[TokenNumber];
70
71 Size = (LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) >> PCD_DATUM_TYPE_SHIFT;
72
73 if ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == PCD_TYPE_SKU_ENABLED) {
74 if (Size == 0) {
75 GetPtrTypeSize (TokenNumber, &MaxSize);
76 } else {
77 MaxSize = Size;
78 }
79 LocalTokenNumber = GetSkuEnabledTokenNumber (LocalTokenNumber & ~PCD_TYPE_SKU_ENABLED, MaxSize, IsPeiDb);
80 }
81
82 return LocalTokenNumber;
83 }
84
85 /**
86 Get PCD type by Local Token Number.
87
88 @param[in] LocalTokenNumber The PCD local token number.
89
90 @return PCD type.
91 **/
92 EFI_PCD_TYPE
93 GetPcdType (
94 IN UINT32 LocalTokenNumber
95 )
96 {
97 switch (LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) {
98 case PCD_DATUM_TYPE_POINTER:
99 return EFI_PCD_TYPE_PTR;
100 case PCD_DATUM_TYPE_UINT8:
101 if (LocalTokenNumber & PCD_DATUM_TYPE_UINT8_BOOLEAN) {
102 return EFI_PCD_TYPE_BOOL;
103 } else {
104 return EFI_PCD_TYPE_8;
105 }
106 case PCD_DATUM_TYPE_UINT16:
107 return EFI_PCD_TYPE_16;
108 case PCD_DATUM_TYPE_UINT32:
109 return EFI_PCD_TYPE_32;
110 case PCD_DATUM_TYPE_UINT64:
111 return EFI_PCD_TYPE_64;
112 default:
113 ASSERT (FALSE);
114 return EFI_PCD_TYPE_8;
115 }
116 }
117
118 /**
119 Get PCD name.
120
121 @param[in] OnlyTokenSpaceName If TRUE, only need to get the TokenSpaceCName.
122 If FALSE, need to get the full PCD name.
123 @param[in] IsPeiDb If TRUE, the pcd entry is initialized in PEI phase,
124 If FALSE, the pcd entry is initialized in DXE phase.
125 @param[in] TokenNumber The PCD token number.
126
127 @return The TokenSpaceCName or full PCD name.
128 **/
129 CHAR8 *
130 GetPcdName (
131 IN BOOLEAN OnlyTokenSpaceName,
132 IN BOOLEAN IsPeiDb,
133 IN UINTN TokenNumber
134 )
135 {
136 PCD_DATABASE_INIT *Database;
137 UINT8 *StringTable;
138 PCD_NAME_INDEX *PcdNameIndex;
139 CHAR8 *TokenSpaceName;
140 CHAR8 *PcdName;
141 CHAR8 *Name;
142
143 //
144 // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
145 // We have to decrement TokenNumber by 1 to make it usable
146 // as the array index.
147 //
148 TokenNumber--;
149
150 Database = IsPeiDb ? mPcdDatabase.PeiDb: mPcdDatabase.DxeDb;
151 TokenNumber = IsPeiDb ? TokenNumber : TokenNumber - mPeiLocalTokenCount;
152
153 StringTable = (UINT8 *) Database + Database->StringTableOffset;
154
155 //
156 // Get the PCD name index.
157 //
158 PcdNameIndex = (PCD_NAME_INDEX *)((UINT8 *) Database + Database->PcdNameTableOffset) + TokenNumber;
159 TokenSpaceName = (CHAR8 *)&StringTable[PcdNameIndex->TokenSpaceCNameIndex];
160 PcdName = (CHAR8 *)&StringTable[PcdNameIndex->PcdCNameIndex];
161
162 if (OnlyTokenSpaceName) {
163 //
164 // Only need to get the TokenSpaceCName.
165 //
166 Name = AllocateCopyPool (AsciiStrSize (TokenSpaceName), TokenSpaceName);
167 } else {
168 //
169 // Need to get the full PCD name.
170 //
171 Name = AllocateZeroPool (AsciiStrSize (TokenSpaceName) + AsciiStrSize (PcdName));
172 //
173 // Catenate TokenSpaceCName and PcdCName with a '.' to form the full PCD name.
174 //
175 AsciiStrCat (Name, TokenSpaceName);
176 Name[AsciiStrSize (TokenSpaceName) - sizeof (CHAR8)] = '.';
177 AsciiStrCat (Name, PcdName);
178 }
179
180 return Name;
181 }
182
183 /**
184 Retrieve additional information associated with a PCD token.
185
186 This includes information such as the type of value the TokenNumber is associated with as well as possible
187 human readable name that is associated with the token.
188
189 @param[in] IsPeiDb If TRUE, the pcd entry is initialized in PEI phase,
190 If FALSE, the pcd entry is initialized in DXE phase.
191 @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
192 @param[in] TokenNumber The PCD token number.
193 @param[out] PcdInfo The returned information associated with the requested TokenNumber.
194 The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
195
196 @retval EFI_SUCCESS The PCD information was returned successfully
197 @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
198 **/
199 EFI_STATUS
200 ExGetPcdInfo (
201 IN BOOLEAN IsPeiDb,
202 IN CONST EFI_GUID *Guid,
203 IN UINTN TokenNumber,
204 OUT EFI_PCD_INFO *PcdInfo
205 )
206 {
207 PCD_DATABASE_INIT *Database;
208 UINTN GuidTableIdx;
209 EFI_GUID *MatchGuid;
210 EFI_GUID *GuidTable;
211 DYNAMICEX_MAPPING *ExMapTable;
212 UINTN Index;
213 UINT32 LocalTokenNumber;
214
215 Database = IsPeiDb ? mPcdDatabase.PeiDb: mPcdDatabase.DxeDb;
216
217 GuidTable = (EFI_GUID *)((UINT8 *)Database + Database->GuidTableOffset);
218 MatchGuid = ScanGuid (GuidTable, Database->GuidTableCount * sizeof(EFI_GUID), Guid);
219
220 if (MatchGuid == NULL) {
221 return EFI_NOT_FOUND;
222 }
223
224 GuidTableIdx = MatchGuid - GuidTable;
225
226 ExMapTable = (DYNAMICEX_MAPPING *)((UINT8 *)Database + Database->ExMapTableOffset);
227
228 //
229 // Find the PCD by GuidTableIdx and ExTokenNumber in ExMapTable.
230 //
231 for (Index = 0; Index < Database->ExTokenCount; Index++) {
232 if (ExMapTable[Index].ExGuidIndex == GuidTableIdx) {
233 if (TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
234 //
235 // TokenNumber is 0, follow spec to set PcdType to EFI_PCD_TYPE_8,
236 // PcdSize to 0 and PcdName to the null-terminated ASCII string
237 // associated with the token's namespace Guid.
238 //
239 PcdInfo->PcdType = EFI_PCD_TYPE_8;
240 PcdInfo->PcdSize = 0;
241 //
242 // Here use one representative in the token space to get the TokenSpaceCName.
243 //
244 PcdInfo->PcdName = GetPcdName (TRUE, IsPeiDb, ExMapTable[Index].TokenNumber);
245 return EFI_SUCCESS;
246 } else if (ExMapTable[Index].ExTokenNumber == TokenNumber) {
247 PcdInfo->PcdSize = DxePcdGetSize (ExMapTable[Index].TokenNumber);
248 LocalTokenNumber = GetLocalTokenNumber (IsPeiDb, ExMapTable[Index].TokenNumber);
249 PcdInfo->PcdType = GetPcdType (LocalTokenNumber);
250 PcdInfo->PcdName = GetPcdName (FALSE, IsPeiDb, ExMapTable[Index].TokenNumber);
251 return EFI_SUCCESS;
252 }
253 }
254 }
255
256 return EFI_NOT_FOUND;
257 }
258
259 /**
260 Retrieve additional information associated with a PCD token.
261
262 This includes information such as the type of value the TokenNumber is associated with as well as possible
263 human readable name that is associated with the token.
264
265 @param[in] Guid The 128-bit unique value that designates the namespace from which to extract the value.
266 @param[in] TokenNumber The PCD token number.
267 @param[out] PcdInfo The returned information associated with the requested TokenNumber.
268 The caller is responsible for freeing the buffer that is allocated by callee for PcdInfo->PcdName.
269
270 @retval EFI_SUCCESS The PCD information was returned successfully.
271 @retval EFI_NOT_FOUND The PCD service could not find the requested token number.
272 **/
273 EFI_STATUS
274 DxeGetPcdInfo (
275 IN CONST EFI_GUID *Guid,
276 IN UINTN TokenNumber,
277 OUT EFI_PCD_INFO *PcdInfo
278 )
279 {
280 EFI_STATUS Status;
281 BOOLEAN PeiExMapTableEmpty;
282 BOOLEAN DxeExMapTableEmpty;
283 UINT32 LocalTokenNumber;
284 BOOLEAN IsPeiDb;
285
286 if (!FeaturePcdGet (PcdPcdInfoGeneration)) {
287 return EFI_UNSUPPORTED;
288 }
289
290 ASSERT (PcdInfo != NULL);
291
292 Status = EFI_NOT_FOUND;
293 PeiExMapTableEmpty = mPeiExMapTableEmpty;
294 DxeExMapTableEmpty = mDxeExMapTableEmpty;
295
296 if (Guid == NULL) {
297 if (((TokenNumber + 1 > mPeiNexTokenCount + 1) && (TokenNumber + 1 <= mPeiLocalTokenCount + 1)) ||
298 ((TokenNumber + 1 > (mPeiLocalTokenCount + mDxeNexTokenCount + 1)))) {
299 return EFI_NOT_FOUND;
300 } else if (TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
301 //
302 // TokenNumber is 0, follow spec to set PcdType to EFI_PCD_TYPE_8,
303 // PcdSize to 0 and PcdName to NULL for default Token Space.
304 //
305 PcdInfo->PcdType = EFI_PCD_TYPE_8;
306 PcdInfo->PcdSize = 0;
307 PcdInfo->PcdName = NULL;
308 } else {
309 PcdInfo->PcdSize = DxePcdGetSize (TokenNumber);
310 IsPeiDb = FALSE;
311 if ((TokenNumber + 1 <= mPeiNexTokenCount + 1)) {
312 IsPeiDb = TRUE;
313 }
314 LocalTokenNumber = GetLocalTokenNumber (IsPeiDb, TokenNumber);
315 PcdInfo->PcdType = GetPcdType (LocalTokenNumber);
316 PcdInfo->PcdName = GetPcdName (FALSE, IsPeiDb, TokenNumber);
317 }
318 return EFI_SUCCESS;
319 }
320
321 if (PeiExMapTableEmpty && DxeExMapTableEmpty) {
322 return EFI_NOT_FOUND;
323 }
324
325 if (!PeiExMapTableEmpty) {
326 Status = ExGetPcdInfo (
327 TRUE,
328 Guid,
329 TokenNumber,
330 PcdInfo
331 );
332 }
333
334 if (Status == EFI_SUCCESS) {
335 return Status;
336 }
337
338 if (!DxeExMapTableEmpty) {
339 Status = ExGetPcdInfo (
340 FALSE,
341 Guid,
342 TokenNumber,
343 PcdInfo
344 );
345 }
346
347 return Status;
348 }
349
350 /**
351 Get the PCD entry pointer in PCD database.
352
353 This routine will visit PCD database to find the PCD entry according to given
354 token number. The given token number is autogened by build tools and it will be
355 translated to local token number. Local token number contains PCD's type and
356 offset of PCD entry in PCD database.
357
358 @param TokenNumber Token's number, it is autogened by build tools
359 @param GetSize The size of token's value
360
361 @return PCD entry pointer in PCD database
362
363 **/
364 VOID *
365 GetWorker (
366 IN UINTN TokenNumber,
367 IN UINTN GetSize
368 )
369 {
370 EFI_GUID *GuidTable;
371 UINT8 *StringTable;
372 EFI_GUID *Guid;
373 UINT16 *Name;
374 VARIABLE_HEAD *VariableHead;
375 UINT8 *VaraiableDefaultBuffer;
376 UINT8 *Data;
377 VPD_HEAD *VpdHead;
378 UINT8 *PcdDb;
379 VOID *RetPtr;
380 UINTN TmpTokenNumber;
381 UINTN DataSize;
382 EFI_STATUS Status;
383 UINT32 LocalTokenNumber;
384 UINT32 Offset;
385 STRING_HEAD StringTableIdx;
386 BOOLEAN IsPeiDb;
387
388 //
389 // Aquire lock to prevent reentrance from TPL_CALLBACK level
390 //
391 EfiAcquireLock (&mPcdDatabaseLock);
392
393 RetPtr = NULL;
394
395 ASSERT (TokenNumber > 0);
396 //
397 // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
398 // We have to decrement TokenNumber by 1 to make it usable
399 // as the array index.
400 //
401 TokenNumber--;
402
403 TmpTokenNumber = TokenNumber;
404
405 //
406 // EBC compiler is very choosy. It may report warning about comparison
407 // between UINTN and 0 . So we add 1 in each size of the
408 // comparison.
409 //
410 ASSERT (TokenNumber + 1 < mPcdTotalTokenCount + 1);
411
412 ASSERT ((GetSize == DxePcdGetSize (TokenNumber + 1)) || (GetSize == 0));
413
414 // EBC compiler is very choosy. It may report warning about comparison
415 // between UINTN and 0 . So we add 1 in each size of the
416 // comparison.
417 IsPeiDb = (BOOLEAN) ((TokenNumber + 1 < mPeiLocalTokenCount + 1) ? TRUE : FALSE);
418
419 LocalTokenNumber = GetLocalTokenNumber (IsPeiDb, TokenNumber + 1);
420
421 PcdDb = IsPeiDb ? ((UINT8 *) mPcdDatabase.PeiDb) : ((UINT8 *) mPcdDatabase.DxeDb);
422
423 if (IsPeiDb) {
424 StringTable = (UINT8 *) ((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->StringTableOffset);
425 } else {
426 StringTable = (UINT8 *) ((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->StringTableOffset);
427 }
428
429
430 Offset = LocalTokenNumber & PCD_DATABASE_OFFSET_MASK;
431
432 switch (LocalTokenNumber & PCD_TYPE_ALL_SET) {
433 case PCD_TYPE_VPD:
434 VpdHead = (VPD_HEAD *) ((UINT8 *) PcdDb + Offset);
435 RetPtr = (VOID *) (UINTN) (PcdGet32 (PcdVpdBaseAddress) + VpdHead->Offset);
436
437 break;
438
439 case PCD_TYPE_HII|PCD_TYPE_STRING:
440 case PCD_TYPE_HII:
441 if (IsPeiDb) {
442 GuidTable = (EFI_GUID *) ((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->GuidTableOffset);
443 } else {
444 GuidTable = (EFI_GUID *) ((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->GuidTableOffset);
445 }
446
447 VariableHead = (VARIABLE_HEAD *) (PcdDb + Offset);
448 Guid = GuidTable + VariableHead->GuidTableIndex;
449 Name = (UINT16*)(StringTable + VariableHead->StringIndex);
450
451 if ((LocalTokenNumber & PCD_TYPE_ALL_SET) == (PCD_TYPE_HII|PCD_TYPE_STRING)) {
452 //
453 // If a HII type PCD's datum type is VOID*, the DefaultValueOffset is the index of
454 // string array in string table.
455 //
456 StringTableIdx = *(STRING_HEAD*)((UINT8 *) PcdDb + VariableHead->DefaultValueOffset);
457 VaraiableDefaultBuffer = (VOID *) (StringTable + StringTableIdx);
458 } else {
459 VaraiableDefaultBuffer = (UINT8 *) PcdDb + VariableHead->DefaultValueOffset;
460 }
461 Status = GetHiiVariable (Guid, Name, &Data, &DataSize);
462 if (Status == EFI_SUCCESS) {
463 if (GetSize == 0) {
464 //
465 // It is a pointer type. So get the MaxSize reserved for
466 // this PCD entry.
467 //
468 GetPtrTypeSize (TmpTokenNumber, &GetSize);
469 }
470 //
471 // If the operation is successful, we copy the data
472 // to the default value buffer in the PCD Database.
473 // So that we can free the Data allocated in GetHiiVariable.
474 //
475 CopyMem (VaraiableDefaultBuffer, Data + VariableHead->Offset, GetSize);
476 FreePool (Data);
477 }
478 RetPtr = (VOID *) VaraiableDefaultBuffer;
479 break;
480
481 case PCD_TYPE_STRING:
482 StringTableIdx = *(STRING_HEAD*)((UINT8 *) PcdDb + Offset);
483 RetPtr = (VOID *) (StringTable + StringTableIdx);
484 break;
485
486 case PCD_TYPE_DATA:
487 RetPtr = (VOID *) ((UINT8 *) PcdDb + Offset);
488 break;
489
490 default:
491 ASSERT (FALSE);
492 break;
493
494 }
495
496 EfiReleaseLock (&mPcdDatabaseLock);
497
498 return RetPtr;
499
500 }
501
502 /**
503 Register the callback function for a PCD entry.
504
505 This routine will register a callback function to a PCD entry by given token number
506 and token space guid.
507
508 @param TokenNumber PCD token's number, it is autogened by build tools.
509 @param Guid PCD token space's guid,
510 if not NULL, this PCD is dynamicEx type PCD.
511 @param CallBackFunction Callback function pointer
512
513 @return EFI_SUCCESS Always success for registering callback function.
514
515 **/
516 EFI_STATUS
517 DxeRegisterCallBackWorker (
518 IN UINTN TokenNumber,
519 IN CONST EFI_GUID *Guid, OPTIONAL
520 IN PCD_PROTOCOL_CALLBACK CallBackFunction
521 )
522 {
523 CALLBACK_FN_ENTRY *FnTableEntry;
524 LIST_ENTRY *ListHead;
525 LIST_ENTRY *ListNode;
526
527 if (Guid != NULL) {
528 TokenNumber = GetExPcdTokenNumber (Guid, (UINT32) TokenNumber);
529 }
530
531 //
532 // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
533 // We have to decrement TokenNumber by 1 to make it usable
534 // as the array index of mCallbackFnTable[].
535 //
536 ListHead = &mCallbackFnTable[TokenNumber - 1];
537 ListNode = GetFirstNode (ListHead);
538
539 while (ListNode != ListHead) {
540 FnTableEntry = CR_FNENTRY_FROM_LISTNODE(ListNode, CALLBACK_FN_ENTRY, Node);
541
542 if (FnTableEntry->CallbackFn == CallBackFunction) {
543 //
544 // We only allow a Callback function to be register once
545 // for a TokenNumber. So just return EFI_SUCCESS
546 //
547 return EFI_SUCCESS;
548 }
549 ListNode = GetNextNode (ListHead, ListNode);
550 }
551
552 FnTableEntry = AllocatePool (sizeof(CALLBACK_FN_ENTRY));
553 ASSERT (FnTableEntry != NULL);
554
555 FnTableEntry->CallbackFn = CallBackFunction;
556 InsertTailList (ListHead, &FnTableEntry->Node);
557
558 return EFI_SUCCESS;
559 }
560
561 /**
562 UnRegister the callback function for a PCD entry.
563
564 This routine will unregister a callback function to a PCD entry by given token number
565 and token space guid.
566
567 @param TokenNumber PCD token's number, it is autogened by build tools.
568 @param Guid PCD token space's guid.
569 if not NULL, this PCD is dynamicEx type PCD.
570 @param CallBackFunction Callback function pointer
571
572 @retval EFI_SUCCESS Callback function is success to be unregister.
573 @retval EFI_INVALID_PARAMETER Can not find the PCD entry by given token number.
574 **/
575 EFI_STATUS
576 DxeUnRegisterCallBackWorker (
577 IN UINTN TokenNumber,
578 IN CONST EFI_GUID *Guid, OPTIONAL
579 IN PCD_PROTOCOL_CALLBACK CallBackFunction
580 )
581 {
582 CALLBACK_FN_ENTRY *FnTableEntry;
583 LIST_ENTRY *ListHead;
584 LIST_ENTRY *ListNode;
585
586 if (Guid != NULL) {
587 TokenNumber = GetExPcdTokenNumber (Guid, (UINT32) TokenNumber);
588 }
589
590 //
591 // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
592 // We have to decrement TokenNumber by 1 to make it usable
593 // as the array index of mCallbackFnTable[].
594 //
595 ListHead = &mCallbackFnTable[TokenNumber - 1];
596 ListNode = GetFirstNode (ListHead);
597
598 while (ListNode != ListHead) {
599 FnTableEntry = CR_FNENTRY_FROM_LISTNODE(ListNode, CALLBACK_FN_ENTRY, Node);
600
601 if (FnTableEntry->CallbackFn == CallBackFunction) {
602 //
603 // We only allow a Callback function to be register once
604 // for a TokenNumber. So we can safely remove the Node from
605 // the Link List and return EFI_SUCCESS.
606 //
607 RemoveEntryList (ListNode);
608 FreePool (FnTableEntry);
609
610 return EFI_SUCCESS;
611 }
612 ListNode = GetNextNode (ListHead, ListNode);
613 }
614
615 return EFI_INVALID_PARAMETER;
616 }
617
618 /**
619 Get next token number in given token space.
620
621 This routine is used for dynamicEx type PCD. It will firstly scan token space
622 table to get token space according to given token space guid. Then scan given
623 token number in found token space, if found, then return next token number in
624 this token space.
625
626 @param Guid Token space guid. Next token number will be scaned in
627 this token space.
628 @param TokenNumber Token number.
629 If PCD_INVALID_TOKEN_NUMBER, return first token number in
630 token space table.
631 If not PCD_INVALID_TOKEN_NUMBER, return next token number
632 in token space table.
633 @param GuidTable Token space guid table. It will be used for scan token space
634 by given token space guid.
635 @param SizeOfGuidTable The size of guid table.
636 @param ExMapTable DynamicEx token number mapping table.
637 @param SizeOfExMapTable The size of dynamicEx token number mapping table.
638
639 @retval EFI_NOT_FOUND Can not given token space or token number.
640 @retval EFI_SUCCESS Success to get next token number.
641
642 **/
643 EFI_STATUS
644 ExGetNextTokeNumber (
645 IN CONST EFI_GUID *Guid,
646 IN OUT UINTN *TokenNumber,
647 IN EFI_GUID *GuidTable,
648 IN UINTN SizeOfGuidTable,
649 IN DYNAMICEX_MAPPING *ExMapTable,
650 IN UINTN SizeOfExMapTable
651 )
652 {
653 EFI_GUID *MatchGuid;
654 UINTN Index;
655 UINTN GuidTableIdx;
656 BOOLEAN Found;
657 UINTN ExMapTableCount;
658
659 //
660 // Scan token space guid
661 //
662 MatchGuid = ScanGuid (GuidTable, SizeOfGuidTable, Guid);
663 if (MatchGuid == NULL) {
664 return EFI_NOT_FOUND;
665 }
666
667 //
668 // Find the token space table in dynamicEx mapping table.
669 //
670 Found = FALSE;
671 GuidTableIdx = MatchGuid - GuidTable;
672 ExMapTableCount = SizeOfExMapTable / sizeof(ExMapTable[0]);
673 for (Index = 0; Index < ExMapTableCount; Index++) {
674 if (ExMapTable[Index].ExGuidIndex == GuidTableIdx) {
675 Found = TRUE;
676 break;
677 }
678 }
679
680 if (Found) {
681 //
682 // If given token number is PCD_INVALID_TOKEN_NUMBER, then return the first
683 // token number in found token space.
684 //
685 if (*TokenNumber == PCD_INVALID_TOKEN_NUMBER) {
686 *TokenNumber = ExMapTable[Index].ExTokenNumber;
687 return EFI_SUCCESS;
688 }
689
690 for ( ; Index < ExMapTableCount; Index++) {
691 if (ExMapTable[Index].ExTokenNumber == *TokenNumber) {
692 break;
693 }
694 }
695
696 while (Index < ExMapTableCount) {
697 Index++;
698 if (Index == ExMapTableCount) {
699 //
700 // Exceed the length of ExMap Table
701 //
702 *TokenNumber = PCD_INVALID_TOKEN_NUMBER;
703 return EFI_NOT_FOUND;
704 } else if (ExMapTable[Index].ExGuidIndex == GuidTableIdx) {
705 //
706 // Found the next match
707 //
708 *TokenNumber = ExMapTable[Index].ExTokenNumber;
709 return EFI_SUCCESS;
710 }
711 }
712 }
713
714 return EFI_NOT_FOUND;
715 }
716
717 /**
718 Find the PCD database.
719
720 @retval The base address of external PCD database binary.
721 @retval NULL Return NULL if not find.
722 **/
723 DXE_PCD_DATABASE *
724 LocateExPcdBinary (
725 VOID
726 )
727 {
728 DXE_PCD_DATABASE *DxePcdDbBinary;
729 UINTN DxePcdDbSize;
730 EFI_STATUS Status;
731
732 DxePcdDbBinary = NULL;
733 //
734 // Search the External Pcd database from one section of current FFS,
735 // and read it to memory
736 //
737 Status = GetSectionFromFfs (
738 EFI_SECTION_RAW,
739 0,
740 (VOID **) &DxePcdDbBinary,
741 &DxePcdDbSize
742 );
743 ASSERT_EFI_ERROR (Status);
744
745 //
746 // Check the first bytes (Header Signature Guid) and build version.
747 //
748 if (!CompareGuid ((VOID *)DxePcdDbBinary, &gPcdDataBaseSignatureGuid) ||
749 (DxePcdDbBinary->BuildVersion != PCD_SERVICE_DXE_VERSION)) {
750 ASSERT (FALSE);
751 }
752
753 return DxePcdDbBinary;
754 }
755
756 /**
757 Initialize the PCD database in DXE phase.
758
759 PCD database in DXE phase also contains PCD database in PEI phase which is copied
760 from GUID Hob.
761
762 **/
763 VOID
764 BuildPcdDxeDataBase (
765 VOID
766 )
767 {
768 PEI_PCD_DATABASE *PeiDatabase;
769 EFI_HOB_GUID_TYPE *GuidHob;
770 UINTN Index;
771 UINT32 PcdDxeDbLen;
772 VOID *PcdDxeDb;
773
774 GuidHob = GetFirstGuidHob (&gPcdDataBaseHobGuid);
775 if (GuidHob != NULL) {
776
777 //
778 // If no PEIMs use dynamic Pcd Entry, the Pcd Service PEIM
779 // should not be included at all. So the GuidHob could
780 // be NULL. If it is NULL, we just copy over the DXE Default
781 // Value to PCD Database.
782 //
783
784 PeiDatabase = (PEI_PCD_DATABASE *) GET_GUID_HOB_DATA (GuidHob);
785 //
786 // Assign PCD Entries refereneced in PEI phase to PCD DATABASE
787 //
788 mPcdDatabase.PeiDb = PeiDatabase;
789 }
790
791 //
792 // Assign PCD Entries with default value to PCD DATABASE
793 //
794 mPcdDatabase.DxeDb = LocateExPcdBinary ();
795 ASSERT(mPcdDatabase.DxeDb != NULL);
796 PcdDxeDbLen = mPcdDatabase.DxeDb->Length + mPcdDatabase.DxeDb->UninitDataBaseSize;
797 PcdDxeDb = AllocateZeroPool (PcdDxeDbLen);
798 ASSERT (PcdDxeDb != NULL);
799 CopyMem (PcdDxeDb, mPcdDatabase.DxeDb, mPcdDatabase.DxeDb->Length);
800 FreePool (mPcdDatabase.DxeDb);
801 mPcdDatabase.DxeDb = PcdDxeDb;
802
803 //
804 // Initialized the external PCD database local variables
805 //
806 mPeiLocalTokenCount = mPcdDatabase.PeiDb->LocalTokenCount;
807 mDxeLocalTokenCount = mPcdDatabase.DxeDb->LocalTokenCount;
808
809 mPeiExMapppingTableSize = mPcdDatabase.PeiDb->ExTokenCount * sizeof (DYNAMICEX_MAPPING);
810 mDxeExMapppingTableSize = mPcdDatabase.DxeDb->ExTokenCount * sizeof (DYNAMICEX_MAPPING);
811 mPeiGuidTableSize = mPcdDatabase.PeiDb->GuidTableCount * sizeof(GUID);
812 mDxeGuidTableSize = mPcdDatabase.DxeDb->GuidTableCount * sizeof (GUID);
813
814 mPcdTotalTokenCount = mPeiLocalTokenCount + mDxeLocalTokenCount;
815 mPeiNexTokenCount = mPeiLocalTokenCount - mPcdDatabase.PeiDb->ExTokenCount;
816 mDxeNexTokenCount = mDxeLocalTokenCount - mPcdDatabase.DxeDb->ExTokenCount;
817
818 mPeiExMapTableEmpty = (mPcdDatabase.PeiDb->ExTokenCount == 0) ? TRUE : FALSE;
819 mDxeExMapTableEmpty = (mPcdDatabase.DxeDb->ExTokenCount == 0) ? TRUE : FALSE;
820 mPeiDatabaseEmpty = (mPeiLocalTokenCount == 0) ? TRUE : FALSE;
821
822 TmpTokenSpaceBufferCount = mPcdDatabase.PeiDb->ExTokenCount + mPcdDatabase.DxeDb->ExTokenCount;
823 TmpTokenSpaceBuffer = (EFI_GUID **)AllocateZeroPool(TmpTokenSpaceBufferCount * sizeof (EFI_GUID *));
824
825 //
826 // Initialized the Callback Function Table
827 //
828 mCallbackFnTable = AllocateZeroPool (mPcdTotalTokenCount * sizeof (LIST_ENTRY));
829 ASSERT(mCallbackFnTable != NULL);
830
831 //
832 // EBC compiler is very choosy. It may report warning about comparison
833 // between UINTN and 0 . So we add 1 in each size of the
834 // comparison.
835 //
836 for (Index = 0; Index + 1 < mPcdTotalTokenCount + 1; Index++) {
837 InitializeListHead (&mCallbackFnTable[Index]);
838 }
839 }
840
841 /**
842 Get Variable which contains HII type PCD entry.
843
844 @param VariableGuid Variable's guid
845 @param VariableName Variable's unicode name string
846 @param VariableData Variable's data pointer,
847 @param VariableSize Variable's size.
848
849 @return the status of gRT->GetVariable
850 **/
851 EFI_STATUS
852 GetHiiVariable (
853 IN EFI_GUID *VariableGuid,
854 IN UINT16 *VariableName,
855 OUT UINT8 **VariableData,
856 OUT UINTN *VariableSize
857 )
858 {
859 UINTN Size;
860 EFI_STATUS Status;
861 UINT8 *Buffer;
862
863 Size = 0;
864 Buffer = NULL;
865
866 //
867 // Firstly get the real size of HII variable
868 //
869 Status = gRT->GetVariable (
870 (UINT16 *)VariableName,
871 VariableGuid,
872 NULL,
873 &Size,
874 Buffer
875 );
876
877 //
878 // Allocate buffer to hold whole variable data according to variable size.
879 //
880 if (Status == EFI_BUFFER_TOO_SMALL) {
881 Buffer = (UINT8 *) AllocatePool (Size);
882
883 ASSERT (Buffer != NULL);
884
885 Status = gRT->GetVariable (
886 VariableName,
887 VariableGuid,
888 NULL,
889 &Size,
890 Buffer
891 );
892
893 ASSERT (Status == EFI_SUCCESS);
894 *VariableData = Buffer;
895 *VariableSize = Size;
896 } else {
897 //
898 // Use Default Data only when variable is not found.
899 // For other error status, correct data can't be got, and trig ASSERT().
900 //
901 ASSERT (Status == EFI_NOT_FOUND);
902 }
903
904 return Status;
905 }
906
907 /**
908 Find the local token number according to system SKU ID.
909
910 @param LocalTokenNumber PCD token number
911 @param Size The size of PCD entry.
912 @param IsPeiDb If TRUE, the PCD entry is initialized in PEI phase.
913 If False, the PCD entry is initialized in DXE phase.
914
915 @return Token number according to system SKU ID.
916
917 **/
918 UINT32
919 GetSkuEnabledTokenNumber (
920 UINT32 LocalTokenNumber,
921 UINTN Size,
922 BOOLEAN IsPeiDb
923 )
924 {
925 SKU_HEAD *SkuHead;
926 SKU_ID *SkuIdTable;
927 INTN Index;
928 UINT8 *Value;
929 UINT8 *PcdDb;
930 BOOLEAN FoundSku;
931
932 ASSERT ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == 0);
933
934 PcdDb = IsPeiDb ? (UINT8 *) mPcdDatabase.PeiDb : (UINT8 *) mPcdDatabase.DxeDb;
935
936 SkuHead = (SKU_HEAD *) (PcdDb + (LocalTokenNumber & PCD_DATABASE_OFFSET_MASK));
937 Value = (UINT8 *) (PcdDb + SkuHead->SkuDataStartOffset);
938
939 SkuIdTable = (SKU_ID *)(PcdDb + SkuHead->SkuIdTableOffset);
940 //
941 // Find the current system's SKU ID entry in SKU ID table.
942 //
943 FoundSku = FALSE;
944 for (Index = 0; Index < SkuIdTable[0]; Index++) {
945 if (mPcdDatabase.PeiDb->SystemSkuId == SkuIdTable[Index + 1]) {
946 FoundSku = TRUE;
947 break;
948 }
949 }
950
951 //
952 // Find the default SKU ID entry in SKU ID table.
953 //
954
955 if(!FoundSku) {
956 for (Index = 0; Index < SkuIdTable[0]; Index++) {
957 if (0 == SkuIdTable[Index + 1]) {
958 break;
959 }
960 }
961 }
962 ASSERT (Index < SkuIdTable[0]);
963
964 switch (LocalTokenNumber & PCD_TYPE_ALL_SET) {
965 case PCD_TYPE_VPD:
966 Value = (UINT8 *) &(((VPD_HEAD *) Value)[Index]);
967 return (UINT32) ((Value - PcdDb) | PCD_TYPE_VPD);
968
969 case PCD_TYPE_HII:
970 Value = (UINT8 *) &(((VARIABLE_HEAD *) Value)[Index]);
971 return (UINT32) ((Value - PcdDb) | PCD_TYPE_HII);
972
973 case PCD_TYPE_HII|PCD_TYPE_STRING:
974 Value = (UINT8 *) &(((VARIABLE_HEAD *) Value)[Index]);
975 return (UINT32) ((Value - PcdDb) | PCD_TYPE_HII | PCD_TYPE_STRING);
976
977 case PCD_TYPE_STRING:
978 Value = (UINT8 *) &(((STRING_HEAD *) Value)[Index]);
979 return (UINT32) ((Value - PcdDb) | PCD_TYPE_STRING);
980
981 case PCD_TYPE_DATA:
982 Value += Size * Index;
983 return (UINT32) ((Value - PcdDb) | PCD_TYPE_DATA);
984
985 default:
986 ASSERT (FALSE);
987 }
988
989 ASSERT (FALSE);
990
991 return 0;
992
993 }
994
995 /**
996 Invoke the callback function when dynamic PCD entry was set, if this PCD entry
997 has registered callback function.
998
999 @param ExTokenNumber DynamicEx PCD's token number, if this PCD entry is dyanmicEx
1000 type PCD.
1001 @param Guid DynamicEx PCD's guid, if this PCD entry is dynamicEx type
1002 PCD.
1003 @param TokenNumber PCD token number generated by build tools.
1004 @param Data Value want to be set for this PCD entry
1005 @param Size The size of value
1006
1007 **/
1008 VOID
1009 InvokeCallbackOnSet (
1010 UINT32 ExTokenNumber,
1011 CONST EFI_GUID *Guid, OPTIONAL
1012 UINTN TokenNumber,
1013 VOID *Data,
1014 UINTN Size
1015 )
1016 {
1017 CALLBACK_FN_ENTRY *FnTableEntry;
1018 LIST_ENTRY *ListHead;
1019 LIST_ENTRY *ListNode;
1020
1021 //
1022 // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
1023 // We have to decrement TokenNumber by 1 to make it usable
1024 // as the array index of mCallbackFnTable[].
1025 //
1026 ListHead = &mCallbackFnTable[TokenNumber - 1];
1027 ListNode = GetFirstNode (ListHead);
1028
1029 while (ListNode != ListHead) {
1030 FnTableEntry = CR_FNENTRY_FROM_LISTNODE (ListNode, CALLBACK_FN_ENTRY, Node);
1031
1032 FnTableEntry->CallbackFn(Guid,
1033 (Guid == NULL) ? TokenNumber : ExTokenNumber,
1034 Data,
1035 Size);
1036
1037 ListNode = GetNextNode (ListHead, ListNode);
1038 }
1039
1040 return;
1041 }
1042
1043
1044 /**
1045 Wrapper function for setting non-pointer type value for a PCD entry.
1046
1047 @param TokenNumber Pcd token number autogenerated by build tools.
1048 @param Data Value want to be set for PCD entry
1049 @param Size Size of value.
1050
1051 @return status of SetWorker.
1052
1053 **/
1054 EFI_STATUS
1055 SetValueWorker (
1056 IN UINTN TokenNumber,
1057 IN VOID *Data,
1058 IN UINTN Size
1059 )
1060 {
1061 return SetWorker (TokenNumber, Data, &Size, FALSE);
1062 }
1063
1064
1065 /**
1066 Set value for an PCD entry
1067
1068 @param TokenNumber Pcd token number autogenerated by build tools.
1069 @param Data Value want to be set for PCD entry
1070 @param Size Size of value.
1071 @param PtrType If TRUE, the type of PCD entry's value is Pointer.
1072 If False, the type of PCD entry's value is not Pointer.
1073
1074 @retval EFI_INVALID_PARAMETER If this PCD type is VPD, VPD PCD can not be set.
1075 @retval EFI_INVALID_PARAMETER If Size can not be set to size table.
1076 @retval EFI_INVALID_PARAMETER If Size of non-Ptr type PCD does not match the size information in PCD database.
1077 @retval EFI_NOT_FOUND If value type of PCD entry is intergrate, but not in
1078 range of UINT8, UINT16, UINT32, UINT64
1079 @retval EFI_NOT_FOUND Can not find the PCD type according to token number.
1080 **/
1081 EFI_STATUS
1082 SetWorker (
1083 IN UINTN TokenNumber,
1084 IN VOID *Data,
1085 IN OUT UINTN *Size,
1086 IN BOOLEAN PtrType
1087 )
1088 {
1089 BOOLEAN IsPeiDb;
1090 UINT32 LocalTokenNumber;
1091 EFI_GUID *GuidTable;
1092 UINT8 *StringTable;
1093 EFI_GUID *Guid;
1094 UINT16 *Name;
1095 UINTN VariableOffset;
1096 VOID *InternalData;
1097 VARIABLE_HEAD *VariableHead;
1098 UINTN Offset;
1099 UINT8 *PcdDb;
1100 EFI_STATUS Status;
1101 UINTN MaxSize;
1102 UINTN TmpTokenNumber;
1103
1104 //
1105 // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.
1106 // We have to decrement TokenNumber by 1 to make it usable
1107 // as the array index.
1108 //
1109 TokenNumber--;
1110
1111 TmpTokenNumber = TokenNumber;
1112
1113 //
1114 // EBC compiler is very choosy. It may report warning about comparison
1115 // between UINTN and 0 . So we add 1 in each size of the
1116 // comparison.
1117 //
1118 ASSERT (TokenNumber + 1 < mPcdTotalTokenCount + 1);
1119
1120 if (PtrType) {
1121 //
1122 // Get MaxSize first, then check new size with max buffer size.
1123 //
1124 GetPtrTypeSize (TokenNumber, &MaxSize);
1125 if (*Size > MaxSize) {
1126 *Size = MaxSize;
1127 return EFI_INVALID_PARAMETER;
1128 }
1129 } else {
1130 if (*Size != DxePcdGetSize (TokenNumber + 1)) {
1131 return EFI_INVALID_PARAMETER;
1132 }
1133 }
1134
1135 //
1136 // EBC compiler is very choosy. It may report warning about comparison
1137 // between UINTN and 0 . So we add 1 in each size of the
1138 // comparison.
1139 //
1140 if ((TokenNumber + 1 < mPeiNexTokenCount + 1) ||
1141 (TokenNumber + 1 >= mPeiLocalTokenCount + 1 && TokenNumber + 1 < (mPeiLocalTokenCount + mDxeNexTokenCount + 1))) {
1142 InvokeCallbackOnSet (0, NULL, TokenNumber + 1, Data, *Size);
1143 }
1144
1145 //
1146 // Aquire lock to prevent reentrance from TPL_CALLBACK level
1147 //
1148 EfiAcquireLock (&mPcdDatabaseLock);
1149
1150 //
1151 // EBC compiler is very choosy. It may report warning about comparison
1152 // between UINTN and 0 . So we add 1 in each size of the
1153 // comparison.
1154 //
1155 IsPeiDb = (BOOLEAN) ((TokenNumber + 1 < mPeiLocalTokenCount + 1) ? TRUE : FALSE);
1156
1157 LocalTokenNumber = GetLocalTokenNumber (IsPeiDb, TokenNumber + 1);
1158
1159 Offset = LocalTokenNumber & PCD_DATABASE_OFFSET_MASK;
1160
1161 PcdDb = IsPeiDb ? ((UINT8 *) mPcdDatabase.PeiDb) : ((UINT8 *) mPcdDatabase.DxeDb);
1162
1163 if (IsPeiDb) {
1164 StringTable = (UINT8 *) ((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->StringTableOffset);
1165 } else {
1166 StringTable = (UINT8 *) ((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->StringTableOffset);
1167 }
1168
1169
1170 InternalData = PcdDb + Offset;
1171
1172 switch (LocalTokenNumber & PCD_TYPE_ALL_SET) {
1173 case PCD_TYPE_VPD:
1174 ASSERT (FALSE);
1175 Status = EFI_INVALID_PARAMETER;
1176 break;
1177
1178 case PCD_TYPE_STRING:
1179 if (SetPtrTypeSize (TmpTokenNumber, Size)) {
1180 CopyMem (StringTable + *((STRING_HEAD *)InternalData), Data, *Size);
1181 Status = EFI_SUCCESS;
1182 } else {
1183 Status = EFI_INVALID_PARAMETER;
1184 }
1185 break;
1186
1187 case PCD_TYPE_HII|PCD_TYPE_STRING:
1188 case PCD_TYPE_HII:
1189 if (PtrType) {
1190 if (!SetPtrTypeSize (TmpTokenNumber, Size)) {
1191 Status = EFI_INVALID_PARAMETER;
1192 break;
1193 }
1194 }
1195
1196 if (IsPeiDb) {
1197 GuidTable = (EFI_GUID *) ((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->GuidTableOffset);
1198 } else {
1199 GuidTable = (EFI_GUID *) ((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->GuidTableOffset);
1200 }
1201
1202 VariableHead = (VARIABLE_HEAD *) (PcdDb + Offset);
1203
1204 Guid = GuidTable + VariableHead->GuidTableIndex;
1205 Name = (UINT16*) (StringTable + VariableHead->StringIndex);
1206 VariableOffset = VariableHead->Offset;
1207 Status = SetHiiVariable (Guid, Name, Data, *Size, VariableOffset);
1208
1209 if (EFI_NOT_FOUND == Status) {
1210 if ((LocalTokenNumber & PCD_TYPE_ALL_SET) == (PCD_TYPE_HII|PCD_TYPE_STRING)) {
1211 CopyMem (
1212 StringTable + *(STRING_HEAD *)(PcdDb + VariableHead->DefaultValueOffset),
1213 Data,
1214 *Size
1215 );
1216 } else {
1217 CopyMem (PcdDb + VariableHead->DefaultValueOffset, Data, *Size);
1218 }
1219 Status = EFI_SUCCESS;
1220 }
1221 break;
1222
1223 case PCD_TYPE_DATA:
1224 if (PtrType) {
1225 if (SetPtrTypeSize (TmpTokenNumber, Size)) {
1226 CopyMem (InternalData, Data, *Size);
1227 Status = EFI_SUCCESS;
1228 } else {
1229 Status = EFI_INVALID_PARAMETER;
1230 }
1231 break;
1232 }
1233
1234 Status = EFI_SUCCESS;
1235 switch (*Size) {
1236 case sizeof(UINT8):
1237 *((UINT8 *) InternalData) = *((UINT8 *) Data);
1238 break;
1239
1240 case sizeof(UINT16):
1241 *((UINT16 *) InternalData) = *((UINT16 *) Data);
1242 break;
1243
1244 case sizeof(UINT32):
1245 *((UINT32 *) InternalData) = *((UINT32 *) Data);
1246 break;
1247
1248 case sizeof(UINT64):
1249 *((UINT64 *) InternalData) = *((UINT64 *) Data);
1250 break;
1251
1252 default:
1253 ASSERT (FALSE);
1254 Status = EFI_NOT_FOUND;
1255 break;
1256 }
1257 break;
1258
1259 default:
1260 ASSERT (FALSE);
1261 Status = EFI_NOT_FOUND;
1262 break;
1263 }
1264
1265 EfiReleaseLock (&mPcdDatabaseLock);
1266
1267 return Status;
1268 }
1269
1270 /**
1271 Wrapper function for get PCD value for dynamic-ex PCD.
1272
1273 @param Guid Token space guid for dynamic-ex PCD.
1274 @param ExTokenNumber Token number for dynamic-ex PCD.
1275 @param GetSize The size of dynamic-ex PCD value.
1276
1277 @return PCD entry in PCD database.
1278
1279 **/
1280 VOID *
1281 ExGetWorker (
1282 IN CONST EFI_GUID *Guid,
1283 IN UINTN ExTokenNumber,
1284 IN UINTN GetSize
1285 )
1286 {
1287 return GetWorker(GetExPcdTokenNumber (Guid, (UINT32) ExTokenNumber), GetSize);
1288 }
1289
1290 /**
1291 Wrapper function for set PCD value for non-Pointer type dynamic-ex PCD.
1292
1293 @param ExTokenNumber Token number for dynamic-ex PCD.
1294 @param Guid Token space guid for dynamic-ex PCD.
1295 @param Data Value want to be set.
1296 @param SetSize The size of value.
1297
1298 @return status of ExSetWorker().
1299
1300 **/
1301 EFI_STATUS
1302 ExSetValueWorker (
1303 IN UINTN ExTokenNumber,
1304 IN CONST EFI_GUID *Guid,
1305 IN VOID *Data,
1306 IN UINTN SetSize
1307 )
1308 {
1309 return ExSetWorker (ExTokenNumber, Guid, Data, &SetSize, FALSE);
1310 }
1311
1312 /**
1313 Set value for a dynamic-ex PCD entry.
1314
1315 This routine find the local token number according to dynamic-ex PCD's token
1316 space guid and token number firstly, and invoke callback function if this PCD
1317 entry registered callback function. Finally, invoken general SetWorker to set
1318 PCD value.
1319
1320 @param ExTokenNumber Dynamic-ex PCD token number.
1321 @param Guid Token space guid for dynamic-ex PCD.
1322 @param Data PCD value want to be set
1323 @param SetSize Size of value.
1324 @param PtrType If TRUE, this PCD entry is pointer type.
1325 If FALSE, this PCD entry is not pointer type.
1326
1327 @return status of SetWorker().
1328
1329 **/
1330 EFI_STATUS
1331 ExSetWorker (
1332 IN UINTN ExTokenNumber,
1333 IN CONST EFI_GUID *Guid,
1334 IN VOID *Data,
1335 IN OUT UINTN *SetSize,
1336 IN BOOLEAN PtrType
1337 )
1338 {
1339 UINTN TokenNumber;
1340
1341 TokenNumber = GetExPcdTokenNumber (Guid, (UINT32) ExTokenNumber);
1342
1343 InvokeCallbackOnSet ((UINT32) ExTokenNumber, Guid, TokenNumber, Data, *SetSize);
1344
1345 return SetWorker (TokenNumber, Data, SetSize, PtrType);
1346
1347 }
1348
1349 /**
1350 Set value for HII-type PCD.
1351
1352 A HII-type PCD's value is stored in a variable. Setting/Getting the value of
1353 HII-type PCD is to visit this variable.
1354
1355 @param VariableGuid Guid of variable which stored value of a HII-type PCD.
1356 @param VariableName Unicode name of variable which stored value of a HII-type PCD.
1357 @param Data Value want to be set.
1358 @param DataSize Size of value
1359 @param Offset Value offset of HII-type PCD in variable.
1360
1361 @return status of GetVariable()/SetVariable().
1362
1363 **/
1364 EFI_STATUS
1365 SetHiiVariable (
1366 IN EFI_GUID *VariableGuid,
1367 IN UINT16 *VariableName,
1368 IN CONST VOID *Data,
1369 IN UINTN DataSize,
1370 IN UINTN Offset
1371 )
1372 {
1373 UINTN Size;
1374 VOID *Buffer;
1375 EFI_STATUS Status;
1376 UINT32 Attribute;
1377 UINTN SetSize;
1378
1379 Size = 0;
1380 SetSize = 0;
1381
1382 //
1383 // Try to get original variable size information.
1384 //
1385 Status = gRT->GetVariable (
1386 (UINT16 *)VariableName,
1387 VariableGuid,
1388 NULL,
1389 &Size,
1390 NULL
1391 );
1392
1393 if (Status == EFI_BUFFER_TOO_SMALL) {
1394 //
1395 // Patch new PCD's value to offset in given HII variable.
1396 //
1397 if (Size >= (DataSize + Offset)) {
1398 SetSize = Size;
1399 } else {
1400 SetSize = DataSize + Offset;
1401 }
1402 Buffer = AllocatePool (SetSize);
1403 ASSERT (Buffer != NULL);
1404
1405 Status = gRT->GetVariable (
1406 VariableName,
1407 VariableGuid,
1408 &Attribute,
1409 &Size,
1410 Buffer
1411 );
1412
1413 ASSERT_EFI_ERROR (Status);
1414
1415 CopyMem ((UINT8 *)Buffer + Offset, Data, DataSize);
1416
1417 Status = gRT->SetVariable (
1418 VariableName,
1419 VariableGuid,
1420 Attribute,
1421 SetSize,
1422 Buffer
1423 );
1424
1425 FreePool (Buffer);
1426 return Status;
1427 } else if (Status == EFI_NOT_FOUND) {
1428 //
1429 // If variable does not exist, a new variable need to be created.
1430 //
1431
1432 Size = Offset + DataSize;
1433
1434 Buffer = AllocateZeroPool (Size);
1435 ASSERT (Buffer != NULL);
1436
1437 CopyMem ((UINT8 *)Buffer + Offset, Data, DataSize);
1438
1439 Status = gRT->SetVariable (
1440 VariableName,
1441 VariableGuid,
1442 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
1443 Size,
1444 Buffer
1445 );
1446
1447 FreePool (Buffer);
1448 return Status;
1449 }
1450
1451 //
1452 // If we drop to here, the value is failed to be written in to variable area
1453 // So, we will save the data in the PCD Database's volatile area.
1454 //
1455 return Status;
1456 }
1457
1458 /**
1459 Get Token Number according to dynamic-ex PCD's {token space guid:token number}
1460
1461 A dynamic-ex type PCD, developer must provide pair of token space guid: token number
1462 in DEC file. PCD database maintain a mapping table that translate pair of {token
1463 space guid: token number} to Token Number.
1464
1465 @param Guid Token space guid for dynamic-ex PCD entry.
1466 @param ExTokenNumber Dynamic-ex PCD token number.
1467
1468 @return Token Number for dynamic-ex PCD.
1469
1470 **/
1471 UINTN
1472 GetExPcdTokenNumber (
1473 IN CONST EFI_GUID *Guid,
1474 IN UINT32 ExTokenNumber
1475 )
1476 {
1477 UINT32 Index;
1478 DYNAMICEX_MAPPING *ExMap;
1479 EFI_GUID *GuidTable;
1480 EFI_GUID *MatchGuid;
1481 UINTN MatchGuidIdx;
1482
1483 if (!mPeiDatabaseEmpty) {
1484 ExMap = (DYNAMICEX_MAPPING *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->ExMapTableOffset);
1485 GuidTable = (EFI_GUID *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->GuidTableOffset);
1486
1487 MatchGuid = ScanGuid (GuidTable, mPeiGuidTableSize, Guid);
1488
1489 if (MatchGuid != NULL) {
1490
1491 MatchGuidIdx = MatchGuid - GuidTable;
1492
1493 for (Index = 0; Index < mPeiExMapppingTableSize; Index++) {
1494 if ((ExTokenNumber == ExMap[Index].ExTokenNumber) &&
1495 (MatchGuidIdx == ExMap[Index].ExGuidIndex)) {
1496 return ExMap[Index].TokenNumber;
1497 }
1498 }
1499 }
1500 }
1501
1502 ExMap = (DYNAMICEX_MAPPING *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->ExMapTableOffset);
1503 GuidTable = (EFI_GUID *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->GuidTableOffset);
1504
1505 MatchGuid = ScanGuid (GuidTable, mDxeGuidTableSize, Guid);
1506 //
1507 // We need to ASSERT here. If GUID can't be found in GuidTable, this is a
1508 // error in the BUILD system.
1509 //
1510 ASSERT (MatchGuid != NULL);
1511
1512 MatchGuidIdx = MatchGuid - GuidTable;
1513
1514 for (Index = 0; Index < mDxeExMapppingTableSize; Index++) {
1515 if ((ExTokenNumber == ExMap[Index].ExTokenNumber) &&
1516 (MatchGuidIdx == ExMap[Index].ExGuidIndex)) {
1517 return ExMap[Index].TokenNumber;
1518 }
1519 }
1520
1521 ASSERT (FALSE);
1522
1523 return 0;
1524 }
1525
1526 /**
1527 Get SKU ID table from PCD database.
1528
1529 @param LocalTokenNumberTableIdx Index of local token number in token number table.
1530 @param IsPeiDb If TRUE, the pcd entry is initialized in PEI phase,
1531 If FALSE, the pcd entry is initialized in DXE phase.
1532 @return Pointer to SKU ID array table
1533
1534 **/
1535 SKU_ID *
1536 GetSkuIdArray (
1537 IN UINTN LocalTokenNumberTableIdx,
1538 IN BOOLEAN IsPeiDb
1539 )
1540 {
1541 SKU_HEAD *SkuHead;
1542 UINTN LocalTokenNumber;
1543 UINT8 *Database;
1544
1545 if (IsPeiDb) {
1546 LocalTokenNumber = *((UINT32 *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->LocalTokenNumberTableOffset) + LocalTokenNumberTableIdx);
1547 Database = (UINT8 *) mPcdDatabase.PeiDb;
1548 } else {
1549 LocalTokenNumber = *((UINT32 *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->LocalTokenNumberTableOffset) + LocalTokenNumberTableIdx);
1550 Database = (UINT8 *) mPcdDatabase.DxeDb;
1551 }
1552
1553 ASSERT ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) != 0);
1554
1555 SkuHead = (SKU_HEAD *) ((UINT8 *)Database + (LocalTokenNumber & PCD_DATABASE_OFFSET_MASK));
1556
1557 return (SKU_ID *) (Database + SkuHead->SkuIdTableOffset);
1558
1559 }
1560
1561 /**
1562 Wrapper function of getting index of PCD entry in size table.
1563
1564 @param LocalTokenNumberTableIdx Index of this PCD in local token number table.
1565 @param IsPeiDb If TRUE, the pcd entry is initialized in PEI phase,
1566 If FALSE, the pcd entry is initialized in DXE phase.
1567
1568 @return index of PCD entry in size table.
1569 **/
1570 UINTN
1571 GetSizeTableIndex (
1572 IN UINTN LocalTokenNumberTableIdx,
1573 IN BOOLEAN IsPeiDb
1574 )
1575 {
1576 UINT32 *LocalTokenNumberTable;
1577 UINTN LocalTokenNumber;
1578 UINTN Index;
1579 UINTN SizeTableIdx;
1580 SKU_ID *SkuIdTable;
1581
1582 if (IsPeiDb) {
1583 LocalTokenNumberTable = (UINT32 *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->LocalTokenNumberTableOffset);
1584 } else {
1585 LocalTokenNumberTable = (UINT32 *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->LocalTokenNumberTableOffset);
1586 }
1587
1588 SizeTableIdx = 0;
1589
1590 for (Index = 0; Index < LocalTokenNumberTableIdx; Index ++) {
1591 LocalTokenNumber = LocalTokenNumberTable[Index];
1592
1593 if ((LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) == PCD_DATUM_TYPE_POINTER) {
1594 //
1595 // SizeTable only contain record for PCD_DATUM_TYPE_POINTER type
1596 // PCD entry.
1597 //
1598 if ((LocalTokenNumber & PCD_TYPE_VPD) != 0) {
1599 //
1600 // We have only two entry for VPD enabled PCD entry:
1601 // 1) MAX Size.
1602 // 2) Current Size
1603 // Current size is equal to MAX size.
1604 //
1605 SizeTableIdx += 2;
1606 } else {
1607 if ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == 0) {
1608 //
1609 // We have only two entry for Non-Sku enabled PCD entry:
1610 // 1) MAX SIZE
1611 // 2) Current Size
1612 //
1613 SizeTableIdx += 2;
1614 } else {
1615 //
1616 // We have these entry for SKU enabled PCD entry
1617 // 1) MAX SIZE
1618 // 2) Current Size for each SKU_ID (It is equal to MaxSku).
1619 //
1620 SkuIdTable = GetSkuIdArray (Index, IsPeiDb);
1621 SizeTableIdx += (UINTN)*SkuIdTable + 1;
1622 }
1623 }
1624 }
1625
1626 }
1627
1628 return SizeTableIdx;
1629 }
1630
1631 /**
1632 Get size of POINTER type PCD value.
1633
1634 @param LocalTokenNumberTableIdx Index of local token number in local token number table.
1635 @param MaxSize Maxmium size of POINTER type PCD value.
1636
1637 @return size of POINTER type PCD value.
1638
1639 **/
1640 UINTN
1641 GetPtrTypeSize (
1642 IN UINTN LocalTokenNumberTableIdx,
1643 OUT UINTN *MaxSize
1644 )
1645 {
1646 INTN SizeTableIdx;
1647 UINTN LocalTokenNumber;
1648 SKU_ID *SkuIdTable;
1649 SIZE_INFO *SizeTable;
1650 UINTN Index;
1651 BOOLEAN IsPeiDb;
1652 UINT32 *LocalTokenNumberTable;
1653
1654 // EBC compiler is very choosy. It may report warning about comparison
1655 // between UINTN and 0 . So we add 1 in each size of the
1656 // comparison.
1657 IsPeiDb = (BOOLEAN) (LocalTokenNumberTableIdx + 1 < mPeiLocalTokenCount + 1);
1658
1659
1660 if (IsPeiDb) {
1661 LocalTokenNumberTable = (UINT32 *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->LocalTokenNumberTableOffset);
1662 SizeTable = (SIZE_INFO *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->SizeTableOffset);
1663 } else {
1664 LocalTokenNumberTableIdx -= mPeiLocalTokenCount;
1665 LocalTokenNumberTable = (UINT32 *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->LocalTokenNumberTableOffset);
1666 SizeTable = (SIZE_INFO *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->SizeTableOffset);
1667 }
1668
1669 LocalTokenNumber = LocalTokenNumberTable[LocalTokenNumberTableIdx];
1670
1671 ASSERT ((LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) == PCD_DATUM_TYPE_POINTER);
1672
1673 SizeTableIdx = GetSizeTableIndex (LocalTokenNumberTableIdx, IsPeiDb);
1674
1675 *MaxSize = SizeTable[SizeTableIdx];
1676 //
1677 // SizeTable only contain record for PCD_DATUM_TYPE_POINTER type
1678 // PCD entry.
1679 //
1680 if ((LocalTokenNumber & PCD_TYPE_VPD) != 0) {
1681 //
1682 // We have only two entry for VPD enabled PCD entry:
1683 // 1) MAX Size.
1684 // 2) Current Size
1685 // We consider current size is equal to MAX size.
1686 //
1687 return *MaxSize;
1688 } else {
1689 if ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == 0) {
1690 //
1691 // We have only two entry for Non-Sku enabled PCD entry:
1692 // 1) MAX SIZE
1693 // 2) Current Size
1694 //
1695 return SizeTable[SizeTableIdx + 1];
1696 } else {
1697 //
1698 // We have these entry for SKU enabled PCD entry
1699 // 1) MAX SIZE
1700 // 2) Current Size for each SKU_ID (It is equal to MaxSku).
1701 //
1702 SkuIdTable = GetSkuIdArray (LocalTokenNumberTableIdx, IsPeiDb);
1703 for (Index = 0; Index < SkuIdTable[0]; Index++) {
1704 if (SkuIdTable[1 + Index] == mPcdDatabase.PeiDb->SystemSkuId) {
1705 return SizeTable[SizeTableIdx + 1 + Index];
1706 }
1707 }
1708 return SizeTable[SizeTableIdx + 1];
1709 }
1710 }
1711 }
1712
1713 /**
1714 Set size of POINTER type PCD value. The size should not exceed the maximum size
1715 of this PCD value.
1716
1717 @param LocalTokenNumberTableIdx Index of local token number in local token number table.
1718 @param CurrentSize Size of POINTER type PCD value.
1719
1720 @retval TRUE Success to set size of PCD value.
1721 @retval FALSE Fail to set size of PCD value.
1722 **/
1723 BOOLEAN
1724 SetPtrTypeSize (
1725 IN UINTN LocalTokenNumberTableIdx,
1726 IN OUT UINTN *CurrentSize
1727 )
1728 {
1729 INTN SizeTableIdx;
1730 UINTN LocalTokenNumber;
1731 SKU_ID *SkuIdTable;
1732 SIZE_INFO *SizeTable;
1733 UINTN Index;
1734 UINTN MaxSize;
1735 BOOLEAN IsPeiDb;
1736 UINT32 *LocalTokenNumberTable;
1737
1738 //
1739 // EBC compiler is very choosy. It may report warning about comparison
1740 // between UINTN and 0 . So we add 1 in each size of the
1741 // comparison.
1742 //
1743 IsPeiDb = (BOOLEAN) (LocalTokenNumberTableIdx + 1 < mPeiLocalTokenCount + 1);
1744
1745 if (IsPeiDb) {
1746 LocalTokenNumberTable = (UINT32 *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->LocalTokenNumberTableOffset);
1747 SizeTable = (SIZE_INFO *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->SizeTableOffset);
1748 } else {
1749 LocalTokenNumberTableIdx -= mPeiLocalTokenCount;
1750 LocalTokenNumberTable = (UINT32 *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->LocalTokenNumberTableOffset);
1751 SizeTable = (SIZE_INFO *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->SizeTableOffset);
1752 }
1753
1754 LocalTokenNumber = LocalTokenNumberTable[LocalTokenNumberTableIdx];
1755
1756 ASSERT ((LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) == PCD_DATUM_TYPE_POINTER);
1757
1758 SizeTableIdx = GetSizeTableIndex (LocalTokenNumberTableIdx, IsPeiDb);
1759
1760 MaxSize = SizeTable[SizeTableIdx];
1761 //
1762 // SizeTable only contain record for PCD_DATUM_TYPE_POINTER type
1763 // PCD entry.
1764 //
1765 if ((LocalTokenNumber & PCD_TYPE_VPD) != 0) {
1766 //
1767 // We shouldn't come here as we don't support SET for VPD
1768 //
1769 ASSERT (FALSE);
1770 return FALSE;
1771 } else {
1772 if ((*CurrentSize > MaxSize) ||
1773 (*CurrentSize == MAX_ADDRESS)) {
1774 *CurrentSize = MaxSize;
1775 return FALSE;
1776 }
1777
1778 if ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == 0) {
1779 //
1780 // We have only two entry for Non-Sku enabled PCD entry:
1781 // 1) MAX SIZE
1782 // 2) Current Size
1783 //
1784 SizeTable[SizeTableIdx + 1] = (SIZE_INFO) *CurrentSize;
1785 return TRUE;
1786 } else {
1787 //
1788 // We have these entry for SKU enabled PCD entry
1789 // 1) MAX SIZE
1790 // 2) Current Size for each SKU_ID (It is equal to MaxSku).
1791 //
1792 SkuIdTable = GetSkuIdArray (LocalTokenNumberTableIdx, IsPeiDb);
1793 for (Index = 0; Index < SkuIdTable[0]; Index++) {
1794 if (SkuIdTable[1 + Index] == mPcdDatabase.PeiDb->SystemSkuId) {
1795 SizeTable[SizeTableIdx + 1 + Index] = (SIZE_INFO) *CurrentSize;
1796 return TRUE;
1797 }
1798 }
1799 SizeTable[SizeTableIdx + 1] = (SIZE_INFO) *CurrentSize;
1800 return TRUE;
1801 }
1802 }
1803 }