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