]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/PCD/Dxe/Service.c
MdeModulePkg: Update PCD driver to support the optimized PcdDataBase
[mirror_edk2.git] / MdeModulePkg / Universal / PCD / Dxe / Service.c
CommitLineData
80408db0 1/** @file\r
2ab6330e 2 Help functions used by PCD DXE driver.\r
80408db0 3\r
8cc87d32 4Copyright (c) 2014, Hewlett-Packard Development Company, L.P.<BR>\r
16f69227 5Copyright (c) 2006 - 2017, Intel Corporation. All rights reserved.<BR>\r
bfb4c2ba 6(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
e5eed7d3 7This program and the accompanying materials\r
80408db0 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
80408db0 15**/\r
80408db0 16\r
17#include "Service.h"\r
419db80b 18#include <Library/DxeServicesLib.h>\r
80408db0 19\r
419db80b
BF
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
80408db0 35\r
b07a5b68 36LIST_ENTRY *mCallbackFnTable;\r
419db80b
BF
37EFI_GUID **TmpTokenSpaceBuffer;\r
38UINTN TmpTokenSpaceBufferCount; \r
39\r
7c736265
LG
40UINTN mPeiPcdDbSize = 0;\r
41PEI_PCD_DATABASE *mPeiPcdDbBinary = NULL;\r
42UINTN mDxePcdDbSize = 0;\r
43DXE_PCD_DATABASE *mDxePcdDbBinary = NULL;\r
44\r
96d6d004
SZ
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
96d6d004
SZ
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
7c736265 73 return LocalTokenNumberTable[TokenNumber];\r
96d6d004
SZ
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
b5bd21b0 92 if ((LocalTokenNumber & PCD_DATUM_TYPE_UINT8_BOOLEAN) == PCD_DATUM_TYPE_UINT8_BOOLEAN) {\r
96d6d004
SZ
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
e85e284e 129 UINTN NameSize;\r
96d6d004
SZ
130 PCD_NAME_INDEX *PcdNameIndex;\r
131 CHAR8 *TokenSpaceName;\r
132 CHAR8 *PcdName;\r
133 CHAR8 *Name;\r
134\r
85d0b97d
SZ
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
96d6d004
SZ
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
e85e284e
QS
176 NameSize = AsciiStrSize (TokenSpaceName) + AsciiStrSize (PcdName);\r
177 Name = AllocateZeroPool (NameSize);\r
f47fc1cb 178 ASSERT (Name != NULL);\r
96d6d004
SZ
179 //\r
180 // Catenate TokenSpaceCName and PcdCName with a '.' to form the full PCD name.\r
181 //\r
e85e284e 182 AsciiStrCatS (Name, NameSize, TokenSpaceName);\r
96d6d004 183 Name[AsciiStrSize (TokenSpaceName) - sizeof (CHAR8)] = '.';\r
e85e284e 184 AsciiStrCatS (Name, NameSize, PcdName); \r
96d6d004
SZ
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
96d6d004
SZ
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
80408db0 352\r
2ab6330e 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
80408db0 367VOID *\r
368GetWorker (\r
2ab6330e 369 IN UINTN TokenNumber,\r
370 IN UINTN GetSize\r
80408db0 371 )\r
372{\r
80408db0 373 EFI_GUID *GuidTable;\r
d0965169 374 UINT8 *StringTable;\r
80408db0 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
80408db0 383 UINTN TmpTokenNumber;\r
384 UINTN DataSize;\r
385 EFI_STATUS Status;\r
386 UINT32 LocalTokenNumber;\r
387 UINT32 Offset;\r
6cfc7292 388 STRING_HEAD StringTableIdx; \r
80408db0 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
419db80b
BF
397\r
398 ASSERT (TokenNumber > 0);\r
80408db0 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
419db80b 407\r
80408db0 408 //\r
419db80b
BF
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
80408db0 411 // comparison.\r
412 //\r
419db80b 413 ASSERT (TokenNumber + 1 < mPcdTotalTokenCount + 1);\r
80408db0 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
419db80b 420 IsPeiDb = (BOOLEAN) ((TokenNumber + 1 < mPeiLocalTokenCount + 1) ? TRUE : FALSE);\r
80408db0 421\r
96d6d004 422 LocalTokenNumber = GetLocalTokenNumber (IsPeiDb, TokenNumber + 1);\r
80408db0 423\r
419db80b 424 PcdDb = IsPeiDb ? ((UINT8 *) mPcdDatabase.PeiDb) : ((UINT8 *) mPcdDatabase.DxeDb);\r
309e3122 425 \r
426 if (IsPeiDb) {\r
419db80b 427 StringTable = (UINT8 *) ((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->StringTableOffset);\r
309e3122 428 } else {\r
419db80b 429 StringTable = (UINT8 *) ((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->StringTableOffset);\r
309e3122 430 }\r
419db80b
BF
431\r
432\r
80408db0 433 Offset = LocalTokenNumber & PCD_DATABASE_OFFSET_MASK;\r
419db80b 434\r
80408db0 435 switch (LocalTokenNumber & PCD_TYPE_ALL_SET) {\r
436 case PCD_TYPE_VPD:\r
437 VpdHead = (VPD_HEAD *) ((UINT8 *) PcdDb + Offset);\r
16f69227 438 RetPtr = (VOID *) ((UINTN) PcdGet32 (PcdVpdBaseAddress) + VpdHead->Offset);\r
419db80b 439\r
80408db0 440 break;\r
419db80b 441\r
6ac15f7c 442 case PCD_TYPE_HII|PCD_TYPE_STRING:\r
80408db0 443 case PCD_TYPE_HII:\r
309e3122 444 if (IsPeiDb) {\r
419db80b 445 GuidTable = (EFI_GUID *) ((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->GuidTableOffset);\r
309e3122 446 } else {\r
419db80b 447 GuidTable = (EFI_GUID *) ((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->GuidTableOffset);\r
309e3122 448 }\r
419db80b 449\r
80408db0 450 VariableHead = (VARIABLE_HEAD *) (PcdDb + Offset);\r
1fef733c 451 Guid = GuidTable + VariableHead->GuidTableIndex;\r
d0965169 452 Name = (UINT16*)(StringTable + VariableHead->StringIndex);\r
419db80b 453\r
6ac15f7c 454 if ((LocalTokenNumber & PCD_TYPE_ALL_SET) == (PCD_TYPE_HII|PCD_TYPE_STRING)) {\r
419db80b
BF
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
6cfc7292 459 StringTableIdx = *(STRING_HEAD*)((UINT8 *) PcdDb + VariableHead->DefaultValueOffset); \r
553e8669 460 VaraiableDefaultBuffer = (UINT8 *) (StringTable + StringTableIdx); \r
6ac15f7c 461 } else {\r
462 VaraiableDefaultBuffer = (UINT8 *) PcdDb + VariableHead->DefaultValueOffset;\r
419db80b
BF
463 }\r
464 Status = GetHiiVariable (Guid, Name, &Data, &DataSize);\r
465 if (Status == EFI_SUCCESS) {\r
553e8669
SZ
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
0b1ef275 480 //\r
553e8669
SZ
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
0b1ef275 484 //\r
553e8669 485 CopyMem (VaraiableDefaultBuffer, Data + VariableHead->Offset, GetSize);\r
6ac15f7c 486 }\r
419db80b 487 FreePool (Data);\r
80408db0 488 }\r
419db80b 489 RetPtr = (VOID *) VaraiableDefaultBuffer;\r
80408db0 490 break;\r
491\r
492 case PCD_TYPE_STRING:\r
6cfc7292 493 StringTableIdx = *(STRING_HEAD*)((UINT8 *) PcdDb + Offset);\r
1fef733c 494 RetPtr = (VOID *) (StringTable + StringTableIdx);\r
80408db0 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
419db80b 508\r
80408db0 509 return RetPtr;\r
419db80b 510\r
80408db0 511}\r
512\r
2ab6330e 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
80408db0 523\r
2ab6330e 524 @return EFI_SUCCESS Always success for registering callback function.\r
80408db0 525\r
2ab6330e 526**/\r
80408db0 527EFI_STATUS\r
528DxeRegisterCallBackWorker (\r
529 IN UINTN TokenNumber,\r
2ab6330e 530 IN CONST EFI_GUID *Guid, OPTIONAL\r
80408db0 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
b07a5b68 545 // as the array index of mCallbackFnTable[].\r
80408db0 546 //\r
b07a5b68 547 ListHead = &mCallbackFnTable[TokenNumber - 1];\r
80408db0 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
2ab6330e 572/**\r
573 UnRegister the callback function for a PCD entry.\r
80408db0 574\r
2ab6330e 575 This routine will unregister a callback function to a PCD entry by given token number\r
576 and token space guid.\r
80408db0 577\r
2ab6330e 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
80408db0 582\r
2ab6330e 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
80408db0 586EFI_STATUS\r
587DxeUnRegisterCallBackWorker (\r
588 IN UINTN TokenNumber,\r
2ab6330e 589 IN CONST EFI_GUID *Guid, OPTIONAL\r
80408db0 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
b07a5b68 604 // as the array index of mCallbackFnTable[].\r
80408db0 605 //\r
b07a5b68 606 ListHead = &mCallbackFnTable[TokenNumber - 1];\r
80408db0 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
2ab6330e 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
80408db0 652\r
2ab6330e 653**/\r
80408db0 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
2ab6330e 665 UINTN Index;\r
80408db0 666 UINTN GuidTableIdx;\r
667 BOOLEAN Found;\r
419db80b 668 UINTN ExMapTableCount;\r
80408db0 669\r
2ab6330e 670 //\r
671 // Scan token space guid \r
672 // \r
80408db0 673 MatchGuid = ScanGuid (GuidTable, SizeOfGuidTable, Guid);\r
674 if (MatchGuid == NULL) {\r
675 return EFI_NOT_FOUND;\r
676 }\r
677\r
2ab6330e 678 //\r
679 // Find the token space table in dynamicEx mapping table.\r
680 //\r
80408db0 681 Found = FALSE;\r
682 GuidTableIdx = MatchGuid - GuidTable;\r
419db80b
BF
683 ExMapTableCount = SizeOfExMapTable / sizeof(ExMapTable[0]);\r
684 for (Index = 0; Index < ExMapTableCount; Index++) {\r
2ab6330e 685 if (ExMapTable[Index].ExGuidIndex == GuidTableIdx) {\r
80408db0 686 Found = TRUE;\r
687 break;\r
688 }\r
689 }\r
690\r
691 if (Found) {\r
2ab6330e 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
80408db0 696 if (*TokenNumber == PCD_INVALID_TOKEN_NUMBER) {\r
2ab6330e 697 *TokenNumber = ExMapTable[Index].ExTokenNumber;\r
80408db0 698 return EFI_SUCCESS;\r
699 }\r
700\r
419db80b 701 for ( ; Index < ExMapTableCount; Index++) {\r
bfb4c2ba 702 if ((ExMapTable[Index].ExTokenNumber == *TokenNumber) && (ExMapTable[Index].ExGuidIndex == GuidTableIdx)) {\r
419db80b
BF
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
80408db0 721 }\r
722 }\r
723 }\r
419db80b 724\r
80408db0 725 return EFI_NOT_FOUND;\r
726}\r
80408db0 727\r
419db80b
BF
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
419db80b
BF
739 EFI_STATUS Status;\r
740 \r
419db80b
BF
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
7c736265
LG
748 (VOID **) &mDxePcdDbBinary,\r
749 &mDxePcdDbSize\r
419db80b
BF
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
7c736265
LG
756 if (!CompareGuid ((VOID *)mDxePcdDbBinary, &gPcdDataBaseSignatureGuid) ||\r
757 (mDxePcdDbBinary->BuildVersion != PCD_SERVICE_DXE_VERSION)) {\r
419db80b
BF
758 ASSERT (FALSE);\r
759 }\r
760\r
7c736265
LG
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 == (UINT16) 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
419db80b 837}\r
80408db0 838\r
2ab6330e 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
80408db0 844\r
2ab6330e 845**/\r
80408db0 846VOID\r
847BuildPcdDxeDataBase (\r
848 VOID\r
849 )\r
850{\r
851 PEI_PCD_DATABASE *PeiDatabase;\r
852 EFI_HOB_GUID_TYPE *GuidHob;\r
2ab6330e 853 UINTN Index;\r
419db80b
BF
854 UINT32 PcdDxeDbLen;\r
855 VOID *PcdDxeDb;\r
7c736265 856 EFI_STATUS Status;\r
80408db0 857\r
efd6b412
SZ
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
efd6b412
SZ
867 mPcdDatabase.DxeDb = PcdDxeDb;\r
868\r
80408db0 869 GuidHob = GetFirstGuidHob (&gPcdDataBaseHobGuid);\r
870 if (GuidHob != NULL) {\r
871\r
80408db0 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
80408db0 878 PeiDatabase = (PEI_PCD_DATABASE *) GET_GUID_HOB_DATA (GuidHob);\r
7c736265
LG
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
80408db0 889 //\r
419db80b 890 // Assign PCD Entries refereneced in PEI phase to PCD DATABASE\r
80408db0 891 //\r
419db80b 892 mPcdDatabase.PeiDb = PeiDatabase;\r
efd6b412
SZ
893 //\r
894 // Inherit the SystemSkuId from PEI phase.\r
895 //\r
7c736265
LG
896 if (mPcdDatabase.PeiDb->SystemSkuId != 0) {\r
897 Status = UpdatePcdDatabase (mPcdDatabase.PeiDb->SystemSkuId, FALSE);\r
898 ASSERT_EFI_ERROR (Status);\r
899 }\r
efd6b412
SZ
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
80408db0 904 }\r
905\r
419db80b
BF
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
80408db0 927\r
928 //\r
929 // Initialized the Callback Function Table\r
930 //\r
419db80b 931 mCallbackFnTable = AllocateZeroPool (mPcdTotalTokenCount * sizeof (LIST_ENTRY));\r
3fd8027e 932 ASSERT(mCallbackFnTable != NULL);\r
419db80b
BF
933\r
934 //\r
80408db0 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
419db80b
BF
938 //\r
939 for (Index = 0; Index + 1 < mPcdTotalTokenCount + 1; Index++) {\r
2ab6330e 940 InitializeListHead (&mCallbackFnTable[Index]);\r
80408db0 941 }\r
80408db0 942}\r
943\r
2ab6330e 944/**\r
945 Get Variable which contains HII type PCD entry.\r
80408db0 946\r
2ab6330e 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
80408db0 951\r
2ab6330e 952 @return the status of gRT->GetVariable\r
953**/\r
80408db0 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
2ab6330e 969 //\r
970 // Firstly get the real size of HII variable\r
971 //\r
80408db0 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
2ab6330e 980 //\r
981 // Allocate buffer to hold whole variable data according to variable size.\r
982 //\r
80408db0 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
0b1ef275
LG
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
80408db0 1005 }\r
1006\r
1007 return Status;\r
1008}\r
1009\r
2ab6330e 1010/**\r
1011 Invoke the callback function when dynamic PCD entry was set, if this PCD entry \r
1012 has registered callback function.\r
80408db0 1013\r
2ab6330e 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
80408db0 1021\r
2ab6330e 1022**/\r
80408db0 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
b07a5b68 1039 // as the array index of mCallbackFnTable[].\r
80408db0 1040 //\r
b07a5b68 1041 ListHead = &mCallbackFnTable[TokenNumber - 1];\r
80408db0 1042 ListNode = GetFirstNode (ListHead);\r
1043\r
1044 while (ListNode != ListHead) {\r
b07a5b68 1045 FnTableEntry = CR_FNENTRY_FROM_LISTNODE (ListNode, CALLBACK_FN_ENTRY, Node);\r
80408db0 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
2ab6330e 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
80408db0 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
2ab6330e 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
149fb6d6 1091 @retval EFI_INVALID_PARAMETER If Size of non-Ptr type PCD does not match the size information in PCD database. \r
2ab6330e 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
80408db0 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
80408db0 1104 BOOLEAN IsPeiDb;\r
1105 UINT32 LocalTokenNumber;\r
1106 EFI_GUID *GuidTable;\r
d0965169 1107 UINT8 *StringTable;\r
80408db0 1108 EFI_GUID *Guid;\r
1109 UINT16 *Name;\r
1110 UINTN VariableOffset;\r
23f3e119 1111 UINT32 Attributes;\r
80408db0 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
80408db0 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
2ab6330e 1129 //\r
80408db0 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
2ab6330e 1133 //\r
419db80b 1134 ASSERT (TokenNumber + 1 < mPcdTotalTokenCount + 1);\r
80408db0 1135\r
8ec8bed4 1136 if (PtrType) {\r
64894410
LG
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
cb40609c 1142 *Size = MaxSize;\r
8ec8bed4 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
80408db0 1149 }\r
b07a5b68 1150\r
2ab6330e 1151 //\r
80408db0 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
2ab6330e 1155 //\r
419db80b
BF
1156 if ((TokenNumber + 1 < mPeiNexTokenCount + 1) ||\r
1157 (TokenNumber + 1 >= mPeiLocalTokenCount + 1 && TokenNumber + 1 < (mPeiLocalTokenCount + mDxeNexTokenCount + 1))) {\r
b07a5b68 1158 InvokeCallbackOnSet (0, NULL, TokenNumber + 1, Data, *Size);\r
1159 }\r
80408db0 1160\r
b07a5b68 1161 //\r
1162 // Aquire lock to prevent reentrance from TPL_CALLBACK level\r
1163 //\r
1164 EfiAcquireLock (&mPcdDatabaseLock);\r
80408db0 1165\r
2ab6330e 1166 //\r
80408db0 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
2ab6330e 1170 //\r
419db80b 1171 IsPeiDb = (BOOLEAN) ((TokenNumber + 1 < mPeiLocalTokenCount + 1) ? TRUE : FALSE);\r
b07a5b68 1172\r
96d6d004 1173 LocalTokenNumber = GetLocalTokenNumber (IsPeiDb, TokenNumber + 1);\r
80408db0 1174\r
1175 Offset = LocalTokenNumber & PCD_DATABASE_OFFSET_MASK;\r
1176\r
419db80b 1177 PcdDb = IsPeiDb ? ((UINT8 *) mPcdDatabase.PeiDb) : ((UINT8 *) mPcdDatabase.DxeDb);\r
80408db0 1178\r
309e3122 1179 if (IsPeiDb) {\r
419db80b 1180 StringTable = (UINT8 *) ((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->StringTableOffset);\r
309e3122 1181 } else {\r
419db80b 1182 StringTable = (UINT8 *) ((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->StringTableOffset);\r
309e3122 1183 }\r
1184\r
80408db0 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
6cfc7292 1196 CopyMem (StringTable + *((STRING_HEAD *)InternalData), Data, *Size);\r
80408db0 1197 Status = EFI_SUCCESS;\r
1198 } else {\r
1199 Status = EFI_INVALID_PARAMETER;\r
1200 }\r
1201 break;\r
1202\r
6ac15f7c 1203 case PCD_TYPE_HII|PCD_TYPE_STRING:\r
80408db0 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
419db80b 1211\r
309e3122 1212 if (IsPeiDb) {\r
419db80b 1213 GuidTable = (EFI_GUID *) ((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->GuidTableOffset);\r
309e3122 1214 } else {\r
419db80b 1215 GuidTable = (EFI_GUID *) ((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->GuidTableOffset);\r
309e3122 1216 }\r
419db80b 1217\r
80408db0 1218 VariableHead = (VARIABLE_HEAD *) (PcdDb + Offset);\r
419db80b 1219\r
1fef733c 1220 Guid = GuidTable + VariableHead->GuidTableIndex;\r
d0965169 1221 Name = (UINT16*) (StringTable + VariableHead->StringIndex);\r
80408db0 1222 VariableOffset = VariableHead->Offset;\r
23f3e119
SZ
1223 Attributes = VariableHead->Attributes;\r
1224 Status = SetHiiVariable (Guid, Name, Attributes, Data, *Size, VariableOffset);\r
80408db0 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
2ab6330e 1274/**\r
1275 Wrapper function for get PCD value for dynamic-ex PCD.\r
80408db0 1276\r
2ab6330e 1277 @param Guid Token space guid for dynamic-ex PCD.\r
3fd8027e 1278 @param ExTokenNumber Token number for dynamic-ex PCD.\r
2ab6330e 1279 @param GetSize The size of dynamic-ex PCD value.\r
80408db0 1280\r
2ab6330e 1281 @return PCD entry in PCD database.\r
80408db0 1282\r
2ab6330e 1283**/\r
80408db0 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
2ab6330e 1294/**\r
1295 Wrapper function for set PCD value for non-Pointer type dynamic-ex PCD.\r
80408db0 1296\r
2ab6330e 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
80408db0 1301\r
2ab6330e 1302 @return status of ExSetWorker().\r
80408db0 1303\r
2ab6330e 1304**/\r
80408db0 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
2ab6330e 1316/**\r
419db80b 1317 Set value for a dynamic-ex PCD entry.\r
2ab6330e 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
80408db0 1332\r
2ab6330e 1333**/\r
80408db0 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
c73cf875
SZ
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
2ab6330e 1431/**\r
1432 Set value for HII-type PCD.\r
80408db0 1433\r
2ab6330e 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
23f3e119 1439 @param SetAttributes Attributes bitmask to set for the variable.\r
2ab6330e 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
80408db0 1443\r
2ab6330e 1444 @return status of GetVariable()/SetVariable().\r
80408db0 1445\r
2ab6330e 1446**/\r
80408db0 1447EFI_STATUS\r
1448SetHiiVariable (\r
1449 IN EFI_GUID *VariableGuid,\r
1450 IN UINT16 *VariableName,\r
23f3e119 1451 IN UINT32 SetAttributes,\r
80408db0 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
b13151ff 1461 UINTN SetSize;\r
80408db0 1462\r
1463 Size = 0;\r
b13151ff 1464 SetSize = 0;\r
80408db0 1465\r
746be876 1466 //\r
1467 // Try to get original variable size information.\r
1468 //\r
80408db0 1469 Status = gRT->GetVariable (\r
1470 (UINT16 *)VariableName,\r
1471 VariableGuid,\r
1472 NULL,\r
1473 &Size,\r
1474 NULL\r
1475 );\r
b13151ff 1476 \r
80408db0 1477 if (Status == EFI_BUFFER_TOO_SMALL) {\r
746be876 1478 //\r
1479 // Patch new PCD's value to offset in given HII variable.\r
1480 //\r
23f3e119 1481 if (Size >= (DataSize + Offset)) {\r
b13151ff
LG
1482 SetSize = Size;\r
1483 } else {\r
1484 SetSize = DataSize + Offset;\r
1485 }\r
1486 Buffer = AllocatePool (SetSize);\r
80408db0 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
23f3e119
SZ
1501 if (SetAttributes == 0) {\r
1502 SetAttributes = Attribute;\r
1503 }\r
1504\r
80408db0 1505 Status = gRT->SetVariable (\r
1506 VariableName,\r
1507 VariableGuid,\r
23f3e119 1508 SetAttributes,\r
b13151ff 1509 SetSize,\r
80408db0 1510 Buffer\r
1511 );\r
1512\r
1513 FreePool (Buffer);\r
1514 return Status;\r
746be876 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
c73cf875
SZ
1519\r
1520 //\r
1521 // Get size, allocate buffer and get data.\r
1522 //\r
1523 GetVariableSizeAndDataFromHiiPcd (VariableGuid, VariableName, &Size, NULL);\r
746be876 1524 Buffer = AllocateZeroPool (Size);\r
1525 ASSERT (Buffer != NULL);\r
c73cf875
SZ
1526 GetVariableSizeAndDataFromHiiPcd (VariableGuid, VariableName, &Size, Buffer);\r
1527\r
1528 //\r
1529 // Update buffer.\r
1530 //\r
746be876 1531 CopyMem ((UINT8 *)Buffer + Offset, Data, DataSize);\r
23f3e119
SZ
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
746be876 1537 Status = gRT->SetVariable (\r
1538 VariableName,\r
1539 VariableGuid,\r
23f3e119 1540 SetAttributes,\r
746be876 1541 Size,\r
1542 Buffer\r
1543 );\r
1544\r
1545 FreePool (Buffer);\r
1546 return Status; \r
1547 }\r
80408db0 1548 \r
1549 //\r
23f3e119 1550 // If we drop to here, the value is failed to be written in to variable area.\r
80408db0 1551 //\r
1552 return Status;\r
1553}\r
1554\r
2ab6330e 1555/**\r
419db80b 1556 Get Token Number according to dynamic-ex PCD's {token space guid:token number}\r
80408db0 1557\r
2ab6330e 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
419db80b 1560 space guid: token number} to Token Number.\r
2ab6330e 1561 \r
1562 @param Guid Token space guid for dynamic-ex PCD entry.\r
b9982883 1563 @param ExTokenNumber Dynamic-ex PCD token number.\r
80408db0 1564\r
419db80b 1565 @return Token Number for dynamic-ex PCD.\r
80408db0 1566\r
2ab6330e 1567**/\r
80408db0 1568UINTN \r
1569GetExPcdTokenNumber (\r
1570 IN CONST EFI_GUID *Guid,\r
1571 IN UINT32 ExTokenNumber\r
1572 )\r
1573{\r
2ab6330e 1574 UINT32 Index;\r
80408db0 1575 DYNAMICEX_MAPPING *ExMap;\r
1576 EFI_GUID *GuidTable;\r
1577 EFI_GUID *MatchGuid;\r
1578 UINTN MatchGuidIdx;\r
1579\r
419db80b
BF
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
80408db0 1586 if (MatchGuid != NULL) {\r
1587\r
1588 MatchGuidIdx = MatchGuid - GuidTable;\r
419db80b 1589\r
8cc87d32 1590 for (Index = 0; Index < mPcdDatabase.PeiDb->ExTokenCount; Index++) {\r
2ab6330e 1591 if ((ExTokenNumber == ExMap[Index].ExTokenNumber) &&\r
1592 (MatchGuidIdx == ExMap[Index].ExGuidIndex)) {\r
419db80b 1593 return ExMap[Index].TokenNumber;\r
80408db0 1594 }\r
1595 }\r
1596 }\r
1597 }\r
80408db0 1598\r
419db80b
BF
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
80408db0 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
419db80b 1610\r
8cc87d32 1611 for (Index = 0; Index < mPcdDatabase.DxeDb->ExTokenCount; Index++) {\r
2ab6330e 1612 if ((ExTokenNumber == ExMap[Index].ExTokenNumber) &&\r
1613 (MatchGuidIdx == ExMap[Index].ExGuidIndex)) {\r
419db80b 1614 return ExMap[Index].TokenNumber;\r
80408db0 1615 }\r
1616 }\r
1617\r
1618 ASSERT (FALSE);\r
1619\r
1620 return 0;\r
1621}\r
1622\r
2ab6330e 1623/**\r
3d53ba8b 1624 Wrapper function of getting index of PCD entry in size table.\r
1625 \r
2ab6330e 1626 @param LocalTokenNumberTableIdx Index of this PCD in local token number table.\r
2ab6330e 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
2ab6330e 1631**/\r
80408db0 1632UINTN\r
3d53ba8b 1633GetSizeTableIndex (\r
1634 IN UINTN LocalTokenNumberTableIdx,\r
1635 IN BOOLEAN IsPeiDb\r
80408db0 1636 )\r
1637{\r
3d53ba8b 1638 UINT32 *LocalTokenNumberTable;\r
1639 UINTN LocalTokenNumber;\r
1640 UINTN Index;\r
1641 UINTN SizeTableIdx;\r
80408db0 1642 \r
3d53ba8b 1643 if (IsPeiDb) {\r
419db80b 1644 LocalTokenNumberTable = (UINT32 *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->LocalTokenNumberTableOffset);\r
3d53ba8b 1645 } else {\r
419db80b 1646 LocalTokenNumberTable = (UINT32 *)((UINT8 *)mPcdDatabase.DxeDb + mPcdDatabase.DxeDb->LocalTokenNumberTableOffset);\r
3d53ba8b 1647 }\r
1648\r
80408db0 1649 SizeTableIdx = 0;\r
1650\r
3d53ba8b 1651 for (Index = 0; Index < LocalTokenNumberTableIdx; Index ++) {\r
2ab6330e 1652 LocalTokenNumber = LocalTokenNumberTable[Index];\r
80408db0 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
2ab6330e 1659 if ((LocalTokenNumber & PCD_TYPE_VPD) != 0) {\r
80408db0 1660 //\r
419db80b 1661 // We have only two entry for VPD enabled PCD entry:\r
80408db0 1662 // 1) MAX Size.\r
419db80b
BF
1663 // 2) Current Size\r
1664 // Current size is equal to MAX size.\r
80408db0 1665 //\r
419db80b 1666 SizeTableIdx += 2;\r
80408db0 1667 } else {\r
80408db0 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
80408db0 1674 }\r
1675 }\r
1676\r
1677 }\r
1678\r
3d53ba8b 1679 return SizeTableIdx; \r
80408db0 1680}\r
1681\r
2ab6330e 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
80408db0 1687\r
2ab6330e 1688 @return size of POINTER type PCD value.\r
80408db0 1689\r
2ab6330e 1690**/\r
80408db0 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
80408db0 1699 SIZE_INFO *SizeTable;\r
80408db0 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
419db80b 1706 IsPeiDb = (BOOLEAN) (LocalTokenNumberTableIdx + 1 < mPeiLocalTokenCount + 1);\r
80408db0 1707\r
1708\r
1709 if (IsPeiDb) {\r
419db80b
BF
1710 LocalTokenNumberTable = (UINT32 *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->LocalTokenNumberTableOffset);\r
1711 SizeTable = (SIZE_INFO *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->SizeTableOffset);\r
80408db0 1712 } else {\r
419db80b
BF
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
80408db0 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
2ab6330e 1729 if ((LocalTokenNumber & PCD_TYPE_VPD) != 0) {\r
80408db0 1730 //\r
419db80b 1731 // We have only two entry for VPD enabled PCD entry:\r
80408db0 1732 // 1) MAX Size.\r
419db80b 1733 // 2) Current Size\r
80408db0 1734 // We consider current size is equal to MAX size.\r
1735 //\r
1736 return *MaxSize;\r
1737 } else {\r
80408db0 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
80408db0 1744 }\r
1745}\r
1746\r
2ab6330e 1747/**\r
3fd8027e 1748 Set size of POINTER type PCD value. The size should not exceed the maximum size\r
2ab6330e 1749 of this PCD value.\r
80408db0 1750\r
2ab6330e 1751 @param LocalTokenNumberTableIdx Index of local token number in local token number table.\r
1752 @param CurrentSize Size of POINTER type PCD value.\r
80408db0 1753\r
2ab6330e 1754 @retval TRUE Success to set size of PCD value.\r
1755 @retval FALSE Fail to set size of PCD value.\r
1756**/\r
80408db0 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
80408db0 1765 SIZE_INFO *SizeTable;\r
80408db0 1766 UINTN MaxSize;\r
1767 BOOLEAN IsPeiDb;\r
1768 UINT32 *LocalTokenNumberTable;\r
1769\r
2ab6330e 1770 //\r
80408db0 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
2ab6330e 1774 //\r
419db80b 1775 IsPeiDb = (BOOLEAN) (LocalTokenNumberTableIdx + 1 < mPeiLocalTokenCount + 1);\r
80408db0 1776\r
1777 if (IsPeiDb) {\r
419db80b
BF
1778 LocalTokenNumberTable = (UINT32 *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->LocalTokenNumberTableOffset);\r
1779 SizeTable = (SIZE_INFO *)((UINT8 *)mPcdDatabase.PeiDb + mPcdDatabase.PeiDb->SizeTableOffset);\r
80408db0 1780 } else {\r
419db80b
BF
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
80408db0 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
2ab6330e 1797 if ((LocalTokenNumber & PCD_TYPE_VPD) != 0) {\r
80408db0 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
7c736265
LG
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
80408db0 1817 }\r
1818}\r
23f3e119
SZ
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
a856128a 1852 for (TokenNumber = 1; TokenNumber <= LocalTokenCount; TokenNumber++) {\r
23f3e119
SZ
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