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