]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
Replace references to RFC 3066 with RFC 4646.
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / Variable.c
1 /** @file
2
3 Implement all four UEFI Runtime Variable services for the nonvolatile
4 and volatile storage space and install variable architecture protocol.
5
6 Copyright (c) 2006 - 2009, Intel Corporation
7 All rights reserved. This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "Variable.h"
18
19 VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;
20 EFI_EVENT mVirtualAddressChangeEvent = NULL;
21 EFI_HANDLE mHandle = NULL;
22 ///
23 /// The size of a 3 character ISO639 language code.
24 ///
25 #define ISO_639_2_ENTRY_SIZE 3
26
27 ///
28 /// The current Hii implementation accesses this variable many times on every boot.
29 /// Other common variables are only accessed once. This is why this cache algorithm
30 /// only targets a single variable. Probably to get an performance improvement out of
31 /// a Cache you would need a cache that improves the search performance for a variable.
32 ///
33 VARIABLE_CACHE_ENTRY mVariableCache[] = {
34 {
35 &gEfiGlobalVariableGuid,
36 L"Lang",
37 0x00000000,
38 0x00,
39 NULL
40 },
41 {
42 &gEfiGlobalVariableGuid,
43 L"PlatformLang",
44 0x00000000,
45 0x00,
46 NULL
47 }
48 };
49
50 VARIABLE_INFO_ENTRY *gVariableInfo = NULL;
51 EFI_EVENT mFvbRegistration = NULL;
52
53 /**
54 Update the variable region with Variable information. These are the same
55 arguments as the EFI Variable services.
56
57 @param[in] VariableName Name of variable
58
59 @param[in] VendorGuid Guid of variable
60
61 @param[in] Data Variable data
62
63 @param[in] DataSize Size of data. 0 means delete
64
65 @param[in] Attributes Attribues of the variable
66
67 @param[in] Variable The variable information which is used to keep track of variable usage.
68
69 @retval EFI_SUCCESS The update operation is success.
70
71 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
72
73 **/
74 EFI_STATUS
75 EFIAPI
76 UpdateVariable (
77 IN CHAR16 *VariableName,
78 IN EFI_GUID *VendorGuid,
79 IN VOID *Data,
80 IN UINTN DataSize,
81 IN UINT32 Attributes OPTIONAL,
82 IN VARIABLE_POINTER_TRACK *Variable
83 );
84
85 /**
86 Acquires lock only at boot time. Simply returns at runtime.
87
88 This is a temperary function which will be removed when
89 EfiAcquireLock() in UefiLib can handle the call in UEFI
90 Runtimer driver in RT phase.
91 It calls EfiAcquireLock() at boot time, and simply returns
92 at runtime.
93
94 @param Lock A pointer to the lock to acquire
95
96 **/
97 VOID
98 AcquireLockOnlyAtBootTime (
99 IN EFI_LOCK *Lock
100 )
101 {
102 if (!EfiAtRuntime ()) {
103 EfiAcquireLock (Lock);
104 }
105 }
106
107 /**
108 Releases lock only at boot time. Simply returns at runtime.
109
110 This is a temperary function which will be removed when
111 EfiReleaseLock() in UefiLib can handle the call in UEFI
112 Runtimer driver in RT phase.
113 It calls EfiReleaseLock() at boot time, and simply returns
114 at runtime.
115
116 @param Lock A pointer to the lock to release
117
118 **/
119 VOID
120 ReleaseLockOnlyAtBootTime (
121 IN EFI_LOCK *Lock
122 )
123 {
124 if (!EfiAtRuntime ()) {
125 EfiReleaseLock (Lock);
126 }
127 }
128
129
130 /**
131 Routine used to track statistical information about variable usage.
132 The data is stored in the EFI system table so it can be accessed later.
133 VariableInfo.efi can dump out the table. Only Boot Services variable
134 accesses are tracked by this code. The PcdVariableCollectStatistics
135 build flag controls if this feature is enabled.
136
137 A read that hits in the cache will have Read and Cache true for
138 the transaction. Data is allocated by this routine, but never
139 freed.
140
141 @param[in] VariableName Name of the Variable to track
142 @param[in] VendorGuid Guid of the Variable to track
143 @param[in] Volatile TRUE if volatile FALSE if non-volatile
144 @param[in] Read TRUE if GetVariable() was called
145 @param[in] Write TRUE if SetVariable() was called
146 @param[in] Delete TRUE if deleted via SetVariable()
147 @param[in] Cache TRUE for a cache hit.
148
149 **/
150 VOID
151 UpdateVariableInfo (
152 IN CHAR16 *VariableName,
153 IN EFI_GUID *VendorGuid,
154 IN BOOLEAN Volatile,
155 IN BOOLEAN Read,
156 IN BOOLEAN Write,
157 IN BOOLEAN Delete,
158 IN BOOLEAN Cache
159 )
160 {
161 VARIABLE_INFO_ENTRY *Entry;
162
163 if (FeaturePcdGet (PcdVariableCollectStatistics)) {
164
165 if (EfiAtRuntime ()) {
166 // Don't collect statistics at runtime
167 return;
168 }
169
170 if (gVariableInfo == NULL) {
171 //
172 // on the first call allocate a entry and place a pointer to it in
173 // the EFI System Table
174 //
175 gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
176 ASSERT (gVariableInfo != NULL);
177
178 CopyGuid (&gVariableInfo->VendorGuid, VendorGuid);
179 gVariableInfo->Name = AllocatePool (StrLen (VariableName));
180 ASSERT (gVariableInfo->Name != NULL);
181 StrCpy (gVariableInfo->Name, VariableName);
182 gVariableInfo->Volatile = Volatile;
183
184 gBS->InstallConfigurationTable (&gEfiVariableGuid, gVariableInfo);
185 }
186
187
188 for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) {
189 if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {
190 if (StrCmp (VariableName, Entry->Name) == 0) {
191 if (Read) {
192 Entry->ReadCount++;
193 }
194 if (Write) {
195 Entry->WriteCount++;
196 }
197 if (Delete) {
198 Entry->DeleteCount++;
199 }
200 if (Cache) {
201 Entry->CacheCount++;
202 }
203
204 return;
205 }
206 }
207
208 if (Entry->Next == NULL) {
209 //
210 // If the entry is not in the table add it.
211 // Next iteration of the loop will fill in the data
212 //
213 Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
214 ASSERT (Entry->Next != NULL);
215
216 CopyGuid (&Entry->Next->VendorGuid, VendorGuid);
217 Entry->Next->Name = AllocatePool (StrLen (VariableName));
218 ASSERT (Entry->Next->Name != NULL);
219 StrCpy (Entry->Next->Name, VariableName);
220 Entry->Next->Volatile = Volatile;
221 }
222
223 }
224 }
225 }
226
227
228 /**
229
230 This code checks if variable header is valid or not.
231
232 @param Variable Pointer to the Variable Header.
233
234 @retval TRUE Variable header is valid.
235 @retval FALSE Variable header is not valid.
236
237 **/
238 BOOLEAN
239 IsValidVariableHeader (
240 IN VARIABLE_HEADER *Variable
241 )
242 {
243 if (Variable == NULL || Variable->StartId != VARIABLE_DATA) {
244 return FALSE;
245 }
246
247 return TRUE;
248 }
249
250
251 /**
252
253 This function writes data to the FWH at the correct LBA even if the LBAs
254 are fragmented.
255
256 @param Global Pointer to VARAIBLE_GLOBAL structure
257 @param Volatile Point out the Variable is Volatile or Non-Volatile
258 @param SetByIndex TRUE if target pointer is given as index
259 FALSE if target pointer is absolute
260 @param Fvb Pointer to the writable FVB protocol
261 @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER
262 structure
263 @param DataSize Size of data to be written
264 @param Buffer Pointer to the buffer from which data is written
265
266 @retval EFI_INVALID_PARAMETER Parameters not valid
267 @retval EFI_SUCCESS Variable store successfully updated
268
269 **/
270 EFI_STATUS
271 UpdateVariableStore (
272 IN VARIABLE_GLOBAL *Global,
273 IN BOOLEAN Volatile,
274 IN BOOLEAN SetByIndex,
275 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
276 IN UINTN DataPtrIndex,
277 IN UINT32 DataSize,
278 IN UINT8 *Buffer
279 )
280 {
281 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
282 UINTN BlockIndex2;
283 UINTN LinearOffset;
284 UINTN CurrWriteSize;
285 UINTN CurrWritePtr;
286 UINT8 *CurrBuffer;
287 EFI_LBA LbaNumber;
288 UINTN Size;
289 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
290 VARIABLE_STORE_HEADER *VolatileBase;
291 EFI_PHYSICAL_ADDRESS FvVolHdr;
292 EFI_PHYSICAL_ADDRESS DataPtr;
293 EFI_STATUS Status;
294
295 FwVolHeader = NULL;
296 DataPtr = DataPtrIndex;
297
298 //
299 // Check if the Data is Volatile
300 //
301 if (!Volatile) {
302 Status = Fvb->GetPhysicalAddress(Fvb, &FvVolHdr);
303 ASSERT_EFI_ERROR (Status);
304
305 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);
306 //
307 // Data Pointer should point to the actual Address where data is to be
308 // written
309 //
310 if (SetByIndex) {
311 DataPtr += mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;
312 }
313
314 if ((DataPtr + DataSize) >= ((EFI_PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) FwVolHeader + FwVolHeader->FvLength))) {
315 return EFI_INVALID_PARAMETER;
316 }
317 } else {
318 //
319 // Data Pointer should point to the actual Address where data is to be
320 // written
321 //
322 VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
323 if (SetByIndex) {
324 DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
325 }
326
327 if ((DataPtr + DataSize) >= ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) {
328 return EFI_INVALID_PARAMETER;
329 }
330
331 //
332 // If Volatile Variable just do a simple mem copy.
333 //
334 CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize);
335 return EFI_SUCCESS;
336 }
337
338 //
339 // If we are here we are dealing with Non-Volatile Variables
340 //
341 LinearOffset = (UINTN) FwVolHeader;
342 CurrWritePtr = (UINTN) DataPtr;
343 CurrWriteSize = DataSize;
344 CurrBuffer = Buffer;
345 LbaNumber = 0;
346
347 if (CurrWritePtr < LinearOffset) {
348 return EFI_INVALID_PARAMETER;
349 }
350
351 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
352 for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {
353 //
354 // Check to see if the Variable Writes are spanning through multiple
355 // blocks.
356 //
357 if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) {
358 if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {
359 Status = Fvb->Write (
360 Fvb,
361 LbaNumber,
362 (UINTN) (CurrWritePtr - LinearOffset),
363 &CurrWriteSize,
364 CurrBuffer
365 );
366 return Status;
367 } else {
368 Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);
369 Status = Fvb->Write (
370 Fvb,
371 LbaNumber,
372 (UINTN) (CurrWritePtr - LinearOffset),
373 &Size,
374 CurrBuffer
375 );
376 if (EFI_ERROR (Status)) {
377 return Status;
378 }
379
380 CurrWritePtr = LinearOffset + PtrBlockMapEntry->Length;
381 CurrBuffer = CurrBuffer + Size;
382 CurrWriteSize = CurrWriteSize - Size;
383 }
384 }
385
386 LinearOffset += PtrBlockMapEntry->Length;
387 LbaNumber++;
388 }
389 }
390
391 return EFI_SUCCESS;
392 }
393
394
395 /**
396
397 This code gets the current status of Variable Store.
398
399 @param VarStoreHeader Pointer to the Variable Store Header.
400
401 @retval EfiRaw Variable store status is raw
402 @retval EfiValid Variable store status is valid
403 @retval EfiInvalid Variable store status is invalid
404
405 **/
406 VARIABLE_STORE_STATUS
407 GetVariableStoreStatus (
408 IN VARIABLE_STORE_HEADER *VarStoreHeader
409 )
410 {
411 if (CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid) &&
412 VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&
413 VarStoreHeader->State == VARIABLE_STORE_HEALTHY
414 ) {
415
416 return EfiValid;
417 } else if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff &&
418 ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff &&
419 ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff &&
420 ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff &&
421 VarStoreHeader->Size == 0xffffffff &&
422 VarStoreHeader->Format == 0xff &&
423 VarStoreHeader->State == 0xff
424 ) {
425
426 return EfiRaw;
427 } else {
428 return EfiInvalid;
429 }
430 }
431
432
433 /**
434
435 This code gets the size of name of variable.
436
437 @param Variable Pointer to the Variable Header
438
439 @return UINTN Size of variable in bytes
440
441 **/
442 UINTN
443 NameSizeOfVariable (
444 IN VARIABLE_HEADER *Variable
445 )
446 {
447 if (Variable->State == (UINT8) (-1) ||
448 Variable->DataSize == (UINT32) (-1) ||
449 Variable->NameSize == (UINT32) (-1) ||
450 Variable->Attributes == (UINT32) (-1)) {
451 return 0;
452 }
453 return (UINTN) Variable->NameSize;
454 }
455
456 /**
457
458 This code gets the size of variable data.
459
460 @param Variable Pointer to the Variable Header
461
462 @return Size of variable in bytes
463
464 **/
465 UINTN
466 DataSizeOfVariable (
467 IN VARIABLE_HEADER *Variable
468 )
469 {
470 if (Variable->State == (UINT8) (-1) ||
471 Variable->DataSize == (UINT32) (-1) ||
472 Variable->NameSize == (UINT32) (-1) ||
473 Variable->Attributes == (UINT32) (-1)) {
474 return 0;
475 }
476 return (UINTN) Variable->DataSize;
477 }
478
479 /**
480
481 This code gets the pointer to the variable name.
482
483 @param Variable Pointer to the Variable Header
484
485 @return Pointer to Variable Name which is Unicode encoding
486
487 **/
488 CHAR16 *
489 GetVariableNamePtr (
490 IN VARIABLE_HEADER *Variable
491 )
492 {
493
494 return (CHAR16 *) (Variable + 1);
495 }
496
497 /**
498
499 This code gets the pointer to the variable data.
500
501 @param Variable Pointer to the Variable Header
502
503 @return Pointer to Variable Data
504
505 **/
506 UINT8 *
507 GetVariableDataPtr (
508 IN VARIABLE_HEADER *Variable
509 )
510 {
511 UINTN Value;
512
513 //
514 // Be careful about pad size for alignment
515 //
516 Value = (UINTN) GetVariableNamePtr (Variable);
517 Value += NameSizeOfVariable (Variable);
518 Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));
519
520 return (UINT8 *) Value;
521 }
522
523
524 /**
525
526 This code gets the pointer to the next variable header.
527
528 @param Variable Pointer to the Variable Header
529
530 @return Pointer to next variable header
531
532 **/
533 VARIABLE_HEADER *
534 GetNextVariablePtr (
535 IN VARIABLE_HEADER *Variable
536 )
537 {
538 UINTN Value;
539
540 if (!IsValidVariableHeader (Variable)) {
541 return NULL;
542 }
543
544 Value = (UINTN) GetVariableDataPtr (Variable);
545 Value += DataSizeOfVariable (Variable);
546 Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));
547
548 //
549 // Be careful about pad size for alignment
550 //
551 return (VARIABLE_HEADER *) HEADER_ALIGN (Value);
552 }
553
554 /**
555
556 Gets the pointer to the first variable header in given variable store area.
557
558 @param VarStoreHeader Pointer to the Variable Store Header.
559
560 @return Pointer to the first variable header
561
562 **/
563 VARIABLE_HEADER *
564 GetStartPointer (
565 IN VARIABLE_STORE_HEADER *VarStoreHeader
566 )
567 {
568 //
569 // The end of variable store
570 //
571 return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);
572 }
573
574 /**
575
576 Gets the pointer to the end of the variable storage area.
577
578 This function gets pointer to the end of the variable storage
579 area, according to the input variable store header.
580
581 @param VarStoreHeader Pointer to the Variable Store Header
582
583 @return Pointer to the end of the variable storage area
584
585 **/
586 VARIABLE_HEADER *
587 GetEndPointer (
588 IN VARIABLE_STORE_HEADER *VarStoreHeader
589 )
590 {
591 //
592 // The end of variable store
593 //
594 return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);
595 }
596
597
598 /**
599
600 Variable store garbage collection and reclaim operation.
601
602 @param VariableBase Base address of variable store
603 @param LastVariableOffset Offset of last variable
604 @param IsVolatile The variable store is volatile or not,
605 if it is non-volatile, need FTW
606 @param UpdatingVariable Pointer to updateing variable.
607
608 @return EFI_OUT_OF_RESOURCES
609 @return EFI_SUCCESS
610 @return Others
611
612 **/
613 EFI_STATUS
614 Reclaim (
615 IN EFI_PHYSICAL_ADDRESS VariableBase,
616 OUT UINTN *LastVariableOffset,
617 IN BOOLEAN IsVolatile,
618 IN VARIABLE_HEADER *UpdatingVariable
619 )
620 {
621 VARIABLE_HEADER *Variable;
622 VARIABLE_HEADER *AddedVariable;
623 VARIABLE_HEADER *NextVariable;
624 VARIABLE_HEADER *NextAddedVariable;
625 VARIABLE_STORE_HEADER *VariableStoreHeader;
626 UINT8 *ValidBuffer;
627 UINTN MaximumBufferSize;
628 UINTN VariableSize;
629 UINTN VariableNameSize;
630 UINTN UpdatingVariableNameSize;
631 UINTN NameSize;
632 UINT8 *CurrPtr;
633 VOID *Point0;
634 VOID *Point1;
635 BOOLEAN FoundAdded;
636 EFI_STATUS Status;
637 CHAR16 *VariableNamePtr;
638 CHAR16 *UpdatingVariableNamePtr;
639
640 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);
641 //
642 // recaluate the total size of Common/HwErr type variables in non-volatile area.
643 //
644 if (!IsVolatile) {
645 mVariableModuleGlobal->CommonVariableTotalSize = 0;
646 mVariableModuleGlobal->HwErrVariableTotalSize = 0;
647 }
648
649 //
650 // Start Pointers for the variable.
651 //
652 Variable = GetStartPointer (VariableStoreHeader);
653 MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);
654
655 while (IsValidVariableHeader (Variable)) {
656 NextVariable = GetNextVariablePtr (Variable);
657 if (Variable->State == VAR_ADDED ||
658 Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)
659 ) {
660 VariableSize = (UINTN) NextVariable - (UINTN) Variable;
661 MaximumBufferSize += VariableSize;
662 }
663
664 Variable = NextVariable;
665 }
666
667 //
668 // Reserve the 1 Bytes with Oxff to identify the
669 // end of the variable buffer.
670 //
671 MaximumBufferSize += 1;
672 ValidBuffer = AllocatePool (MaximumBufferSize);
673 if (ValidBuffer == NULL) {
674 return EFI_OUT_OF_RESOURCES;
675 }
676
677 SetMem (ValidBuffer, MaximumBufferSize, 0xff);
678
679 //
680 // Copy variable store header
681 //
682 CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));
683 CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);
684
685 //
686 // Reinstall all ADDED variables as long as they are not identical to Updating Variable
687 //
688 Variable = GetStartPointer (VariableStoreHeader);
689 while (IsValidVariableHeader (Variable)) {
690 NextVariable = GetNextVariablePtr (Variable);
691 if (Variable->State == VAR_ADDED) {
692 if (UpdatingVariable != NULL) {
693 if (UpdatingVariable == Variable) {
694 Variable = NextVariable;
695 continue;
696 }
697
698 VariableNameSize = NameSizeOfVariable(Variable);
699 UpdatingVariableNameSize = NameSizeOfVariable(UpdatingVariable);
700
701 VariableNamePtr = GetVariableNamePtr (Variable);
702 UpdatingVariableNamePtr = GetVariableNamePtr (UpdatingVariable);
703 if (CompareGuid (&Variable->VendorGuid, &UpdatingVariable->VendorGuid) &&
704 VariableNameSize == UpdatingVariableNameSize &&
705 CompareMem (VariableNamePtr, UpdatingVariableNamePtr, VariableNameSize) == 0 ) {
706 Variable = NextVariable;
707 continue;
708 }
709 }
710 VariableSize = (UINTN) NextVariable - (UINTN) Variable;
711 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
712 CurrPtr += VariableSize;
713 if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
714 mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
715 } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
716 mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
717 }
718 }
719 Variable = NextVariable;
720 }
721
722 //
723 // Reinstall the variable being updated if it is not NULL
724 //
725 if (UpdatingVariable != NULL) {
726 VariableSize = (UINTN)(GetNextVariablePtr (UpdatingVariable)) - (UINTN)UpdatingVariable;
727 CopyMem (CurrPtr, (UINT8 *) UpdatingVariable, VariableSize);
728 CurrPtr += VariableSize;
729 if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
730 mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
731 } else if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
732 mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
733 }
734 }
735
736 //
737 // Reinstall all in delete transition variables
738 //
739 Variable = GetStartPointer (VariableStoreHeader);
740 while (IsValidVariableHeader (Variable)) {
741 NextVariable = GetNextVariablePtr (Variable);
742 if (Variable != UpdatingVariable && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
743
744 //
745 // Buffer has cached all ADDED variable.
746 // Per IN_DELETED variable, we have to guarantee that
747 // no ADDED one in previous buffer.
748 //
749
750 FoundAdded = FALSE;
751 AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);
752 while (IsValidVariableHeader (AddedVariable)) {
753 NextAddedVariable = GetNextVariablePtr (AddedVariable);
754 NameSize = NameSizeOfVariable (AddedVariable);
755 if (CompareGuid (&AddedVariable->VendorGuid, &Variable->VendorGuid) &&
756 NameSize == NameSizeOfVariable (Variable)
757 ) {
758 Point0 = (VOID *) GetVariableNamePtr (AddedVariable);
759 Point1 = (VOID *) GetVariableNamePtr (Variable);
760 if (CompareMem (Point0, Point1, NameSizeOfVariable (AddedVariable)) == 0) {
761 FoundAdded = TRUE;
762 break;
763 }
764 }
765 AddedVariable = NextAddedVariable;
766 }
767 if (!FoundAdded) {
768 //
769 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED
770 //
771 VariableSize = (UINTN) NextVariable - (UINTN) Variable;
772 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
773 ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;
774 CurrPtr += VariableSize;
775 if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
776 mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
777 } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
778 mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
779 }
780 }
781 }
782
783 Variable = NextVariable;
784 }
785
786 if (IsVolatile) {
787 //
788 // If volatile variable store, just copy valid buffer
789 //
790 SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);
791 CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - (UINT8 *) ValidBuffer));
792 Status = EFI_SUCCESS;
793 } else {
794 //
795 // If non-volatile variable store, perform FTW here.
796 //
797 Status = FtwVariableSpace (
798 VariableBase,
799 ValidBuffer,
800 (UINTN) (CurrPtr - (UINT8 *) ValidBuffer)
801 );
802 }
803 if (!EFI_ERROR (Status)) {
804 *LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer);
805 } else {
806 *LastVariableOffset = 0;
807 }
808
809 FreePool (ValidBuffer);
810
811 return Status;
812 }
813
814
815 /**
816 Update the Cache with Variable information. These are the same
817 arguments as the EFI Variable services.
818
819 @param[in] VariableName Name of variable
820 @param[in] VendorGuid Guid of variable
821 @param[in] Attributes Attribues of the variable
822 @param[in] DataSize Size of data. 0 means delete
823 @param[in] Data Variable data
824
825 **/
826 VOID
827 UpdateVariableCache (
828 IN CHAR16 *VariableName,
829 IN EFI_GUID *VendorGuid,
830 IN UINT32 Attributes,
831 IN UINTN DataSize,
832 IN VOID *Data
833 )
834 {
835 VARIABLE_CACHE_ENTRY *Entry;
836 UINTN Index;
837
838 if (EfiAtRuntime ()) {
839 //
840 // Don't use the cache at runtime
841 //
842 return;
843 }
844
845 for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {
846 if (CompareGuid (VendorGuid, Entry->Guid)) {
847 if (StrCmp (VariableName, Entry->Name) == 0) {
848 Entry->Attributes = Attributes;
849 if (DataSize == 0) {
850 //
851 // Delete Case
852 //
853 if (Entry->DataSize != 0) {
854 FreePool (Entry->Data);
855 }
856 Entry->DataSize = DataSize;
857 } else if (DataSize == Entry->DataSize) {
858 CopyMem (Entry->Data, Data, DataSize);
859 } else {
860 Entry->Data = AllocatePool (DataSize);
861 ASSERT (Entry->Data != NULL);
862
863 Entry->DataSize = DataSize;
864 CopyMem (Entry->Data, Data, DataSize);
865 }
866 }
867 }
868 }
869 }
870
871
872 /**
873 Search the cache to check if the variable is in it.
874
875 This function searches the variable cache. If the variable to find exists, return its data
876 and attributes.
877
878 @param VariableName A Null-terminated Unicode string that is the name of the vendor's
879 variable. Each VariableName is unique for each
880 VendorGuid.
881 @param VendorGuid A unique identifier for the vendor
882 @param Attributes Pointer to the attributes bitmask of the variable for output.
883 @param DataSize On input, size of the buffer of Data.
884 On output, size of the variable's data.
885 @param Data Pointer to the data buffer for output.
886
887 @retval EFI_SUCCESS VariableGuid & VariableName data was returned.
888 @retval EFI_NOT_FOUND No matching variable found in cache.
889 @retval EFI_BUFFER_TOO_SMALL *DataSize is smaller than size of the variable's data to return.
890
891 **/
892 EFI_STATUS
893 FindVariableInCache (
894 IN CHAR16 *VariableName,
895 IN EFI_GUID *VendorGuid,
896 OUT UINT32 *Attributes OPTIONAL,
897 IN OUT UINTN *DataSize,
898 OUT VOID *Data
899 )
900 {
901 VARIABLE_CACHE_ENTRY *Entry;
902 UINTN Index;
903
904 if (EfiAtRuntime ()) {
905 // Don't use the cache at runtime
906 return EFI_NOT_FOUND;
907 }
908
909 for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {
910 if (CompareGuid (VendorGuid, Entry->Guid)) {
911 if (StrCmp (VariableName, Entry->Name) == 0) {
912 if (Entry->DataSize == 0) {
913 // Variable was deleted so return not found
914 return EFI_NOT_FOUND;
915 } else if (Entry->DataSize > *DataSize) {
916 // If the buffer is too small return correct size
917 *DataSize = Entry->DataSize;
918 return EFI_BUFFER_TOO_SMALL;
919 } else {
920 *DataSize = Entry->DataSize;
921 // Return the data
922 CopyMem (Data, Entry->Data, Entry->DataSize);
923 if (Attributes != NULL) {
924 *Attributes = Entry->Attributes;
925 }
926 return EFI_SUCCESS;
927 }
928 }
929 }
930 }
931
932 return EFI_NOT_FOUND;
933 }
934
935 /**
936 Finds variable in storage blocks of volatile and non-volatile storage areas.
937
938 This code finds variable in storage blocks of volatile and non-volatile storage areas.
939 If VariableName is an empty string, then we just return the first
940 qualified variable without comparing VariableName and VendorGuid.
941 Otherwise, VariableName and VendorGuid are compared.
942
943 @param VariableName Name of the variable to be found
944 @param VendorGuid Vendor GUID to be found.
945 @param PtrTrack VARIABLE_POINTER_TRACK structure for output,
946 including the range searched and the target position.
947 @param Global Pointer to VARIABLE_GLOBAL structure, including
948 base of volatile variable storage area, base of
949 NV variable storage area, and a lock.
950
951 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
952 VendorGuid is NULL
953 @retval EFI_SUCCESS Variable successfully found
954 @retval EFI_INVALID_PARAMETER Variable not found
955
956 **/
957 EFI_STATUS
958 FindVariable (
959 IN CHAR16 *VariableName,
960 IN EFI_GUID *VendorGuid,
961 OUT VARIABLE_POINTER_TRACK *PtrTrack,
962 IN VARIABLE_GLOBAL *Global
963 )
964 {
965 VARIABLE_HEADER *Variable[2];
966 VARIABLE_HEADER *InDeletedVariable;
967 VARIABLE_STORE_HEADER *VariableStoreHeader[2];
968 UINTN InDeletedStorageIndex;
969 UINTN Index;
970 VOID *Point;
971
972 //
973 // 0: Volatile, 1: Non-Volatile
974 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
975 // make use of this mapping to implement search algorithme.
976 //
977 VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
978 VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
979
980 //
981 // Start Pointers for the variable.
982 // Actual Data Pointer where data can be written.
983 //
984 Variable[0] = GetStartPointer (VariableStoreHeader[0]);
985 Variable[1] = GetStartPointer (VariableStoreHeader[1]);
986
987 if (VariableName[0] != 0 && VendorGuid == NULL) {
988 return EFI_INVALID_PARAMETER;
989 }
990
991 //
992 // Find the variable by walk through volatile and then non-volatile variable store
993 //
994 InDeletedVariable = NULL;
995 InDeletedStorageIndex = 0;
996 for (Index = 0; Index < 2; Index++) {
997 while ((Variable[Index] < GetEndPointer (VariableStoreHeader[Index])) && IsValidVariableHeader (Variable[Index])) {
998 if (Variable[Index]->State == VAR_ADDED ||
999 Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)
1000 ) {
1001 if (!EfiAtRuntime () || ((Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {
1002 if (VariableName[0] == 0) {
1003 if (Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
1004 InDeletedVariable = Variable[Index];
1005 InDeletedStorageIndex = Index;
1006 } else {
1007 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]);
1008 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]);
1009 PtrTrack->CurrPtr = Variable[Index];
1010 PtrTrack->Volatile = (BOOLEAN)(Index == 0);
1011
1012 return EFI_SUCCESS;
1013 }
1014 } else {
1015 if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) {
1016 Point = (VOID *) GetVariableNamePtr (Variable[Index]);
1017
1018 ASSERT (NameSizeOfVariable (Variable[Index]) != 0);
1019 if (CompareMem (VariableName, Point, NameSizeOfVariable (Variable[Index])) == 0) {
1020 if (Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
1021 InDeletedVariable = Variable[Index];
1022 InDeletedStorageIndex = Index;
1023 } else {
1024 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]);
1025 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]);
1026 PtrTrack->CurrPtr = Variable[Index];
1027 PtrTrack->Volatile = (BOOLEAN)(Index == 0);
1028
1029 return EFI_SUCCESS;
1030 }
1031 }
1032 }
1033 }
1034 }
1035 }
1036
1037 Variable[Index] = GetNextVariablePtr (Variable[Index]);
1038 }
1039 if (InDeletedVariable != NULL) {
1040 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[InDeletedStorageIndex]);
1041 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[InDeletedStorageIndex]);
1042 PtrTrack->CurrPtr = InDeletedVariable;
1043 PtrTrack->Volatile = (BOOLEAN)(InDeletedStorageIndex == 0);
1044 return EFI_SUCCESS;
1045 }
1046 }
1047 PtrTrack->CurrPtr = NULL;
1048 return EFI_NOT_FOUND;
1049 }
1050
1051 /**
1052 Get index from supported language codes according to language string.
1053
1054 This code is used to get corresponding index in supported language codes. It can handle
1055 RFC4646 and ISO639 language tags.
1056 In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.
1057 In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.
1058
1059 For example:
1060 SupportedLang = "engfraengfra"
1061 Lang = "eng"
1062 Iso639Language = TRUE
1063 The return value is "0".
1064 Another example:
1065 SupportedLang = "en;fr;en-US;fr-FR"
1066 Lang = "fr-FR"
1067 Iso639Language = FALSE
1068 The return value is "3".
1069
1070 @param SupportedLang Platform supported language codes.
1071 @param Lang Configured language.
1072 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
1073
1074 @retval the index of language in the language codes.
1075
1076 **/
1077 UINTN
1078 EFIAPI
1079 GetIndexFromSupportedLangCodes(
1080 IN CHAR8 *SupportedLang,
1081 IN CHAR8 *Lang,
1082 IN BOOLEAN Iso639Language
1083 )
1084 {
1085 UINTN Index;
1086 UINT32 CompareLength;
1087 CHAR8 *Supported;
1088
1089 Index = 0;
1090 Supported = SupportedLang;
1091 if (Iso639Language) {
1092 CompareLength = 3;
1093 for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {
1094 if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {
1095 //
1096 // Successfully find the index of Lang string in SupportedLang string.
1097 //
1098 Index = Index / CompareLength;
1099 return Index;
1100 }
1101 }
1102 ASSERT (FALSE);
1103 return 0;
1104 } else {
1105 //
1106 // Compare RFC4646 language code
1107 //
1108 while (*Supported != '\0') {
1109 //
1110 // take semicolon as delimitation, sequentially traverse supported language codes.
1111 //
1112 for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {
1113 Supported++;
1114 }
1115 if (AsciiStrnCmp (Lang, Supported - CompareLength, CompareLength) == 0) {
1116 //
1117 // Successfully find the index of Lang string in SupportedLang string.
1118 //
1119 return Index;
1120 }
1121 Index++;
1122 }
1123 ASSERT (FALSE);
1124 return 0;
1125 }
1126 }
1127
1128 /**
1129 Get language string from supported language codes according to index.
1130
1131 This code is used to get corresponding language string in supported language codes. It can handle
1132 RFC4646 and ISO639 language tags.
1133 In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.
1134 In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.
1135
1136 For example:
1137 SupportedLang = "engfraengfra"
1138 Index = "1"
1139 Iso639Language = TRUE
1140 The return value is "fra".
1141 Another example:
1142 SupportedLang = "en;fr;en-US;fr-FR"
1143 Index = "1"
1144 Iso639Language = FALSE
1145 The return value is "fr".
1146
1147 @param SupportedLang Platform supported language codes.
1148 @param Index the index in supported language codes.
1149 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
1150
1151 @retval the language string in the language codes.
1152
1153 **/
1154 CHAR8 *
1155 EFIAPI
1156 GetLangFromSupportedLangCodes (
1157 IN CHAR8 *SupportedLang,
1158 IN UINTN Index,
1159 IN BOOLEAN Iso639Language
1160 )
1161 {
1162 UINTN SubIndex;
1163 UINT32 CompareLength;
1164 CHAR8 *Supported;
1165
1166 SubIndex = 0;
1167 Supported = SupportedLang;
1168 if (Iso639Language) {
1169 //
1170 // according to the index of Lang string in SupportedLang string to get the language.
1171 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
1172 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1173 //
1174 CompareLength = 3;
1175 SetMem (mVariableModuleGlobal->Lang, sizeof(mVariableModuleGlobal->Lang), 0);
1176 return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength);
1177
1178 } else {
1179 while (TRUE) {
1180 //
1181 // take semicolon as delimitation, sequentially traverse supported language codes.
1182 //
1183 for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {
1184 Supported++;
1185 }
1186 if ((*Supported == '\0') && (SubIndex != Index)) {
1187 //
1188 // Have completed the traverse, but not find corrsponding string.
1189 // This case is not allowed to happen.
1190 //
1191 ASSERT(FALSE);
1192 return NULL;
1193 }
1194 if (SubIndex == Index) {
1195 //
1196 // according to the index of Lang string in SupportedLang string to get the language.
1197 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
1198 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1199 //
1200 SetMem (mVariableModuleGlobal->PlatformLang, sizeof (mVariableModuleGlobal->PlatformLang), 0);
1201 return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - CompareLength, CompareLength);
1202 }
1203 SubIndex++;
1204 }
1205 }
1206 }
1207
1208 /**
1209 Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.
1210
1211 When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.
1212
1213 According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,
1214 and are read-only. Therefore, in variable driver, only store the original value for other use.
1215
1216 @param[in] VariableName Name of variable
1217
1218 @param[in] Data Variable data
1219
1220 @param[in] DataSize Size of data. 0 means delete
1221
1222 @retval EFI_SUCCESS auto update operation is successful.
1223
1224 **/
1225 EFI_STATUS
1226 EFIAPI
1227 AutoUpdateLangVariable(
1228 IN CHAR16 *VariableName,
1229 IN VOID *Data,
1230 IN UINTN DataSize
1231 )
1232 {
1233 EFI_STATUS Status;
1234 CHAR8 *BestPlatformLang;
1235 CHAR8 *BestLang;
1236 UINTN Index;
1237 UINT32 Attributes;
1238 VARIABLE_POINTER_TRACK Variable;
1239
1240 //
1241 // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
1242 //
1243 Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
1244
1245 if (StrCmp (VariableName, L"PlatformLangCodes") == 0) {
1246 //
1247 // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
1248 // Therefore, in variable driver, only store the original value for other use.
1249 //
1250 AsciiStrnCpy (mVariableModuleGlobal->PlatformLangCodes, Data, DataSize);
1251 } else if (StrCmp (VariableName, L"LangCodes") == 0) {
1252 //
1253 // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
1254 // Therefore, in variable driver, only store the original value for other use.
1255 //
1256 AsciiStrnCpy (mVariableModuleGlobal->LangCodes, Data, DataSize);
1257 } else if (StrCmp (VariableName, L"PlatformLang") == 0) {
1258 ASSERT (AsciiStrLen (mVariableModuleGlobal->PlatformLangCodes) != 0);
1259
1260 //
1261 // When setting PlatformLang, firstly get most matched language string from supported language codes.
1262 //
1263 BestPlatformLang = GetBestLanguage(mVariableModuleGlobal->PlatformLangCodes, FALSE, Data, NULL);
1264
1265 //
1266 // Get the corresponding index in language codes.
1267 //
1268 Index = GetIndexFromSupportedLangCodes(mVariableModuleGlobal->PlatformLangCodes, BestPlatformLang, FALSE);
1269
1270 //
1271 // Get the corresponding ISO639 language tag according to RFC4646 language tag.
1272 //
1273 BestLang = GetLangFromSupportedLangCodes(mVariableModuleGlobal->LangCodes, Index, TRUE);
1274
1275 //
1276 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
1277 //
1278 FindVariable(L"Lang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal);
1279
1280 Status = UpdateVariable(L"Lang", &gEfiGlobalVariableGuid,
1281 BestLang, ISO_639_2_ENTRY_SIZE + 1, Attributes, &Variable);
1282
1283 DEBUG((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang));
1284
1285 ASSERT_EFI_ERROR(Status);
1286
1287 } else if (StrCmp (VariableName, L"Lang") == 0) {
1288 ASSERT (AsciiStrLen (mVariableModuleGlobal->LangCodes) != 0);
1289
1290 //
1291 // When setting Lang, firstly get most matched language string from supported language codes.
1292 //
1293 BestLang = GetBestLanguage(mVariableModuleGlobal->LangCodes, TRUE, Data, NULL);
1294
1295 //
1296 // Get the corresponding index in language codes.
1297 //
1298 Index = GetIndexFromSupportedLangCodes(mVariableModuleGlobal->LangCodes, BestLang, TRUE);
1299
1300 //
1301 // Get the corresponding RFC4646 language tag according to ISO639 language tag.
1302 //
1303 BestPlatformLang = GetLangFromSupportedLangCodes(mVariableModuleGlobal->PlatformLangCodes, Index, FALSE);
1304
1305 //
1306 // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
1307 //
1308 FindVariable(L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal);
1309
1310 Status = UpdateVariable(L"PlatformLang", &gEfiGlobalVariableGuid,
1311 BestPlatformLang, AsciiStrLen (BestPlatformLang), Attributes, &Variable);
1312
1313 DEBUG((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a\n", BestLang, BestPlatformLang));
1314 ASSERT_EFI_ERROR(Status);
1315 }
1316 return EFI_SUCCESS;
1317 }
1318
1319 /**
1320 Update the variable region with Variable information. These are the same
1321 arguments as the EFI Variable services.
1322
1323 @param[in] VariableName Name of variable
1324
1325 @param[in] VendorGuid Guid of variable
1326
1327 @param[in] Data Variable data
1328
1329 @param[in] DataSize Size of data. 0 means delete
1330
1331 @param[in] Attributes Attribues of the variable
1332
1333 @param[in] Variable The variable information which is used to keep track of variable usage.
1334
1335 @retval EFI_SUCCESS The update operation is success.
1336
1337 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
1338
1339 **/
1340 EFI_STATUS
1341 EFIAPI
1342 UpdateVariable (
1343 IN CHAR16 *VariableName,
1344 IN EFI_GUID *VendorGuid,
1345 IN VOID *Data,
1346 IN UINTN DataSize,
1347 IN UINT32 Attributes OPTIONAL,
1348 IN VARIABLE_POINTER_TRACK *Variable
1349 )
1350 {
1351 EFI_STATUS Status;
1352 VARIABLE_HEADER *NextVariable;
1353 UINTN ScratchSize;
1354 UINTN NonVolatileVarableStoreSize;
1355 UINTN VarNameOffset;
1356 UINTN VarDataOffset;
1357 UINTN VarNameSize;
1358 UINTN VarSize;
1359 BOOLEAN Volatile;
1360 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
1361 UINT8 State;
1362 BOOLEAN Reclaimed;
1363
1364 Fvb = mVariableModuleGlobal->FvbInstance;
1365 Reclaimed = FALSE;
1366
1367 if (Variable->CurrPtr != NULL) {
1368 //
1369 // Update/Delete existing variable
1370 //
1371 Volatile = Variable->Volatile;
1372
1373 if (EfiAtRuntime ()) {
1374 //
1375 // If EfiAtRuntime and the variable is Volatile and Runtime Access,
1376 // the volatile is ReadOnly, and SetVariable should be aborted and
1377 // return EFI_WRITE_PROTECTED.
1378 //
1379 if (Variable->Volatile) {
1380 Status = EFI_WRITE_PROTECTED;
1381 goto Done;
1382 }
1383 //
1384 // Only variable have NV attribute can be updated/deleted in Runtime
1385 //
1386 if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
1387 Status = EFI_INVALID_PARAMETER;
1388 goto Done;
1389 }
1390 }
1391 //
1392 // Setting a data variable with no access, or zero DataSize attributes
1393 // specified causes it to be deleted.
1394 //
1395 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
1396 State = Variable->CurrPtr->State;
1397 State &= VAR_DELETED;
1398
1399 Status = UpdateVariableStore (
1400 &mVariableModuleGlobal->VariableGlobal,
1401 Variable->Volatile,
1402 FALSE,
1403 Fvb,
1404 (UINTN) &Variable->CurrPtr->State,
1405 sizeof (UINT8),
1406 &State
1407 );
1408 if (!EFI_ERROR (Status)) {
1409 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, FALSE, TRUE, FALSE);
1410 UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);
1411 }
1412 goto Done;
1413 }
1414 //
1415 // If the variable is marked valid and the same data has been passed in
1416 // then return to the caller immediately.
1417 //
1418 if (DataSizeOfVariable (Variable->CurrPtr) == DataSize &&
1419 (CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0)) {
1420
1421 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);
1422 Status = EFI_SUCCESS;
1423 goto Done;
1424 } else if ((Variable->CurrPtr->State == VAR_ADDED) ||
1425 (Variable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {
1426
1427 //
1428 // Mark the old variable as in delete transition
1429 //
1430 State = Variable->CurrPtr->State;
1431 State &= VAR_IN_DELETED_TRANSITION;
1432
1433 Status = UpdateVariableStore (
1434 &mVariableModuleGlobal->VariableGlobal,
1435 Variable->Volatile,
1436 FALSE,
1437 Fvb,
1438 (UINTN) &Variable->CurrPtr->State,
1439 sizeof (UINT8),
1440 &State
1441 );
1442 if (EFI_ERROR (Status)) {
1443 goto Done;
1444 }
1445 }
1446 } else {
1447 //
1448 // Not found existing variable. Create a new variable
1449 //
1450
1451 //
1452 // Make sure we are trying to create a new variable.
1453 // Setting a data variable with no access, or zero DataSize attributes means to delete it.
1454 //
1455 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
1456 Status = EFI_NOT_FOUND;
1457 goto Done;
1458 }
1459
1460 //
1461 // Only variable have NV|RT attribute can be created in Runtime
1462 //
1463 if (EfiAtRuntime () &&
1464 (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {
1465 Status = EFI_INVALID_PARAMETER;
1466 goto Done;
1467 }
1468 }
1469
1470 //
1471 // Function part - create a new variable and copy the data.
1472 // Both update a variable and create a variable will come here.
1473 //
1474 // Tricky part: Use scratch data area at the end of volatile variable store
1475 // as a temporary storage.
1476 //
1477 NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));
1478 ScratchSize = MAX(FixedPcdGet32(PcdMaxVariableSize), FixedPcdGet32(PcdMaxHardwareErrorVariableSize));
1479
1480 SetMem (NextVariable, ScratchSize, 0xff);
1481
1482 NextVariable->StartId = VARIABLE_DATA;
1483 NextVariable->Attributes = Attributes;
1484 //
1485 // NextVariable->State = VAR_ADDED;
1486 //
1487 NextVariable->Reserved = 0;
1488 VarNameOffset = sizeof (VARIABLE_HEADER);
1489 VarNameSize = StrSize (VariableName);
1490 CopyMem (
1491 (UINT8 *) ((UINTN) NextVariable + VarNameOffset),
1492 VariableName,
1493 VarNameSize
1494 );
1495 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);
1496 CopyMem (
1497 (UINT8 *) ((UINTN) NextVariable + VarDataOffset),
1498 Data,
1499 DataSize
1500 );
1501 CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));
1502 //
1503 // There will be pad bytes after Data, the NextVariable->NameSize and
1504 // NextVariable->DataSize should not include pad size so that variable
1505 // service can get actual size in GetVariable
1506 //
1507 NextVariable->NameSize = (UINT32)VarNameSize;
1508 NextVariable->DataSize = (UINT32)DataSize;
1509
1510 //
1511 // The actual size of the variable that stores in storage should
1512 // include pad size.
1513 //
1514 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
1515 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
1516 //
1517 // Create a nonvolatile variable
1518 //
1519 Volatile = FALSE;
1520 NonVolatileVarableStoreSize = ((VARIABLE_STORE_HEADER *)(UINTN)(mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase))->Size;
1521 if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)
1522 && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > FixedPcdGet32(PcdHwErrStorageSize)))
1523 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0)
1524 && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - FixedPcdGet32(PcdHwErrStorageSize)))) {
1525 if (EfiAtRuntime ()) {
1526 Status = EFI_OUT_OF_RESOURCES;
1527 goto Done;
1528 }
1529 //
1530 // Perform garbage collection & reclaim operation
1531 //
1532 Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
1533 &mVariableModuleGlobal->NonVolatileLastVariableOffset, FALSE, Variable->CurrPtr);
1534 if (EFI_ERROR (Status)) {
1535 goto Done;
1536 }
1537 //
1538 // If still no enough space, return out of resources
1539 //
1540 if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)
1541 && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > FixedPcdGet32(PcdHwErrStorageSize)))
1542 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0)
1543 && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - FixedPcdGet32(PcdHwErrStorageSize)))) {
1544 Status = EFI_OUT_OF_RESOURCES;
1545 goto Done;
1546 }
1547 Reclaimed = TRUE;
1548 }
1549 //
1550 // Three steps
1551 // 1. Write variable header
1552 // 2. Set variable state to header valid
1553 // 3. Write variable data
1554 // 4. Set variable state to valid
1555 //
1556 //
1557 // Step 1:
1558 //
1559 Status = UpdateVariableStore (
1560 &mVariableModuleGlobal->VariableGlobal,
1561 FALSE,
1562 TRUE,
1563 Fvb,
1564 mVariableModuleGlobal->NonVolatileLastVariableOffset,
1565 sizeof (VARIABLE_HEADER),
1566 (UINT8 *) NextVariable
1567 );
1568
1569 if (EFI_ERROR (Status)) {
1570 goto Done;
1571 }
1572
1573 //
1574 // Step 2:
1575 //
1576 NextVariable->State = VAR_HEADER_VALID_ONLY;
1577 Status = UpdateVariableStore (
1578 &mVariableModuleGlobal->VariableGlobal,
1579 FALSE,
1580 TRUE,
1581 Fvb,
1582 mVariableModuleGlobal->NonVolatileLastVariableOffset,
1583 sizeof (VARIABLE_HEADER),
1584 (UINT8 *) NextVariable
1585 );
1586
1587 if (EFI_ERROR (Status)) {
1588 goto Done;
1589 }
1590 //
1591 // Step 3:
1592 //
1593 Status = UpdateVariableStore (
1594 &mVariableModuleGlobal->VariableGlobal,
1595 FALSE,
1596 TRUE,
1597 Fvb,
1598 mVariableModuleGlobal->NonVolatileLastVariableOffset + sizeof (VARIABLE_HEADER),
1599 (UINT32) VarSize - sizeof (VARIABLE_HEADER),
1600 (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)
1601 );
1602
1603 if (EFI_ERROR (Status)) {
1604 goto Done;
1605 }
1606 //
1607 // Step 4:
1608 //
1609 NextVariable->State = VAR_ADDED;
1610 Status = UpdateVariableStore (
1611 &mVariableModuleGlobal->VariableGlobal,
1612 FALSE,
1613 TRUE,
1614 Fvb,
1615 mVariableModuleGlobal->NonVolatileLastVariableOffset,
1616 sizeof (VARIABLE_HEADER),
1617 (UINT8 *) NextVariable
1618 );
1619
1620 if (EFI_ERROR (Status)) {
1621 goto Done;
1622 }
1623
1624 mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);
1625
1626 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
1627 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);
1628 } else {
1629 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);
1630 }
1631 } else {
1632 //
1633 // Create a volatile variable
1634 //
1635 Volatile = TRUE;
1636
1637 if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >
1638 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) {
1639 //
1640 // Perform garbage collection & reclaim operation
1641 //
1642 Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase,
1643 &mVariableModuleGlobal->VolatileLastVariableOffset, TRUE, Variable->CurrPtr);
1644 if (EFI_ERROR (Status)) {
1645 goto Done;
1646 }
1647 //
1648 // If still no enough space, return out of resources
1649 //
1650 if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >
1651 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size
1652 ) {
1653 Status = EFI_OUT_OF_RESOURCES;
1654 goto Done;
1655 }
1656 Reclaimed = TRUE;
1657 }
1658
1659 NextVariable->State = VAR_ADDED;
1660 Status = UpdateVariableStore (
1661 &mVariableModuleGlobal->VariableGlobal,
1662 TRUE,
1663 TRUE,
1664 Fvb,
1665 mVariableModuleGlobal->VolatileLastVariableOffset,
1666 (UINT32) VarSize,
1667 (UINT8 *) NextVariable
1668 );
1669
1670 if (EFI_ERROR (Status)) {
1671 goto Done;
1672 }
1673
1674 mVariableModuleGlobal->VolatileLastVariableOffset += HEADER_ALIGN (VarSize);
1675 }
1676
1677 //
1678 // Mark the old variable as deleted
1679 //
1680 if (!Reclaimed && !EFI_ERROR (Status) && Variable->CurrPtr != NULL) {
1681 State = Variable->CurrPtr->State;
1682 State &= VAR_DELETED;
1683
1684 Status = UpdateVariableStore (
1685 &mVariableModuleGlobal->VariableGlobal,
1686 Variable->Volatile,
1687 FALSE,
1688 Fvb,
1689 (UINTN) &Variable->CurrPtr->State,
1690 sizeof (UINT8),
1691 &State
1692 );
1693 }
1694
1695 if (!EFI_ERROR (Status)) {
1696 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);
1697 UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);
1698 }
1699
1700 Done:
1701 return Status;
1702 }
1703
1704 /**
1705
1706 This code finds variable in storage blocks (Volatile or Non-Volatile).
1707
1708 @param VariableName Name of Variable to be found.
1709 @param VendorGuid Variable vendor GUID.
1710 @param Attributes Attribute value of the variable found.
1711 @param DataSize Size of Data found. If size is less than the
1712 data, this value contains the required size.
1713 @param Data Data pointer.
1714
1715 @return EFI_INVALID_PARAMETER Invalid parameter
1716 @return EFI_SUCCESS Find the specified variable
1717 @return EFI_NOT_FOUND Not found
1718 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result
1719
1720 **/
1721 EFI_STATUS
1722 EFIAPI
1723 RuntimeServiceGetVariable (
1724 IN CHAR16 *VariableName,
1725 IN EFI_GUID *VendorGuid,
1726 OUT UINT32 *Attributes OPTIONAL,
1727 IN OUT UINTN *DataSize,
1728 OUT VOID *Data
1729 )
1730 {
1731 EFI_STATUS Status;
1732 VARIABLE_POINTER_TRACK Variable;
1733 UINTN VarDataSize;
1734
1735 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
1736 return EFI_INVALID_PARAMETER;
1737 }
1738
1739 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1740
1741 //
1742 // Find existing variable
1743 //
1744 Status = FindVariableInCache (VariableName, VendorGuid, Attributes, DataSize, Data);
1745 if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_SUCCESS)){
1746 // Hit in the Cache
1747 UpdateVariableInfo (VariableName, VendorGuid, FALSE, TRUE, FALSE, FALSE, TRUE);
1748 goto Done;
1749 }
1750
1751 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);
1752 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
1753 goto Done;
1754 }
1755
1756 //
1757 // Get data size
1758 //
1759 VarDataSize = DataSizeOfVariable (Variable.CurrPtr);
1760 ASSERT (VarDataSize != 0);
1761
1762 if (*DataSize >= VarDataSize) {
1763 if (Data == NULL) {
1764 Status = EFI_INVALID_PARAMETER;
1765 goto Done;
1766 }
1767
1768 CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);
1769 if (Attributes != NULL) {
1770 *Attributes = Variable.CurrPtr->Attributes;
1771 }
1772
1773 *DataSize = VarDataSize;
1774 UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);
1775 UpdateVariableCache (VariableName, VendorGuid, Variable.CurrPtr->Attributes, VarDataSize, Data);
1776
1777 Status = EFI_SUCCESS;
1778 goto Done;
1779 } else {
1780 *DataSize = VarDataSize;
1781 Status = EFI_BUFFER_TOO_SMALL;
1782 goto Done;
1783 }
1784
1785 Done:
1786 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1787 return Status;
1788 }
1789
1790
1791
1792 /**
1793
1794 This code Finds the Next available variable.
1795
1796 @param VariableNameSize Size of the variable name
1797 @param VariableName Pointer to variable name
1798 @param VendorGuid Variable Vendor Guid
1799
1800 @return EFI_INVALID_PARAMETER Invalid parameter
1801 @return EFI_SUCCESS Find the specified variable
1802 @return EFI_NOT_FOUND Not found
1803 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result
1804
1805 **/
1806 EFI_STATUS
1807 EFIAPI
1808 RuntimeServiceGetNextVariableName (
1809 IN OUT UINTN *VariableNameSize,
1810 IN OUT CHAR16 *VariableName,
1811 IN OUT EFI_GUID *VendorGuid
1812 )
1813 {
1814 VARIABLE_POINTER_TRACK Variable;
1815 UINTN VarNameSize;
1816 EFI_STATUS Status;
1817
1818 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
1819 return EFI_INVALID_PARAMETER;
1820 }
1821
1822 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1823
1824 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);
1825 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
1826 goto Done;
1827 }
1828
1829 if (VariableName[0] != 0) {
1830 //
1831 // If variable name is not NULL, get next variable
1832 //
1833 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
1834 }
1835
1836 while (TRUE) {
1837 //
1838 // If both volatile and non-volatile variable store are parsed,
1839 // return not found
1840 //
1841 if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) {
1842 Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));
1843 if (!Variable.Volatile) {
1844 Variable.StartPtr = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
1845 Variable.EndPtr = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase));
1846 } else {
1847 Status = EFI_NOT_FOUND;
1848 goto Done;
1849 }
1850
1851 Variable.CurrPtr = Variable.StartPtr;
1852 if (!IsValidVariableHeader (Variable.CurrPtr)) {
1853 continue;
1854 }
1855 }
1856 //
1857 // Variable is found
1858 //
1859 if (IsValidVariableHeader (Variable.CurrPtr) && Variable.CurrPtr->State == VAR_ADDED) {
1860 if ((EfiAtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) == 0) {
1861 VarNameSize = NameSizeOfVariable (Variable.CurrPtr);
1862 ASSERT (VarNameSize != 0);
1863
1864 if (VarNameSize <= *VariableNameSize) {
1865 CopyMem (
1866 VariableName,
1867 GetVariableNamePtr (Variable.CurrPtr),
1868 VarNameSize
1869 );
1870 CopyMem (
1871 VendorGuid,
1872 &Variable.CurrPtr->VendorGuid,
1873 sizeof (EFI_GUID)
1874 );
1875 Status = EFI_SUCCESS;
1876 } else {
1877 Status = EFI_BUFFER_TOO_SMALL;
1878 }
1879
1880 *VariableNameSize = VarNameSize;
1881 goto Done;
1882 }
1883 }
1884
1885 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
1886 }
1887
1888 Done:
1889 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1890 return Status;
1891 }
1892
1893 /**
1894
1895 This code sets variable in storage blocks (Volatile or Non-Volatile).
1896
1897 @param VariableName Name of Variable to be found
1898 @param VendorGuid Variable vendor GUID
1899 @param Attributes Attribute value of the variable found
1900 @param DataSize Size of Data found. If size is less than the
1901 data, this value contains the required size.
1902 @param Data Data pointer
1903
1904 @return EFI_INVALID_PARAMETER Invalid parameter
1905 @return EFI_SUCCESS Set successfully
1906 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable
1907 @return EFI_NOT_FOUND Not found
1908 @return EFI_WRITE_PROTECTED Variable is read-only
1909
1910 **/
1911 EFI_STATUS
1912 EFIAPI
1913 RuntimeServiceSetVariable (
1914 IN CHAR16 *VariableName,
1915 IN EFI_GUID *VendorGuid,
1916 IN UINT32 Attributes,
1917 IN UINTN DataSize,
1918 IN VOID *Data
1919 )
1920 {
1921 VARIABLE_POINTER_TRACK Variable;
1922 EFI_STATUS Status;
1923 VARIABLE_HEADER *NextVariable;
1924 EFI_PHYSICAL_ADDRESS Point;
1925
1926 //
1927 // Check input parameters
1928 //
1929 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
1930 return EFI_INVALID_PARAMETER;
1931 }
1932 //
1933 // Make sure if runtime bit is set, boot service bit is set also
1934 //
1935 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
1936 return EFI_INVALID_PARAMETER;
1937 }
1938
1939 //
1940 // The size of the VariableName, including the Unicode Null in bytes plus
1941 // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxHardwareErrorVariableSize)
1942 // bytes for HwErrRec, and FixedPcdGet32(PcdMaxVariableSize) bytes for the others.
1943 //
1944 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1945 if ((DataSize > FixedPcdGet32(PcdMaxHardwareErrorVariableSize)) ||
1946 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > FixedPcdGet32(PcdMaxHardwareErrorVariableSize))) {
1947 return EFI_INVALID_PARAMETER;
1948 }
1949 //
1950 // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX"
1951 //
1952 if (StrnCmp(VariableName, L"HwErrRec", StrLen(L"HwErrRec")) != 0) {
1953 return EFI_INVALID_PARAMETER;
1954 }
1955 } else {
1956 //
1957 // The size of the VariableName, including the Unicode Null in bytes plus
1958 // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxVariableSize) bytes.
1959 //
1960 if ((DataSize > FixedPcdGet32(PcdMaxVariableSize)) ||
1961 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > FixedPcdGet32(PcdMaxVariableSize))) {
1962 return EFI_INVALID_PARAMETER;
1963 }
1964 }
1965
1966 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1967
1968 //
1969 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated;
1970 //
1971 if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {
1972 Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;;
1973 //
1974 // Parse non-volatile variable data and get last variable offset
1975 //
1976 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point);
1977 while ((NextVariable < GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point))
1978 && IsValidVariableHeader (NextVariable)) {
1979 NextVariable = GetNextVariablePtr (NextVariable);
1980 }
1981 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;
1982 }
1983
1984 //
1985 // Check whether the input variable is already existed
1986 //
1987 FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);
1988
1989 //
1990 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang
1991 //
1992 AutoUpdateLangVariable (VariableName, Data, DataSize);
1993
1994 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, &Variable);
1995
1996 InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);
1997 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1998
1999 return Status;
2000 }
2001
2002 /**
2003
2004 This code returns information about the EFI variables.
2005
2006 @param Attributes Attributes bitmask to specify the type of variables
2007 on which to return information.
2008 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
2009 for the EFI variables associated with the attributes specified.
2010 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
2011 for EFI variables associated with the attributes specified.
2012 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
2013 associated with the attributes specified.
2014
2015 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
2016 @return EFI_SUCCESS Query successfully.
2017 @return EFI_UNSUPPORTED The attribute is not supported on this platform.
2018
2019 **/
2020 EFI_STATUS
2021 EFIAPI
2022 RuntimeServiceQueryVariableInfo (
2023 IN UINT32 Attributes,
2024 OUT UINT64 *MaximumVariableStorageSize,
2025 OUT UINT64 *RemainingVariableStorageSize,
2026 OUT UINT64 *MaximumVariableSize
2027 )
2028 {
2029 VARIABLE_HEADER *Variable;
2030 VARIABLE_HEADER *NextVariable;
2031 UINT64 VariableSize;
2032 VARIABLE_STORE_HEADER *VariableStoreHeader;
2033 UINT64 CommonVariableTotalSize;
2034 UINT64 HwErrVariableTotalSize;
2035
2036 CommonVariableTotalSize = 0;
2037 HwErrVariableTotalSize = 0;
2038
2039 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
2040 return EFI_INVALID_PARAMETER;
2041 }
2042
2043 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {
2044 //
2045 // Make sure the Attributes combination is supported by the platform.
2046 //
2047 return EFI_UNSUPPORTED;
2048 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
2049 //
2050 // Make sure if runtime bit is set, boot service bit is set also.
2051 //
2052 return EFI_INVALID_PARAMETER;
2053 } else if (EfiAtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {
2054 //
2055 // Make sure RT Attribute is set if we are in Runtime phase.
2056 //
2057 return EFI_INVALID_PARAMETER;
2058 } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
2059 //
2060 // Make sure Hw Attribute is set with NV.
2061 //
2062 return EFI_INVALID_PARAMETER;
2063 }
2064
2065 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
2066
2067 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
2068 //
2069 // Query is Volatile related.
2070 //
2071 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
2072 } else {
2073 //
2074 // Query is Non-Volatile related.
2075 //
2076 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
2077 }
2078
2079 //
2080 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
2081 // with the storage size (excluding the storage header size).
2082 //
2083 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
2084
2085 //
2086 // Harware error record variable needs larger size.
2087 //
2088 if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
2089 *MaximumVariableStorageSize = FixedPcdGet32(PcdHwErrStorageSize);
2090 *MaximumVariableSize = FixedPcdGet32(PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);
2091 } else {
2092 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
2093 ASSERT (FixedPcdGet32(PcdHwErrStorageSize) < VariableStoreHeader->Size);
2094 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - FixedPcdGet32(PcdHwErrStorageSize);
2095 }
2096
2097 //
2098 // Let *MaximumVariableSize be FixedPcdGet32(PcdMaxVariableSize) with the exception of the variable header size.
2099 //
2100 *MaximumVariableSize = FixedPcdGet32(PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);
2101 }
2102
2103 //
2104 // Point to the starting address of the variables.
2105 //
2106 Variable = GetStartPointer (VariableStoreHeader);
2107
2108 //
2109 // Now walk through the related variable store.
2110 //
2111 while ((Variable < GetEndPointer (VariableStoreHeader)) && IsValidVariableHeader (Variable)) {
2112 NextVariable = GetNextVariablePtr (Variable);
2113 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;
2114
2115 if (EfiAtRuntime ()) {
2116 //
2117 // we don't take the state of the variables in mind
2118 // when calculating RemainingVariableStorageSize,
2119 // since the space occupied by variables not marked with
2120 // VAR_ADDED is not allowed to be reclaimed in Runtime.
2121 //
2122 if ((NextVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
2123 HwErrVariableTotalSize += VariableSize;
2124 } else {
2125 CommonVariableTotalSize += VariableSize;
2126 }
2127 } else {
2128 //
2129 // Only care about Variables with State VAR_ADDED,because
2130 // the space not marked as VAR_ADDED is reclaimable now.
2131 //
2132 if (Variable->State == VAR_ADDED) {
2133 if ((NextVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
2134 HwErrVariableTotalSize += VariableSize;
2135 } else {
2136 CommonVariableTotalSize += VariableSize;
2137 }
2138 }
2139 }
2140
2141 //
2142 // Go to the next one
2143 //
2144 Variable = NextVariable;
2145 }
2146
2147 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){
2148 *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;
2149 }else {
2150 *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;
2151 }
2152
2153 if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {
2154 *MaximumVariableSize = 0;
2155 } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {
2156 *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);
2157 }
2158
2159 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
2160 return EFI_SUCCESS;
2161 }
2162
2163
2164 /**
2165 Notification function of EVT_GROUP_READY_TO_BOOT event group.
2166
2167 This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.
2168 When the Boot Manager is about to load and execute a boot option, it reclaims variable
2169 storage if free size is below the threshold.
2170
2171 @param Event Event whose notification function is being invoked
2172 @param Context Pointer to the notification function's context
2173
2174 **/
2175 VOID
2176 EFIAPI
2177 ReclaimForOS(
2178 EFI_EVENT Event,
2179 VOID *Context
2180 )
2181 {
2182 EFI_STATUS Status;
2183 UINTN CommonVariableSpace;
2184 UINTN RemainingCommonVariableSpace;
2185 UINTN RemainingHwErrVariableSpace;
2186
2187 Status = EFI_SUCCESS;
2188
2189 CommonVariableSpace = ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize); //Allowable max size of common variable storage space
2190
2191 RemainingCommonVariableSpace = CommonVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;
2192
2193 RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;
2194 //
2195 // Check if the free area is blow a threshold
2196 //
2197 if ((RemainingCommonVariableSpace < PcdGet32 (PcdMaxVariableSize))
2198 || (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize))){
2199 Status = Reclaim (
2200 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
2201 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
2202 FALSE,
2203 NULL
2204 );
2205 ASSERT_EFI_ERROR (Status);
2206 }
2207 }
2208
2209 /**
2210 Initializes variable store area for non-volatile and volatile variable.
2211
2212 @param SystemTable The pointer of EFI_SYSTEM_TABLE.
2213
2214 @retval EFI_SUCCESS Function successfully executed.
2215 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
2216
2217 **/
2218 EFI_STATUS
2219 VariableCommonInitialize (
2220 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol
2221 )
2222 {
2223 EFI_STATUS Status;
2224 VARIABLE_STORE_HEADER *VolatileVariableStore;
2225 VARIABLE_STORE_HEADER *VariableStoreHeader;
2226 VARIABLE_HEADER *NextVariable;
2227 EFI_PHYSICAL_ADDRESS TempVariableStoreHeader;
2228 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
2229 EFI_PHYSICAL_ADDRESS BaseAddress;
2230 UINT64 Length;
2231 UINTN Index;
2232 UINT8 Data;
2233 EFI_PHYSICAL_ADDRESS VariableStoreBase;
2234 UINT64 VariableStoreLength;
2235 EFI_EVENT ReadyToBootEvent;
2236 UINTN ScratchSize;
2237
2238 Status = EFI_SUCCESS;
2239 //
2240 // Allocate runtime memory for variable driver global structure.
2241 //
2242 mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL));
2243 if (mVariableModuleGlobal == NULL) {
2244 return EFI_OUT_OF_RESOURCES;
2245 }
2246
2247 EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);
2248
2249 //
2250 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
2251 //
2252 ScratchSize = MAX(FixedPcdGet32(PcdMaxVariableSize), FixedPcdGet32(PcdMaxHardwareErrorVariableSize));
2253 VolatileVariableStore = AllocateRuntimePool (FixedPcdGet32(PcdVariableStoreSize) + ScratchSize);
2254 if (VolatileVariableStore == NULL) {
2255 FreePool (mVariableModuleGlobal);
2256 return EFI_OUT_OF_RESOURCES;
2257 }
2258
2259 SetMem (VolatileVariableStore, FixedPcdGet32(PcdVariableStoreSize) + ScratchSize, 0xff);
2260
2261 //
2262 // Variable Specific Data
2263 //
2264 mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;
2265 mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;
2266 mVariableModuleGlobal->FvbInstance = FvbProtocol;
2267
2268 CopyGuid (&VolatileVariableStore->Signature, &gEfiVariableGuid);
2269 VolatileVariableStore->Size = FixedPcdGet32(PcdVariableStoreSize);
2270 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;
2271 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;
2272 VolatileVariableStore->Reserved = 0;
2273 VolatileVariableStore->Reserved1 = 0;
2274
2275 //
2276 // Get non volatile varaible store
2277 //
2278
2279 TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);
2280 VariableStoreBase = TempVariableStoreHeader + \
2281 (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);
2282 VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \
2283 (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);
2284 //
2285 // Mark the variable storage region of the FLASH as RUNTIME
2286 //
2287 BaseAddress = VariableStoreBase & (~EFI_PAGE_MASK);
2288 Length = VariableStoreLength + (VariableStoreBase - BaseAddress);
2289 Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);
2290
2291 Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);
2292 if (EFI_ERROR (Status)) {
2293 goto Done;
2294 }
2295
2296 Status = gDS->SetMemorySpaceAttributes (
2297 BaseAddress,
2298 Length,
2299 GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME
2300 );
2301 if (EFI_ERROR (Status)) {
2302 goto Done;
2303 }
2304 //
2305 // Get address of non volatile variable store base
2306 //
2307 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;
2308 VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;
2309 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
2310 if (~VariableStoreHeader->Size == 0) {
2311 Status = UpdateVariableStore (
2312 &mVariableModuleGlobal->VariableGlobal,
2313 FALSE,
2314 FALSE,
2315 mVariableModuleGlobal->FvbInstance,
2316 (UINTN) &VariableStoreHeader->Size,
2317 sizeof (UINT32),
2318 (UINT8 *) &VariableStoreLength
2319 );
2320 //
2321 // As Variables are stored in NV storage, which are slow devices,such as flash.
2322 // Variable operation may skip checking variable program result to improve performance,
2323 // We can assume Variable program is OK through some check point.
2324 // Variable Store Size Setting should be the first Variable write operation,
2325 // We can assume all Read/Write is OK if we can set Variable store size successfully.
2326 // If write fail, we will assert here
2327 //
2328 ASSERT(VariableStoreHeader->Size == VariableStoreLength);
2329
2330 if (EFI_ERROR (Status)) {
2331 goto Done;
2332 }
2333 }
2334
2335 //
2336 // Parse non-volatile variable data and get last variable offset
2337 //
2338 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);
2339 Status = EFI_SUCCESS;
2340
2341 while (IsValidVariableHeader (NextVariable)) {
2342 UINTN VariableSize = 0;
2343 VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);
2344 if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
2345 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);
2346 } else {
2347 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);
2348 }
2349
2350 NextVariable = GetNextVariablePtr (NextVariable);
2351 }
2352
2353 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;
2354
2355 //
2356 // Check if the free area is really free.
2357 //
2358 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {
2359 Data = ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)[Index];
2360 if (Data != 0xff) {
2361 //
2362 // There must be something wrong in variable store, do reclaim operation.
2363 //
2364 Status = Reclaim (
2365 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
2366 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
2367 FALSE,
2368 NULL
2369 );
2370
2371 if (EFI_ERROR (Status)) {
2372 goto Done;
2373 }
2374
2375 break;
2376 }
2377 }
2378
2379 //
2380 // Register the event handling function to reclaim variable for OS usage.
2381 //
2382 Status = EfiCreateEventReadyToBootEx (
2383 TPL_NOTIFY,
2384 ReclaimForOS,
2385 NULL,
2386 &ReadyToBootEvent
2387 );
2388 } else {
2389 Status = EFI_VOLUME_CORRUPTED;
2390 DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));
2391 }
2392
2393 Done:
2394 if (EFI_ERROR (Status)) {
2395 FreePool (mVariableModuleGlobal);
2396 FreePool (VolatileVariableStore);
2397 }
2398
2399 return Status;
2400 }
2401
2402 /**
2403 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
2404
2405 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
2406 It convers pointer to new virtual address.
2407
2408 @param Event Event whose notification function is being invoked
2409 @param Context Pointer to the notification function's context
2410
2411 **/
2412 VOID
2413 EFIAPI
2414 VariableClassAddressChangeEvent (
2415 IN EFI_EVENT Event,
2416 IN VOID *Context
2417 )
2418 {
2419 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);
2420 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);
2421 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);
2422 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes);
2423 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read);
2424 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write);
2425 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks);
2426 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance);
2427 EfiConvertPointer (
2428 0x0,
2429 (VOID **) &mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase
2430 );
2431 EfiConvertPointer (
2432 0x0,
2433 (VOID **) &mVariableModuleGlobal->VariableGlobal.VolatileVariableBase
2434 );
2435 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal);
2436 }
2437
2438 VOID
2439 EFIAPI
2440 FvbNotificationEvent (
2441 IN EFI_EVENT Event,
2442 IN VOID *Context
2443 )
2444 {
2445 EFI_STATUS Status;
2446 EFI_HANDLE *HandleBuffer;
2447 UINTN HandleCount;
2448 UINTN Index;
2449 EFI_PHYSICAL_ADDRESS FvbBaseAddress;
2450 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
2451 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
2452 EFI_FVB_ATTRIBUTES_2 Attributes;
2453 EFI_SYSTEM_TABLE *SystemTable;
2454 EFI_PHYSICAL_ADDRESS NvStorageVariableBase;
2455
2456 SystemTable = (EFI_SYSTEM_TABLE *)Context;
2457 Fvb = NULL;
2458
2459 //
2460 // Locate all handles of Fvb protocol
2461 //
2462 Status = gBS->LocateHandleBuffer (
2463 ByProtocol,
2464 &gEfiFirmwareVolumeBlockProtocolGuid,
2465 NULL,
2466 &HandleCount,
2467 &HandleBuffer
2468 );
2469 if (EFI_ERROR (Status)) {
2470 return ;
2471 }
2472
2473 //
2474 // Get the FVB to access variable store
2475 //
2476 for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {
2477 Status = gBS->HandleProtocol (
2478 HandleBuffer[Index],
2479 &gEfiFirmwareVolumeBlockProtocolGuid,
2480 (VOID **) &Fvb
2481 );
2482 if (EFI_ERROR (Status)) {
2483 Status = EFI_NOT_FOUND;
2484 break;
2485 }
2486
2487 //
2488 // Ensure this FVB protocol supported Write operation.
2489 //
2490 Status = Fvb->GetAttributes (Fvb, &Attributes);
2491 if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
2492 continue;
2493 }
2494 //
2495 // Compare the address and select the right one
2496 //
2497 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
2498 if (EFI_ERROR (Status)) {
2499 continue;
2500 }
2501
2502 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
2503 NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);
2504 if ((NvStorageVariableBase >= FvbBaseAddress) && (NvStorageVariableBase < (FvbBaseAddress + FwVolHeader->FvLength))) {
2505 Status = EFI_SUCCESS;
2506 break;
2507 }
2508 }
2509
2510 FreePool (HandleBuffer);
2511 if (!EFI_ERROR (Status) && Fvb != NULL) {
2512 //
2513 // Close the notify event to avoid install gEfiVariableArchProtocolGuid & gEfiVariableWriteArchProtocolGuid again.
2514 //
2515 Status = gBS->CloseEvent (Event);
2516 ASSERT_EFI_ERROR (Status);
2517
2518 Status = VariableCommonInitialize (Fvb);
2519 ASSERT_EFI_ERROR (Status);
2520
2521 SystemTable->RuntimeServices->GetVariable = RuntimeServiceGetVariable;
2522 SystemTable->RuntimeServices->GetNextVariableName = RuntimeServiceGetNextVariableName;
2523 SystemTable->RuntimeServices->SetVariable = RuntimeServiceSetVariable;
2524 SystemTable->RuntimeServices->QueryVariableInfo = RuntimeServiceQueryVariableInfo;
2525
2526 //
2527 // Now install the Variable Runtime Architectural Protocol on a new handle
2528 //
2529 Status = gBS->InstallMultipleProtocolInterfaces (
2530 &mHandle,
2531 &gEfiVariableArchProtocolGuid, NULL,
2532 &gEfiVariableWriteArchProtocolGuid, NULL,
2533 NULL
2534 );
2535 ASSERT_EFI_ERROR (Status);
2536
2537 Status = gBS->CreateEventEx (
2538 EVT_NOTIFY_SIGNAL,
2539 TPL_NOTIFY,
2540 VariableClassAddressChangeEvent,
2541 NULL,
2542 &gEfiEventVirtualAddressChangeGuid,
2543 &mVirtualAddressChangeEvent
2544 );
2545 ASSERT_EFI_ERROR (Status);
2546 }
2547
2548 }
2549
2550 /**
2551 Variable Driver main entry point. The Variable driver places the 4 EFI
2552 runtime services in the EFI System Table and installs arch protocols
2553 for variable read and write services being availible. It also registers
2554 notification function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
2555
2556 @param[in] ImageHandle The firmware allocated handle for the EFI image.
2557 @param[in] SystemTable A pointer to the EFI System Table.
2558
2559 @retval EFI_SUCCESS Variable service successfully initialized.
2560
2561 **/
2562 EFI_STATUS
2563 EFIAPI
2564 VariableServiceInitialize (
2565 IN EFI_HANDLE ImageHandle,
2566 IN EFI_SYSTEM_TABLE *SystemTable
2567 )
2568 {
2569 //
2570 // Register FvbNotificationEvent () notify function.
2571 //
2572 EfiCreateProtocolNotifyEvent (
2573 &gEfiFirmwareVolumeBlockProtocolGuid,
2574 TPL_CALLBACK,
2575 FvbNotificationEvent,
2576 (VOID *)SystemTable,
2577 &mFvbRegistration
2578 );
2579
2580 return EFI_SUCCESS;
2581 }
2582