Import PCD dxe and PCD pei modules.
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Universal / PCD / Dxe / Service.c
1 /** @file\r
2 Private functions used by PCD DXE driver.\r
3 \r
4 Copyright (c) 2006 - 2007, Intel Corporation\r
5 All rights reserved. This program and the accompanying materials\r
6 are licensed and made available under the terms and conditions of the BSD License\r
7 which accompanies this distribution.  The full text of the license may be found at\r
8 http://opensource.org/licenses/bsd-license.php\r
9 \r
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12 \r
13 \r
14 Module Name: Service.c\r
15 \r
16 **/\r
17 //\r
18 // Include common header file for this module.\r
19 //\r
20 #include "CommonHeader.h"\r
21 \r
22 #include "Service.h"\r
23 \r
24 \r
25 PCD_DATABASE * mPcdDatabase;\r
26 \r
27 LIST_ENTRY *mCallbackFnTable;\r
28 \r
29 VOID *\r
30 GetWorker (\r
31   UINTN             TokenNumber,\r
32   UINTN             GetSize\r
33   )\r
34 {\r
35   UINT32              *LocalTokenNumberTable;\r
36   EFI_GUID            *GuidTable;\r
37   UINT16              *StringTable;\r
38   EFI_GUID            *Guid;\r
39   UINT16              *Name;\r
40   VARIABLE_HEAD       *VariableHead;\r
41   UINT8               *VaraiableDefaultBuffer;\r
42   UINT8               *Data;\r
43   VPD_HEAD            *VpdHead;\r
44   UINT8               *PcdDb;\r
45   VOID                *RetPtr;\r
46   UINTN               MaxSize;\r
47   UINTN               TmpTokenNumber;\r
48   UINTN               DataSize;\r
49   EFI_STATUS          Status;\r
50   UINT32              LocalTokenNumber;\r
51   UINT32              Offset;\r
52   UINT16              StringTableIdx;      \r
53   BOOLEAN             IsPeiDb;\r
54 \r
55   //\r
56   // Aquire lock to prevent reentrance from TPL_CALLBACK level\r
57   //\r
58   EfiAcquireLock (&mPcdDatabaseLock);\r
59 \r
60   RetPtr = NULL;\r
61   //\r
62   // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.\r
63   // We have to decrement TokenNumber by 1 to make it usable\r
64   // as the array index.\r
65   //\r
66   TokenNumber--;\r
67 \r
68   TmpTokenNumber = TokenNumber;\r
69   \r
70   //\r
71   // PCD_TOTAL_TOKEN_NUMBER is a auto-generated constant.\r
72   // It could be zero. EBC compiler is very choosy. It may\r
73   // report warning. So we add 1 in each size of the \r
74   // comparison.\r
75   //\r
76   ASSERT (TokenNumber + 1 < PCD_TOTAL_TOKEN_NUMBER + 1);\r
77 \r
78   ASSERT ((GetSize == DxePcdGetSize (TokenNumber + 1)) || (GetSize == 0));\r
79 \r
80   // EBC compiler is very choosy. It may report warning about comparison\r
81   // between UINTN and 0 . So we add 1 in each size of the \r
82   // comparison.\r
83   IsPeiDb = (BOOLEAN) ((TokenNumber + 1 < PEI_LOCAL_TOKEN_NUMBER + 1) ? TRUE : FALSE);\r
84 \r
85   LocalTokenNumberTable  = IsPeiDb ? mPcdDatabase->PeiDb.Init.LocalTokenNumberTable : \r
86                                      mPcdDatabase->DxeDb.Init.LocalTokenNumberTable;\r
87 \r
88   TokenNumber            = IsPeiDb ? TokenNumber :\r
89                                      TokenNumber - PEI_LOCAL_TOKEN_NUMBER;\r
90 \r
91   LocalTokenNumber = LocalTokenNumberTable[TokenNumber];\r
92   \r
93   if ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == PCD_TYPE_SKU_ENABLED) {\r
94     if (GetSize == 0) {\r
95       GetPtrTypeSize (TmpTokenNumber, &MaxSize);\r
96     } else {\r
97       MaxSize = GetSize;\r
98     }\r
99     LocalTokenNumber = GetSkuEnabledTokenNumber (LocalTokenNumber & ~PCD_TYPE_SKU_ENABLED, MaxSize, IsPeiDb);\r
100   }\r
101 \r
102   PcdDb = IsPeiDb ? ((UINT8 *) &mPcdDatabase->PeiDb) : ((UINT8 *) &mPcdDatabase->DxeDb);\r
103   StringTable = IsPeiDb ? mPcdDatabase->PeiDb.Init.StringTable :\r
104                           mPcdDatabase->DxeDb.Init.StringTable;\r
105   \r
106   Offset     = LocalTokenNumber & PCD_DATABASE_OFFSET_MASK;\r
107   \r
108   switch (LocalTokenNumber & PCD_TYPE_ALL_SET) {\r
109     case PCD_TYPE_VPD:\r
110       VpdHead = (VPD_HEAD *) ((UINT8 *) PcdDb + Offset);\r
111       RetPtr = (VOID *) (UINTN) (FixedPcdGet32(PcdVpdBaseAddress) + VpdHead->Offset);\r
112       break;\r
113       \r
114     case PCD_TYPE_HII:\r
115       GuidTable   = IsPeiDb ? mPcdDatabase->PeiDb.Init.GuidTable :\r
116                               mPcdDatabase->DxeDb.Init.GuidTable;\r
117                               \r
118       VariableHead = (VARIABLE_HEAD *) (PcdDb + Offset);\r
119       \r
120       Guid = &(GuidTable[VariableHead->GuidTableIndex]);\r
121       Name = &(StringTable[VariableHead->StringIndex]);\r
122       VaraiableDefaultBuffer = (UINT8 *) PcdDb + VariableHead->DefaultValueOffset;\r
123 \r
124       Status = GetHiiVariable (Guid, Name, &Data, &DataSize);\r
125       if (Status == EFI_SUCCESS) {\r
126         if (GetSize == 0) {\r
127           //\r
128           // It is a pointer type. So get the MaxSize reserved for\r
129           // this PCD entry.\r
130           //\r
131           GetPtrTypeSize (TmpTokenNumber, &GetSize);\r
132         }\r
133         CopyMem (VaraiableDefaultBuffer, Data + VariableHead->Offset, GetSize);\r
134         FreePool (Data);\r
135       }\r
136       //\r
137       // If the operation is successful, we copy the data\r
138       // to the default value buffer in the PCD Database.\r
139       // So that we can free the Data allocated in GetHiiVariable.\r
140       //\r
141       //\r
142       // If the operation is not successful, \r
143       // Return 1) either the default value specified by Platform Integrator \r
144       //        2) Or the value Set by a PCD set operation.\r
145       //\r
146       RetPtr = (VOID *) VaraiableDefaultBuffer;\r
147       break;\r
148 \r
149     case PCD_TYPE_STRING:\r
150       StringTableIdx = (UINT16) *((UINT8 *) PcdDb + Offset);\r
151       RetPtr = (VOID *) &StringTable[StringTableIdx];\r
152       break;\r
153 \r
154     case PCD_TYPE_DATA:\r
155       RetPtr = (VOID *) ((UINT8 *) PcdDb + Offset);\r
156       break;\r
157 \r
158     default:\r
159       ASSERT (FALSE);\r
160       break;\r
161       \r
162   }\r
163 \r
164   EfiReleaseLock (&mPcdDatabaseLock);\r
165   \r
166   return RetPtr;\r
167   \r
168 }\r
169 \r
170 \r
171 \r
172 EFI_STATUS\r
173 DxeRegisterCallBackWorker (\r
174   IN  UINTN                   TokenNumber,\r
175   IN  CONST GUID              *Guid, OPTIONAL\r
176   IN  PCD_PROTOCOL_CALLBACK   CallBackFunction\r
177 )\r
178 {\r
179   CALLBACK_FN_ENTRY       *FnTableEntry;\r
180   LIST_ENTRY              *ListHead;\r
181   LIST_ENTRY              *ListNode;\r
182 \r
183   if (Guid != NULL) {\r
184     TokenNumber = GetExPcdTokenNumber (Guid, (UINT32) TokenNumber);\r
185   }\r
186 \r
187   //\r
188   // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.\r
189   // We have to decrement TokenNumber by 1 to make it usable\r
190   // as the array index.\r
191   //\r
192   TokenNumber--;\r
193 \r
194   ListHead = &mCallbackFnTable[TokenNumber];\r
195   ListNode = GetFirstNode (ListHead);\r
196 \r
197   while (ListNode != ListHead) {\r
198     FnTableEntry = CR_FNENTRY_FROM_LISTNODE(ListNode, CALLBACK_FN_ENTRY, Node);\r
199 \r
200     if (FnTableEntry->CallbackFn == CallBackFunction) {\r
201       //\r
202       // We only allow a Callback function to be register once\r
203       // for a TokenNumber. So just return EFI_SUCCESS\r
204       //\r
205       return EFI_SUCCESS;\r
206     }\r
207     ListNode = GetNextNode (ListHead, ListNode);\r
208   }\r
209 \r
210   FnTableEntry = AllocatePool (sizeof(CALLBACK_FN_ENTRY));\r
211   ASSERT (FnTableEntry != NULL);\r
212 \r
213   FnTableEntry->CallbackFn = CallBackFunction;\r
214   InsertTailList (ListHead, &FnTableEntry->Node);\r
215   \r
216   return EFI_SUCCESS;\r
217 }\r
218 \r
219 \r
220 \r
221 \r
222 EFI_STATUS\r
223 DxeUnRegisterCallBackWorker (\r
224   IN  UINTN                   TokenNumber,\r
225   IN  CONST GUID              *Guid, OPTIONAL\r
226   IN  PCD_PROTOCOL_CALLBACK   CallBackFunction\r
227 )\r
228 {\r
229   CALLBACK_FN_ENTRY       *FnTableEntry;\r
230   LIST_ENTRY              *ListHead;\r
231   LIST_ENTRY              *ListNode;\r
232 \r
233   if (Guid != NULL) {\r
234     TokenNumber = GetExPcdTokenNumber (Guid, (UINT32) TokenNumber);\r
235   }\r
236 \r
237   //\r
238   // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.\r
239   // We have to decrement TokenNumber by 1 to make it usable\r
240   // as the array index.\r
241   //\r
242   TokenNumber--;\r
243 \r
244   ListHead = &mCallbackFnTable[TokenNumber];\r
245   ListNode = GetFirstNode (ListHead);\r
246 \r
247   while (ListNode != ListHead) {\r
248     FnTableEntry = CR_FNENTRY_FROM_LISTNODE(ListNode, CALLBACK_FN_ENTRY, Node);\r
249 \r
250     if (FnTableEntry->CallbackFn == CallBackFunction) {\r
251       //\r
252       // We only allow a Callback function to be register once\r
253       // for a TokenNumber. So we can safely remove the Node from\r
254       // the Link List and return EFI_SUCCESS.\r
255       //\r
256       RemoveEntryList (ListNode);\r
257       FreePool (FnTableEntry);\r
258       \r
259       return EFI_SUCCESS;\r
260     }\r
261     ListNode = GetNextNode (ListHead, ListNode);\r
262   }\r
263 \r
264   return EFI_INVALID_PARAMETER;\r
265 }\r
266 \r
267 \r
268 \r
269 EFI_STATUS\r
270 ExGetNextTokeNumber (\r
271   IN      CONST EFI_GUID         *Guid,\r
272   IN OUT  UINTN                  *TokenNumber,\r
273   IN      EFI_GUID               *GuidTable,\r
274   IN      UINTN                  SizeOfGuidTable,\r
275   IN      DYNAMICEX_MAPPING      *ExMapTable,\r
276   IN      UINTN                  SizeOfExMapTable\r
277   )\r
278 {\r
279   EFI_GUID         *MatchGuid;\r
280   UINTN            Idx;\r
281   UINTN            GuidTableIdx;\r
282   BOOLEAN          Found;\r
283 \r
284   MatchGuid = ScanGuid (GuidTable, SizeOfGuidTable, Guid);\r
285   if (MatchGuid == NULL) {\r
286     return EFI_NOT_FOUND;\r
287   }\r
288 \r
289   Found = FALSE;\r
290   GuidTableIdx = MatchGuid - GuidTable;\r
291   for (Idx = 0; Idx < SizeOfExMapTable; Idx++) {\r
292     if (ExMapTable[Idx].ExGuidIndex == GuidTableIdx) {\r
293       Found = TRUE;\r
294       break;\r
295     }\r
296   }\r
297 \r
298   if (Found) {\r
299     if (*TokenNumber == PCD_INVALID_TOKEN_NUMBER) {\r
300       *TokenNumber = ExMapTable[Idx].ExTokenNumber;\r
301       return EFI_SUCCESS;\r
302     }\r
303 \r
304     for ( ; Idx < SizeOfExMapTable; Idx++) {\r
305       if (ExMapTable[Idx].ExTokenNumber == *TokenNumber) {\r
306         Idx++;\r
307         if (Idx == SizeOfExMapTable) {\r
308           //\r
309           // Exceed the length of ExMap Table\r
310           //\r
311           *TokenNumber = PCD_INVALID_TOKEN_NUMBER;\r
312           return EFI_SUCCESS;\r
313         } else if (ExMapTable[Idx].ExGuidIndex == GuidTableIdx) {\r
314           //\r
315           // Found the next match\r
316           //\r
317           *TokenNumber = ExMapTable[Idx].ExTokenNumber;\r
318           return EFI_SUCCESS;\r
319         } else {\r
320           //\r
321           // Guid has been changed. It is the next Token Space Guid.\r
322           // We should flag no more TokenNumber.\r
323           //\r
324           *TokenNumber = PCD_INVALID_TOKEN_NUMBER;\r
325           return EFI_SUCCESS;\r
326         }\r
327       }\r
328     }\r
329   }\r
330   \r
331   return EFI_NOT_FOUND;\r
332 }\r
333   \r
334 \r
335 \r
336 \r
337 VOID\r
338 BuildPcdDxeDataBase (\r
339   VOID\r
340   )\r
341 {\r
342   PEI_PCD_DATABASE    *PeiDatabase;\r
343   EFI_HOB_GUID_TYPE   *GuidHob;\r
344   UINTN               Idx;\r
345 \r
346   mPcdDatabase = AllocateZeroPool (sizeof(PCD_DATABASE));\r
347   ASSERT (mPcdDatabase != NULL);\r
348 \r
349   GuidHob = GetFirstGuidHob (&gPcdDataBaseHobGuid);\r
350   if (GuidHob != NULL) {\r
351 \r
352     //\r
353     // We will copy over the PEI phase's PCD Database.\r
354     // \r
355     // If no PEIMs use dynamic Pcd Entry, the Pcd Service PEIM\r
356     // should not be included at all. So the GuidHob could\r
357     // be NULL. If it is NULL, we just copy over the DXE Default\r
358     // Value to PCD Database.\r
359     //\r
360     \r
361     PeiDatabase = (PEI_PCD_DATABASE *) GET_GUID_HOB_DATA (GuidHob);\r
362     //\r
363     // Copy PCD Entries refereneced in PEI phase to PCD DATABASE\r
364     //\r
365     CopyMem (&mPcdDatabase->PeiDb, PeiDatabase, sizeof (PEI_PCD_DATABASE));\r
366   }\r
367 \r
368   //\r
369   // Copy PCD Entries with default value to PCD DATABASE\r
370   //\r
371   CopyMem (&mPcdDatabase->DxeDb.Init, &gDXEPcdDbInit, sizeof(DXE_PCD_DATABASE_INIT));\r
372 \r
373 \r
374   //\r
375   // Initialized the Callback Function Table\r
376   //\r
377 \r
378   mCallbackFnTable = AllocateZeroPool (PCD_TOTAL_TOKEN_NUMBER * sizeof (LIST_ENTRY));\r
379   \r
380   // EBC compiler is very choosy. It may report warning about comparison\r
381   // between UINTN and 0 . So we add 1 in each size of the \r
382   // comparison.\r
383   for (Idx = 0; Idx + 1 < PCD_TOTAL_TOKEN_NUMBER + 1; Idx++) {\r
384     InitializeListHead (&mCallbackFnTable[Idx]);\r
385   }\r
386     \r
387   return;\r
388 }\r
389 \r
390 \r
391 \r
392 EFI_STATUS\r
393 GetHiiVariable (\r
394   IN  EFI_GUID      *VariableGuid,\r
395   IN  UINT16        *VariableName,\r
396   OUT UINT8         **VariableData,\r
397   OUT UINTN         *VariableSize\r
398   )\r
399 {\r
400   UINTN      Size;\r
401   EFI_STATUS Status;\r
402   UINT8      *Buffer;\r
403 \r
404   Size = 0;\r
405   Buffer = NULL;\r
406   \r
407   Status = gRT->GetVariable (\r
408     (UINT16 *)VariableName,\r
409     VariableGuid,\r
410     NULL,\r
411     &Size,\r
412     Buffer\r
413     );\r
414   \r
415   if (Status == EFI_BUFFER_TOO_SMALL) {\r
416     Buffer = (UINT8 *) AllocatePool (Size);\r
417 \r
418     ASSERT (Buffer != NULL);\r
419 \r
420     Status = gRT->GetVariable (\r
421       VariableName,\r
422       VariableGuid,\r
423       NULL,\r
424       &Size,\r
425       Buffer\r
426       );\r
427 \r
428     ASSERT (Status == EFI_SUCCESS);\r
429     *VariableData = Buffer;\r
430     *VariableSize = Size;\r
431   }\r
432 \r
433   return Status;\r
434 }\r
435 \r
436 \r
437 UINT32\r
438 GetSkuEnabledTokenNumber (\r
439   UINT32    LocalTokenNumber,\r
440   UINTN     Size,\r
441   BOOLEAN   IsPeiDb\r
442   ) \r
443 {\r
444   SKU_HEAD              *SkuHead;\r
445   SKU_ID                *SkuIdTable;\r
446   INTN                  i;\r
447   UINT8                 *Value;\r
448   SKU_ID                *PhaseSkuIdTable;\r
449   UINT8                 *PcdDb;\r
450 \r
451   ASSERT ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == 0);\r
452 \r
453   PcdDb = IsPeiDb ? (UINT8 *) &mPcdDatabase->PeiDb : (UINT8 *) &mPcdDatabase->DxeDb;\r
454 \r
455   SkuHead     = (SKU_HEAD *) (PcdDb + (LocalTokenNumber & PCD_DATABASE_OFFSET_MASK));\r
456   Value       = (UINT8 *) (PcdDb + SkuHead->SkuDataStartOffset); \r
457 \r
458   PhaseSkuIdTable = IsPeiDb ? mPcdDatabase->PeiDb.Init.SkuIdTable :\r
459                               mPcdDatabase->DxeDb.Init.SkuIdTable;\r
460                               \r
461   SkuIdTable  = &PhaseSkuIdTable[SkuHead->SkuIdTableOffset];\r
462         \r
463   for (i = 0; i < SkuIdTable[0]; i++) {\r
464     if (mPcdDatabase->PeiDb.Init.SystemSkuId == SkuIdTable[i + 1]) {\r
465       break;\r
466     }\r
467   }\r
468   ASSERT (i < SkuIdTable[0]);\r
469 \r
470   switch (LocalTokenNumber & PCD_TYPE_ALL_SET) {\r
471     case PCD_TYPE_VPD:\r
472       Value = (UINT8 *) &(((VPD_HEAD *) Value)[i]);\r
473       return (UINT32) ((Value - PcdDb) | PCD_TYPE_VPD);\r
474 \r
475     case PCD_TYPE_HII:\r
476       Value = (UINT8 *) &(((VARIABLE_HEAD *) Value)[i]);\r
477       return (UINT32) ((Value - PcdDb) | PCD_TYPE_HII);\r
478 \r
479     case PCD_TYPE_STRING:\r
480       Value = (UINT8 *) &(((STRING_HEAD *) Value)[i]);\r
481       return (UINT32) ((Value - PcdDb) | PCD_TYPE_STRING);\r
482       \r
483     case PCD_TYPE_DATA:\r
484       Value += Size * i;\r
485       return (UINT32) (Value - PcdDb);\r
486 \r
487     default:\r
488       ASSERT (FALSE);\r
489   }\r
490 \r
491   ASSERT (FALSE);\r
492 \r
493   return 0;\r
494   \r
495 }\r
496 \r
497 \r
498 \r
499 \r
500 STATIC\r
501 VOID\r
502 InvokeCallbackOnSet (\r
503   UINT32            ExTokenNumber,\r
504   CONST EFI_GUID    *Guid, OPTIONAL\r
505   UINTN             TokenNumber,\r
506   VOID              *Data,\r
507   UINTN             Size\r
508   )\r
509 {\r
510   CALLBACK_FN_ENTRY       *FnTableEntry;\r
511   LIST_ENTRY              *ListHead;\r
512   LIST_ENTRY              *ListNode;\r
513 \r
514   //\r
515   // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.\r
516   // We have to decrement TokenNumber by 1 to make it usable\r
517   // as the array index.\r
518   //\r
519   TokenNumber--;\r
520   \r
521   ListHead = &mCallbackFnTable[TokenNumber];\r
522   ListNode = GetFirstNode (ListHead);\r
523 \r
524   while (ListNode != ListHead) {\r
525     FnTableEntry = CR_FNENTRY_FROM_LISTNODE(ListNode, CALLBACK_FN_ENTRY, Node);\r
526 \r
527     FnTableEntry->CallbackFn(Guid, \r
528                     (Guid == NULL) ? TokenNumber : ExTokenNumber,\r
529                     Data,\r
530                     Size);\r
531     \r
532     ListNode = GetNextNode (ListHead, ListNode);\r
533   }\r
534   \r
535   return;\r
536 }\r
537 \r
538 \r
539 EFI_STATUS\r
540 SetValueWorker (\r
541   IN UINTN                   TokenNumber,\r
542   IN VOID                    *Data,\r
543   IN UINTN                   Size\r
544   )\r
545 {\r
546   return SetWorker (TokenNumber, Data, &Size, FALSE);\r
547 }\r
548 \r
549 \r
550 EFI_STATUS\r
551 SetWorker (\r
552   IN          UINTN                   TokenNumber,\r
553   IN          VOID                    *Data,\r
554   IN OUT      UINTN                   *Size,\r
555   IN          BOOLEAN                 PtrType\r
556   )\r
557 {\r
558   UINT32              *LocalTokenNumberTable;\r
559   BOOLEAN             IsPeiDb;\r
560   UINT32              LocalTokenNumber;\r
561   EFI_GUID            *GuidTable;\r
562   UINT16              *StringTable;\r
563   EFI_GUID            *Guid;\r
564   UINT16              *Name;\r
565   UINTN               VariableOffset;\r
566   VOID                *InternalData;\r
567   VARIABLE_HEAD       *VariableHead;\r
568   UINTN               Offset;\r
569   UINT8               *PcdDb;\r
570   EFI_STATUS          Status;\r
571   UINTN               MaxSize;\r
572   UINTN               TmpTokenNumber;\r
573 \r
574   //\r
575   // Aquire lock to prevent reentrance from TPL_CALLBACK level\r
576   //\r
577   EfiAcquireLock (&mPcdDatabaseLock);\r
578 \r
579   //\r
580   // TokenNumber Zero is reserved as PCD_INVALID_TOKEN_NUMBER.\r
581   // We have to decrement TokenNumber by 1 to make it usable\r
582   // as the array index.\r
583   //\r
584   TokenNumber--;\r
585 \r
586   TmpTokenNumber = TokenNumber;\r
587   \r
588   // EBC compiler is very choosy. It may report warning about comparison\r
589   // between UINTN and 0 . So we add 1 in each size of the \r
590   // comparison.\r
591 \r
592   ASSERT (TokenNumber + 1 < PCD_TOTAL_TOKEN_NUMBER + 1);\r
593 \r
594   if (!PtrType) {\r
595     ASSERT (*Size == DxePcdGetSize (TokenNumber + 1));\r
596   }\r
597   \r
598   // EBC compiler is very choosy. It may report warning about comparison\r
599   // between UINTN and 0 . So we add 1 in each size of the \r
600   // comparison.\r
601   IsPeiDb = (BOOLEAN) ((TokenNumber + 1 < PEI_LOCAL_TOKEN_NUMBER + 1) ? TRUE : FALSE);\r
602 \r
603   LocalTokenNumberTable  = IsPeiDb ? mPcdDatabase->PeiDb.Init.LocalTokenNumberTable : \r
604                                      mPcdDatabase->DxeDb.Init.LocalTokenNumberTable;\r
605 \r
606   // EBC compiler is very choosy. It may report warning about comparison\r
607   // between UINTN and 0 . So we add 1 in each size of the \r
608   // comparison.\r
609   if ((TokenNumber + 1 < PEI_NEX_TOKEN_NUMBER + 1) ||\r
610       (TokenNumber + 1 >= PEI_LOCAL_TOKEN_NUMBER + 1 || TokenNumber + 1 < (PEI_LOCAL_TOKEN_NUMBER + DXE_NEX_TOKEN_NUMBER + 1))) {\r
611     InvokeCallbackOnSet (0, NULL, TokenNumber + 1, Data, *Size);\r
612   }\r
613 \r
614   TokenNumber = IsPeiDb ? TokenNumber\r
615                         : TokenNumber - PEI_LOCAL_TOKEN_NUMBER;\r
616 \r
617   LocalTokenNumber = LocalTokenNumberTable[TokenNumber];\r
618   \r
619   if ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == PCD_TYPE_SKU_ENABLED) {\r
620     if (PtrType) {\r
621       GetPtrTypeSize (TmpTokenNumber, &MaxSize);\r
622     } else {\r
623       MaxSize = *Size;\r
624     }\r
625     LocalTokenNumber = GetSkuEnabledTokenNumber (LocalTokenNumber & ~PCD_TYPE_SKU_ENABLED, MaxSize, IsPeiDb);\r
626   }\r
627 \r
628   Offset = LocalTokenNumber & PCD_DATABASE_OFFSET_MASK;\r
629 \r
630   PcdDb = IsPeiDb ? ((UINT8 *) &mPcdDatabase->PeiDb) : ((UINT8 *) &mPcdDatabase->DxeDb);\r
631 \r
632   StringTable = IsPeiDb ? mPcdDatabase->PeiDb.Init.StringTable :\r
633                           mPcdDatabase->DxeDb.Init.StringTable;\r
634   \r
635   InternalData = PcdDb + Offset;\r
636 \r
637   switch (LocalTokenNumber & PCD_TYPE_ALL_SET) {\r
638     case PCD_TYPE_VPD:\r
639       ASSERT (FALSE);\r
640       Status = EFI_INVALID_PARAMETER;\r
641       break;\r
642     \r
643     case PCD_TYPE_STRING:\r
644       if (SetPtrTypeSize (TmpTokenNumber, Size)) {\r
645         CopyMem (&StringTable[*((UINT16 *)InternalData)], Data, *Size);\r
646         Status = EFI_SUCCESS;\r
647       } else {\r
648         Status = EFI_INVALID_PARAMETER;\r
649       }\r
650       break;\r
651 \r
652     case PCD_TYPE_HII:\r
653       if (PtrType) {\r
654         if (!SetPtrTypeSize (TmpTokenNumber, Size)) {\r
655           Status = EFI_INVALID_PARAMETER;\r
656           break;\r
657         }\r
658       }\r
659       \r
660       GuidTable   = IsPeiDb ? mPcdDatabase->PeiDb.Init.GuidTable :\r
661                               mPcdDatabase->DxeDb.Init.GuidTable;\r
662                               \r
663       VariableHead = (VARIABLE_HEAD *) (PcdDb + Offset);\r
664       \r
665       Guid = &(GuidTable[VariableHead->GuidTableIndex]);\r
666       Name = &(StringTable[VariableHead->StringIndex]);\r
667       VariableOffset = VariableHead->Offset;\r
668 \r
669       Status = SetHiiVariable (Guid, Name, Data, *Size, VariableOffset);\r
670 \r
671       if (EFI_NOT_FOUND == Status) {\r
672         CopyMem (PcdDb + VariableHead->DefaultValueOffset, Data, *Size);\r
673         Status = EFI_SUCCESS;\r
674       } \r
675       break;\r
676       \r
677     case PCD_TYPE_DATA:\r
678       if (PtrType) {\r
679         if (SetPtrTypeSize (TmpTokenNumber, Size)) {\r
680           CopyMem (InternalData, Data, *Size);\r
681           Status = EFI_SUCCESS;\r
682         } else {\r
683           Status = EFI_INVALID_PARAMETER;\r
684         }\r
685         break;\r
686       }\r
687 \r
688       Status = EFI_SUCCESS;\r
689       switch (*Size) {\r
690         case sizeof(UINT8):\r
691           *((UINT8 *) InternalData) = *((UINT8 *) Data);\r
692           break;\r
693 \r
694         case sizeof(UINT16):\r
695           *((UINT16 *) InternalData) = *((UINT16 *) Data);\r
696           break;\r
697 \r
698         case sizeof(UINT32):\r
699           *((UINT32 *) InternalData) = *((UINT32 *) Data);\r
700           break;\r
701 \r
702         case sizeof(UINT64):\r
703           *((UINT64 *) InternalData) = *((UINT64 *) Data);\r
704           break;\r
705 \r
706         default:\r
707           ASSERT (FALSE);\r
708           Status = EFI_NOT_FOUND;\r
709           break;\r
710       }\r
711       break;\r
712 \r
713     default:\r
714       ASSERT (FALSE);\r
715       Status = EFI_NOT_FOUND;\r
716       break;\r
717     }\r
718 \r
719   EfiReleaseLock (&mPcdDatabaseLock);\r
720   \r
721   return Status;\r
722 }\r
723 \r
724 \r
725 \r
726 \r
727 \r
728 VOID *\r
729 ExGetWorker (\r
730   IN CONST EFI_GUID         *Guid,\r
731   IN UINTN                  ExTokenNumber,\r
732   IN UINTN                  GetSize\r
733   ) \r
734 {\r
735   return GetWorker(GetExPcdTokenNumber (Guid, (UINT32) ExTokenNumber), GetSize);\r
736 }\r
737 \r
738 \r
739 \r
740 \r
741 EFI_STATUS\r
742 ExSetValueWorker (\r
743   IN          UINTN                ExTokenNumber,\r
744   IN          CONST EFI_GUID       *Guid,\r
745   IN          VOID                 *Data,\r
746   IN          UINTN                SetSize\r
747   )\r
748 {\r
749   return ExSetWorker (ExTokenNumber, Guid, Data, &SetSize, FALSE);\r
750 }\r
751 \r
752 \r
753 EFI_STATUS\r
754 ExSetWorker (\r
755   IN          UINTN                ExTokenNumber,\r
756   IN          CONST EFI_GUID       *Guid,\r
757   IN          VOID                 *Data,\r
758   IN OUT      UINTN                *SetSize,\r
759   IN          BOOLEAN              PtrType\r
760   )\r
761 {\r
762   UINTN                   TokenNumber;\r
763   \r
764   TokenNumber = GetExPcdTokenNumber (Guid, (UINT32) ExTokenNumber);\r
765 \r
766   InvokeCallbackOnSet ((UINT32) ExTokenNumber, Guid, TokenNumber, Data, *SetSize);\r
767 \r
768   return SetWorker (TokenNumber, Data, SetSize, PtrType);\r
769 \r
770 }\r
771 \r
772 \r
773 \r
774 \r
775 EFI_STATUS\r
776 SetHiiVariable (\r
777   IN  EFI_GUID     *VariableGuid,\r
778   IN  UINT16       *VariableName,\r
779   IN  CONST VOID   *Data,\r
780   IN  UINTN        DataSize,\r
781   IN  UINTN        Offset\r
782   )\r
783 {\r
784   UINTN       Size;\r
785   VOID        *Buffer;\r
786   EFI_STATUS  Status;\r
787   UINT32      Attribute;\r
788 \r
789   Size = 0;\r
790 \r
791   Status = gRT->GetVariable (\r
792     (UINT16 *)VariableName,\r
793     VariableGuid,\r
794     NULL,\r
795     &Size,\r
796     NULL\r
797     );\r
798 \r
799   if (Status == EFI_BUFFER_TOO_SMALL) {\r
800 \r
801     Buffer = AllocatePool (Size);\r
802 \r
803     ASSERT (Buffer != NULL);\r
804 \r
805     Status = gRT->GetVariable (\r
806       VariableName,\r
807       VariableGuid,\r
808       &Attribute,\r
809       &Size,\r
810       Buffer\r
811       );\r
812     \r
813     ASSERT_EFI_ERROR (Status);\r
814 \r
815     CopyMem ((UINT8 *)Buffer + Offset, Data, DataSize);\r
816 \r
817     Status = gRT->SetVariable (\r
818               VariableName,\r
819               VariableGuid,\r
820               Attribute,\r
821               Size,\r
822               Buffer\r
823               );\r
824 \r
825     FreePool (Buffer);\r
826     return Status;\r
827 \r
828   } \r
829   \r
830   //\r
831   // If we drop to here, we don't have a Variable entry in\r
832   // the variable service yet. So, we will save the data\r
833   // in the PCD Database's volatile area.\r
834   //\r
835   return Status;\r
836 }\r
837 \r
838 \r
839 \r
840 \r
841 \r
842 UINTN           \r
843 GetExPcdTokenNumber (\r
844   IN CONST EFI_GUID             *Guid,\r
845   IN UINT32                     ExTokenNumber\r
846   )\r
847 {\r
848   UINT32              i;\r
849   DYNAMICEX_MAPPING   *ExMap;\r
850   EFI_GUID            *GuidTable;\r
851   EFI_GUID            *MatchGuid;\r
852   UINTN               MatchGuidIdx;\r
853 \r
854   if (!PEI_DATABASE_EMPTY) {\r
855     ExMap       = mPcdDatabase->PeiDb.Init.ExMapTable;\r
856     GuidTable   = mPcdDatabase->PeiDb.Init.GuidTable;\r
857     \r
858     MatchGuid   = ScanGuid (GuidTable, sizeof(mPcdDatabase->PeiDb.Init.GuidTable), Guid);\r
859     \r
860     if (MatchGuid != NULL) {\r
861 \r
862       MatchGuidIdx = MatchGuid - GuidTable;\r
863       \r
864       for (i = 0; i < PEI_EXMAPPING_TABLE_SIZE; i++) {\r
865         if ((ExTokenNumber == ExMap[i].ExTokenNumber) &&\r
866             (MatchGuidIdx == ExMap[i].ExGuidIndex)) {\r
867             return ExMap[i].LocalTokenNumber;\r
868 \r
869         }\r
870       }\r
871     }\r
872   }\r
873   \r
874   ExMap       = mPcdDatabase->DxeDb.Init.ExMapTable;\r
875   GuidTable   = mPcdDatabase->DxeDb.Init.GuidTable;\r
876 \r
877   MatchGuid   = ScanGuid (GuidTable, sizeof(mPcdDatabase->DxeDb.Init.GuidTable), Guid);\r
878   //\r
879   // We need to ASSERT here. If GUID can't be found in GuidTable, this is a\r
880   // error in the BUILD system.\r
881   //\r
882   ASSERT (MatchGuid != NULL);\r
883 \r
884   MatchGuidIdx = MatchGuid - GuidTable;\r
885   \r
886   for (i = 0; i < DXE_EXMAPPING_TABLE_SIZE; i++) {\r
887     if ((ExTokenNumber == ExMap[i].ExTokenNumber) &&\r
888          (MatchGuidIdx == ExMap[i].ExGuidIndex)) {\r
889         return ExMap[i].LocalTokenNumber;\r
890     }\r
891   }\r
892 \r
893   ASSERT (FALSE);\r
894 \r
895   return 0;\r
896 }\r
897 \r
898 \r
899 STATIC\r
900 SKU_ID *\r
901 GetSkuIdArray (\r
902   IN    UINTN             LocalTokenNumberTableIdx,\r
903   IN    BOOLEAN           IsPeiPcd\r
904   )\r
905 {\r
906   SKU_HEAD  *SkuHead;\r
907   UINTN     LocalTokenNumber;\r
908   UINT8     *Database;\r
909 \r
910   if (IsPeiPcd) {\r
911     LocalTokenNumber = mPcdDatabase->PeiDb.Init.LocalTokenNumberTable[LocalTokenNumberTableIdx];\r
912     Database         = (UINT8 *) &mPcdDatabase->PeiDb;\r
913   } else {\r
914     LocalTokenNumber = mPcdDatabase->DxeDb.Init.LocalTokenNumberTable[LocalTokenNumberTableIdx - PEI_LOCAL_TOKEN_NUMBER];\r
915     Database         = (UINT8 *) &mPcdDatabase->DxeDb;\r
916   }\r
917 \r
918   ASSERT ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) != 0);\r
919 \r
920   SkuHead = (SKU_HEAD *) ((UINT8 *)Database + (LocalTokenNumber & PCD_DATABASE_OFFSET_MASK));\r
921 \r
922   return (SKU_ID *) (Database + SkuHead->SkuIdTableOffset);\r
923   \r
924 }\r
925 \r
926 \r
927 STATIC\r
928 UINTN\r
929 GetSizeTableIndexA (\r
930   IN UINTN        LocalTokenNumberTableIdx,\r
931   IN UINT32       *LocalTokenNumberTable,\r
932   IN BOOLEAN      IsPeiDb\r
933   )\r
934 {\r
935   UINTN       i;\r
936   UINTN       SizeTableIdx;\r
937   UINTN       LocalTokenNumber;\r
938   SKU_ID      *SkuIdTable;\r
939   \r
940   SizeTableIdx = 0;\r
941 \r
942   for (i=0; i<LocalTokenNumberTableIdx; i++) {\r
943     LocalTokenNumber = LocalTokenNumberTable[i];\r
944 \r
945     if ((LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) == PCD_DATUM_TYPE_POINTER) {\r
946       //\r
947       // SizeTable only contain record for PCD_DATUM_TYPE_POINTER type \r
948       // PCD entry.\r
949       //\r
950       if (LocalTokenNumber & PCD_TYPE_VPD) {\r
951           //\r
952           // We have only one entry for VPD enabled PCD entry:\r
953           // 1) MAX Size.\r
954           // We consider current size is equal to MAX size.\r
955           //\r
956           SizeTableIdx++;\r
957       } else {\r
958         if ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == 0) {\r
959           //\r
960           // We have only two entry for Non-Sku enabled PCD entry:\r
961           // 1) MAX SIZE\r
962           // 2) Current Size\r
963           //\r
964           SizeTableIdx += 2;\r
965         } else {\r
966           //\r
967           // We have these entry for SKU enabled PCD entry\r
968           // 1) MAX SIZE\r
969           // 2) Current Size for each SKU_ID (It is equal to MaxSku).\r
970           //\r
971           SkuIdTable = GetSkuIdArray (i, IsPeiDb);\r
972           SizeTableIdx += (UINTN)*SkuIdTable + 1;\r
973         }\r
974       }\r
975     }\r
976 \r
977   }\r
978 \r
979   return SizeTableIdx;\r
980 }\r
981 \r
982 \r
983 \r
984 STATIC\r
985 UINTN\r
986 GetSizeTableIndex (\r
987   IN    UINTN             LocalTokenNumberTableIdx,\r
988   IN    BOOLEAN           IsPeiDb\r
989   )\r
990 {\r
991   UINT32 *LocalTokenNumberTable;\r
992   \r
993   if (IsPeiDb) {\r
994     LocalTokenNumberTable = mPcdDatabase->PeiDb.Init.LocalTokenNumberTable;\r
995   } else {\r
996     LocalTokenNumberTable = mPcdDatabase->DxeDb.Init.LocalTokenNumberTable;\r
997   }\r
998   return GetSizeTableIndexA (LocalTokenNumberTableIdx, \r
999                               LocalTokenNumberTable,\r
1000                               IsPeiDb);\r
1001 }\r
1002 \r
1003 \r
1004 \r
1005 UINTN\r
1006 GetPtrTypeSize (\r
1007   IN    UINTN             LocalTokenNumberTableIdx,\r
1008   OUT   UINTN             *MaxSize\r
1009   )\r
1010 {\r
1011   INTN        SizeTableIdx;\r
1012   UINTN       LocalTokenNumber;\r
1013   SKU_ID      *SkuIdTable;\r
1014   SIZE_INFO   *SizeTable;\r
1015   UINTN       i;\r
1016   BOOLEAN     IsPeiDb;\r
1017   UINT32      *LocalTokenNumberTable;\r
1018 \r
1019   // EBC compiler is very choosy. It may report warning about comparison\r
1020   // between UINTN and 0 . So we add 1 in each size of the \r
1021   // comparison.\r
1022   IsPeiDb = (BOOLEAN) (LocalTokenNumberTableIdx + 1 < PEI_LOCAL_TOKEN_NUMBER + 1);\r
1023 \r
1024 \r
1025   if (IsPeiDb) {\r
1026     LocalTokenNumberTable = mPcdDatabase->PeiDb.Init.LocalTokenNumberTable;\r
1027     SizeTable = mPcdDatabase->PeiDb.Init.SizeTable;\r
1028   } else {\r
1029     LocalTokenNumberTableIdx -= PEI_LOCAL_TOKEN_NUMBER;\r
1030     LocalTokenNumberTable = mPcdDatabase->DxeDb.Init.LocalTokenNumberTable;\r
1031     SizeTable = mPcdDatabase->DxeDb.Init.SizeTable;\r
1032   }\r
1033 \r
1034   LocalTokenNumber = LocalTokenNumberTable[LocalTokenNumberTableIdx];\r
1035 \r
1036   ASSERT ((LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) == PCD_DATUM_TYPE_POINTER);\r
1037   \r
1038   SizeTableIdx = GetSizeTableIndex (LocalTokenNumberTableIdx, IsPeiDb);\r
1039 \r
1040   *MaxSize = SizeTable[SizeTableIdx];\r
1041   //\r
1042   // SizeTable only contain record for PCD_DATUM_TYPE_POINTER type \r
1043   // PCD entry.\r
1044   //\r
1045   if (LocalTokenNumber & PCD_TYPE_VPD) {\r
1046       //\r
1047       // We have only one entry for VPD enabled PCD entry:\r
1048       // 1) MAX Size.\r
1049       // We consider current size is equal to MAX size.\r
1050       //\r
1051       return *MaxSize;\r
1052   } else {\r
1053     if ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == 0) {\r
1054       //\r
1055       // We have only two entry for Non-Sku enabled PCD entry:\r
1056       // 1) MAX SIZE\r
1057       // 2) Current Size\r
1058       //\r
1059       return SizeTable[SizeTableIdx + 1];\r
1060     } else {\r
1061       //\r
1062       // We have these entry for SKU enabled PCD entry\r
1063       // 1) MAX SIZE\r
1064       // 2) Current Size for each SKU_ID (It is equal to MaxSku).\r
1065       //\r
1066       SkuIdTable = GetSkuIdArray (LocalTokenNumberTableIdx, IsPeiDb);\r
1067       for (i = 0; i < SkuIdTable[0]; i++) {\r
1068         if (SkuIdTable[1 + i] == mPcdDatabase->PeiDb.Init.SystemSkuId) {\r
1069           return SizeTable[SizeTableIdx + 1 + i];\r
1070         }\r
1071       }\r
1072       return SizeTable[SizeTableIdx + 1];\r
1073     }\r
1074   }\r
1075 }\r
1076 \r
1077 \r
1078 \r
1079 BOOLEAN\r
1080 SetPtrTypeSize (\r
1081   IN          UINTN             LocalTokenNumberTableIdx,\r
1082   IN    OUT   UINTN             *CurrentSize\r
1083   )\r
1084 {\r
1085   INTN        SizeTableIdx;\r
1086   UINTN       LocalTokenNumber;\r
1087   SKU_ID      *SkuIdTable;\r
1088   SIZE_INFO   *SizeTable;\r
1089   UINTN       i;\r
1090   UINTN       MaxSize;\r
1091   BOOLEAN     IsPeiDb;\r
1092   UINT32      *LocalTokenNumberTable;\r
1093 \r
1094   // EBC compiler is very choosy. It may report warning about comparison\r
1095   // between UINTN and 0 . So we add 1 in each size of the \r
1096   // comparison.\r
1097   IsPeiDb = (BOOLEAN) (LocalTokenNumberTableIdx + 1 < PEI_LOCAL_TOKEN_NUMBER + 1);\r
1098 \r
1099   if (IsPeiDb) {\r
1100     LocalTokenNumberTable = mPcdDatabase->PeiDb.Init.LocalTokenNumberTable;\r
1101     SizeTable = mPcdDatabase->PeiDb.Init.SizeTable;\r
1102   } else {\r
1103     LocalTokenNumberTableIdx -= PEI_LOCAL_TOKEN_NUMBER;\r
1104     LocalTokenNumberTable = mPcdDatabase->DxeDb.Init.LocalTokenNumberTable;\r
1105     SizeTable = mPcdDatabase->DxeDb.Init.SizeTable;\r
1106   }\r
1107 \r
1108   LocalTokenNumber = LocalTokenNumberTable[LocalTokenNumberTableIdx];\r
1109 \r
1110   ASSERT ((LocalTokenNumber & PCD_DATUM_TYPE_ALL_SET) == PCD_DATUM_TYPE_POINTER);\r
1111   \r
1112   SizeTableIdx = GetSizeTableIndex (LocalTokenNumberTableIdx, IsPeiDb);\r
1113 \r
1114   MaxSize = SizeTable[SizeTableIdx];\r
1115   //\r
1116   // SizeTable only contain record for PCD_DATUM_TYPE_POINTER type \r
1117   // PCD entry.\r
1118   //\r
1119   if (LocalTokenNumber & PCD_TYPE_VPD) {\r
1120       //\r
1121       // We shouldn't come here as we don't support SET for VPD\r
1122       //\r
1123       ASSERT (FALSE);\r
1124       return FALSE;\r
1125   } else {\r
1126     if ((*CurrentSize > MaxSize) ||\r
1127       (*CurrentSize == MAX_ADDRESS)) {\r
1128        *CurrentSize = MaxSize;\r
1129        return FALSE;\r
1130     } \r
1131     \r
1132     if ((LocalTokenNumber & PCD_TYPE_SKU_ENABLED) == 0) {\r
1133       //\r
1134       // We have only two entry for Non-Sku enabled PCD entry:\r
1135       // 1) MAX SIZE\r
1136       // 2) Current Size\r
1137       //\r
1138       SizeTable[SizeTableIdx + 1] = (SIZE_INFO) *CurrentSize;\r
1139       return TRUE;\r
1140     } else {\r
1141       //\r
1142       // We have these entry for SKU enabled PCD entry\r
1143       // 1) MAX SIZE\r
1144       // 2) Current Size for each SKU_ID (It is equal to MaxSku).\r
1145       //\r
1146       SkuIdTable = GetSkuIdArray (LocalTokenNumberTableIdx, IsPeiDb);\r
1147       for (i = 0; i < SkuIdTable[0]; i++) {\r
1148         if (SkuIdTable[1 + i] == mPcdDatabase->PeiDb.Init.SystemSkuId) {\r
1149           SizeTable[SizeTableIdx + 1 + i] = (SIZE_INFO) *CurrentSize;\r
1150           return TRUE;\r
1151         }\r
1152       }\r
1153       SizeTable[SizeTableIdx + 1] = (SIZE_INFO) *CurrentSize;\r
1154       return TRUE;\r
1155     }\r
1156   }\r
1157 }\r
1158 \r