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