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