]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
Update the file description in IpSec.h to refer to an accurate UEFI version.
[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 - 2010, Intel Corporation. All rights reserved.<BR>
7 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 (StrSize (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 (StrSize (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) && (DataSize != 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) && (DataSize != 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, AsciiStrSize (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 (PcdGet32 (PcdMaxVariableSize), PcdGet32 (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) > PcdGet32 (PcdHwErrStorageSize)))
1523 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0)
1524 && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (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) > PcdGet32 (PcdHwErrStorageSize)))
1542 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0)
1543 && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (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 if (DataSize != 0 && Data == NULL) {
1934 return EFI_INVALID_PARAMETER;
1935 }
1936
1937 //
1938 // Not support authenticated variable write yet.
1939 //
1940 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
1941 return EFI_INVALID_PARAMETER;
1942 }
1943
1944 //
1945 // Make sure if runtime bit is set, boot service bit is set also
1946 //
1947 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
1948 return EFI_INVALID_PARAMETER;
1949 }
1950
1951 //
1952 // The size of the VariableName, including the Unicode Null in bytes plus
1953 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
1954 // bytes for HwErrRec, and PcdGet32 (PcdMaxVariableSize) bytes for the others.
1955 //
1956 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1957 if ((DataSize > PcdGet32 (PcdMaxHardwareErrorVariableSize)) ||
1958 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxHardwareErrorVariableSize))) {
1959 return EFI_INVALID_PARAMETER;
1960 }
1961 //
1962 // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX"
1963 //
1964 if (StrnCmp(VariableName, L"HwErrRec", StrLen(L"HwErrRec")) != 0) {
1965 return EFI_INVALID_PARAMETER;
1966 }
1967 } else {
1968 //
1969 // The size of the VariableName, including the Unicode Null in bytes plus
1970 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxVariableSize) bytes.
1971 //
1972 if ((DataSize > PcdGet32 (PcdMaxVariableSize)) ||
1973 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxVariableSize))) {
1974 return EFI_INVALID_PARAMETER;
1975 }
1976 }
1977
1978 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1979
1980 //
1981 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated;
1982 //
1983 if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {
1984 Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;;
1985 //
1986 // Parse non-volatile variable data and get last variable offset
1987 //
1988 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point);
1989 while ((NextVariable < GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point))
1990 && IsValidVariableHeader (NextVariable)) {
1991 NextVariable = GetNextVariablePtr (NextVariable);
1992 }
1993 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;
1994 }
1995
1996 //
1997 // Check whether the input variable is already existed
1998 //
1999 FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);
2000
2001 //
2002 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang
2003 //
2004 AutoUpdateLangVariable (VariableName, Data, DataSize);
2005
2006 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, &Variable);
2007
2008 InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);
2009 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
2010
2011 return Status;
2012 }
2013
2014 /**
2015
2016 This code returns information about the EFI variables.
2017
2018 @param Attributes Attributes bitmask to specify the type of variables
2019 on which to return information.
2020 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
2021 for the EFI variables associated with the attributes specified.
2022 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
2023 for EFI variables associated with the attributes specified.
2024 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
2025 associated with the attributes specified.
2026
2027 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
2028 @return EFI_SUCCESS Query successfully.
2029 @return EFI_UNSUPPORTED The attribute is not supported on this platform.
2030
2031 **/
2032 EFI_STATUS
2033 EFIAPI
2034 RuntimeServiceQueryVariableInfo (
2035 IN UINT32 Attributes,
2036 OUT UINT64 *MaximumVariableStorageSize,
2037 OUT UINT64 *RemainingVariableStorageSize,
2038 OUT UINT64 *MaximumVariableSize
2039 )
2040 {
2041 VARIABLE_HEADER *Variable;
2042 VARIABLE_HEADER *NextVariable;
2043 UINT64 VariableSize;
2044 VARIABLE_STORE_HEADER *VariableStoreHeader;
2045 UINT64 CommonVariableTotalSize;
2046 UINT64 HwErrVariableTotalSize;
2047
2048 CommonVariableTotalSize = 0;
2049 HwErrVariableTotalSize = 0;
2050
2051 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
2052 return EFI_INVALID_PARAMETER;
2053 }
2054
2055 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {
2056 //
2057 // Make sure the Attributes combination is supported by the platform.
2058 //
2059 return EFI_UNSUPPORTED;
2060 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
2061 //
2062 // Make sure if runtime bit is set, boot service bit is set also.
2063 //
2064 return EFI_INVALID_PARAMETER;
2065 } else if (EfiAtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {
2066 //
2067 // Make sure RT Attribute is set if we are in Runtime phase.
2068 //
2069 return EFI_INVALID_PARAMETER;
2070 } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
2071 //
2072 // Make sure Hw Attribute is set with NV.
2073 //
2074 return EFI_INVALID_PARAMETER;
2075 } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
2076 //
2077 // Not support authentiated variable write yet.
2078 //
2079 return EFI_UNSUPPORTED;
2080 }
2081
2082 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
2083
2084 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
2085 //
2086 // Query is Volatile related.
2087 //
2088 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
2089 } else {
2090 //
2091 // Query is Non-Volatile related.
2092 //
2093 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
2094 }
2095
2096 //
2097 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
2098 // with the storage size (excluding the storage header size).
2099 //
2100 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
2101
2102 //
2103 // Harware error record variable needs larger size.
2104 //
2105 if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
2106 *MaximumVariableStorageSize = PcdGet32 (PcdHwErrStorageSize);
2107 *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);
2108 } else {
2109 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
2110 ASSERT (PcdGet32 (PcdHwErrStorageSize) < VariableStoreHeader->Size);
2111 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize);
2112 }
2113
2114 //
2115 // Let *MaximumVariableSize be PcdGet32 (PcdMaxVariableSize) with the exception of the variable header size.
2116 //
2117 *MaximumVariableSize = PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);
2118 }
2119
2120 //
2121 // Point to the starting address of the variables.
2122 //
2123 Variable = GetStartPointer (VariableStoreHeader);
2124
2125 //
2126 // Now walk through the related variable store.
2127 //
2128 while ((Variable < GetEndPointer (VariableStoreHeader)) && IsValidVariableHeader (Variable)) {
2129 NextVariable = GetNextVariablePtr (Variable);
2130 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;
2131
2132 if (EfiAtRuntime ()) {
2133 //
2134 // we don't take the state of the variables in mind
2135 // when calculating RemainingVariableStorageSize,
2136 // since the space occupied by variables not marked with
2137 // VAR_ADDED is not allowed to be reclaimed in Runtime.
2138 //
2139 if ((NextVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
2140 HwErrVariableTotalSize += VariableSize;
2141 } else {
2142 CommonVariableTotalSize += VariableSize;
2143 }
2144 } else {
2145 //
2146 // Only care about Variables with State VAR_ADDED,because
2147 // the space not marked as VAR_ADDED is reclaimable now.
2148 //
2149 if (Variable->State == VAR_ADDED) {
2150 if ((NextVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
2151 HwErrVariableTotalSize += VariableSize;
2152 } else {
2153 CommonVariableTotalSize += VariableSize;
2154 }
2155 }
2156 }
2157
2158 //
2159 // Go to the next one
2160 //
2161 Variable = NextVariable;
2162 }
2163
2164 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){
2165 *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;
2166 }else {
2167 *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;
2168 }
2169
2170 if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {
2171 *MaximumVariableSize = 0;
2172 } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {
2173 *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);
2174 }
2175
2176 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
2177 return EFI_SUCCESS;
2178 }
2179
2180
2181 /**
2182 Notification function of EVT_GROUP_READY_TO_BOOT event group.
2183
2184 This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.
2185 When the Boot Manager is about to load and execute a boot option, it reclaims variable
2186 storage if free size is below the threshold.
2187
2188 @param Event Event whose notification function is being invoked
2189 @param Context Pointer to the notification function's context
2190
2191 **/
2192 VOID
2193 EFIAPI
2194 ReclaimForOS(
2195 EFI_EVENT Event,
2196 VOID *Context
2197 )
2198 {
2199 EFI_STATUS Status;
2200 UINTN CommonVariableSpace;
2201 UINTN RemainingCommonVariableSpace;
2202 UINTN RemainingHwErrVariableSpace;
2203
2204 Status = EFI_SUCCESS;
2205
2206 CommonVariableSpace = ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize); //Allowable max size of common variable storage space
2207
2208 RemainingCommonVariableSpace = CommonVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;
2209
2210 RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;
2211 //
2212 // Check if the free area is blow a threshold.
2213 //
2214 if ((RemainingCommonVariableSpace < PcdGet32 (PcdMaxVariableSize))
2215 || ((PcdGet32 (PcdHwErrStorageSize) != 0) &&
2216 (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize)))){
2217 Status = Reclaim (
2218 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
2219 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
2220 FALSE,
2221 NULL
2222 );
2223 ASSERT_EFI_ERROR (Status);
2224 }
2225 }
2226
2227 /**
2228 Initializes variable store area for non-volatile and volatile variable.
2229
2230 @param FvbProtocol Pointer to an instance of EFI Firmware Volume Block Protocol.
2231
2232 @retval EFI_SUCCESS Function successfully executed.
2233 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
2234
2235 **/
2236 EFI_STATUS
2237 VariableCommonInitialize (
2238 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol
2239 )
2240 {
2241 EFI_STATUS Status;
2242 VARIABLE_STORE_HEADER *VolatileVariableStore;
2243 VARIABLE_STORE_HEADER *VariableStoreHeader;
2244 VARIABLE_HEADER *NextVariable;
2245 EFI_PHYSICAL_ADDRESS TempVariableStoreHeader;
2246 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
2247 EFI_PHYSICAL_ADDRESS BaseAddress;
2248 UINT64 Length;
2249 UINTN Index;
2250 UINT8 Data;
2251 EFI_PHYSICAL_ADDRESS VariableStoreBase;
2252 UINT64 VariableStoreLength;
2253 EFI_EVENT ReadyToBootEvent;
2254 UINTN ScratchSize;
2255 UINTN VariableSize;
2256
2257 Status = EFI_SUCCESS;
2258 //
2259 // Allocate runtime memory for variable driver global structure.
2260 //
2261 mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL));
2262 if (mVariableModuleGlobal == NULL) {
2263 return EFI_OUT_OF_RESOURCES;
2264 }
2265
2266 EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);
2267
2268 //
2269 // Note that in EdkII variable driver implementation, Hardware Error Record type variable
2270 // is stored with common variable in the same NV region. So the platform integrator should
2271 // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of
2272 // PcdFlashNvStorageVariableSize.
2273 //
2274 ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));
2275
2276 //
2277 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
2278 //
2279 ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));
2280 VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);
2281 if (VolatileVariableStore == NULL) {
2282 FreePool (mVariableModuleGlobal);
2283 return EFI_OUT_OF_RESOURCES;
2284 }
2285
2286 SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);
2287
2288 //
2289 // Variable Specific Data
2290 //
2291 mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;
2292 mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;
2293 mVariableModuleGlobal->FvbInstance = FvbProtocol;
2294
2295 CopyGuid (&VolatileVariableStore->Signature, &gEfiVariableGuid);
2296 VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize);
2297 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;
2298 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;
2299 VolatileVariableStore->Reserved = 0;
2300 VolatileVariableStore->Reserved1 = 0;
2301
2302 //
2303 // Get non volatile varaible store
2304 //
2305
2306 TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);
2307 if (TempVariableStoreHeader == 0) {
2308 TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);
2309 }
2310
2311 VariableStoreBase = TempVariableStoreHeader + \
2312 (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);
2313 VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \
2314 (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);
2315 //
2316 // Mark the variable storage region of the FLASH as RUNTIME
2317 //
2318 BaseAddress = VariableStoreBase & (~EFI_PAGE_MASK);
2319 Length = VariableStoreLength + (VariableStoreBase - BaseAddress);
2320 Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);
2321
2322 Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);
2323 if (EFI_ERROR (Status)) {
2324 goto Done;
2325 }
2326
2327 Status = gDS->SetMemorySpaceAttributes (
2328 BaseAddress,
2329 Length,
2330 GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME
2331 );
2332 if (EFI_ERROR (Status)) {
2333 goto Done;
2334 }
2335 //
2336 // Get address of non volatile variable store base
2337 //
2338 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;
2339 VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;
2340 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
2341 if (~VariableStoreHeader->Size == 0) {
2342 Status = UpdateVariableStore (
2343 &mVariableModuleGlobal->VariableGlobal,
2344 FALSE,
2345 FALSE,
2346 mVariableModuleGlobal->FvbInstance,
2347 (UINTN) &VariableStoreHeader->Size,
2348 sizeof (UINT32),
2349 (UINT8 *) &VariableStoreLength
2350 );
2351 //
2352 // As Variables are stored in NV storage, which are slow devices,such as flash.
2353 // Variable operation may skip checking variable program result to improve performance,
2354 // We can assume Variable program is OK through some check point.
2355 // Variable Store Size Setting should be the first Variable write operation,
2356 // We can assume all Read/Write is OK if we can set Variable store size successfully.
2357 // If write fail, we will assert here
2358 //
2359 ASSERT(VariableStoreHeader->Size == VariableStoreLength);
2360
2361 if (EFI_ERROR (Status)) {
2362 goto Done;
2363 }
2364 }
2365
2366 //
2367 // Parse non-volatile variable data and get last variable offset
2368 //
2369 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);
2370 Status = EFI_SUCCESS;
2371
2372 while (IsValidVariableHeader (NextVariable)) {
2373 VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);
2374 if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
2375 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);
2376 } else {
2377 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);
2378 }
2379
2380 NextVariable = GetNextVariablePtr (NextVariable);
2381 }
2382
2383 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;
2384
2385 //
2386 // Check if the free area is really free.
2387 //
2388 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {
2389 Data = ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)[Index];
2390 if (Data != 0xff) {
2391 //
2392 // There must be something wrong in variable store, do reclaim operation.
2393 //
2394 Status = Reclaim (
2395 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
2396 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
2397 FALSE,
2398 NULL
2399 );
2400
2401 if (EFI_ERROR (Status)) {
2402 goto Done;
2403 }
2404
2405 break;
2406 }
2407 }
2408
2409 //
2410 // Register the event handling function to reclaim variable for OS usage.
2411 //
2412 Status = EfiCreateEventReadyToBootEx (
2413 TPL_NOTIFY,
2414 ReclaimForOS,
2415 NULL,
2416 &ReadyToBootEvent
2417 );
2418 } else {
2419 Status = EFI_VOLUME_CORRUPTED;
2420 DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));
2421 }
2422
2423 Done:
2424 if (EFI_ERROR (Status)) {
2425 FreePool (mVariableModuleGlobal);
2426 FreePool (VolatileVariableStore);
2427 }
2428
2429 return Status;
2430 }
2431
2432 /**
2433 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
2434
2435 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
2436 It convers pointer to new virtual address.
2437
2438 @param Event Event whose notification function is being invoked
2439 @param Context Pointer to the notification function's context
2440
2441 **/
2442 VOID
2443 EFIAPI
2444 VariableClassAddressChangeEvent (
2445 IN EFI_EVENT Event,
2446 IN VOID *Context
2447 )
2448 {
2449 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);
2450 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);
2451 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);
2452 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes);
2453 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read);
2454 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write);
2455 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks);
2456 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance);
2457 EfiConvertPointer (
2458 0x0,
2459 (VOID **) &mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase
2460 );
2461 EfiConvertPointer (
2462 0x0,
2463 (VOID **) &mVariableModuleGlobal->VariableGlobal.VolatileVariableBase
2464 );
2465 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal);
2466 }
2467
2468 /**
2469 Firmware Volume Block Protocol notification event handler.
2470
2471 Discover NV Variable Store and install Variable Arch Protocol.
2472
2473 @param[in] Event Event whose notification function is being invoked.
2474 @param[in] Context Pointer to the notification function's context.
2475 **/
2476 VOID
2477 EFIAPI
2478 FvbNotificationEvent (
2479 IN EFI_EVENT Event,
2480 IN VOID *Context
2481 )
2482 {
2483 EFI_STATUS Status;
2484 EFI_HANDLE *HandleBuffer;
2485 UINTN HandleCount;
2486 UINTN Index;
2487 EFI_PHYSICAL_ADDRESS FvbBaseAddress;
2488 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
2489 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
2490 EFI_FVB_ATTRIBUTES_2 Attributes;
2491 EFI_SYSTEM_TABLE *SystemTable;
2492 EFI_PHYSICAL_ADDRESS NvStorageVariableBase;
2493
2494 SystemTable = (EFI_SYSTEM_TABLE *)Context;
2495 Fvb = NULL;
2496
2497 //
2498 // Locate all handles of Fvb protocol
2499 //
2500 Status = gBS->LocateHandleBuffer (
2501 ByProtocol,
2502 &gEfiFirmwareVolumeBlockProtocolGuid,
2503 NULL,
2504 &HandleCount,
2505 &HandleBuffer
2506 );
2507 if (EFI_ERROR (Status)) {
2508 return ;
2509 }
2510
2511 //
2512 // Get the FVB to access variable store
2513 //
2514 for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {
2515 Status = gBS->HandleProtocol (
2516 HandleBuffer[Index],
2517 &gEfiFirmwareVolumeBlockProtocolGuid,
2518 (VOID **) &Fvb
2519 );
2520 if (EFI_ERROR (Status)) {
2521 Status = EFI_NOT_FOUND;
2522 break;
2523 }
2524
2525 //
2526 // Ensure this FVB protocol supported Write operation.
2527 //
2528 Status = Fvb->GetAttributes (Fvb, &Attributes);
2529 if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
2530 continue;
2531 }
2532 //
2533 // Compare the address and select the right one
2534 //
2535 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
2536 if (EFI_ERROR (Status)) {
2537 continue;
2538 }
2539
2540 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
2541 NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);
2542 if (NvStorageVariableBase == 0) {
2543 NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);
2544 }
2545
2546 if ((NvStorageVariableBase >= FvbBaseAddress) && (NvStorageVariableBase < (FvbBaseAddress + FwVolHeader->FvLength))) {
2547 Status = EFI_SUCCESS;
2548 break;
2549 }
2550 }
2551
2552 FreePool (HandleBuffer);
2553 if (!EFI_ERROR (Status) && Fvb != NULL) {
2554 //
2555 // Close the notify event to avoid install gEfiVariableArchProtocolGuid & gEfiVariableWriteArchProtocolGuid again.
2556 //
2557 Status = gBS->CloseEvent (Event);
2558 ASSERT_EFI_ERROR (Status);
2559
2560 Status = VariableCommonInitialize (Fvb);
2561 ASSERT_EFI_ERROR (Status);
2562
2563 SystemTable->RuntimeServices->GetVariable = RuntimeServiceGetVariable;
2564 SystemTable->RuntimeServices->GetNextVariableName = RuntimeServiceGetNextVariableName;
2565 SystemTable->RuntimeServices->SetVariable = RuntimeServiceSetVariable;
2566 SystemTable->RuntimeServices->QueryVariableInfo = RuntimeServiceQueryVariableInfo;
2567
2568 //
2569 // Now install the Variable Runtime Architectural Protocol on a new handle
2570 //
2571 Status = gBS->InstallMultipleProtocolInterfaces (
2572 &mHandle,
2573 &gEfiVariableArchProtocolGuid, NULL,
2574 &gEfiVariableWriteArchProtocolGuid, NULL,
2575 NULL
2576 );
2577 ASSERT_EFI_ERROR (Status);
2578
2579 Status = gBS->CreateEventEx (
2580 EVT_NOTIFY_SIGNAL,
2581 TPL_NOTIFY,
2582 VariableClassAddressChangeEvent,
2583 NULL,
2584 &gEfiEventVirtualAddressChangeGuid,
2585 &mVirtualAddressChangeEvent
2586 );
2587 ASSERT_EFI_ERROR (Status);
2588 }
2589
2590 }
2591
2592 /**
2593 Variable Driver main entry point. The Variable driver places the 4 EFI
2594 runtime services in the EFI System Table and installs arch protocols
2595 for variable read and write services being availible. It also registers
2596 notification function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.
2597
2598 @param[in] ImageHandle The firmware allocated handle for the EFI image.
2599 @param[in] SystemTable A pointer to the EFI System Table.
2600
2601 @retval EFI_SUCCESS Variable service successfully initialized.
2602
2603 **/
2604 EFI_STATUS
2605 EFIAPI
2606 VariableServiceInitialize (
2607 IN EFI_HANDLE ImageHandle,
2608 IN EFI_SYSTEM_TABLE *SystemTable
2609 )
2610 {
2611 //
2612 // Register FvbNotificationEvent () notify function.
2613 //
2614 EfiCreateProtocolNotifyEvent (
2615 &gEfiFirmwareVolumeBlockProtocolGuid,
2616 TPL_CALLBACK,
2617 FvbNotificationEvent,
2618 (VOID *)SystemTable,
2619 &mFvbRegistration
2620 );
2621
2622 return EFI_SUCCESS;
2623 }
2624