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