]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Universal/PCD/Pei/Service.c
MdePkg and MdeModulePkg Pcd: Implement PCD Driver for External PCD Database and SKU...
[mirror_edk2.git] / MdeModulePkg / Universal / PCD / Pei / Service.c
... / ...
CommitLineData
1/** @file\r
2 The driver internal functions are implmented here.\r
3 They build Pei PCD database, and provide access service to PCD database.\r
4\r
5Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
6This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
13\r
14**/\r
15\r
16#include "Service.h"\r
17\r
18/**\r
19 The function registers the CallBackOnSet fucntion\r
20 according to TokenNumber and EFI_GUID space.\r
21\r
22 @param ExTokenNumber The token number.\r
23 @param Guid The GUID space.\r
24 @param CallBackFunction The Callback function to be registered.\r
25 @param Register To register or unregister the callback function.\r
26\r
27 @retval EFI_SUCCESS If the Callback function is registered.\r
28 @retval EFI_NOT_FOUND If the PCD Entry is not found according to Token Number and GUID space.\r
29 @retval EFI_OUT_OF_RESOURCES If the callback function can't be registered because there is not free\r
30 slot left in the CallbackFnTable.\r
31 @retval EFI_INVALID_PARAMETER If the callback function want to be de-registered can not be found.\r
32**/\r
33EFI_STATUS\r
34PeiRegisterCallBackWorker (\r
35 IN UINTN ExTokenNumber,\r
36 IN CONST EFI_GUID *Guid, OPTIONAL\r
37 IN PCD_PPI_CALLBACK CallBackFunction,\r
38 IN BOOLEAN Register\r
39)\r
40{\r
41 EFI_HOB_GUID_TYPE *GuidHob;\r
42 PCD_PPI_CALLBACK *CallbackTable;\r
43 PCD_PPI_CALLBACK Compare;\r
44 PCD_PPI_CALLBACK Assign;\r
45 UINT32 LocalTokenNumber;\r
46 UINT32 LocalTokenCount;\r
47 UINTN PeiNexTokenNumber;\r
48 UINTN TokenNumber;\r
49 UINTN Idx;\r
50 PEI_PCD_DATABASE *PeiPcdDb;\r
51\r
52 PeiPcdDb = GetPcdDatabase();\r
53 LocalTokenCount = PeiPcdDb->LocalTokenCount;\r
54 PeiNexTokenNumber = PeiPcdDb->LocalTokenCount - PeiPcdDb->ExTokenCount;\r
55\r
56 if (Guid == NULL) {\r
57 TokenNumber = ExTokenNumber;\r
58 //\r
59 // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.\r
60 // We have to decrement TokenNumber by 1 to make it usable\r
61 // as the array index.\r
62 //\r
63 TokenNumber--;\r
64 ASSERT (TokenNumber + 1 < (PeiNexTokenNumber + 1));\r
65 } else {\r
66 TokenNumber = GetExPcdTokenNumber (Guid, ExTokenNumber);\r
67 if (TokenNumber == PCD_INVALID_TOKEN_NUMBER) {\r
68 return EFI_NOT_FOUND;\r
69 }\r
70 //\r
71 // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.\r
72 // We have to decrement TokenNumber by 1 to make it usable\r
73 // as the array index.\r
74 //\r
75 TokenNumber--;\r
76 // EBC compiler is very choosy. It may report warning about comparison\r
77 // between UINTN and 0 . So we add 1 in each size of the \r
78 // comparison.\r
79 ASSERT ((TokenNumber + 1) < (LocalTokenCount + 1));\r
80 }\r
81\r
82\r
83 LocalTokenNumber = *((UINT32 *)((UINT8 *)PeiPcdDb + PeiPcdDb->LocalTokenNumberTableOffset) + TokenNumber);\r
84\r
85 //\r
86 // We don't support SET for HII and VPD type PCD entry in PEI phase.\r
87 // So we will assert if any register callback for such PCD entry.\r
88 //\r
89 ASSERT ((LocalTokenNumber & PCD_TYPE_HII) == 0);\r
90 ASSERT ((LocalTokenNumber & PCD_TYPE_VPD) == 0);\r
91\r
92 GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);\r
93 ASSERT (GuidHob != NULL);\r
94 \r
95 CallbackTable = GET_GUID_HOB_DATA (GuidHob);\r
96 CallbackTable = CallbackTable + (TokenNumber * PcdGet32 (PcdMaxPeiPcdCallBackNumberPerPcdEntry));\r
97\r
98 Compare = Register? NULL: CallBackFunction;\r
99 Assign = Register? CallBackFunction: NULL;\r
100\r
101\r
102 for (Idx = 0; Idx < PcdGet32 (PcdMaxPeiPcdCallBackNumberPerPcdEntry); Idx++) {\r
103 if (CallbackTable[Idx] == Compare) {\r
104 CallbackTable[Idx] = Assign;\r
105 return EFI_SUCCESS;\r
106 }\r
107 }\r
108\r
109 return Register? EFI_OUT_OF_RESOURCES : EFI_INVALID_PARAMETER;\r
110\r
111}\r
112\r
113\r
114/**\r
115 Find the Pcd database. \r
116\r
117 @param FileHandle Handle of the file the external PCD database binary located.\r
118\r
119 @retval The base address of external PCD database binary.\r
120 @retval NULL Return NULL if not find.\r
121**/\r
122VOID *\r
123LocateExPcdBinary (\r
124 IN EFI_PEI_FILE_HANDLE FileHandle\r
125 )\r
126{\r
127 EFI_STATUS Status;\r
128 VOID *PcdDb;\r
129\r
130 PcdDb = NULL;\r
131\r
132 ASSERT (FileHandle != NULL);\r
133\r
134 Status = PeiServicesFfsFindSectionData (EFI_SECTION_RAW, FileHandle, &PcdDb);\r
135 ASSERT_EFI_ERROR (Status);\r
136\r
137 //\r
138 // Check the first bytes (Header Signature Guid) and build version.\r
139 //\r
140 if (!CompareGuid (PcdDb, &gPcdDataBaseSignatureGuid) ||\r
141 (((PEI_PCD_DATABASE *) PcdDb)->BuildVersion != PCD_SERVICE_PEIM_VERSION)) {\r
142 ASSERT (FALSE);\r
143 }\r
144 return PcdDb;\r
145}\r
146\r
147\r
148/**\r
149 The function builds the PCD database.\r
150\r
151 @param FileHandle Handle of the file the external PCD database binary located.\r
152\r
153**/\r
154VOID\r
155BuildPcdDatabase (\r
156 IN EFI_PEI_FILE_HANDLE FileHandle\r
157 )\r
158{\r
159 PEI_PCD_DATABASE *Database;\r
160 PEI_PCD_DATABASE *PeiPcdDbBinary;\r
161 VOID *CallbackFnTable;\r
162 UINTN SizeOfCallbackFnTable;\r
163\r
164 //\r
165 // Locate the external PCD database binary for one section of current FFS\r
166 //\r
167 PeiPcdDbBinary = LocateExPcdBinary (FileHandle);\r
168\r
169 ASSERT(PeiPcdDbBinary != NULL);\r
170\r
171 Database = BuildGuidHob (&gPcdDataBaseHobGuid, PeiPcdDbBinary->Length + PeiPcdDbBinary->UninitDataBaseSize);\r
172\r
173 ZeroMem (Database, PeiPcdDbBinary->Length + PeiPcdDbBinary->UninitDataBaseSize);\r
174\r
175 //\r
176 // PeiPcdDbBinary is smaller than Database\r
177 //\r
178 CopyMem (Database, PeiPcdDbBinary, PeiPcdDbBinary->Length);\r
179\r
180 SizeOfCallbackFnTable = Database->LocalTokenCount * sizeof (PCD_PPI_CALLBACK) * PcdGet32 (PcdMaxPeiPcdCallBackNumberPerPcdEntry);\r
181\r
182 CallbackFnTable = BuildGuidHob (&gEfiCallerIdGuid, SizeOfCallbackFnTable);\r
183 \r
184 ZeroMem (CallbackFnTable, SizeOfCallbackFnTable);\r
185}\r
186\r
187/**\r
188 The function is provided by PCD PEIM and PCD DXE driver to\r
189 do the work of reading a HII variable from variable service.\r
190\r
191 @param VariableGuid The Variable GUID.\r
192 @param VariableName The Variable Name.\r
193 @param VariableData The output data.\r
194 @param VariableSize The size of the variable.\r
195\r
196 @retval EFI_SUCCESS Operation successful.\r
197 @retval EFI_NOT_FOUND Variablel not found.\r
198**/\r
199EFI_STATUS\r
200GetHiiVariable (\r
201 IN CONST EFI_GUID *VariableGuid,\r
202 IN UINT16 *VariableName,\r
203 OUT VOID **VariableData,\r
204 OUT UINTN *VariableSize\r
205 )\r
206{\r
207 UINTN Size;\r
208 EFI_STATUS Status;\r
209 VOID *Buffer;\r
210 EFI_PEI_READ_ONLY_VARIABLE2_PPI *VariablePpi;\r
211\r
212 Status = PeiServicesLocatePpi (&gEfiPeiReadOnlyVariable2PpiGuid, 0, NULL, (VOID **) &VariablePpi);\r
213 ASSERT_EFI_ERROR (Status);\r
214\r
215 Size = 0;\r
216 Status = VariablePpi->GetVariable (\r
217 VariablePpi,\r
218 VariableName,\r
219 (EFI_GUID *) VariableGuid,\r
220 NULL,\r
221 &Size,\r
222 NULL\r
223 );\r
224\r
225 if (Status == EFI_BUFFER_TOO_SMALL) {\r
226 Status = PeiServicesAllocatePool (Size, &Buffer);\r
227 ASSERT_EFI_ERROR (Status);\r
228\r
229 Status = VariablePpi->GetVariable (\r
230 VariablePpi,\r
231 (UINT16 *) VariableName,\r
232 (EFI_GUID *) VariableGuid,\r
233 NULL,\r
234 &Size,\r
235 Buffer\r
236 );\r
237 ASSERT_EFI_ERROR (Status);\r
238\r
239 *VariableSize = Size;\r
240 *VariableData = Buffer;\r
241\r
242 return EFI_SUCCESS;\r
243 }\r
244\r
245 return EFI_NOT_FOUND;\r
246}\r
247\r
248/**\r
249 Find the local token number according to system SKU ID.\r
250\r
251 @param LocalTokenNumber PCD token number\r
252 @param Size The size of PCD entry.\r
253\r
254 @return Token number according to system SKU ID.\r
255\r
256**/\r
257UINT32\r
258GetSkuEnabledTokenNumber (\r
259 UINT32 LocalTokenNumber,\r
260 UINTN Size\r
261 ) \r
262{\r
263 PEI_PCD_DATABASE *PeiPcdDb;\r
264 SKU_HEAD *SkuHead;\r
265 SKU_ID *SkuIdTable;\r
266 INTN Index;\r
267 UINT8 *Value;\r
268 BOOLEAN FoundSku;\r
269\r
270 PeiPcdDb = GetPcdDatabase ();\r
271\r
272 ASSERT ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == 0);\r
273\r
274 SkuHead = (SKU_HEAD *) ((UINT8 *)PeiPcdDb + (LocalTokenNumber & PCD_DATABASE_OFFSET_MASK));\r
275 Value = (UINT8 *) ((UINT8 *)PeiPcdDb + (SkuHead->SkuDataStartOffset));\r
276 SkuIdTable = (SKU_ID *) ((UINT8 *)PeiPcdDb + (SkuHead->SkuIdTableOffset));\r
277\r
278 //\r
279 // Find the current system's SKU ID entry in SKU ID table.\r
280 //\r
281 FoundSku = FALSE;\r
282 for (Index = 0; Index < SkuIdTable[0]; Index++) {\r
283 if (PeiPcdDb->SystemSkuId == SkuIdTable[Index + 1]) {\r
284 FoundSku = TRUE;\r
285 break;\r
286 }\r
287 }\r
288\r
289 //\r
290 // Find the default SKU ID entry in SKU ID table.\r
291 //\r
292 if(!FoundSku) {\r
293 for (Index = 0; Index < SkuIdTable[0]; Index++) {\r
294 if (0 == SkuIdTable[Index + 1]) {\r
295 break;\r
296 }\r
297 }\r
298 }\r
299 ASSERT (Index < SkuIdTable[0]);\r
300\r
301 switch (LocalTokenNumber & PCD_TYPE_ALL_SET) {\r
302 case PCD_TYPE_VPD:\r
303 Value = (UINT8 *) &(((VPD_HEAD *) Value)[Index]);\r
304 return (UINT32) ((Value - (UINT8 *) PeiPcdDb) | PCD_TYPE_VPD);\r
305\r
306 case PCD_TYPE_HII:\r
307 Value = (UINT8 *) &(((VARIABLE_HEAD *) Value)[Index]);\r
308 return (UINT32) ((Value - (UINT8 *) PeiPcdDb) | PCD_TYPE_HII);\r
309\r
310 case PCD_TYPE_HII|PCD_TYPE_STRING:\r
311 Value = (UINT8 *) &(((VARIABLE_HEAD *) Value)[Index]);\r
312 return (UINT32) ((Value - (UINT8 *) PeiPcdDb) | PCD_TYPE_HII | PCD_TYPE_STRING);\r
313\r
314 case PCD_TYPE_STRING:\r
315 Value = (UINT8 *) &(((STRING_HEAD *) Value)[Index]);\r
316 return (UINT32) ((Value - (UINT8 *) PeiPcdDb) | PCD_TYPE_STRING);\r
317\r
318 case PCD_TYPE_DATA:\r
319 Value += Size * Index;\r
320 return (UINT32) ((Value - (UINT8 *) PeiPcdDb) | PCD_TYPE_DATA);\r
321\r
322 default:\r
323 ASSERT (FALSE);\r
324 }\r
325\r
326 ASSERT (FALSE);\r
327\r
328 return 0;\r
329}\r
330\r
331/**\r
332 Invoke the callback function when dynamic PCD entry was set, if this PCD entry \r
333 has registered callback function.\r
334\r
335 @param ExTokenNumber DynamicEx PCD's token number, if this PCD entry is dyanmicEx\r
336 type PCD.\r
337 @param Guid DynamicEx PCD's guid, if this PCD entry is dynamicEx type\r
338 PCD.\r
339 @param TokenNumber PCD token number generated by build tools.\r
340 @param Data Value want to be set for this PCD entry\r
341 @param Size The size of value\r
342\r
343**/\r
344VOID\r
345InvokeCallbackOnSet (\r
346 UINTN ExTokenNumber,\r
347 CONST EFI_GUID *Guid, OPTIONAL\r
348 UINTN TokenNumber,\r
349 VOID *Data,\r
350 UINTN Size\r
351 )\r
352{\r
353 EFI_HOB_GUID_TYPE *GuidHob;\r
354 PCD_PPI_CALLBACK *CallbackTable;\r
355 UINTN Idx;\r
356 PEI_PCD_DATABASE *PeiPcdDb;\r
357 UINT32 LocalTokenCount;\r
358\r
359 //\r
360 // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.\r
361 // We have to decrement TokenNumber by 1 to make it usable\r
362 // as the array index.\r
363 //\r
364 TokenNumber--;\r
365\r
366 PeiPcdDb = GetPcdDatabase ();\r
367 LocalTokenCount = PeiPcdDb->LocalTokenCount;\r
368\r
369 if (Guid == NULL) {\r
370 // EBC compiler is very choosy. It may report warning about comparison\r
371 // between UINTN and 0 . So we add 1 in each size of the \r
372 // comparison.\r
373 ASSERT (TokenNumber + 1 < (LocalTokenCount + 1));\r
374 }\r
375\r
376 GuidHob = GetFirstGuidHob (&gEfiCallerIdGuid);\r
377 ASSERT (GuidHob != NULL);\r
378 \r
379 CallbackTable = GET_GUID_HOB_DATA (GuidHob);\r
380\r
381 CallbackTable += (TokenNumber * PcdGet32 (PcdMaxPeiPcdCallBackNumberPerPcdEntry));\r
382\r
383 for (Idx = 0; Idx < PcdGet32 (PcdMaxPeiPcdCallBackNumberPerPcdEntry); Idx++) {\r
384 if (CallbackTable[Idx] != NULL) {\r
385 CallbackTable[Idx] (Guid,\r
386 (Guid == NULL) ? (TokenNumber + 1) : ExTokenNumber,\r
387 Data,\r
388 Size\r
389 );\r
390 }\r
391 }\r
392}\r
393\r
394/**\r
395 Wrapper function for setting non-pointer type value for a PCD entry.\r
396\r
397 @param TokenNumber Pcd token number autogenerated by build tools.\r
398 @param Data Value want to be set for PCD entry\r
399 @param Size Size of value.\r
400\r
401 @return status of SetWorker.\r
402\r
403**/\r
404EFI_STATUS\r
405SetValueWorker (\r
406 IN UINTN TokenNumber,\r
407 IN VOID *Data,\r
408 IN UINTN Size\r
409 )\r
410{\r
411 return SetWorker (TokenNumber, Data, &Size, FALSE);\r
412}\r
413\r
414/**\r
415 Set value for an PCD entry\r
416\r
417 @param TokenNumber Pcd token number autogenerated by build tools.\r
418 @param Data Value want to be set for PCD entry\r
419 @param Size Size of value.\r
420 @param PtrType If TRUE, the type of PCD entry's value is Pointer.\r
421 If False, the type of PCD entry's value is not Pointer.\r
422\r
423 @retval EFI_INVALID_PARAMETER If this PCD type is VPD, VPD PCD can not be set.\r
424 @retval EFI_INVALID_PARAMETER If Size can not be set to size table.\r
425 @retval EFI_INVALID_PARAMETER If Size of non-Ptr type PCD does not match the size information in PCD database.\r
426 @retval EFI_NOT_FOUND If value type of PCD entry is intergrate, but not in\r
427 range of UINT8, UINT16, UINT32, UINT64\r
428 @retval EFI_NOT_FOUND Can not find the PCD type according to token number. \r
429**/\r
430EFI_STATUS\r
431SetWorker (\r
432 IN UINTN TokenNumber,\r
433 IN VOID *Data,\r
434 IN OUT UINTN *Size,\r
435 IN BOOLEAN PtrType\r
436 )\r
437{\r
438 UINT32 LocalTokenNumber;\r
439 UINTN PeiNexTokenNumber;\r
440 PEI_PCD_DATABASE *PeiPcdDb;\r
441 STRING_HEAD StringTableIdx;\r
442 UINTN Offset;\r
443 VOID *InternalData;\r
444 UINTN MaxSize;\r
445 UINT32 LocalTokenCount;\r
446\r
447 if (!FeaturePcdGet(PcdPeiFullPcdDatabaseEnable)) {\r
448 return EFI_UNSUPPORTED;\r
449 }\r
450 \r
451 //\r
452 // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.\r
453 // We have to decrement TokenNumber by 1 to make it usable\r
454 // as the array index.\r
455 //\r
456 TokenNumber--;\r
457 PeiPcdDb = GetPcdDatabase ();\r
458 LocalTokenCount = PeiPcdDb->LocalTokenCount;\r
459\r
460 // EBC compiler is very choosy. It may report warning about comparison\r
461 // between UINTN and 0 . So we add 1 in each size of the \r
462 // comparison.\r
463 ASSERT (TokenNumber + 1 < (LocalTokenCount + 1));\r
464\r
465 LocalTokenNumber = *((UINT32 *)((UINT8 *)PeiPcdDb + PeiPcdDb->LocalTokenNumberTableOffset) + TokenNumber);\r
466\r
467 if (PtrType) {\r
468 //\r
469 // Get MaxSize first, then check new size with max buffer size.\r
470 //\r
471 GetPtrTypeSize (TokenNumber, &MaxSize, PeiPcdDb);\r
472 if (*Size > MaxSize) {\r
473 *Size = MaxSize;\r
474 return EFI_INVALID_PARAMETER;\r
475 }\r
476 } else {\r
477 if (*Size != PeiPcdGetSize (TokenNumber + 1)) {\r
478 return EFI_INVALID_PARAMETER;\r
479 }\r
480 }\r
481\r
482 //\r
483 // We only invoke the callback function for Dynamic Type PCD Entry.\r
484 // For Dynamic EX PCD entry, we have invoked the callback function for Dynamic EX\r
485 // type PCD entry in ExSetWorker.\r
486 //\r
487 PeiNexTokenNumber = PeiPcdDb->LocalTokenCount - PeiPcdDb->ExTokenCount;\r
488 if (TokenNumber + 1 < PeiNexTokenNumber + 1) {\r
489 InvokeCallbackOnSet (0, NULL, TokenNumber + 1, Data, *Size);\r
490 }\r
491\r
492 if ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == PCD_TYPE_SKU_ENABLED) {\r
493 if (PtrType) {\r
494 GetPtrTypeSize (TokenNumber, &MaxSize, PeiPcdDb);\r
495 } else {\r
496 MaxSize = *Size;\r
497 }\r
498 LocalTokenNumber = GetSkuEnabledTokenNumber (LocalTokenNumber & ~PCD_TYPE_SKU_ENABLED, MaxSize);\r
499 }\r
500\r
501 Offset = LocalTokenNumber & PCD_DATABASE_OFFSET_MASK;\r
502 InternalData = (VOID *) ((UINT8 *) PeiPcdDb + Offset);\r
503 \r
504 switch (LocalTokenNumber & PCD_TYPE_ALL_SET) {\r
505 case PCD_TYPE_VPD:\r
506 case PCD_TYPE_HII:\r
507 case PCD_TYPE_HII|PCD_TYPE_STRING:\r
508 {\r
509 ASSERT (FALSE);\r
510 return EFI_INVALID_PARAMETER;\r
511 }\r
512\r
513 case PCD_TYPE_STRING:\r
514 if (SetPtrTypeSize (TokenNumber, Size, PeiPcdDb)) {\r
515 StringTableIdx = *((STRING_HEAD *)InternalData);\r
516 CopyMem ((UINT8 *)PeiPcdDb + PeiPcdDb->StringTableOffset + StringTableIdx, Data, *Size);\r
517 return EFI_SUCCESS;\r
518 } else {\r
519 return EFI_INVALID_PARAMETER;\r
520 }\r
521\r
522 case PCD_TYPE_DATA:\r
523 {\r
524 if (PtrType) {\r
525 if (SetPtrTypeSize (TokenNumber, Size, PeiPcdDb)) {\r
526 CopyMem (InternalData, Data, *Size);\r
527 return EFI_SUCCESS;\r
528 } else {\r
529 return EFI_INVALID_PARAMETER;\r
530 }\r
531 }\r
532\r
533 switch (*Size) {\r
534 case sizeof(UINT8):\r
535 *((UINT8 *) InternalData) = *((UINT8 *) Data);\r
536 return EFI_SUCCESS;\r
537\r
538 case sizeof(UINT16):\r
539 *((UINT16 *) InternalData) = *((UINT16 *) Data);\r
540 return EFI_SUCCESS;\r
541\r
542 case sizeof(UINT32):\r
543 *((UINT32 *) InternalData) = *((UINT32 *) Data);\r
544 return EFI_SUCCESS;\r
545\r
546 case sizeof(UINT64):\r
547 *((UINT64 *) InternalData) = *((UINT64 *) Data);\r
548 return EFI_SUCCESS;\r
549\r
550 default:\r
551 ASSERT (FALSE);\r
552 return EFI_NOT_FOUND;\r
553 }\r
554 }\r
555 \r
556 }\r
557\r
558 ASSERT (FALSE);\r
559 return EFI_NOT_FOUND;\r
560\r
561}\r
562\r
563/**\r
564 Wrapper function for set PCD value for non-Pointer type dynamic-ex PCD.\r
565\r
566 @param ExTokenNumber Token number for dynamic-ex PCD.\r
567 @param Guid Token space guid for dynamic-ex PCD.\r
568 @param Data Value want to be set.\r
569 @param SetSize The size of value.\r
570\r
571 @return status of ExSetWorker().\r
572\r
573**/\r
574EFI_STATUS\r
575ExSetValueWorker (\r
576 IN UINTN ExTokenNumber,\r
577 IN CONST EFI_GUID *Guid,\r
578 IN VOID *Data,\r
579 IN UINTN Size\r
580 )\r
581{\r
582 return ExSetWorker (ExTokenNumber, Guid, Data, &Size, FALSE);\r
583}\r
584\r
585/**\r
586 Set value for a dynamic-ex PCD entry.\r
587 \r
588 This routine find the local token number according to dynamic-ex PCD's token \r
589 space guid and token number firstly, and invoke callback function if this PCD\r
590 entry registered callback function. Finally, invoken general SetWorker to set\r
591 PCD value.\r
592 \r
593 @param ExTokenNumber Dynamic-ex PCD token number.\r
594 @param Guid Token space guid for dynamic-ex PCD.\r
595 @param Data PCD value want to be set\r
596 @param SetSize Size of value.\r
597 @param PtrType If TRUE, this PCD entry is pointer type.\r
598 If FALSE, this PCD entry is not pointer type.\r
599\r
600 @return status of SetWorker().\r
601\r
602**/\r
603EFI_STATUS\r
604ExSetWorker (\r
605 IN UINTN ExTokenNumber,\r
606 IN CONST EFI_GUID *Guid,\r
607 IN VOID *Data,\r
608 IN OUT UINTN *Size,\r
609 IN BOOLEAN PtrType\r
610 )\r
611{\r
612 UINTN TokenNumber;\r
613\r
614 if (!FeaturePcdGet(PcdPeiFullPcdDatabaseEnable)) {\r
615 return EFI_UNSUPPORTED;\r
616 }\r
617\r
618 TokenNumber = GetExPcdTokenNumber (Guid, ExTokenNumber);\r
619 if (TokenNumber == PCD_INVALID_TOKEN_NUMBER) {\r
620 return EFI_NOT_FOUND;\r
621 }\r
622 \r
623 InvokeCallbackOnSet (ExTokenNumber, Guid, TokenNumber, Data, *Size);\r
624\r
625 return SetWorker (TokenNumber, Data, Size, PtrType);\r
626\r
627}\r
628\r
629/**\r
630 Wrapper function for get PCD value for dynamic-ex PCD.\r
631\r
632 @param Guid Token space guid for dynamic-ex PCD.\r
633 @param ExTokenNumber Token number for dyanmic-ex PCD.\r
634 @param GetSize The size of dynamic-ex PCD value.\r
635\r
636 @return PCD entry in PCD database.\r
637\r
638**/\r
639VOID *\r
640ExGetWorker (\r
641 IN CONST EFI_GUID *Guid,\r
642 IN UINTN ExTokenNumber,\r
643 IN UINTN GetSize\r
644 )\r
645{ \r
646 return GetWorker (GetExPcdTokenNumber (Guid, ExTokenNumber), GetSize);\r
647}\r
648\r
649/**\r
650 Get the PCD entry pointer in PCD database.\r
651 \r
652 This routine will visit PCD database to find the PCD entry according to given\r
653 token number. The given token number is autogened by build tools and it will be \r
654 translated to local token number. Local token number contains PCD's type and \r
655 offset of PCD entry in PCD database.\r
656\r
657 @param TokenNumber Token's number, it is autogened by build tools\r
658 @param GetSize The size of token's value\r
659\r
660 @return PCD entry pointer in PCD database\r
661\r
662**/\r
663VOID *\r
664GetWorker (\r
665 IN UINTN TokenNumber,\r
666 IN UINTN GetSize\r
667 )\r
668{\r
669 UINT32 Offset;\r
670 EFI_GUID *Guid;\r
671 UINT16 *Name;\r
672 VARIABLE_HEAD *VariableHead;\r
673 EFI_STATUS Status;\r
674 UINTN DataSize;\r
675 VOID *Data;\r
676 UINT8 *StringTable;\r
677 STRING_HEAD StringTableIdx;\r
678 PEI_PCD_DATABASE *PeiPcdDb;\r
679 UINT32 LocalTokenNumber;\r
680 UINTN MaxSize;\r
681 UINT32 LocalTokenCount;\r
682\r
683 //\r
684 // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.\r
685 // We have to decrement TokenNumber by 1 to make it usable\r
686 // as the array index.\r
687 //\r
688 TokenNumber--;\r
689\r
690 PeiPcdDb = GetPcdDatabase ();\r
691 LocalTokenCount = PeiPcdDb->LocalTokenCount;\r
692\r
693 // EBC compiler is very choosy. It may report warning about comparison\r
694 // between UINTN and 0 . So we add 1 in each size of the \r
695 // comparison.\r
696 ASSERT (TokenNumber + 1 < (LocalTokenCount + 1));\r
697\r
698 ASSERT ((GetSize == PeiPcdGetSize(TokenNumber + 1)) || (GetSize == 0));\r
699\r
700 LocalTokenNumber = *((UINT32 *)((UINT8 *)PeiPcdDb + PeiPcdDb->LocalTokenNumberTableOffset) + TokenNumber);\r
701\r
702 if ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == PCD_TYPE_SKU_ENABLED) {\r
703 if (GetSize == 0) {\r
704 GetPtrTypeSize (TokenNumber, &MaxSize, PeiPcdDb);\r
705 } else {\r
706 MaxSize = GetSize;\r
707 }\r
708 LocalTokenNumber = GetSkuEnabledTokenNumber (LocalTokenNumber & ~PCD_TYPE_SKU_ENABLED, MaxSize);\r
709 }\r
710\r
711 Offset = LocalTokenNumber & PCD_DATABASE_OFFSET_MASK;\r
712 StringTable = (UINT8 *)PeiPcdDb + PeiPcdDb->StringTableOffset;\r
713\r
714 switch (LocalTokenNumber & PCD_TYPE_ALL_SET) {\r
715 case PCD_TYPE_VPD:\r
716 {\r
717 VPD_HEAD *VpdHead;\r
718 VpdHead = (VPD_HEAD *) ((UINT8 *)PeiPcdDb + Offset);\r
719 return (VOID *) (UINTN) (PcdGet32 (PcdVpdBaseAddress) + VpdHead->Offset);\r
720 }\r
721 \r
722 case PCD_TYPE_HII|PCD_TYPE_STRING:\r
723 case PCD_TYPE_HII:\r
724 {\r
725 VariableHead = (VARIABLE_HEAD *) ((UINT8 *)PeiPcdDb + Offset);\r
726 \r
727 Guid = (EFI_GUID *) ((UINT8 *)PeiPcdDb + PeiPcdDb->GuidTableOffset) + VariableHead->GuidTableIndex;\r
728 Name = (UINT16*)&StringTable[VariableHead->StringIndex];\r
729\r
730 Status = GetHiiVariable (Guid, Name, &Data, &DataSize);\r
731\r
732 if (Status == EFI_SUCCESS) {\r
733 return (VOID *) ((UINT8 *) Data + VariableHead->Offset);\r
734 } else {\r
735 //\r
736 // Return the default value specified by Platform Integrator \r
737 //\r
738 if ((LocalTokenNumber & PCD_TYPE_ALL_SET) == (PCD_TYPE_HII|PCD_TYPE_STRING)) {\r
739 return (VOID*)&StringTable[*(STRING_HEAD*)((UINT8*)PeiPcdDb + VariableHead->DefaultValueOffset)];\r
740 } else {\r
741 return (VOID *) ((UINT8 *) PeiPcdDb + VariableHead->DefaultValueOffset);\r
742 }\r
743 }\r
744 }\r
745\r
746 case PCD_TYPE_DATA:\r
747 return (VOID *) ((UINT8 *)PeiPcdDb + Offset);\r
748\r
749 case PCD_TYPE_STRING:\r
750 StringTableIdx = * (STRING_HEAD*) ((UINT8 *) PeiPcdDb + Offset);\r
751 return (VOID *) (&StringTable[StringTableIdx]);\r
752\r
753 default:\r
754 ASSERT (FALSE);\r
755 break;\r
756 \r
757 }\r
758\r
759 ASSERT (FALSE);\r
760 \r
761 return NULL;\r
762 \r
763}\r
764\r
765/**\r
766 Get Token Number according to dynamic-ex PCD's {token space guid:token number}\r
767\r
768 A dynamic-ex type PCD, developer must provide pair of token space guid: token number\r
769 in DEC file. PCD database maintain a mapping table that translate pair of {token\r
770 space guid: token number} to Token Number.\r
771 \r
772 @param Guid Token space guid for dynamic-ex PCD entry.\r
773 @param ExTokenNumber Dynamic-ex PCD token number.\r
774\r
775 @return Token Number for dynamic-ex PCD.\r
776\r
777**/\r
778UINTN \r
779GetExPcdTokenNumber (\r
780 IN CONST EFI_GUID *Guid,\r
781 IN UINTN ExTokenNumber\r
782 )\r
783{\r
784 UINT32 Index;\r
785 DYNAMICEX_MAPPING *ExMap;\r
786 EFI_GUID *GuidTable;\r
787 EFI_GUID *MatchGuid;\r
788 UINTN MatchGuidIdx;\r
789 PEI_PCD_DATABASE *PeiPcdDb;\r
790\r
791 PeiPcdDb = GetPcdDatabase();\r
792\r
793 ExMap = (DYNAMICEX_MAPPING *)((UINT8 *)PeiPcdDb + PeiPcdDb->ExMapTableOffset);\r
794 GuidTable = (EFI_GUID *)((UINT8 *)PeiPcdDb + PeiPcdDb->GuidTableOffset);\r
795\r
796 MatchGuid = ScanGuid (GuidTable, PeiPcdDb->GuidTableCount * sizeof(EFI_GUID), Guid);\r
797 //\r
798 // We need to ASSERT here. If GUID can't be found in GuidTable, this is a\r
799 // error in the BUILD system.\r
800 //\r
801 ASSERT (MatchGuid != NULL);\r
802 \r
803 MatchGuidIdx = MatchGuid - GuidTable;\r
804 \r
805 for (Index = 0; Index < PeiPcdDb->ExTokenCount; Index++) {\r
806 if ((ExTokenNumber == ExMap[Index].ExTokenNumber) && \r
807 (MatchGuidIdx == ExMap[Index].ExGuidIndex)) {\r
808 return ExMap[Index].TokenNumber;\r
809 }\r
810 }\r
811 \r
812 return PCD_INVALID_TOKEN_NUMBER;\r
813}\r
814\r
815/**\r
816 Get PCD database from GUID HOB in PEI phase.\r
817\r
818 @return Pointer to PCD database.\r
819\r
820**/\r
821PEI_PCD_DATABASE *\r
822GetPcdDatabase (\r
823 VOID\r
824 )\r
825{\r
826 EFI_HOB_GUID_TYPE *GuidHob;\r
827\r
828 GuidHob = GetFirstGuidHob (&gPcdDataBaseHobGuid);\r
829 ASSERT (GuidHob != NULL);\r
830 \r
831 return (PEI_PCD_DATABASE *) GET_GUID_HOB_DATA (GuidHob);\r
832}\r
833\r
834/**\r
835 Get SKU ID table from PCD database.\r
836\r
837 @param LocalTokenNumberTableIdx Index of local token number in token number table.\r
838 @param Database PCD database.\r
839\r
840 @return Pointer to SKU ID array table\r
841\r
842**/\r
843SKU_ID *\r
844GetSkuIdArray (\r
845 IN UINTN LocalTokenNumberTableIdx,\r
846 IN PEI_PCD_DATABASE *Database\r
847 )\r
848{\r
849 SKU_HEAD *SkuHead;\r
850 UINTN LocalTokenNumber;\r
851\r
852 LocalTokenNumber = *((UINT32 *)((UINT8 *)Database + Database->LocalTokenNumberTableOffset) + LocalTokenNumberTableIdx);\r
853\r
854 ASSERT ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) != 0);\r
855\r
856 SkuHead = (SKU_HEAD *) ((UINT8 *)Database + (LocalTokenNumber & PCD_DATABASE_OFFSET_MASK));\r
857\r
858 return (SKU_ID *) ((UINT8 *)Database + SkuHead->SkuIdTableOffset);\r
859 \r
860}\r
861\r
862/**\r
863 Get index of PCD entry in size table.\r
864\r
865 @param LocalTokenNumberTableIdx Index of this PCD in local token number table.\r
866 @param Database Pointer to PCD database in PEI phase.\r
867\r
868 @return index of PCD entry in size table.\r
869\r
870**/\r
871UINTN\r
872GetSizeTableIndex (\r
873 IN UINTN LocalTokenNumberTableIdx,\r
874 IN PEI_PCD_DATABASE *Database\r
875 )\r
876{\r
877 UINTN Index;\r
878 UINTN SizeTableIdx;\r
879 UINTN LocalTokenNumber;\r
880 SKU_ID *SkuIdTable;\r
881 \r
882 SizeTableIdx = 0;\r
883\r
884 for (Index = 0; Index < LocalTokenNumberTableIdx; Index++) {\r
885 LocalTokenNumber = *((UINT32 *)((UINT8 *)Database + Database->LocalTokenNumberTableOffset) + Index);\r
886\r
887 if ((LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) == PCD_DATUM_TYPE_POINTER) {\r
888 //\r
889 // SizeTable only contain record for PCD_DATUM_TYPE_POINTER type \r
890 // PCD entry.\r
891 //\r
892 if ((LocalTokenNumber & PCD_TYPE_VPD) != 0) {\r
893 //\r
894 // We have only two entry for VPD enabled PCD entry:\r
895 // 1) MAX Size.\r
896 // 2) Current Size\r
897 // Current size is equal to MAX size.\r
898 //\r
899 SizeTableIdx += 2;\r
900 } else {\r
901 if ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == 0) {\r
902 //\r
903 // We have only two entry for Non-Sku enabled PCD entry:\r
904 // 1) MAX SIZE\r
905 // 2) Current Size\r
906 //\r
907 SizeTableIdx += 2;\r
908 } else {\r
909 //\r
910 // We have these entry for SKU enabled PCD entry\r
911 // 1) MAX SIZE\r
912 // 2) Current Size for each SKU_ID (It is equal to MaxSku).\r
913 //\r
914 SkuIdTable = GetSkuIdArray (Index, Database);\r
915 SizeTableIdx += (UINTN)*SkuIdTable + 1;\r
916 }\r
917 }\r
918 }\r
919\r
920 }\r
921\r
922 return SizeTableIdx;\r
923}\r