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