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