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