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