]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
MdeModulePkg Variable: Add emulated variable NV mode support
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / Variable.c
1 /** @file
2 The common variable operation routines shared by DXE_RUNTIME variable
3 module and DXE_SMM variable module.
4
5 Caution: This module requires additional review when modified.
6 This driver will have external input - variable data. They may be input in SMM mode.
7 This external input must be validated carefully to avoid security issue like
8 buffer overflow, integer overflow.
9
10 VariableServiceGetNextVariableName () and VariableServiceQueryVariableInfo() are external API.
11 They need check input parameter.
12
13 VariableServiceGetVariable() and VariableServiceSetVariable() are external API
14 to receive datasize and data buffer. The size should be checked carefully.
15
16 VariableServiceSetVariable() should also check authenticate data to avoid buffer overflow,
17 integer overflow. It should also check attribute to avoid authentication bypass.
18
19 Copyright (c) 2006 - 2019, Intel Corporation. All rights reserved.<BR>
20 (C) Copyright 2015-2018 Hewlett Packard Enterprise Development LP<BR>
21 This program and the accompanying materials
22 are licensed and made available under the terms and conditions of the BSD License
23 which accompanies this distribution. The full text of the license may be found at
24 http://opensource.org/licenses/bsd-license.php
25
26 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
27 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
28
29 **/
30
31 #include "Variable.h"
32
33 VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;
34
35 ///
36 /// Define a memory cache that improves the search performance for a variable.
37 /// For EmuNvMode == TRUE, it will be equal to NonVolatileVariableBase.
38 ///
39 VARIABLE_STORE_HEADER *mNvVariableCache = NULL;
40
41 ///
42 /// Memory cache of Fv Header.
43 ///
44 EFI_FIRMWARE_VOLUME_HEADER *mNvFvHeaderCache = NULL;
45
46 ///
47 /// The memory entry used for variable statistics data.
48 ///
49 VARIABLE_INFO_ENTRY *gVariableInfo = NULL;
50
51 ///
52 /// The flag to indicate whether the platform has left the DXE phase of execution.
53 ///
54 BOOLEAN mEndOfDxe = FALSE;
55
56 ///
57 /// It indicates the var check request source.
58 /// In the implementation, DXE is regarded as untrusted, and SMM is trusted.
59 ///
60 VAR_CHECK_REQUEST_SOURCE mRequestSource = VarCheckFromUntrusted;
61
62 //
63 // It will record the current boot error flag before EndOfDxe.
64 //
65 VAR_ERROR_FLAG mCurrentBootVarErrFlag = VAR_ERROR_FLAG_NO_ERROR;
66
67 VARIABLE_ENTRY_PROPERTY mVariableEntryProperty[] = {
68 {
69 &gEdkiiVarErrorFlagGuid,
70 VAR_ERROR_FLAG_NAME,
71 {
72 VAR_CHECK_VARIABLE_PROPERTY_REVISION,
73 VAR_CHECK_VARIABLE_PROPERTY_READ_ONLY,
74 VARIABLE_ATTRIBUTE_NV_BS_RT,
75 sizeof (VAR_ERROR_FLAG),
76 sizeof (VAR_ERROR_FLAG)
77 }
78 },
79 };
80
81 AUTH_VAR_LIB_CONTEXT_IN mAuthContextIn = {
82 AUTH_VAR_LIB_CONTEXT_IN_STRUCT_VERSION,
83 //
84 // StructSize, TO BE FILLED
85 //
86 0,
87 //
88 // MaxAuthVariableSize, TO BE FILLED
89 //
90 0,
91 VariableExLibFindVariable,
92 VariableExLibFindNextVariable,
93 VariableExLibUpdateVariable,
94 VariableExLibGetScratchBuffer,
95 VariableExLibCheckRemainingSpaceForConsistency,
96 VariableExLibAtRuntime,
97 };
98
99 AUTH_VAR_LIB_CONTEXT_OUT mAuthContextOut;
100
101 /**
102 Routine used to track statistical information about variable usage.
103 The data is stored in the EFI system table so it can be accessed later.
104 VariableInfo.efi can dump out the table. Only Boot Services variable
105 accesses are tracked by this code. The PcdVariableCollectStatistics
106 build flag controls if this feature is enabled.
107
108 A read that hits in the cache will have Read and Cache true for
109 the transaction. Data is allocated by this routine, but never
110 freed.
111
112 @param[in] VariableName Name of the Variable to track.
113 @param[in] VendorGuid Guid of the Variable to track.
114 @param[in] Volatile TRUE if volatile FALSE if non-volatile.
115 @param[in] Read TRUE if GetVariable() was called.
116 @param[in] Write TRUE if SetVariable() was called.
117 @param[in] Delete TRUE if deleted via SetVariable().
118 @param[in] Cache TRUE for a cache hit.
119
120 **/
121 VOID
122 UpdateVariableInfo (
123 IN CHAR16 *VariableName,
124 IN EFI_GUID *VendorGuid,
125 IN BOOLEAN Volatile,
126 IN BOOLEAN Read,
127 IN BOOLEAN Write,
128 IN BOOLEAN Delete,
129 IN BOOLEAN Cache
130 )
131 {
132 VARIABLE_INFO_ENTRY *Entry;
133
134 if (FeaturePcdGet (PcdVariableCollectStatistics)) {
135
136 if (AtRuntime ()) {
137 // Don't collect statistics at runtime.
138 return;
139 }
140
141 if (gVariableInfo == NULL) {
142 //
143 // On the first call allocate a entry and place a pointer to it in
144 // the EFI System Table.
145 //
146 gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
147 ASSERT (gVariableInfo != NULL);
148
149 CopyGuid (&gVariableInfo->VendorGuid, VendorGuid);
150 gVariableInfo->Name = AllocateZeroPool (StrSize (VariableName));
151 ASSERT (gVariableInfo->Name != NULL);
152 StrCpyS (gVariableInfo->Name, StrSize(VariableName)/sizeof(CHAR16), VariableName);
153 gVariableInfo->Volatile = Volatile;
154 }
155
156
157 for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) {
158 if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {
159 if (StrCmp (VariableName, Entry->Name) == 0) {
160 if (Read) {
161 Entry->ReadCount++;
162 }
163 if (Write) {
164 Entry->WriteCount++;
165 }
166 if (Delete) {
167 Entry->DeleteCount++;
168 }
169 if (Cache) {
170 Entry->CacheCount++;
171 }
172
173 return;
174 }
175 }
176
177 if (Entry->Next == NULL) {
178 //
179 // If the entry is not in the table add it.
180 // Next iteration of the loop will fill in the data.
181 //
182 Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
183 ASSERT (Entry->Next != NULL);
184
185 CopyGuid (&Entry->Next->VendorGuid, VendorGuid);
186 Entry->Next->Name = AllocateZeroPool (StrSize (VariableName));
187 ASSERT (Entry->Next->Name != NULL);
188 StrCpyS (Entry->Next->Name, StrSize(VariableName)/sizeof(CHAR16), VariableName);
189 Entry->Next->Volatile = Volatile;
190 }
191
192 }
193 }
194 }
195
196
197 /**
198
199 This code checks if variable header is valid or not.
200
201 @param Variable Pointer to the Variable Header.
202 @param VariableStoreEnd Pointer to the Variable Store End.
203
204 @retval TRUE Variable header is valid.
205 @retval FALSE Variable header is not valid.
206
207 **/
208 BOOLEAN
209 IsValidVariableHeader (
210 IN VARIABLE_HEADER *Variable,
211 IN VARIABLE_HEADER *VariableStoreEnd
212 )
213 {
214 if ((Variable == NULL) || (Variable >= VariableStoreEnd) || (Variable->StartId != VARIABLE_DATA)) {
215 //
216 // Variable is NULL or has reached the end of variable store,
217 // or the StartId is not correct.
218 //
219 return FALSE;
220 }
221
222 return TRUE;
223 }
224
225
226 /**
227
228 This function writes data to the FWH at the correct LBA even if the LBAs
229 are fragmented.
230
231 @param Global Pointer to VARAIBLE_GLOBAL structure.
232 @param Volatile Point out the Variable is Volatile or Non-Volatile.
233 @param SetByIndex TRUE if target pointer is given as index.
234 FALSE if target pointer is absolute.
235 @param Fvb Pointer to the writable FVB protocol.
236 @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER
237 structure.
238 @param DataSize Size of data to be written.
239 @param Buffer Pointer to the buffer from which data is written.
240
241 @retval EFI_INVALID_PARAMETER Parameters not valid.
242 @retval EFI_UNSUPPORTED Fvb is a NULL for Non-Volatile variable update.
243 @retval EFI_OUT_OF_RESOURCES The remaining size is not enough.
244 @retval EFI_SUCCESS Variable store successfully updated.
245
246 **/
247 EFI_STATUS
248 UpdateVariableStore (
249 IN VARIABLE_GLOBAL *Global,
250 IN BOOLEAN Volatile,
251 IN BOOLEAN SetByIndex,
252 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
253 IN UINTN DataPtrIndex,
254 IN UINT32 DataSize,
255 IN UINT8 *Buffer
256 )
257 {
258 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
259 UINTN BlockIndex2;
260 UINTN LinearOffset;
261 UINTN CurrWriteSize;
262 UINTN CurrWritePtr;
263 UINT8 *CurrBuffer;
264 EFI_LBA LbaNumber;
265 UINTN Size;
266 VARIABLE_STORE_HEADER *VolatileBase;
267 EFI_PHYSICAL_ADDRESS FvVolHdr;
268 EFI_PHYSICAL_ADDRESS DataPtr;
269 EFI_STATUS Status;
270
271 FvVolHdr = 0;
272 DataPtr = DataPtrIndex;
273
274 //
275 // Check if the Data is Volatile.
276 //
277 if (!Volatile && !mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
278 if (Fvb == NULL) {
279 return EFI_UNSUPPORTED;
280 }
281 Status = Fvb->GetPhysicalAddress(Fvb, &FvVolHdr);
282 ASSERT_EFI_ERROR (Status);
283
284 //
285 // Data Pointer should point to the actual Address where data is to be
286 // written.
287 //
288 if (SetByIndex) {
289 DataPtr += mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;
290 }
291
292 if ((DataPtr + DataSize) > (FvVolHdr + mNvFvHeaderCache->FvLength)) {
293 return EFI_OUT_OF_RESOURCES;
294 }
295 } else {
296 //
297 // Data Pointer should point to the actual Address where data is to be
298 // written.
299 //
300 if (Volatile) {
301 VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
302 if (SetByIndex) {
303 DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
304 }
305
306 if ((DataPtr + DataSize) > ((UINTN) VolatileBase + VolatileBase->Size)) {
307 return EFI_OUT_OF_RESOURCES;
308 }
309 } else {
310 //
311 // Emulated non-volatile variable mode.
312 //
313 if (SetByIndex) {
314 DataPtr += (UINTN) mNvVariableCache;
315 }
316
317 if ((DataPtr + DataSize) > ((UINTN) mNvVariableCache + mNvVariableCache->Size)) {
318 return EFI_OUT_OF_RESOURCES;
319 }
320 }
321
322 //
323 // If Volatile/Emulated Non-volatile Variable just do a simple mem copy.
324 //
325 CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize);
326 return EFI_SUCCESS;
327 }
328
329 //
330 // If we are here we are dealing with Non-Volatile Variables.
331 //
332 LinearOffset = (UINTN) FvVolHdr;
333 CurrWritePtr = (UINTN) DataPtr;
334 CurrWriteSize = DataSize;
335 CurrBuffer = Buffer;
336 LbaNumber = 0;
337
338 if (CurrWritePtr < LinearOffset) {
339 return EFI_INVALID_PARAMETER;
340 }
341
342 for (PtrBlockMapEntry = mNvFvHeaderCache->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
343 for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {
344 //
345 // Check to see if the Variable Writes are spanning through multiple
346 // blocks.
347 //
348 if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) {
349 if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {
350 Status = Fvb->Write (
351 Fvb,
352 LbaNumber,
353 (UINTN) (CurrWritePtr - LinearOffset),
354 &CurrWriteSize,
355 CurrBuffer
356 );
357 return Status;
358 } else {
359 Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);
360 Status = Fvb->Write (
361 Fvb,
362 LbaNumber,
363 (UINTN) (CurrWritePtr - LinearOffset),
364 &Size,
365 CurrBuffer
366 );
367 if (EFI_ERROR (Status)) {
368 return Status;
369 }
370
371 CurrWritePtr = LinearOffset + PtrBlockMapEntry->Length;
372 CurrBuffer = CurrBuffer + Size;
373 CurrWriteSize = CurrWriteSize - Size;
374 }
375 }
376
377 LinearOffset += PtrBlockMapEntry->Length;
378 LbaNumber++;
379 }
380 }
381
382 return EFI_SUCCESS;
383 }
384
385
386 /**
387
388 This code gets the current status of Variable Store.
389
390 @param VarStoreHeader Pointer to the Variable Store Header.
391
392 @retval EfiRaw Variable store status is raw.
393 @retval EfiValid Variable store status is valid.
394 @retval EfiInvalid Variable store status is invalid.
395
396 **/
397 VARIABLE_STORE_STATUS
398 GetVariableStoreStatus (
399 IN VARIABLE_STORE_HEADER *VarStoreHeader
400 )
401 {
402 if ((CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) ||
403 CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid)) &&
404 VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&
405 VarStoreHeader->State == VARIABLE_STORE_HEALTHY
406 ) {
407
408 return EfiValid;
409 } else if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff &&
410 ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff &&
411 ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff &&
412 ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff &&
413 VarStoreHeader->Size == 0xffffffff &&
414 VarStoreHeader->Format == 0xff &&
415 VarStoreHeader->State == 0xff
416 ) {
417
418 return EfiRaw;
419 } else {
420 return EfiInvalid;
421 }
422 }
423
424 /**
425 This code gets the size of variable header.
426
427 @return Size of variable header in bytes in type UINTN.
428
429 **/
430 UINTN
431 GetVariableHeaderSize (
432 VOID
433 )
434 {
435 UINTN Value;
436
437 if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
438 Value = sizeof (AUTHENTICATED_VARIABLE_HEADER);
439 } else {
440 Value = sizeof (VARIABLE_HEADER);
441 }
442
443 return Value;
444 }
445
446 /**
447
448 This code gets the size of name of variable.
449
450 @param Variable Pointer to the Variable Header.
451
452 @return UINTN Size of variable in bytes.
453
454 **/
455 UINTN
456 NameSizeOfVariable (
457 IN VARIABLE_HEADER *Variable
458 )
459 {
460 AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
461
462 AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
463 if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
464 if (AuthVariable->State == (UINT8) (-1) ||
465 AuthVariable->DataSize == (UINT32) (-1) ||
466 AuthVariable->NameSize == (UINT32) (-1) ||
467 AuthVariable->Attributes == (UINT32) (-1)) {
468 return 0;
469 }
470 return (UINTN) AuthVariable->NameSize;
471 } else {
472 if (Variable->State == (UINT8) (-1) ||
473 Variable->DataSize == (UINT32) (-1) ||
474 Variable->NameSize == (UINT32) (-1) ||
475 Variable->Attributes == (UINT32) (-1)) {
476 return 0;
477 }
478 return (UINTN) Variable->NameSize;
479 }
480 }
481
482 /**
483 This code sets the size of name of variable.
484
485 @param[in] Variable Pointer to the Variable Header.
486 @param[in] NameSize Name size to set.
487
488 **/
489 VOID
490 SetNameSizeOfVariable (
491 IN VARIABLE_HEADER *Variable,
492 IN UINTN NameSize
493 )
494 {
495 AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
496
497 AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
498 if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
499 AuthVariable->NameSize = (UINT32) NameSize;
500 } else {
501 Variable->NameSize = (UINT32) NameSize;
502 }
503 }
504
505 /**
506
507 This code gets the size of variable data.
508
509 @param Variable Pointer to the Variable Header.
510
511 @return Size of variable in bytes.
512
513 **/
514 UINTN
515 DataSizeOfVariable (
516 IN VARIABLE_HEADER *Variable
517 )
518 {
519 AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
520
521 AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
522 if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
523 if (AuthVariable->State == (UINT8) (-1) ||
524 AuthVariable->DataSize == (UINT32) (-1) ||
525 AuthVariable->NameSize == (UINT32) (-1) ||
526 AuthVariable->Attributes == (UINT32) (-1)) {
527 return 0;
528 }
529 return (UINTN) AuthVariable->DataSize;
530 } else {
531 if (Variable->State == (UINT8) (-1) ||
532 Variable->DataSize == (UINT32) (-1) ||
533 Variable->NameSize == (UINT32) (-1) ||
534 Variable->Attributes == (UINT32) (-1)) {
535 return 0;
536 }
537 return (UINTN) Variable->DataSize;
538 }
539 }
540
541 /**
542 This code sets the size of variable data.
543
544 @param[in] Variable Pointer to the Variable Header.
545 @param[in] DataSize Data size to set.
546
547 **/
548 VOID
549 SetDataSizeOfVariable (
550 IN VARIABLE_HEADER *Variable,
551 IN UINTN DataSize
552 )
553 {
554 AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
555
556 AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
557 if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
558 AuthVariable->DataSize = (UINT32) DataSize;
559 } else {
560 Variable->DataSize = (UINT32) DataSize;
561 }
562 }
563
564 /**
565
566 This code gets the pointer to the variable name.
567
568 @param Variable Pointer to the Variable Header.
569
570 @return Pointer to Variable Name which is Unicode encoding.
571
572 **/
573 CHAR16 *
574 GetVariableNamePtr (
575 IN VARIABLE_HEADER *Variable
576 )
577 {
578 return (CHAR16 *) ((UINTN) Variable + GetVariableHeaderSize ());
579 }
580
581 /**
582 This code gets the pointer to the variable guid.
583
584 @param Variable Pointer to the Variable Header.
585
586 @return A EFI_GUID* pointer to Vendor Guid.
587
588 **/
589 EFI_GUID *
590 GetVendorGuidPtr (
591 IN VARIABLE_HEADER *Variable
592 )
593 {
594 AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
595
596 AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) Variable;
597 if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
598 return &AuthVariable->VendorGuid;
599 } else {
600 return &Variable->VendorGuid;
601 }
602 }
603
604 /**
605
606 This code gets the pointer to the variable data.
607
608 @param Variable Pointer to the Variable Header.
609
610 @return Pointer to Variable Data.
611
612 **/
613 UINT8 *
614 GetVariableDataPtr (
615 IN VARIABLE_HEADER *Variable
616 )
617 {
618 UINTN Value;
619
620 //
621 // Be careful about pad size for alignment.
622 //
623 Value = (UINTN) GetVariableNamePtr (Variable);
624 Value += NameSizeOfVariable (Variable);
625 Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));
626
627 return (UINT8 *) Value;
628 }
629
630 /**
631 This code gets the variable data offset related to variable header.
632
633 @param Variable Pointer to the Variable Header.
634
635 @return Variable Data offset.
636
637 **/
638 UINTN
639 GetVariableDataOffset (
640 IN VARIABLE_HEADER *Variable
641 )
642 {
643 UINTN Value;
644
645 //
646 // Be careful about pad size for alignment
647 //
648 Value = GetVariableHeaderSize ();
649 Value += NameSizeOfVariable (Variable);
650 Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));
651
652 return Value;
653 }
654
655 /**
656
657 This code gets the pointer to the next variable header.
658
659 @param Variable Pointer to the Variable Header.
660
661 @return Pointer to next variable header.
662
663 **/
664 VARIABLE_HEADER *
665 GetNextVariablePtr (
666 IN VARIABLE_HEADER *Variable
667 )
668 {
669 UINTN Value;
670
671 Value = (UINTN) GetVariableDataPtr (Variable);
672 Value += DataSizeOfVariable (Variable);
673 Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));
674
675 //
676 // Be careful about pad size for alignment.
677 //
678 return (VARIABLE_HEADER *) HEADER_ALIGN (Value);
679 }
680
681 /**
682
683 Gets the pointer to the first variable header in given variable store area.
684
685 @param VarStoreHeader Pointer to the Variable Store Header.
686
687 @return Pointer to the first variable header.
688
689 **/
690 VARIABLE_HEADER *
691 GetStartPointer (
692 IN VARIABLE_STORE_HEADER *VarStoreHeader
693 )
694 {
695 //
696 // The start of variable store.
697 //
698 return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);
699 }
700
701 /**
702
703 Gets the pointer to the end of the variable storage area.
704
705 This function gets pointer to the end of the variable storage
706 area, according to the input variable store header.
707
708 @param VarStoreHeader Pointer to the Variable Store Header.
709
710 @return Pointer to the end of the variable storage area.
711
712 **/
713 VARIABLE_HEADER *
714 GetEndPointer (
715 IN VARIABLE_STORE_HEADER *VarStoreHeader
716 )
717 {
718 //
719 // The end of variable store
720 //
721 return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);
722 }
723
724 /**
725 Record variable error flag.
726
727 @param[in] Flag Variable error flag to record.
728 @param[in] VariableName Name of variable.
729 @param[in] VendorGuid Guid of variable.
730 @param[in] Attributes Attributes of the variable.
731 @param[in] VariableSize Size of the variable.
732
733 **/
734 VOID
735 RecordVarErrorFlag (
736 IN VAR_ERROR_FLAG Flag,
737 IN CHAR16 *VariableName,
738 IN EFI_GUID *VendorGuid,
739 IN UINT32 Attributes,
740 IN UINTN VariableSize
741 )
742 {
743 EFI_STATUS Status;
744 VARIABLE_POINTER_TRACK Variable;
745 VAR_ERROR_FLAG *VarErrFlag;
746 VAR_ERROR_FLAG TempFlag;
747
748 DEBUG_CODE (
749 DEBUG ((EFI_D_ERROR, "RecordVarErrorFlag (0x%02x) %s:%g - 0x%08x - 0x%x\n", Flag, VariableName, VendorGuid, Attributes, VariableSize));
750 if (Flag == VAR_ERROR_FLAG_SYSTEM_ERROR) {
751 if (AtRuntime ()) {
752 DEBUG ((EFI_D_ERROR, "CommonRuntimeVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonRuntimeVariableSpace, mVariableModuleGlobal->CommonVariableTotalSize));
753 } else {
754 DEBUG ((EFI_D_ERROR, "CommonVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonVariableSpace, mVariableModuleGlobal->CommonVariableTotalSize));
755 }
756 } else {
757 DEBUG ((EFI_D_ERROR, "CommonMaxUserVariableSpace = 0x%x - CommonUserVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonMaxUserVariableSpace, mVariableModuleGlobal->CommonUserVariableTotalSize));
758 }
759 );
760
761 if (!mEndOfDxe) {
762 //
763 // Before EndOfDxe, just record the current boot variable error flag to local variable,
764 // and leave the variable error flag in NV flash as the last boot variable error flag.
765 // After EndOfDxe in InitializeVarErrorFlag (), the variable error flag in NV flash
766 // will be initialized to this local current boot variable error flag.
767 //
768 mCurrentBootVarErrFlag &= Flag;
769 return;
770 }
771
772 //
773 // Record error flag (it should have be initialized).
774 //
775 Status = FindVariable (
776 VAR_ERROR_FLAG_NAME,
777 &gEdkiiVarErrorFlagGuid,
778 &Variable,
779 &mVariableModuleGlobal->VariableGlobal,
780 FALSE
781 );
782 if (!EFI_ERROR (Status)) {
783 VarErrFlag = (VAR_ERROR_FLAG *) GetVariableDataPtr (Variable.CurrPtr);
784 TempFlag = *VarErrFlag;
785 TempFlag &= Flag;
786 if (TempFlag == *VarErrFlag) {
787 return;
788 }
789 Status = UpdateVariableStore (
790 &mVariableModuleGlobal->VariableGlobal,
791 FALSE,
792 FALSE,
793 mVariableModuleGlobal->FvbInstance,
794 (UINTN) VarErrFlag - (UINTN) mNvVariableCache + (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
795 sizeof (TempFlag),
796 &TempFlag
797 );
798 if (!EFI_ERROR (Status)) {
799 //
800 // Update the data in NV cache.
801 //
802 *VarErrFlag = TempFlag;
803 }
804 }
805 }
806
807 /**
808 Initialize variable error flag.
809
810 Before EndOfDxe, the variable indicates the last boot variable error flag,
811 then it means the last boot variable error flag must be got before EndOfDxe.
812 After EndOfDxe, the variable indicates the current boot variable error flag,
813 then it means the current boot variable error flag must be got after EndOfDxe.
814
815 **/
816 VOID
817 InitializeVarErrorFlag (
818 VOID
819 )
820 {
821 EFI_STATUS Status;
822 VARIABLE_POINTER_TRACK Variable;
823 VAR_ERROR_FLAG Flag;
824 VAR_ERROR_FLAG VarErrFlag;
825
826 if (!mEndOfDxe) {
827 return;
828 }
829
830 Flag = mCurrentBootVarErrFlag;
831 DEBUG ((EFI_D_INFO, "Initialize variable error flag (%02x)\n", Flag));
832
833 Status = FindVariable (
834 VAR_ERROR_FLAG_NAME,
835 &gEdkiiVarErrorFlagGuid,
836 &Variable,
837 &mVariableModuleGlobal->VariableGlobal,
838 FALSE
839 );
840 if (!EFI_ERROR (Status)) {
841 VarErrFlag = *((VAR_ERROR_FLAG *) GetVariableDataPtr (Variable.CurrPtr));
842 if (VarErrFlag == Flag) {
843 return;
844 }
845 }
846
847 UpdateVariable (
848 VAR_ERROR_FLAG_NAME,
849 &gEdkiiVarErrorFlagGuid,
850 &Flag,
851 sizeof (Flag),
852 VARIABLE_ATTRIBUTE_NV_BS_RT,
853 0,
854 0,
855 &Variable,
856 NULL
857 );
858 }
859
860 /**
861 Is user variable?
862
863 @param[in] Variable Pointer to variable header.
864
865 @retval TRUE User variable.
866 @retval FALSE System variable.
867
868 **/
869 BOOLEAN
870 IsUserVariable (
871 IN VARIABLE_HEADER *Variable
872 )
873 {
874 VAR_CHECK_VARIABLE_PROPERTY Property;
875
876 //
877 // Only after End Of Dxe, the variables belong to system variable are fixed.
878 // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
879 // then no need to check if the variable is user variable or not specially.
880 //
881 if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) {
882 if (VarCheckLibVariablePropertyGet (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &Property) == EFI_NOT_FOUND) {
883 return TRUE;
884 }
885 }
886 return FALSE;
887 }
888
889 /**
890 Calculate common user variable total size.
891
892 **/
893 VOID
894 CalculateCommonUserVariableTotalSize (
895 VOID
896 )
897 {
898 VARIABLE_HEADER *Variable;
899 VARIABLE_HEADER *NextVariable;
900 UINTN VariableSize;
901 VAR_CHECK_VARIABLE_PROPERTY Property;
902
903 //
904 // Only after End Of Dxe, the variables belong to system variable are fixed.
905 // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,
906 // then no need to calculate the common user variable total size specially.
907 //
908 if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) {
909 Variable = GetStartPointer (mNvVariableCache);
910 while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {
911 NextVariable = GetNextVariablePtr (Variable);
912 VariableSize = (UINTN) NextVariable - (UINTN) Variable;
913 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
914 if (VarCheckLibVariablePropertyGet (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &Property) == EFI_NOT_FOUND) {
915 //
916 // No property, it is user variable.
917 //
918 mVariableModuleGlobal->CommonUserVariableTotalSize += VariableSize;
919 }
920 }
921
922 Variable = NextVariable;
923 }
924 }
925 }
926
927 /**
928 Initialize variable quota.
929
930 **/
931 VOID
932 InitializeVariableQuota (
933 VOID
934 )
935 {
936 if (!mEndOfDxe) {
937 return;
938 }
939
940 InitializeVarErrorFlag ();
941 CalculateCommonUserVariableTotalSize ();
942 }
943
944 /**
945
946 Variable store garbage collection and reclaim operation.
947
948 @param[in] VariableBase Base address of variable store.
949 @param[out] LastVariableOffset Offset of last variable.
950 @param[in] IsVolatile The variable store is volatile or not;
951 if it is non-volatile, need FTW.
952 @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer track structure.
953 @param[in] NewVariable Pointer to new variable.
954 @param[in] NewVariableSize New variable size.
955
956 @return EFI_SUCCESS Reclaim operation has finished successfully.
957 @return EFI_OUT_OF_RESOURCES No enough memory resources or variable space.
958 @return Others Unexpect error happened during reclaim operation.
959
960 **/
961 EFI_STATUS
962 Reclaim (
963 IN EFI_PHYSICAL_ADDRESS VariableBase,
964 OUT UINTN *LastVariableOffset,
965 IN BOOLEAN IsVolatile,
966 IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack,
967 IN VARIABLE_HEADER *NewVariable,
968 IN UINTN NewVariableSize
969 )
970 {
971 VARIABLE_HEADER *Variable;
972 VARIABLE_HEADER *AddedVariable;
973 VARIABLE_HEADER *NextVariable;
974 VARIABLE_HEADER *NextAddedVariable;
975 VARIABLE_STORE_HEADER *VariableStoreHeader;
976 UINT8 *ValidBuffer;
977 UINTN MaximumBufferSize;
978 UINTN VariableSize;
979 UINTN NameSize;
980 UINT8 *CurrPtr;
981 VOID *Point0;
982 VOID *Point1;
983 BOOLEAN FoundAdded;
984 EFI_STATUS Status;
985 UINTN CommonVariableTotalSize;
986 UINTN CommonUserVariableTotalSize;
987 UINTN HwErrVariableTotalSize;
988 VARIABLE_HEADER *UpdatingVariable;
989 VARIABLE_HEADER *UpdatingInDeletedTransition;
990
991 UpdatingVariable = NULL;
992 UpdatingInDeletedTransition = NULL;
993 if (UpdatingPtrTrack != NULL) {
994 UpdatingVariable = UpdatingPtrTrack->CurrPtr;
995 UpdatingInDeletedTransition = UpdatingPtrTrack->InDeletedTransitionPtr;
996 }
997
998 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);
999
1000 CommonVariableTotalSize = 0;
1001 CommonUserVariableTotalSize = 0;
1002 HwErrVariableTotalSize = 0;
1003
1004 if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
1005 //
1006 // Start Pointers for the variable.
1007 //
1008 Variable = GetStartPointer (VariableStoreHeader);
1009 MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);
1010
1011 while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
1012 NextVariable = GetNextVariablePtr (Variable);
1013 if ((Variable->State == VAR_ADDED || Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) &&
1014 Variable != UpdatingVariable &&
1015 Variable != UpdatingInDeletedTransition
1016 ) {
1017 VariableSize = (UINTN) NextVariable - (UINTN) Variable;
1018 MaximumBufferSize += VariableSize;
1019 }
1020
1021 Variable = NextVariable;
1022 }
1023
1024 if (NewVariable != NULL) {
1025 //
1026 // Add the new variable size.
1027 //
1028 MaximumBufferSize += NewVariableSize;
1029 }
1030
1031 //
1032 // Reserve the 1 Bytes with Oxff to identify the
1033 // end of the variable buffer.
1034 //
1035 MaximumBufferSize += 1;
1036 ValidBuffer = AllocatePool (MaximumBufferSize);
1037 if (ValidBuffer == NULL) {
1038 return EFI_OUT_OF_RESOURCES;
1039 }
1040 } else {
1041 //
1042 // For NV variable reclaim, don't allocate pool here and just use mNvVariableCache
1043 // as the buffer to reduce SMRAM consumption for SMM variable driver.
1044 //
1045 MaximumBufferSize = mNvVariableCache->Size;
1046 ValidBuffer = (UINT8 *) mNvVariableCache;
1047 }
1048
1049 SetMem (ValidBuffer, MaximumBufferSize, 0xff);
1050
1051 //
1052 // Copy variable store header.
1053 //
1054 CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));
1055 CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);
1056
1057 //
1058 // Reinstall all ADDED variables as long as they are not identical to Updating Variable.
1059 //
1060 Variable = GetStartPointer (VariableStoreHeader);
1061 while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
1062 NextVariable = GetNextVariablePtr (Variable);
1063 if (Variable != UpdatingVariable && Variable->State == VAR_ADDED) {
1064 VariableSize = (UINTN) NextVariable - (UINTN) Variable;
1065 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
1066 CurrPtr += VariableSize;
1067 if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
1068 HwErrVariableTotalSize += VariableSize;
1069 } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
1070 CommonVariableTotalSize += VariableSize;
1071 if (IsUserVariable (Variable)) {
1072 CommonUserVariableTotalSize += VariableSize;
1073 }
1074 }
1075 }
1076 Variable = NextVariable;
1077 }
1078
1079 //
1080 // Reinstall all in delete transition variables.
1081 //
1082 Variable = GetStartPointer (VariableStoreHeader);
1083 while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
1084 NextVariable = GetNextVariablePtr (Variable);
1085 if (Variable != UpdatingVariable && Variable != UpdatingInDeletedTransition && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
1086
1087 //
1088 // Buffer has cached all ADDED variable.
1089 // Per IN_DELETED variable, we have to guarantee that
1090 // no ADDED one in previous buffer.
1091 //
1092
1093 FoundAdded = FALSE;
1094 AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);
1095 while (IsValidVariableHeader (AddedVariable, GetEndPointer ((VARIABLE_STORE_HEADER *) ValidBuffer))) {
1096 NextAddedVariable = GetNextVariablePtr (AddedVariable);
1097 NameSize = NameSizeOfVariable (AddedVariable);
1098 if (CompareGuid (GetVendorGuidPtr (AddedVariable), GetVendorGuidPtr (Variable)) &&
1099 NameSize == NameSizeOfVariable (Variable)
1100 ) {
1101 Point0 = (VOID *) GetVariableNamePtr (AddedVariable);
1102 Point1 = (VOID *) GetVariableNamePtr (Variable);
1103 if (CompareMem (Point0, Point1, NameSize) == 0) {
1104 FoundAdded = TRUE;
1105 break;
1106 }
1107 }
1108 AddedVariable = NextAddedVariable;
1109 }
1110 if (!FoundAdded) {
1111 //
1112 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.
1113 //
1114 VariableSize = (UINTN) NextVariable - (UINTN) Variable;
1115 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
1116 ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;
1117 CurrPtr += VariableSize;
1118 if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
1119 HwErrVariableTotalSize += VariableSize;
1120 } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
1121 CommonVariableTotalSize += VariableSize;
1122 if (IsUserVariable (Variable)) {
1123 CommonUserVariableTotalSize += VariableSize;
1124 }
1125 }
1126 }
1127 }
1128
1129 Variable = NextVariable;
1130 }
1131
1132 //
1133 // Install the new variable if it is not NULL.
1134 //
1135 if (NewVariable != NULL) {
1136 if (((UINTN) CurrPtr - (UINTN) ValidBuffer) + NewVariableSize > VariableStoreHeader->Size) {
1137 //
1138 // No enough space to store the new variable.
1139 //
1140 Status = EFI_OUT_OF_RESOURCES;
1141 goto Done;
1142 }
1143 if (!IsVolatile) {
1144 if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1145 HwErrVariableTotalSize += NewVariableSize;
1146 } else if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1147 CommonVariableTotalSize += NewVariableSize;
1148 if (IsUserVariable (NewVariable)) {
1149 CommonUserVariableTotalSize += NewVariableSize;
1150 }
1151 }
1152 if ((HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)) ||
1153 (CommonVariableTotalSize > mVariableModuleGlobal->CommonVariableSpace) ||
1154 (CommonUserVariableTotalSize > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {
1155 //
1156 // No enough space to store the new variable by NV or NV+HR attribute.
1157 //
1158 Status = EFI_OUT_OF_RESOURCES;
1159 goto Done;
1160 }
1161 }
1162
1163 CopyMem (CurrPtr, (UINT8 *) NewVariable, NewVariableSize);
1164 ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;
1165 if (UpdatingVariable != NULL) {
1166 UpdatingPtrTrack->CurrPtr = (VARIABLE_HEADER *)((UINTN)UpdatingPtrTrack->StartPtr + ((UINTN)CurrPtr - (UINTN)GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer)));
1167 UpdatingPtrTrack->InDeletedTransitionPtr = NULL;
1168 }
1169 CurrPtr += NewVariableSize;
1170 }
1171
1172 if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
1173 //
1174 // If volatile/emulated non-volatile variable store, just copy valid buffer.
1175 //
1176 SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);
1177 CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) CurrPtr - (UINTN) ValidBuffer);
1178 *LastVariableOffset = (UINTN) CurrPtr - (UINTN) ValidBuffer;
1179 if (!IsVolatile) {
1180 //
1181 // Emulated non-volatile variable mode.
1182 //
1183 mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;
1184 mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;
1185 mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;
1186 }
1187 Status = EFI_SUCCESS;
1188 } else {
1189 //
1190 // If non-volatile variable store, perform FTW here.
1191 //
1192 Status = FtwVariableSpace (
1193 VariableBase,
1194 (VARIABLE_STORE_HEADER *) ValidBuffer
1195 );
1196 if (!EFI_ERROR (Status)) {
1197 *LastVariableOffset = (UINTN) CurrPtr - (UINTN) ValidBuffer;
1198 mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;
1199 mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;
1200 mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;
1201 } else {
1202 mVariableModuleGlobal->HwErrVariableTotalSize = 0;
1203 mVariableModuleGlobal->CommonVariableTotalSize = 0;
1204 mVariableModuleGlobal->CommonUserVariableTotalSize = 0;
1205 Variable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);
1206 while (IsValidVariableHeader (Variable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase))) {
1207 NextVariable = GetNextVariablePtr (Variable);
1208 VariableSize = (UINTN) NextVariable - (UINTN) Variable;
1209 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1210 mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
1211 } else if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1212 mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
1213 if (IsUserVariable (Variable)) {
1214 mVariableModuleGlobal->CommonUserVariableTotalSize += VariableSize;
1215 }
1216 }
1217
1218 Variable = NextVariable;
1219 }
1220 *LastVariableOffset = (UINTN) Variable - (UINTN) VariableBase;
1221 }
1222 }
1223
1224 Done:
1225 if (IsVolatile || mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
1226 FreePool (ValidBuffer);
1227 } else {
1228 //
1229 // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy the data back.
1230 //
1231 CopyMem (mNvVariableCache, (UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size);
1232 }
1233
1234 return Status;
1235 }
1236
1237 /**
1238 Find the variable in the specified variable store.
1239
1240 @param[in] VariableName Name of the variable to be found
1241 @param[in] VendorGuid Vendor GUID to be found.
1242 @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
1243 check at runtime when searching variable.
1244 @param[in, out] PtrTrack Variable Track Pointer structure that contains Variable Information.
1245
1246 @retval EFI_SUCCESS Variable found successfully
1247 @retval EFI_NOT_FOUND Variable not found
1248 **/
1249 EFI_STATUS
1250 FindVariableEx (
1251 IN CHAR16 *VariableName,
1252 IN EFI_GUID *VendorGuid,
1253 IN BOOLEAN IgnoreRtCheck,
1254 IN OUT VARIABLE_POINTER_TRACK *PtrTrack
1255 )
1256 {
1257 VARIABLE_HEADER *InDeletedVariable;
1258 VOID *Point;
1259
1260 PtrTrack->InDeletedTransitionPtr = NULL;
1261
1262 //
1263 // Find the variable by walk through HOB, volatile and non-volatile variable store.
1264 //
1265 InDeletedVariable = NULL;
1266
1267 for ( PtrTrack->CurrPtr = PtrTrack->StartPtr
1268 ; IsValidVariableHeader (PtrTrack->CurrPtr, PtrTrack->EndPtr)
1269 ; PtrTrack->CurrPtr = GetNextVariablePtr (PtrTrack->CurrPtr)
1270 ) {
1271 if (PtrTrack->CurrPtr->State == VAR_ADDED ||
1272 PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)
1273 ) {
1274 if (IgnoreRtCheck || !AtRuntime () || ((PtrTrack->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {
1275 if (VariableName[0] == 0) {
1276 if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
1277 InDeletedVariable = PtrTrack->CurrPtr;
1278 } else {
1279 PtrTrack->InDeletedTransitionPtr = InDeletedVariable;
1280 return EFI_SUCCESS;
1281 }
1282 } else {
1283 if (CompareGuid (VendorGuid, GetVendorGuidPtr (PtrTrack->CurrPtr))) {
1284 Point = (VOID *) GetVariableNamePtr (PtrTrack->CurrPtr);
1285
1286 ASSERT (NameSizeOfVariable (PtrTrack->CurrPtr) != 0);
1287 if (CompareMem (VariableName, Point, NameSizeOfVariable (PtrTrack->CurrPtr)) == 0) {
1288 if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
1289 InDeletedVariable = PtrTrack->CurrPtr;
1290 } else {
1291 PtrTrack->InDeletedTransitionPtr = InDeletedVariable;
1292 return EFI_SUCCESS;
1293 }
1294 }
1295 }
1296 }
1297 }
1298 }
1299 }
1300
1301 PtrTrack->CurrPtr = InDeletedVariable;
1302 return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
1303 }
1304
1305
1306 /**
1307 Finds variable in storage blocks of volatile and non-volatile storage areas.
1308
1309 This code finds variable in storage blocks of volatile and non-volatile storage areas.
1310 If VariableName is an empty string, then we just return the first
1311 qualified variable without comparing VariableName and VendorGuid.
1312 If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check
1313 at runtime when searching existing variable, only VariableName and VendorGuid are compared.
1314 Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime.
1315
1316 @param[in] VariableName Name of the variable to be found.
1317 @param[in] VendorGuid Vendor GUID to be found.
1318 @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output,
1319 including the range searched and the target position.
1320 @param[in] Global Pointer to VARIABLE_GLOBAL structure, including
1321 base of volatile variable storage area, base of
1322 NV variable storage area, and a lock.
1323 @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute
1324 check at runtime when searching variable.
1325
1326 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
1327 VendorGuid is NULL.
1328 @retval EFI_SUCCESS Variable successfully found.
1329 @retval EFI_NOT_FOUND Variable not found
1330
1331 **/
1332 EFI_STATUS
1333 FindVariable (
1334 IN CHAR16 *VariableName,
1335 IN EFI_GUID *VendorGuid,
1336 OUT VARIABLE_POINTER_TRACK *PtrTrack,
1337 IN VARIABLE_GLOBAL *Global,
1338 IN BOOLEAN IgnoreRtCheck
1339 )
1340 {
1341 EFI_STATUS Status;
1342 VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];
1343 VARIABLE_STORE_TYPE Type;
1344
1345 if (VariableName[0] != 0 && VendorGuid == NULL) {
1346 return EFI_INVALID_PARAMETER;
1347 }
1348
1349 //
1350 // 0: Volatile, 1: HOB, 2: Non-Volatile.
1351 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
1352 // make use of this mapping to implement search algorithm.
1353 //
1354 VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) Global->VolatileVariableBase;
1355 VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *) (UINTN) Global->HobVariableBase;
1356 VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache;
1357
1358 //
1359 // Find the variable by walk through HOB, volatile and non-volatile variable store.
1360 //
1361 for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {
1362 if (VariableStoreHeader[Type] == NULL) {
1363 continue;
1364 }
1365
1366 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Type]);
1367 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Type]);
1368 PtrTrack->Volatile = (BOOLEAN) (Type == VariableStoreTypeVolatile);
1369
1370 Status = FindVariableEx (VariableName, VendorGuid, IgnoreRtCheck, PtrTrack);
1371 if (!EFI_ERROR (Status)) {
1372 return Status;
1373 }
1374 }
1375 return EFI_NOT_FOUND;
1376 }
1377
1378 /**
1379 Get index from supported language codes according to language string.
1380
1381 This code is used to get corresponding index in supported language codes. It can handle
1382 RFC4646 and ISO639 language tags.
1383 In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.
1384 In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.
1385
1386 For example:
1387 SupportedLang = "engfraengfra"
1388 Lang = "eng"
1389 Iso639Language = TRUE
1390 The return value is "0".
1391 Another example:
1392 SupportedLang = "en;fr;en-US;fr-FR"
1393 Lang = "fr-FR"
1394 Iso639Language = FALSE
1395 The return value is "3".
1396
1397 @param SupportedLang Platform supported language codes.
1398 @param Lang Configured language.
1399 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
1400
1401 @retval The index of language in the language codes.
1402
1403 **/
1404 UINTN
1405 GetIndexFromSupportedLangCodes(
1406 IN CHAR8 *SupportedLang,
1407 IN CHAR8 *Lang,
1408 IN BOOLEAN Iso639Language
1409 )
1410 {
1411 UINTN Index;
1412 UINTN CompareLength;
1413 UINTN LanguageLength;
1414
1415 if (Iso639Language) {
1416 CompareLength = ISO_639_2_ENTRY_SIZE;
1417 for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {
1418 if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {
1419 //
1420 // Successfully find the index of Lang string in SupportedLang string.
1421 //
1422 Index = Index / CompareLength;
1423 return Index;
1424 }
1425 }
1426 ASSERT (FALSE);
1427 return 0;
1428 } else {
1429 //
1430 // Compare RFC4646 language code
1431 //
1432 Index = 0;
1433 for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++);
1434
1435 for (Index = 0; *SupportedLang != '\0'; Index++, SupportedLang += CompareLength) {
1436 //
1437 // Skip ';' characters in SupportedLang
1438 //
1439 for (; *SupportedLang != '\0' && *SupportedLang == ';'; SupportedLang++);
1440 //
1441 // Determine the length of the next language code in SupportedLang
1442 //
1443 for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++);
1444
1445 if ((CompareLength == LanguageLength) &&
1446 (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0)) {
1447 //
1448 // Successfully find the index of Lang string in SupportedLang string.
1449 //
1450 return Index;
1451 }
1452 }
1453 ASSERT (FALSE);
1454 return 0;
1455 }
1456 }
1457
1458 /**
1459 Get language string from supported language codes according to index.
1460
1461 This code is used to get corresponding language strings in supported language codes. It can handle
1462 RFC4646 and ISO639 language tags.
1463 In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.
1464 In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.
1465
1466 For example:
1467 SupportedLang = "engfraengfra"
1468 Index = "1"
1469 Iso639Language = TRUE
1470 The return value is "fra".
1471 Another example:
1472 SupportedLang = "en;fr;en-US;fr-FR"
1473 Index = "1"
1474 Iso639Language = FALSE
1475 The return value is "fr".
1476
1477 @param SupportedLang Platform supported language codes.
1478 @param Index The index in supported language codes.
1479 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
1480
1481 @retval The language string in the language codes.
1482
1483 **/
1484 CHAR8 *
1485 GetLangFromSupportedLangCodes (
1486 IN CHAR8 *SupportedLang,
1487 IN UINTN Index,
1488 IN BOOLEAN Iso639Language
1489 )
1490 {
1491 UINTN SubIndex;
1492 UINTN CompareLength;
1493 CHAR8 *Supported;
1494
1495 SubIndex = 0;
1496 Supported = SupportedLang;
1497 if (Iso639Language) {
1498 //
1499 // According to the index of Lang string in SupportedLang string to get the language.
1500 // This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation.
1501 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1502 //
1503 CompareLength = ISO_639_2_ENTRY_SIZE;
1504 mVariableModuleGlobal->Lang[CompareLength] = '\0';
1505 return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength);
1506
1507 } else {
1508 while (TRUE) {
1509 //
1510 // Take semicolon as delimitation, sequentially traverse supported language codes.
1511 //
1512 for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {
1513 Supported++;
1514 }
1515 if ((*Supported == '\0') && (SubIndex != Index)) {
1516 //
1517 // Have completed the traverse, but not find corrsponding string.
1518 // This case is not allowed to happen.
1519 //
1520 ASSERT(FALSE);
1521 return NULL;
1522 }
1523 if (SubIndex == Index) {
1524 //
1525 // According to the index of Lang string in SupportedLang string to get the language.
1526 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
1527 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1528 //
1529 mVariableModuleGlobal->PlatformLang[CompareLength] = '\0';
1530 return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - CompareLength, CompareLength);
1531 }
1532 SubIndex++;
1533
1534 //
1535 // Skip ';' characters in Supported
1536 //
1537 for (; *Supported != '\0' && *Supported == ';'; Supported++);
1538 }
1539 }
1540 }
1541
1542 /**
1543 Returns a pointer to an allocated buffer that contains the best matching language
1544 from a set of supported languages.
1545
1546 This function supports both ISO 639-2 and RFC 4646 language codes, but language
1547 code types may not be mixed in a single call to this function. This function
1548 supports a variable argument list that allows the caller to pass in a prioritized
1549 list of language codes to test against all the language codes in SupportedLanguages.
1550
1551 If SupportedLanguages is NULL, then ASSERT().
1552
1553 @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that
1554 contains a set of language codes in the format
1555 specified by Iso639Language.
1556 @param[in] Iso639Language If not zero, then all language codes are assumed to be
1557 in ISO 639-2 format. If zero, then all language
1558 codes are assumed to be in RFC 4646 language format
1559 @param[in] ... A variable argument list that contains pointers to
1560 Null-terminated ASCII strings that contain one or more
1561 language codes in the format specified by Iso639Language.
1562 The first language code from each of these language
1563 code lists is used to determine if it is an exact or
1564 close match to any of the language codes in
1565 SupportedLanguages. Close matches only apply to RFC 4646
1566 language codes, and the matching algorithm from RFC 4647
1567 is used to determine if a close match is present. If
1568 an exact or close match is found, then the matching
1569 language code from SupportedLanguages is returned. If
1570 no matches are found, then the next variable argument
1571 parameter is evaluated. The variable argument list
1572 is terminated by a NULL.
1573
1574 @retval NULL The best matching language could not be found in SupportedLanguages.
1575 @retval NULL There are not enough resources available to return the best matching
1576 language.
1577 @retval Other A pointer to a Null-terminated ASCII string that is the best matching
1578 language in SupportedLanguages.
1579
1580 **/
1581 CHAR8 *
1582 EFIAPI
1583 VariableGetBestLanguage (
1584 IN CONST CHAR8 *SupportedLanguages,
1585 IN UINTN Iso639Language,
1586 ...
1587 )
1588 {
1589 VA_LIST Args;
1590 CHAR8 *Language;
1591 UINTN CompareLength;
1592 UINTN LanguageLength;
1593 CONST CHAR8 *Supported;
1594 CHAR8 *Buffer;
1595
1596 if (SupportedLanguages == NULL) {
1597 return NULL;
1598 }
1599
1600 VA_START (Args, Iso639Language);
1601 while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {
1602 //
1603 // Default to ISO 639-2 mode
1604 //
1605 CompareLength = 3;
1606 LanguageLength = MIN (3, AsciiStrLen (Language));
1607
1608 //
1609 // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
1610 //
1611 if (Iso639Language == 0) {
1612 for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++);
1613 }
1614
1615 //
1616 // Trim back the length of Language used until it is empty
1617 //
1618 while (LanguageLength > 0) {
1619 //
1620 // Loop through all language codes in SupportedLanguages
1621 //
1622 for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {
1623 //
1624 // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
1625 //
1626 if (Iso639Language == 0) {
1627 //
1628 // Skip ';' characters in Supported
1629 //
1630 for (; *Supported != '\0' && *Supported == ';'; Supported++);
1631 //
1632 // Determine the length of the next language code in Supported
1633 //
1634 for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++);
1635 //
1636 // If Language is longer than the Supported, then skip to the next language
1637 //
1638 if (LanguageLength > CompareLength) {
1639 continue;
1640 }
1641 }
1642 //
1643 // See if the first LanguageLength characters in Supported match Language
1644 //
1645 if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {
1646 VA_END (Args);
1647
1648 Buffer = (Iso639Language != 0) ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang;
1649 Buffer[CompareLength] = '\0';
1650 return CopyMem (Buffer, Supported, CompareLength);
1651 }
1652 }
1653
1654 if (Iso639Language != 0) {
1655 //
1656 // If ISO 639 mode, then each language can only be tested once
1657 //
1658 LanguageLength = 0;
1659 } else {
1660 //
1661 // If RFC 4646 mode, then trim Language from the right to the next '-' character
1662 //
1663 for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--);
1664 }
1665 }
1666 }
1667 VA_END (Args);
1668
1669 //
1670 // No matches were found
1671 //
1672 return NULL;
1673 }
1674
1675 /**
1676 This function is to check if the remaining variable space is enough to set
1677 all Variables from argument list successfully. The purpose of the check
1678 is to keep the consistency of the Variables to be in variable storage.
1679
1680 Note: Variables are assumed to be in same storage.
1681 The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
1682 so follow the argument sequence to check the Variables.
1683
1684 @param[in] Attributes Variable attributes for Variable entries.
1685 @param[in] Marker VA_LIST style variable argument list.
1686 The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
1687 A NULL terminates the list. The VariableSize of
1688 VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
1689 It will be changed to variable total size as output.
1690
1691 @retval TRUE Have enough variable space to set the Variables successfully.
1692 @retval FALSE No enough variable space to set the Variables successfully.
1693
1694 **/
1695 BOOLEAN
1696 EFIAPI
1697 CheckRemainingSpaceForConsistencyInternal (
1698 IN UINT32 Attributes,
1699 IN VA_LIST Marker
1700 )
1701 {
1702 EFI_STATUS Status;
1703 VA_LIST Args;
1704 VARIABLE_ENTRY_CONSISTENCY *VariableEntry;
1705 UINT64 MaximumVariableStorageSize;
1706 UINT64 RemainingVariableStorageSize;
1707 UINT64 MaximumVariableSize;
1708 UINTN TotalNeededSize;
1709 UINTN OriginalVarSize;
1710 VARIABLE_STORE_HEADER *VariableStoreHeader;
1711 VARIABLE_POINTER_TRACK VariablePtrTrack;
1712 VARIABLE_HEADER *NextVariable;
1713 UINTN VarNameSize;
1714 UINTN VarDataSize;
1715
1716 //
1717 // Non-Volatile related.
1718 //
1719 VariableStoreHeader = mNvVariableCache;
1720
1721 Status = VariableServiceQueryVariableInfoInternal (
1722 Attributes,
1723 &MaximumVariableStorageSize,
1724 &RemainingVariableStorageSize,
1725 &MaximumVariableSize
1726 );
1727 ASSERT_EFI_ERROR (Status);
1728
1729 TotalNeededSize = 0;
1730 VA_COPY (Args, Marker);
1731 VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
1732 while (VariableEntry != NULL) {
1733 //
1734 // Calculate variable total size.
1735 //
1736 VarNameSize = StrSize (VariableEntry->Name);
1737 VarNameSize += GET_PAD_SIZE (VarNameSize);
1738 VarDataSize = VariableEntry->VariableSize;
1739 VarDataSize += GET_PAD_SIZE (VarDataSize);
1740 VariableEntry->VariableSize = HEADER_ALIGN (GetVariableHeaderSize () + VarNameSize + VarDataSize);
1741
1742 TotalNeededSize += VariableEntry->VariableSize;
1743 VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
1744 }
1745 VA_END (Args);
1746
1747 if (RemainingVariableStorageSize >= TotalNeededSize) {
1748 //
1749 // Already have enough space.
1750 //
1751 return TRUE;
1752 } else if (AtRuntime ()) {
1753 //
1754 // At runtime, no reclaim.
1755 // The original variable space of Variables can't be reused.
1756 //
1757 return FALSE;
1758 }
1759
1760 VA_COPY (Args, Marker);
1761 VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
1762 while (VariableEntry != NULL) {
1763 //
1764 // Check if Variable[Index] has been present and get its size.
1765 //
1766 OriginalVarSize = 0;
1767 VariablePtrTrack.StartPtr = GetStartPointer (VariableStoreHeader);
1768 VariablePtrTrack.EndPtr = GetEndPointer (VariableStoreHeader);
1769 Status = FindVariableEx (
1770 VariableEntry->Name,
1771 VariableEntry->Guid,
1772 FALSE,
1773 &VariablePtrTrack
1774 );
1775 if (!EFI_ERROR (Status)) {
1776 //
1777 // Get size of Variable[Index].
1778 //
1779 NextVariable = GetNextVariablePtr (VariablePtrTrack.CurrPtr);
1780 OriginalVarSize = (UINTN) NextVariable - (UINTN) VariablePtrTrack.CurrPtr;
1781 //
1782 // Add the original size of Variable[Index] to remaining variable storage size.
1783 //
1784 RemainingVariableStorageSize += OriginalVarSize;
1785 }
1786 if (VariableEntry->VariableSize > RemainingVariableStorageSize) {
1787 //
1788 // No enough space for Variable[Index].
1789 //
1790 VA_END (Args);
1791 return FALSE;
1792 }
1793 //
1794 // Sub the (new) size of Variable[Index] from remaining variable storage size.
1795 //
1796 RemainingVariableStorageSize -= VariableEntry->VariableSize;
1797 VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);
1798 }
1799 VA_END (Args);
1800
1801 return TRUE;
1802 }
1803
1804 /**
1805 This function is to check if the remaining variable space is enough to set
1806 all Variables from argument list successfully. The purpose of the check
1807 is to keep the consistency of the Variables to be in variable storage.
1808
1809 Note: Variables are assumed to be in same storage.
1810 The set sequence of Variables will be same with the sequence of VariableEntry from argument list,
1811 so follow the argument sequence to check the Variables.
1812
1813 @param[in] Attributes Variable attributes for Variable entries.
1814 @param ... The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.
1815 A NULL terminates the list. The VariableSize of
1816 VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.
1817 It will be changed to variable total size as output.
1818
1819 @retval TRUE Have enough variable space to set the Variables successfully.
1820 @retval FALSE No enough variable space to set the Variables successfully.
1821
1822 **/
1823 BOOLEAN
1824 EFIAPI
1825 CheckRemainingSpaceForConsistency (
1826 IN UINT32 Attributes,
1827 ...
1828 )
1829 {
1830 VA_LIST Marker;
1831 BOOLEAN Return;
1832
1833 VA_START (Marker, Attributes);
1834
1835 Return = CheckRemainingSpaceForConsistencyInternal (Attributes, Marker);
1836
1837 VA_END (Marker);
1838
1839 return Return;
1840 }
1841
1842 /**
1843 Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.
1844
1845 When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.
1846
1847 According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,
1848 and are read-only. Therefore, in variable driver, only store the original value for other use.
1849
1850 @param[in] VariableName Name of variable.
1851
1852 @param[in] Data Variable data.
1853
1854 @param[in] DataSize Size of data. 0 means delete.
1855
1856 @retval EFI_SUCCESS The update operation is successful or ignored.
1857 @retval EFI_WRITE_PROTECTED Update PlatformLangCodes/LangCodes at runtime.
1858 @retval EFI_OUT_OF_RESOURCES No enough variable space to do the update operation.
1859 @retval Others Other errors happened during the update operation.
1860
1861 **/
1862 EFI_STATUS
1863 AutoUpdateLangVariable (
1864 IN CHAR16 *VariableName,
1865 IN VOID *Data,
1866 IN UINTN DataSize
1867 )
1868 {
1869 EFI_STATUS Status;
1870 CHAR8 *BestPlatformLang;
1871 CHAR8 *BestLang;
1872 UINTN Index;
1873 UINT32 Attributes;
1874 VARIABLE_POINTER_TRACK Variable;
1875 BOOLEAN SetLanguageCodes;
1876 VARIABLE_ENTRY_CONSISTENCY VariableEntry[2];
1877
1878 //
1879 // Don't do updates for delete operation
1880 //
1881 if (DataSize == 0) {
1882 return EFI_SUCCESS;
1883 }
1884
1885 SetLanguageCodes = FALSE;
1886
1887 if (StrCmp (VariableName, EFI_PLATFORM_LANG_CODES_VARIABLE_NAME) == 0) {
1888 //
1889 // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.
1890 //
1891 if (AtRuntime ()) {
1892 return EFI_WRITE_PROTECTED;
1893 }
1894
1895 SetLanguageCodes = TRUE;
1896
1897 //
1898 // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
1899 // Therefore, in variable driver, only store the original value for other use.
1900 //
1901 if (mVariableModuleGlobal->PlatformLangCodes != NULL) {
1902 FreePool (mVariableModuleGlobal->PlatformLangCodes);
1903 }
1904 mVariableModuleGlobal->PlatformLangCodes = AllocateRuntimeCopyPool (DataSize, Data);
1905 ASSERT (mVariableModuleGlobal->PlatformLangCodes != NULL);
1906
1907 //
1908 // PlatformLang holds a single language from PlatformLangCodes,
1909 // so the size of PlatformLangCodes is enough for the PlatformLang.
1910 //
1911 if (mVariableModuleGlobal->PlatformLang != NULL) {
1912 FreePool (mVariableModuleGlobal->PlatformLang);
1913 }
1914 mVariableModuleGlobal->PlatformLang = AllocateRuntimePool (DataSize);
1915 ASSERT (mVariableModuleGlobal->PlatformLang != NULL);
1916
1917 } else if (StrCmp (VariableName, EFI_LANG_CODES_VARIABLE_NAME) == 0) {
1918 //
1919 // LangCodes is a volatile variable, so it can not be updated at runtime.
1920 //
1921 if (AtRuntime ()) {
1922 return EFI_WRITE_PROTECTED;
1923 }
1924
1925 SetLanguageCodes = TRUE;
1926
1927 //
1928 // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
1929 // Therefore, in variable driver, only store the original value for other use.
1930 //
1931 if (mVariableModuleGlobal->LangCodes != NULL) {
1932 FreePool (mVariableModuleGlobal->LangCodes);
1933 }
1934 mVariableModuleGlobal->LangCodes = AllocateRuntimeCopyPool (DataSize, Data);
1935 ASSERT (mVariableModuleGlobal->LangCodes != NULL);
1936 }
1937
1938 if (SetLanguageCodes
1939 && (mVariableModuleGlobal->PlatformLangCodes != NULL)
1940 && (mVariableModuleGlobal->LangCodes != NULL)) {
1941 //
1942 // Update Lang if PlatformLang is already set
1943 // Update PlatformLang if Lang is already set
1944 //
1945 Status = FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
1946 if (!EFI_ERROR (Status)) {
1947 //
1948 // Update Lang
1949 //
1950 VariableName = EFI_PLATFORM_LANG_VARIABLE_NAME;
1951 Data = GetVariableDataPtr (Variable.CurrPtr);
1952 DataSize = DataSizeOfVariable (Variable.CurrPtr);
1953 } else {
1954 Status = FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
1955 if (!EFI_ERROR (Status)) {
1956 //
1957 // Update PlatformLang
1958 //
1959 VariableName = EFI_LANG_VARIABLE_NAME;
1960 Data = GetVariableDataPtr (Variable.CurrPtr);
1961 DataSize = DataSizeOfVariable (Variable.CurrPtr);
1962 } else {
1963 //
1964 // Neither PlatformLang nor Lang is set, directly return
1965 //
1966 return EFI_SUCCESS;
1967 }
1968 }
1969 }
1970
1971 Status = EFI_SUCCESS;
1972
1973 //
1974 // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
1975 //
1976 Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
1977
1978 if (StrCmp (VariableName, EFI_PLATFORM_LANG_VARIABLE_NAME) == 0) {
1979 //
1980 // Update Lang when PlatformLangCodes/LangCodes were set.
1981 //
1982 if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {
1983 //
1984 // When setting PlatformLang, firstly get most matched language string from supported language codes.
1985 //
1986 BestPlatformLang = VariableGetBestLanguage (mVariableModuleGlobal->PlatformLangCodes, FALSE, Data, NULL);
1987 if (BestPlatformLang != NULL) {
1988 //
1989 // Get the corresponding index in language codes.
1990 //
1991 Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, BestPlatformLang, FALSE);
1992
1993 //
1994 // Get the corresponding ISO639 language tag according to RFC4646 language tag.
1995 //
1996 BestLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, Index, TRUE);
1997
1998 //
1999 // Check the variable space for both Lang and PlatformLang variable.
2000 //
2001 VariableEntry[0].VariableSize = ISO_639_2_ENTRY_SIZE + 1;
2002 VariableEntry[0].Guid = &gEfiGlobalVariableGuid;
2003 VariableEntry[0].Name = EFI_LANG_VARIABLE_NAME;
2004
2005 VariableEntry[1].VariableSize = AsciiStrSize (BestPlatformLang);
2006 VariableEntry[1].Guid = &gEfiGlobalVariableGuid;
2007 VariableEntry[1].Name = EFI_PLATFORM_LANG_VARIABLE_NAME;
2008 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {
2009 //
2010 // No enough variable space to set both Lang and PlatformLang successfully.
2011 //
2012 Status = EFI_OUT_OF_RESOURCES;
2013 } else {
2014 //
2015 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
2016 //
2017 FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
2018
2019 Status = UpdateVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestLang,
2020 ISO_639_2_ENTRY_SIZE + 1, Attributes, 0, 0, &Variable, NULL);
2021 }
2022
2023 DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a Status: %r\n", BestPlatformLang, BestLang, Status));
2024 }
2025 }
2026
2027 } else if (StrCmp (VariableName, EFI_LANG_VARIABLE_NAME) == 0) {
2028 //
2029 // Update PlatformLang when PlatformLangCodes/LangCodes were set.
2030 //
2031 if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {
2032 //
2033 // When setting Lang, firstly get most matched language string from supported language codes.
2034 //
2035 BestLang = VariableGetBestLanguage (mVariableModuleGlobal->LangCodes, TRUE, Data, NULL);
2036 if (BestLang != NULL) {
2037 //
2038 // Get the corresponding index in language codes.
2039 //
2040 Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, BestLang, TRUE);
2041
2042 //
2043 // Get the corresponding RFC4646 language tag according to ISO639 language tag.
2044 //
2045 BestPlatformLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, Index, FALSE);
2046
2047 //
2048 // Check the variable space for both PlatformLang and Lang variable.
2049 //
2050 VariableEntry[0].VariableSize = AsciiStrSize (BestPlatformLang);
2051 VariableEntry[0].Guid = &gEfiGlobalVariableGuid;
2052 VariableEntry[0].Name = EFI_PLATFORM_LANG_VARIABLE_NAME;
2053
2054 VariableEntry[1].VariableSize = ISO_639_2_ENTRY_SIZE + 1;
2055 VariableEntry[1].Guid = &gEfiGlobalVariableGuid;
2056 VariableEntry[1].Name = EFI_LANG_VARIABLE_NAME;
2057 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {
2058 //
2059 // No enough variable space to set both PlatformLang and Lang successfully.
2060 //
2061 Status = EFI_OUT_OF_RESOURCES;
2062 } else {
2063 //
2064 // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
2065 //
2066 FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
2067
2068 Status = UpdateVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestPlatformLang,
2069 AsciiStrSize (BestPlatformLang), Attributes, 0, 0, &Variable, NULL);
2070 }
2071
2072 DEBUG ((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a Status: %r\n", BestLang, BestPlatformLang, Status));
2073 }
2074 }
2075 }
2076
2077 if (SetLanguageCodes) {
2078 //
2079 // Continue to set PlatformLangCodes or LangCodes.
2080 //
2081 return EFI_SUCCESS;
2082 } else {
2083 return Status;
2084 }
2085 }
2086
2087 /**
2088 Compare two EFI_TIME data.
2089
2090
2091 @param FirstTime A pointer to the first EFI_TIME data.
2092 @param SecondTime A pointer to the second EFI_TIME data.
2093
2094 @retval TRUE The FirstTime is not later than the SecondTime.
2095 @retval FALSE The FirstTime is later than the SecondTime.
2096
2097 **/
2098 BOOLEAN
2099 VariableCompareTimeStampInternal (
2100 IN EFI_TIME *FirstTime,
2101 IN EFI_TIME *SecondTime
2102 )
2103 {
2104 if (FirstTime->Year != SecondTime->Year) {
2105 return (BOOLEAN) (FirstTime->Year < SecondTime->Year);
2106 } else if (FirstTime->Month != SecondTime->Month) {
2107 return (BOOLEAN) (FirstTime->Month < SecondTime->Month);
2108 } else if (FirstTime->Day != SecondTime->Day) {
2109 return (BOOLEAN) (FirstTime->Day < SecondTime->Day);
2110 } else if (FirstTime->Hour != SecondTime->Hour) {
2111 return (BOOLEAN) (FirstTime->Hour < SecondTime->Hour);
2112 } else if (FirstTime->Minute != SecondTime->Minute) {
2113 return (BOOLEAN) (FirstTime->Minute < SecondTime->Minute);
2114 }
2115
2116 return (BOOLEAN) (FirstTime->Second <= SecondTime->Second);
2117 }
2118
2119 /**
2120 Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
2121 index of associated public key is needed.
2122
2123 @param[in] VariableName Name of variable.
2124 @param[in] VendorGuid Guid of variable.
2125 @param[in] Data Variable data.
2126 @param[in] DataSize Size of data. 0 means delete.
2127 @param[in] Attributes Attributes of the variable.
2128 @param[in] KeyIndex Index of associated public key.
2129 @param[in] MonotonicCount Value of associated monotonic count.
2130 @param[in, out] CacheVariable The variable information which is used to keep track of variable usage.
2131 @param[in] TimeStamp Value of associated TimeStamp.
2132
2133 @retval EFI_SUCCESS The update operation is success.
2134 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
2135
2136 **/
2137 EFI_STATUS
2138 UpdateVariable (
2139 IN CHAR16 *VariableName,
2140 IN EFI_GUID *VendorGuid,
2141 IN VOID *Data,
2142 IN UINTN DataSize,
2143 IN UINT32 Attributes OPTIONAL,
2144 IN UINT32 KeyIndex OPTIONAL,
2145 IN UINT64 MonotonicCount OPTIONAL,
2146 IN OUT VARIABLE_POINTER_TRACK *CacheVariable,
2147 IN EFI_TIME *TimeStamp OPTIONAL
2148 )
2149 {
2150 EFI_STATUS Status;
2151 VARIABLE_HEADER *NextVariable;
2152 UINTN ScratchSize;
2153 UINTN MaxDataSize;
2154 UINTN VarNameOffset;
2155 UINTN VarDataOffset;
2156 UINTN VarNameSize;
2157 UINTN VarSize;
2158 BOOLEAN Volatile;
2159 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
2160 UINT8 State;
2161 VARIABLE_POINTER_TRACK *Variable;
2162 VARIABLE_POINTER_TRACK NvVariable;
2163 VARIABLE_STORE_HEADER *VariableStoreHeader;
2164 UINT8 *BufferForMerge;
2165 UINTN MergedBufSize;
2166 BOOLEAN DataReady;
2167 UINTN DataOffset;
2168 BOOLEAN IsCommonVariable;
2169 BOOLEAN IsCommonUserVariable;
2170 AUTHENTICATED_VARIABLE_HEADER *AuthVariable;
2171
2172 if (mVariableModuleGlobal->FvbInstance == NULL && !mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
2173 //
2174 // The FVB protocol is not ready, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.
2175 //
2176 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
2177 //
2178 // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
2179 //
2180 DEBUG ((EFI_D_ERROR, "Update NV variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET));
2181 return EFI_NOT_AVAILABLE_YET;
2182 } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
2183 //
2184 // Trying to update volatile authenticated variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
2185 // The authenticated variable perhaps is not initialized, just return here.
2186 //
2187 DEBUG ((EFI_D_ERROR, "Update AUTH variable before EFI_VARIABLE_WRITE_ARCH_PROTOCOL ready - %r\n", EFI_NOT_AVAILABLE_YET));
2188 return EFI_NOT_AVAILABLE_YET;
2189 }
2190 }
2191
2192 //
2193 // Check if CacheVariable points to the variable in variable HOB.
2194 // If yes, let CacheVariable points to the variable in NV variable cache.
2195 //
2196 if ((CacheVariable->CurrPtr != NULL) &&
2197 (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) &&
2198 (CacheVariable->StartPtr == GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase))
2199 ) {
2200 CacheVariable->StartPtr = GetStartPointer (mNvVariableCache);
2201 CacheVariable->EndPtr = GetEndPointer (mNvVariableCache);
2202 CacheVariable->Volatile = FALSE;
2203 Status = FindVariableEx (VariableName, VendorGuid, FALSE, CacheVariable);
2204 if (CacheVariable->CurrPtr == NULL || EFI_ERROR (Status)) {
2205 //
2206 // There is no matched variable in NV variable cache.
2207 //
2208 if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0)) || (Attributes == 0)) {
2209 //
2210 // It is to delete variable,
2211 // go to delete this variable in variable HOB and
2212 // try to flush other variables from HOB to flash.
2213 //
2214 UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, FALSE, TRUE, FALSE);
2215 FlushHobVariableToFlash (VariableName, VendorGuid);
2216 return EFI_SUCCESS;
2217 }
2218 }
2219 }
2220
2221 if ((CacheVariable->CurrPtr == NULL) || CacheVariable->Volatile) {
2222 Variable = CacheVariable;
2223 } else {
2224 //
2225 // Update/Delete existing NV variable.
2226 // CacheVariable points to the variable in the memory copy of Flash area
2227 // Now let Variable points to the same variable in Flash area.
2228 //
2229 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
2230 Variable = &NvVariable;
2231 Variable->StartPtr = GetStartPointer (VariableStoreHeader);
2232 Variable->EndPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->EndPtr - (UINTN)CacheVariable->StartPtr));
2233
2234 Variable->CurrPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->CurrPtr - (UINTN)CacheVariable->StartPtr));
2235 if (CacheVariable->InDeletedTransitionPtr != NULL) {
2236 Variable->InDeletedTransitionPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->InDeletedTransitionPtr - (UINTN)CacheVariable->StartPtr));
2237 } else {
2238 Variable->InDeletedTransitionPtr = NULL;
2239 }
2240 Variable->Volatile = FALSE;
2241 }
2242
2243 Fvb = mVariableModuleGlobal->FvbInstance;
2244
2245 //
2246 // Tricky part: Use scratch data area at the end of volatile variable store
2247 // as a temporary storage.
2248 //
2249 NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));
2250 ScratchSize = mVariableModuleGlobal->ScratchBufferSize;
2251 SetMem (NextVariable, ScratchSize, 0xff);
2252 DataReady = FALSE;
2253
2254 if (Variable->CurrPtr != NULL) {
2255 //
2256 // Update/Delete existing variable.
2257 //
2258 if (AtRuntime ()) {
2259 //
2260 // If AtRuntime and the variable is Volatile and Runtime Access,
2261 // the volatile is ReadOnly, and SetVariable should be aborted and
2262 // return EFI_WRITE_PROTECTED.
2263 //
2264 if (Variable->Volatile) {
2265 Status = EFI_WRITE_PROTECTED;
2266 goto Done;
2267 }
2268 //
2269 // Only variable that have NV attributes can be updated/deleted in Runtime.
2270 //
2271 if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
2272 Status = EFI_INVALID_PARAMETER;
2273 goto Done;
2274 }
2275
2276 //
2277 // Only variable that have RT attributes can be updated/deleted in Runtime.
2278 //
2279 if ((CacheVariable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) {
2280 Status = EFI_INVALID_PARAMETER;
2281 goto Done;
2282 }
2283 }
2284
2285 //
2286 // Setting a data variable with no access, or zero DataSize attributes
2287 // causes it to be deleted.
2288 // When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero will
2289 // not delete the variable.
2290 //
2291 if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0))|| ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)) {
2292 if (Variable->InDeletedTransitionPtr != NULL) {
2293 //
2294 // Both ADDED and IN_DELETED_TRANSITION variable are present,
2295 // set IN_DELETED_TRANSITION one to DELETED state first.
2296 //
2297 ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);
2298 State = CacheVariable->InDeletedTransitionPtr->State;
2299 State &= VAR_DELETED;
2300 Status = UpdateVariableStore (
2301 &mVariableModuleGlobal->VariableGlobal,
2302 Variable->Volatile,
2303 FALSE,
2304 Fvb,
2305 (UINTN) &Variable->InDeletedTransitionPtr->State,
2306 sizeof (UINT8),
2307 &State
2308 );
2309 if (!EFI_ERROR (Status)) {
2310 if (!Variable->Volatile) {
2311 CacheVariable->InDeletedTransitionPtr->State = State;
2312 }
2313 } else {
2314 goto Done;
2315 }
2316 }
2317
2318 State = CacheVariable->CurrPtr->State;
2319 State &= VAR_DELETED;
2320
2321 Status = UpdateVariableStore (
2322 &mVariableModuleGlobal->VariableGlobal,
2323 Variable->Volatile,
2324 FALSE,
2325 Fvb,
2326 (UINTN) &Variable->CurrPtr->State,
2327 sizeof (UINT8),
2328 &State
2329 );
2330 if (!EFI_ERROR (Status)) {
2331 UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE);
2332 if (!Variable->Volatile) {
2333 CacheVariable->CurrPtr->State = State;
2334 FlushHobVariableToFlash (VariableName, VendorGuid);
2335 }
2336 }
2337 goto Done;
2338 }
2339 //
2340 // If the variable is marked valid, and the same data has been passed in,
2341 // then return to the caller immediately.
2342 //
2343 if (DataSizeOfVariable (CacheVariable->CurrPtr) == DataSize &&
2344 (CompareMem (Data, GetVariableDataPtr (CacheVariable->CurrPtr), DataSize) == 0) &&
2345 ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) &&
2346 (TimeStamp == NULL)) {
2347 //
2348 // Variable content unchanged and no need to update timestamp, just return.
2349 //
2350 UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE);
2351 Status = EFI_SUCCESS;
2352 goto Done;
2353 } else if ((CacheVariable->CurrPtr->State == VAR_ADDED) ||
2354 (CacheVariable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {
2355
2356 //
2357 // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable.
2358 //
2359 if ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) {
2360 //
2361 // NOTE: From 0 to DataOffset of NextVariable is reserved for Variable Header and Name.
2362 // From DataOffset of NextVariable is to save the existing variable data.
2363 //
2364 DataOffset = GetVariableDataOffset (CacheVariable->CurrPtr);
2365 BufferForMerge = (UINT8 *) ((UINTN) NextVariable + DataOffset);
2366 CopyMem (BufferForMerge, (UINT8 *) ((UINTN) CacheVariable->CurrPtr + DataOffset), DataSizeOfVariable (CacheVariable->CurrPtr));
2367
2368 //
2369 // Set Max Auth/Non-Volatile/Volatile Variable Data Size as default MaxDataSize.
2370 //
2371 if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
2372 MaxDataSize = mVariableModuleGlobal->MaxAuthVariableSize - DataOffset;
2373 } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
2374 MaxDataSize = mVariableModuleGlobal->MaxVariableSize - DataOffset;
2375 } else {
2376 MaxDataSize = mVariableModuleGlobal->MaxVolatileVariableSize - DataOffset;
2377 }
2378
2379 //
2380 // Append the new data to the end of existing data.
2381 // Max Harware error record variable data size is different from common/auth variable.
2382 //
2383 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
2384 MaxDataSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - DataOffset;
2385 }
2386
2387 if (DataSizeOfVariable (CacheVariable->CurrPtr) + DataSize > MaxDataSize) {
2388 //
2389 // Existing data size + new data size exceed maximum variable size limitation.
2390 //
2391 Status = EFI_INVALID_PARAMETER;
2392 goto Done;
2393 }
2394 CopyMem ((UINT8*) ((UINTN) BufferForMerge + DataSizeOfVariable (CacheVariable->CurrPtr)), Data, DataSize);
2395 MergedBufSize = DataSizeOfVariable (CacheVariable->CurrPtr) + DataSize;
2396
2397 //
2398 // BufferForMerge(from DataOffset of NextVariable) has included the merged existing and new data.
2399 //
2400 Data = BufferForMerge;
2401 DataSize = MergedBufSize;
2402 DataReady = TRUE;
2403 }
2404
2405 //
2406 // Mark the old variable as in delete transition.
2407 //
2408 State = CacheVariable->CurrPtr->State;
2409 State &= VAR_IN_DELETED_TRANSITION;
2410
2411 Status = UpdateVariableStore (
2412 &mVariableModuleGlobal->VariableGlobal,
2413 Variable->Volatile,
2414 FALSE,
2415 Fvb,
2416 (UINTN) &Variable->CurrPtr->State,
2417 sizeof (UINT8),
2418 &State
2419 );
2420 if (EFI_ERROR (Status)) {
2421 goto Done;
2422 }
2423 if (!Variable->Volatile) {
2424 CacheVariable->CurrPtr->State = State;
2425 }
2426 }
2427 } else {
2428 //
2429 // Not found existing variable. Create a new variable.
2430 //
2431
2432 if ((DataSize == 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {
2433 Status = EFI_SUCCESS;
2434 goto Done;
2435 }
2436
2437 //
2438 // Make sure we are trying to create a new variable.
2439 // Setting a data variable with zero DataSize or no access attributes means to delete it.
2440 //
2441 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
2442 Status = EFI_NOT_FOUND;
2443 goto Done;
2444 }
2445
2446 //
2447 // Only variable have NV|RT attribute can be created in Runtime.
2448 //
2449 if (AtRuntime () &&
2450 (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {
2451 Status = EFI_INVALID_PARAMETER;
2452 goto Done;
2453 }
2454 }
2455
2456 //
2457 // Function part - create a new variable and copy the data.
2458 // Both update a variable and create a variable will come here.
2459 //
2460 NextVariable->StartId = VARIABLE_DATA;
2461 //
2462 // NextVariable->State = VAR_ADDED;
2463 //
2464 NextVariable->Reserved = 0;
2465 if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
2466 AuthVariable = (AUTHENTICATED_VARIABLE_HEADER *) NextVariable;
2467 AuthVariable->PubKeyIndex = KeyIndex;
2468 AuthVariable->MonotonicCount = MonotonicCount;
2469 ZeroMem (&AuthVariable->TimeStamp, sizeof (EFI_TIME));
2470
2471 if (((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) &&
2472 (TimeStamp != NULL)) {
2473 if ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) {
2474 CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
2475 } else {
2476 //
2477 // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only
2478 // when the new TimeStamp value is later than the current timestamp associated
2479 // with the variable, we need associate the new timestamp with the updated value.
2480 //
2481 if (Variable->CurrPtr != NULL) {
2482 if (VariableCompareTimeStampInternal (&(((AUTHENTICATED_VARIABLE_HEADER *) CacheVariable->CurrPtr)->TimeStamp), TimeStamp)) {
2483 CopyMem (&AuthVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
2484 } else {
2485 CopyMem (&AuthVariable->TimeStamp, &(((AUTHENTICATED_VARIABLE_HEADER *) CacheVariable->CurrPtr)->TimeStamp), sizeof (EFI_TIME));
2486 }
2487 }
2488 }
2489 }
2490 }
2491
2492 //
2493 // The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the returned
2494 // Attributes bitmask parameter of a GetVariable() call.
2495 //
2496 NextVariable->Attributes = Attributes & (~EFI_VARIABLE_APPEND_WRITE);
2497
2498 VarNameOffset = GetVariableHeaderSize ();
2499 VarNameSize = StrSize (VariableName);
2500 CopyMem (
2501 (UINT8 *) ((UINTN) NextVariable + VarNameOffset),
2502 VariableName,
2503 VarNameSize
2504 );
2505 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);
2506
2507 //
2508 // If DataReady is TRUE, it means the variable data has been saved into
2509 // NextVariable during EFI_VARIABLE_APPEND_WRITE operation preparation.
2510 //
2511 if (!DataReady) {
2512 CopyMem (
2513 (UINT8 *) ((UINTN) NextVariable + VarDataOffset),
2514 Data,
2515 DataSize
2516 );
2517 }
2518
2519 CopyMem (GetVendorGuidPtr (NextVariable), VendorGuid, sizeof (EFI_GUID));
2520 //
2521 // There will be pad bytes after Data, the NextVariable->NameSize and
2522 // NextVariable->DataSize should not include pad size so that variable
2523 // service can get actual size in GetVariable.
2524 //
2525 SetNameSizeOfVariable (NextVariable, VarNameSize);
2526 SetDataSizeOfVariable (NextVariable, DataSize);
2527
2528 //
2529 // The actual size of the variable that stores in storage should
2530 // include pad size.
2531 //
2532 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
2533 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
2534 //
2535 // Create a nonvolatile variable.
2536 //
2537 Volatile = FALSE;
2538
2539 IsCommonVariable = FALSE;
2540 IsCommonUserVariable = FALSE;
2541 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) {
2542 IsCommonVariable = TRUE;
2543 IsCommonUserVariable = IsUserVariable (NextVariable);
2544 }
2545 if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)
2546 && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))
2547 || (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonVariableSpace))
2548 || (IsCommonVariable && AtRuntime () && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonRuntimeVariableSpace))
2549 || (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace))) {
2550 if (AtRuntime ()) {
2551 if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {
2552 RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName, VendorGuid, Attributes, VarSize);
2553 }
2554 if (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonRuntimeVariableSpace)) {
2555 RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName, VendorGuid, Attributes, VarSize);
2556 }
2557 Status = EFI_OUT_OF_RESOURCES;
2558 goto Done;
2559 }
2560 //
2561 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
2562 //
2563 Status = Reclaim (
2564 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
2565 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
2566 FALSE,
2567 Variable,
2568 NextVariable,
2569 HEADER_ALIGN (VarSize)
2570 );
2571 if (!EFI_ERROR (Status)) {
2572 //
2573 // The new variable has been integrated successfully during reclaiming.
2574 //
2575 if (Variable->CurrPtr != NULL) {
2576 CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN) CacheVariable->StartPtr + ((UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr));
2577 CacheVariable->InDeletedTransitionPtr = NULL;
2578 }
2579 UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, TRUE, FALSE, FALSE);
2580 FlushHobVariableToFlash (VariableName, VendorGuid);
2581 } else {
2582 if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {
2583 RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName, VendorGuid, Attributes, VarSize);
2584 }
2585 if (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonVariableSpace)) {
2586 RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName, VendorGuid, Attributes, VarSize);
2587 }
2588 }
2589 goto Done;
2590 }
2591
2592 if (!mVariableModuleGlobal->VariableGlobal.EmuNvMode) {
2593 //
2594 // Four steps
2595 // 1. Write variable header
2596 // 2. Set variable state to header valid
2597 // 3. Write variable data
2598 // 4. Set variable state to valid
2599 //
2600 //
2601 // Step 1:
2602 //
2603 Status = UpdateVariableStore (
2604 &mVariableModuleGlobal->VariableGlobal,
2605 FALSE,
2606 TRUE,
2607 Fvb,
2608 mVariableModuleGlobal->NonVolatileLastVariableOffset,
2609 (UINT32) GetVariableHeaderSize (),
2610 (UINT8 *) NextVariable
2611 );
2612
2613 if (EFI_ERROR (Status)) {
2614 goto Done;
2615 }
2616
2617 //
2618 // Step 2:
2619 //
2620 NextVariable->State = VAR_HEADER_VALID_ONLY;
2621 Status = UpdateVariableStore (
2622 &mVariableModuleGlobal->VariableGlobal,
2623 FALSE,
2624 TRUE,
2625 Fvb,
2626 mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),
2627 sizeof (UINT8),
2628 &NextVariable->State
2629 );
2630
2631 if (EFI_ERROR (Status)) {
2632 goto Done;
2633 }
2634 //
2635 // Step 3:
2636 //
2637 Status = UpdateVariableStore (
2638 &mVariableModuleGlobal->VariableGlobal,
2639 FALSE,
2640 TRUE,
2641 Fvb,
2642 mVariableModuleGlobal->NonVolatileLastVariableOffset + GetVariableHeaderSize (),
2643 (UINT32) (VarSize - GetVariableHeaderSize ()),
2644 (UINT8 *) NextVariable + GetVariableHeaderSize ()
2645 );
2646
2647 if (EFI_ERROR (Status)) {
2648 goto Done;
2649 }
2650 //
2651 // Step 4:
2652 //
2653 NextVariable->State = VAR_ADDED;
2654 Status = UpdateVariableStore (
2655 &mVariableModuleGlobal->VariableGlobal,
2656 FALSE,
2657 TRUE,
2658 Fvb,
2659 mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),
2660 sizeof (UINT8),
2661 &NextVariable->State
2662 );
2663
2664 if (EFI_ERROR (Status)) {
2665 goto Done;
2666 }
2667
2668 //
2669 // Update the memory copy of Flash region.
2670 //
2671 CopyMem ((UINT8 *)mNvVariableCache + mVariableModuleGlobal->NonVolatileLastVariableOffset, (UINT8 *)NextVariable, VarSize);
2672 } else {
2673 //
2674 // Emulated non-volatile variable mode.
2675 //
2676 NextVariable->State = VAR_ADDED;
2677 Status = UpdateVariableStore (
2678 &mVariableModuleGlobal->VariableGlobal,
2679 FALSE,
2680 TRUE,
2681 Fvb,
2682 mVariableModuleGlobal->NonVolatileLastVariableOffset,
2683 (UINT32) VarSize,
2684 (UINT8 *) NextVariable
2685 );
2686
2687 if (EFI_ERROR (Status)) {
2688 goto Done;
2689 }
2690 }
2691
2692 mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);
2693
2694 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
2695 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);
2696 } else {
2697 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);
2698 if (IsCommonUserVariable) {
2699 mVariableModuleGlobal->CommonUserVariableTotalSize += HEADER_ALIGN (VarSize);
2700 }
2701 }
2702 } else {
2703 //
2704 // Create a volatile variable.
2705 //
2706 Volatile = TRUE;
2707
2708 if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >
2709 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) {
2710 //
2711 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.
2712 //
2713 Status = Reclaim (
2714 mVariableModuleGlobal->VariableGlobal.VolatileVariableBase,
2715 &mVariableModuleGlobal->VolatileLastVariableOffset,
2716 TRUE,
2717 Variable,
2718 NextVariable,
2719 HEADER_ALIGN (VarSize)
2720 );
2721 if (!EFI_ERROR (Status)) {
2722 //
2723 // The new variable has been integrated successfully during reclaiming.
2724 //
2725 if (Variable->CurrPtr != NULL) {
2726 CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN) CacheVariable->StartPtr + ((UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr));
2727 CacheVariable->InDeletedTransitionPtr = NULL;
2728 }
2729 UpdateVariableInfo (VariableName, VendorGuid, TRUE, FALSE, TRUE, FALSE, FALSE);
2730 }
2731 goto Done;
2732 }
2733
2734 NextVariable->State = VAR_ADDED;
2735 Status = UpdateVariableStore (
2736 &mVariableModuleGlobal->VariableGlobal,
2737 TRUE,
2738 TRUE,
2739 Fvb,
2740 mVariableModuleGlobal->VolatileLastVariableOffset,
2741 (UINT32) VarSize,
2742 (UINT8 *) NextVariable
2743 );
2744
2745 if (EFI_ERROR (Status)) {
2746 goto Done;
2747 }
2748
2749 mVariableModuleGlobal->VolatileLastVariableOffset += HEADER_ALIGN (VarSize);
2750 }
2751
2752 //
2753 // Mark the old variable as deleted.
2754 //
2755 if (!EFI_ERROR (Status) && Variable->CurrPtr != NULL) {
2756 if (Variable->InDeletedTransitionPtr != NULL) {
2757 //
2758 // Both ADDED and IN_DELETED_TRANSITION old variable are present,
2759 // set IN_DELETED_TRANSITION one to DELETED state first.
2760 //
2761 ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);
2762 State = CacheVariable->InDeletedTransitionPtr->State;
2763 State &= VAR_DELETED;
2764 Status = UpdateVariableStore (
2765 &mVariableModuleGlobal->VariableGlobal,
2766 Variable->Volatile,
2767 FALSE,
2768 Fvb,
2769 (UINTN) &Variable->InDeletedTransitionPtr->State,
2770 sizeof (UINT8),
2771 &State
2772 );
2773 if (!EFI_ERROR (Status)) {
2774 if (!Variable->Volatile) {
2775 CacheVariable->InDeletedTransitionPtr->State = State;
2776 }
2777 } else {
2778 goto Done;
2779 }
2780 }
2781
2782 State = CacheVariable->CurrPtr->State;
2783 State &= VAR_DELETED;
2784
2785 Status = UpdateVariableStore (
2786 &mVariableModuleGlobal->VariableGlobal,
2787 Variable->Volatile,
2788 FALSE,
2789 Fvb,
2790 (UINTN) &Variable->CurrPtr->State,
2791 sizeof (UINT8),
2792 &State
2793 );
2794 if (!EFI_ERROR (Status) && !Variable->Volatile) {
2795 CacheVariable->CurrPtr->State = State;
2796 }
2797 }
2798
2799 if (!EFI_ERROR (Status)) {
2800 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);
2801 if (!Volatile) {
2802 FlushHobVariableToFlash (VariableName, VendorGuid);
2803 }
2804 }
2805
2806 Done:
2807 return Status;
2808 }
2809
2810 /**
2811
2812 This code finds variable in storage blocks (Volatile or Non-Volatile).
2813
2814 Caution: This function may receive untrusted input.
2815 This function may be invoked in SMM mode, and datasize is external input.
2816 This function will do basic validation, before parse the data.
2817
2818 @param VariableName Name of Variable to be found.
2819 @param VendorGuid Variable vendor GUID.
2820 @param Attributes Attribute value of the variable found.
2821 @param DataSize Size of Data found. If size is less than the
2822 data, this value contains the required size.
2823 @param Data The buffer to return the contents of the variable. May be NULL
2824 with a zero DataSize in order to determine the size buffer needed.
2825
2826 @return EFI_INVALID_PARAMETER Invalid parameter.
2827 @return EFI_SUCCESS Find the specified variable.
2828 @return EFI_NOT_FOUND Not found.
2829 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
2830
2831 **/
2832 EFI_STATUS
2833 EFIAPI
2834 VariableServiceGetVariable (
2835 IN CHAR16 *VariableName,
2836 IN EFI_GUID *VendorGuid,
2837 OUT UINT32 *Attributes OPTIONAL,
2838 IN OUT UINTN *DataSize,
2839 OUT VOID *Data OPTIONAL
2840 )
2841 {
2842 EFI_STATUS Status;
2843 VARIABLE_POINTER_TRACK Variable;
2844 UINTN VarDataSize;
2845
2846 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
2847 return EFI_INVALID_PARAMETER;
2848 }
2849
2850 if (VariableName[0] == 0) {
2851 return EFI_NOT_FOUND;
2852 }
2853
2854 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
2855
2856 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
2857 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
2858 goto Done;
2859 }
2860
2861 //
2862 // Get data size
2863 //
2864 VarDataSize = DataSizeOfVariable (Variable.CurrPtr);
2865 ASSERT (VarDataSize != 0);
2866
2867 if (*DataSize >= VarDataSize) {
2868 if (Data == NULL) {
2869 Status = EFI_INVALID_PARAMETER;
2870 goto Done;
2871 }
2872
2873 CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);
2874 if (Attributes != NULL) {
2875 *Attributes = Variable.CurrPtr->Attributes;
2876 }
2877
2878 *DataSize = VarDataSize;
2879 UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);
2880
2881 Status = EFI_SUCCESS;
2882 goto Done;
2883 } else {
2884 *DataSize = VarDataSize;
2885 Status = EFI_BUFFER_TOO_SMALL;
2886 goto Done;
2887 }
2888
2889 Done:
2890 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
2891 return Status;
2892 }
2893
2894 /**
2895 This code Finds the Next available variable.
2896
2897 Caution: This function may receive untrusted input.
2898 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
2899
2900 @param[in] VariableName Pointer to variable name.
2901 @param[in] VendorGuid Variable Vendor Guid.
2902 @param[out] VariablePtr Pointer to variable header address.
2903
2904 @retval EFI_SUCCESS The function completed successfully.
2905 @retval EFI_NOT_FOUND The next variable was not found.
2906 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while VendorGuid is NULL.
2907 @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and
2908 GUID of an existing variable.
2909
2910 **/
2911 EFI_STATUS
2912 EFIAPI
2913 VariableServiceGetNextVariableInternal (
2914 IN CHAR16 *VariableName,
2915 IN EFI_GUID *VendorGuid,
2916 OUT VARIABLE_HEADER **VariablePtr
2917 )
2918 {
2919 VARIABLE_STORE_TYPE Type;
2920 VARIABLE_POINTER_TRACK Variable;
2921 VARIABLE_POINTER_TRACK VariableInHob;
2922 VARIABLE_POINTER_TRACK VariablePtrTrack;
2923 EFI_STATUS Status;
2924 VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];
2925
2926 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
2927 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
2928 //
2929 // For VariableName is an empty string, FindVariable() will try to find and return
2930 // the first qualified variable, and if FindVariable() returns error (EFI_NOT_FOUND)
2931 // as no any variable is found, still go to return the error (EFI_NOT_FOUND).
2932 //
2933 if (VariableName[0] != 0) {
2934 //
2935 // For VariableName is not an empty string, and FindVariable() returns error as
2936 // VariableName and VendorGuid are not a name and GUID of an existing variable,
2937 // there is no way to get next variable, follow spec to return EFI_INVALID_PARAMETER.
2938 //
2939 Status = EFI_INVALID_PARAMETER;
2940 }
2941 goto Done;
2942 }
2943
2944 if (VariableName[0] != 0) {
2945 //
2946 // If variable name is not NULL, get next variable.
2947 //
2948 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
2949 }
2950
2951 //
2952 // 0: Volatile, 1: HOB, 2: Non-Volatile.
2953 // The index and attributes mapping must be kept in this order as FindVariable
2954 // makes use of this mapping to implement search algorithm.
2955 //
2956 VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
2957 VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;
2958 VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache;
2959
2960 while (TRUE) {
2961 //
2962 // Switch from Volatile to HOB, to Non-Volatile.
2963 //
2964 while (!IsValidVariableHeader (Variable.CurrPtr, Variable.EndPtr)) {
2965 //
2966 // Find current storage index
2967 //
2968 for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {
2969 if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) {
2970 break;
2971 }
2972 }
2973 ASSERT (Type < VariableStoreTypeMax);
2974 //
2975 // Switch to next storage
2976 //
2977 for (Type++; Type < VariableStoreTypeMax; Type++) {
2978 if (VariableStoreHeader[Type] != NULL) {
2979 break;
2980 }
2981 }
2982 //
2983 // Capture the case that
2984 // 1. current storage is the last one, or
2985 // 2. no further storage
2986 //
2987 if (Type == VariableStoreTypeMax) {
2988 Status = EFI_NOT_FOUND;
2989 goto Done;
2990 }
2991 Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]);
2992 Variable.EndPtr = GetEndPointer (VariableStoreHeader[Type]);
2993 Variable.CurrPtr = Variable.StartPtr;
2994 }
2995
2996 //
2997 // Variable is found
2998 //
2999 if (Variable.CurrPtr->State == VAR_ADDED || Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
3000 if (!AtRuntime () || ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {
3001 if (Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
3002 //
3003 // If it is a IN_DELETED_TRANSITION variable,
3004 // and there is also a same ADDED one at the same time,
3005 // don't return it.
3006 //
3007 VariablePtrTrack.StartPtr = Variable.StartPtr;
3008 VariablePtrTrack.EndPtr = Variable.EndPtr;
3009 Status = FindVariableEx (
3010 GetVariableNamePtr (Variable.CurrPtr),
3011 GetVendorGuidPtr (Variable.CurrPtr),
3012 FALSE,
3013 &VariablePtrTrack
3014 );
3015 if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr->State == VAR_ADDED) {
3016 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
3017 continue;
3018 }
3019 }
3020
3021 //
3022 // Don't return NV variable when HOB overrides it
3023 //
3024 if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) && (VariableStoreHeader[VariableStoreTypeNv] != NULL) &&
3025 (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv]))
3026 ) {
3027 VariableInHob.StartPtr = GetStartPointer (VariableStoreHeader[VariableStoreTypeHob]);
3028 VariableInHob.EndPtr = GetEndPointer (VariableStoreHeader[VariableStoreTypeHob]);
3029 Status = FindVariableEx (
3030 GetVariableNamePtr (Variable.CurrPtr),
3031 GetVendorGuidPtr (Variable.CurrPtr),
3032 FALSE,
3033 &VariableInHob
3034 );
3035 if (!EFI_ERROR (Status)) {
3036 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
3037 continue;
3038 }
3039 }
3040
3041 *VariablePtr = Variable.CurrPtr;
3042 Status = EFI_SUCCESS;
3043 goto Done;
3044 }
3045 }
3046
3047 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
3048 }
3049
3050 Done:
3051 return Status;
3052 }
3053
3054 /**
3055
3056 This code Finds the Next available variable.
3057
3058 Caution: This function may receive untrusted input.
3059 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3060
3061 @param VariableNameSize The size of the VariableName buffer. The size must be large
3062 enough to fit input string supplied in VariableName buffer.
3063 @param VariableName Pointer to variable name.
3064 @param VendorGuid Variable Vendor Guid.
3065
3066 @retval EFI_SUCCESS The function completed successfully.
3067 @retval EFI_NOT_FOUND The next variable was not found.
3068 @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the result.
3069 VariableNameSize has been updated with the size needed to complete the request.
3070 @retval EFI_INVALID_PARAMETER VariableNameSize is NULL.
3071 @retval EFI_INVALID_PARAMETER VariableName is NULL.
3072 @retval EFI_INVALID_PARAMETER VendorGuid is NULL.
3073 @retval EFI_INVALID_PARAMETER The input values of VariableName and VendorGuid are not a name and
3074 GUID of an existing variable.
3075 @retval EFI_INVALID_PARAMETER Null-terminator is not found in the first VariableNameSize bytes of
3076 the input VariableName buffer.
3077
3078 **/
3079 EFI_STATUS
3080 EFIAPI
3081 VariableServiceGetNextVariableName (
3082 IN OUT UINTN *VariableNameSize,
3083 IN OUT CHAR16 *VariableName,
3084 IN OUT EFI_GUID *VendorGuid
3085 )
3086 {
3087 EFI_STATUS Status;
3088 UINTN MaxLen;
3089 UINTN VarNameSize;
3090 VARIABLE_HEADER *VariablePtr;
3091
3092 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
3093 return EFI_INVALID_PARAMETER;
3094 }
3095
3096 //
3097 // Calculate the possible maximum length of name string, including the Null terminator.
3098 //
3099 MaxLen = *VariableNameSize / sizeof (CHAR16);
3100 if ((MaxLen == 0) || (StrnLenS (VariableName, MaxLen) == MaxLen)) {
3101 //
3102 // Null-terminator is not found in the first VariableNameSize bytes of the input VariableName buffer,
3103 // follow spec to return EFI_INVALID_PARAMETER.
3104 //
3105 return EFI_INVALID_PARAMETER;
3106 }
3107
3108 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
3109
3110 Status = VariableServiceGetNextVariableInternal (VariableName, VendorGuid, &VariablePtr);
3111 if (!EFI_ERROR (Status)) {
3112 VarNameSize = NameSizeOfVariable (VariablePtr);
3113 ASSERT (VarNameSize != 0);
3114 if (VarNameSize <= *VariableNameSize) {
3115 CopyMem (VariableName, GetVariableNamePtr (VariablePtr), VarNameSize);
3116 CopyMem (VendorGuid, GetVendorGuidPtr (VariablePtr), sizeof (EFI_GUID));
3117 Status = EFI_SUCCESS;
3118 } else {
3119 Status = EFI_BUFFER_TOO_SMALL;
3120 }
3121
3122 *VariableNameSize = VarNameSize;
3123 }
3124
3125 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
3126 return Status;
3127 }
3128
3129 /**
3130
3131 This code sets variable in storage blocks (Volatile or Non-Volatile).
3132
3133 Caution: This function may receive untrusted input.
3134 This function may be invoked in SMM mode, and datasize and data are external input.
3135 This function will do basic validation, before parse the data.
3136 This function will parse the authentication carefully to avoid security issues, like
3137 buffer overflow, integer overflow.
3138 This function will check attribute carefully to avoid authentication bypass.
3139
3140 @param VariableName Name of Variable to be found.
3141 @param VendorGuid Variable vendor GUID.
3142 @param Attributes Attribute value of the variable found
3143 @param DataSize Size of Data found. If size is less than the
3144 data, this value contains the required size.
3145 @param Data Data pointer.
3146
3147 @return EFI_INVALID_PARAMETER Invalid parameter.
3148 @return EFI_SUCCESS Set successfully.
3149 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
3150 @return EFI_NOT_FOUND Not found.
3151 @return EFI_WRITE_PROTECTED Variable is read-only.
3152
3153 **/
3154 EFI_STATUS
3155 EFIAPI
3156 VariableServiceSetVariable (
3157 IN CHAR16 *VariableName,
3158 IN EFI_GUID *VendorGuid,
3159 IN UINT32 Attributes,
3160 IN UINTN DataSize,
3161 IN VOID *Data
3162 )
3163 {
3164 VARIABLE_POINTER_TRACK Variable;
3165 EFI_STATUS Status;
3166 VARIABLE_HEADER *NextVariable;
3167 EFI_PHYSICAL_ADDRESS Point;
3168 UINTN PayloadSize;
3169
3170 //
3171 // Check input parameters.
3172 //
3173 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
3174 return EFI_INVALID_PARAMETER;
3175 }
3176
3177 if (DataSize != 0 && Data == NULL) {
3178 return EFI_INVALID_PARAMETER;
3179 }
3180
3181 //
3182 // Check for reserverd bit in variable attribute.
3183 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is deprecated but we still allow
3184 // the delete operation of common authenticated variable at user physical presence.
3185 // So leave EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS attribute check to AuthVariableLib
3186 //
3187 if ((Attributes & (~(EFI_VARIABLE_ATTRIBUTES_MASK | EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS))) != 0) {
3188 return EFI_INVALID_PARAMETER;
3189 }
3190
3191 //
3192 // Make sure if runtime bit is set, boot service bit is set also.
3193 //
3194 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
3195 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
3196 return EFI_UNSUPPORTED;
3197 } else {
3198 return EFI_INVALID_PARAMETER;
3199 }
3200 } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
3201 if (!mVariableModuleGlobal->VariableGlobal.AuthSupport) {
3202 //
3203 // Not support authenticated variable write.
3204 //
3205 return EFI_INVALID_PARAMETER;
3206 }
3207 } else if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
3208 if (PcdGet32 (PcdHwErrStorageSize) == 0) {
3209 //
3210 // Not support harware error record variable variable.
3211 //
3212 return EFI_INVALID_PARAMETER;
3213 }
3214 }
3215
3216 //
3217 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute
3218 // cannot be set both.
3219 //
3220 if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
3221 && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {
3222 return EFI_UNSUPPORTED;
3223 }
3224
3225 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) {
3226 //
3227 // If DataSize == AUTHINFO_SIZE and then PayloadSize is 0.
3228 // Maybe it's the delete operation of common authenticated variable at user physical presence.
3229 //
3230 if (DataSize != AUTHINFO_SIZE) {
3231 return EFI_UNSUPPORTED;
3232 }
3233 PayloadSize = DataSize - AUTHINFO_SIZE;
3234 } else if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
3235 //
3236 // Sanity check for EFI_VARIABLE_AUTHENTICATION_2 descriptor.
3237 //
3238 if (DataSize < OFFSET_OF_AUTHINFO2_CERT_DATA ||
3239 ((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->AuthInfo.Hdr.dwLength > DataSize - (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo)) ||
3240 ((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->AuthInfo.Hdr.dwLength < OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)) {
3241 return EFI_SECURITY_VIOLATION;
3242 }
3243 //
3244 // The VariableSpeculationBarrier() call here is to ensure the above sanity
3245 // check for the EFI_VARIABLE_AUTHENTICATION_2 descriptor has been completed
3246 // before the execution of subsequent codes.
3247 //
3248 VariableSpeculationBarrier ();
3249 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
3250 } else {
3251 PayloadSize = DataSize;
3252 }
3253
3254 if ((UINTN)(~0) - PayloadSize < StrSize(VariableName)){
3255 //
3256 // Prevent whole variable size overflow
3257 //
3258 return EFI_INVALID_PARAMETER;
3259 }
3260
3261 //
3262 // The size of the VariableName, including the Unicode Null in bytes plus
3263 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
3264 // bytes for HwErrRec#### variable.
3265 //
3266 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
3267 if (StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize) - GetVariableHeaderSize ()) {
3268 return EFI_INVALID_PARAMETER;
3269 }
3270 } else {
3271 //
3272 // The size of the VariableName, including the Unicode Null in bytes plus
3273 // the DataSize is limited to maximum size of Max(Auth|Volatile)VariableSize bytes.
3274 //
3275 if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
3276 if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize ()) {
3277 DEBUG ((DEBUG_ERROR,
3278 "%a: Failed to set variable '%s' with Guid %g\n",
3279 __FUNCTION__, VariableName, VendorGuid));
3280 DEBUG ((DEBUG_ERROR,
3281 "NameSize(0x%x) + PayloadSize(0x%x) > "
3282 "MaxAuthVariableSize(0x%x) - HeaderSize(0x%x)\n",
3283 StrSize (VariableName), PayloadSize,
3284 mVariableModuleGlobal->MaxAuthVariableSize,
3285 GetVariableHeaderSize ()
3286 ));
3287 return EFI_INVALID_PARAMETER;
3288 }
3289 } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
3290 if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxVariableSize - GetVariableHeaderSize ()) {
3291 DEBUG ((DEBUG_ERROR,
3292 "%a: Failed to set variable '%s' with Guid %g\n",
3293 __FUNCTION__, VariableName, VendorGuid));
3294 DEBUG ((DEBUG_ERROR,
3295 "NameSize(0x%x) + PayloadSize(0x%x) > "
3296 "MaxVariableSize(0x%x) - HeaderSize(0x%x)\n",
3297 StrSize (VariableName), PayloadSize,
3298 mVariableModuleGlobal->MaxVariableSize,
3299 GetVariableHeaderSize ()
3300 ));
3301 return EFI_INVALID_PARAMETER;
3302 }
3303 } else {
3304 if (StrSize (VariableName) + PayloadSize > mVariableModuleGlobal->MaxVolatileVariableSize - GetVariableHeaderSize ()) {
3305 DEBUG ((DEBUG_ERROR,
3306 "%a: Failed to set variable '%s' with Guid %g\n",
3307 __FUNCTION__, VariableName, VendorGuid));
3308 DEBUG ((DEBUG_ERROR,
3309 "NameSize(0x%x) + PayloadSize(0x%x) > "
3310 "MaxVolatileVariableSize(0x%x) - HeaderSize(0x%x)\n",
3311 StrSize (VariableName), PayloadSize,
3312 mVariableModuleGlobal->MaxVolatileVariableSize,
3313 GetVariableHeaderSize ()
3314 ));
3315 return EFI_INVALID_PARAMETER;
3316 }
3317 }
3318 }
3319
3320 //
3321 // Special Handling for MOR Lock variable.
3322 //
3323 Status = SetVariableCheckHandlerMor (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *) ((UINTN) Data + DataSize - PayloadSize));
3324 if (Status == EFI_ALREADY_STARTED) {
3325 //
3326 // EFI_ALREADY_STARTED means the SetVariable() action is handled inside of SetVariableCheckHandlerMor().
3327 // Variable driver can just return SUCCESS.
3328 //
3329 return EFI_SUCCESS;
3330 }
3331 if (EFI_ERROR (Status)) {
3332 return Status;
3333 }
3334
3335 Status = VarCheckLibSetVariableCheck (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *) ((UINTN) Data + DataSize - PayloadSize), mRequestSource);
3336 if (EFI_ERROR (Status)) {
3337 return Status;
3338 }
3339
3340 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
3341
3342 //
3343 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.
3344 //
3345 if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {
3346 Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;
3347 //
3348 // Parse non-volatile variable data and get last variable offset.
3349 //
3350 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point);
3351 while (IsValidVariableHeader (NextVariable, GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point))) {
3352 NextVariable = GetNextVariablePtr (NextVariable);
3353 }
3354 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;
3355 }
3356
3357 //
3358 // Check whether the input variable is already existed.
3359 //
3360 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, TRUE);
3361 if (!EFI_ERROR (Status)) {
3362 if (((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) && AtRuntime ()) {
3363 Status = EFI_WRITE_PROTECTED;
3364 goto Done;
3365 }
3366 if (Attributes != 0 && (Attributes & (~EFI_VARIABLE_APPEND_WRITE)) != Variable.CurrPtr->Attributes) {
3367 //
3368 // If a preexisting variable is rewritten with different attributes, SetVariable() shall not
3369 // modify the variable and shall return EFI_INVALID_PARAMETER. Two exceptions to this rule:
3370 // 1. No access attributes specified
3371 // 2. The only attribute differing is EFI_VARIABLE_APPEND_WRITE
3372 //
3373 Status = EFI_INVALID_PARAMETER;
3374 DEBUG ((EFI_D_INFO, "[Variable]: Rewritten a preexisting variable(0x%08x) with different attributes(0x%08x) - %g:%s\n", Variable.CurrPtr->Attributes, Attributes, VendorGuid, VariableName));
3375 goto Done;
3376 }
3377 }
3378
3379 if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate)) {
3380 //
3381 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.
3382 //
3383 Status = AutoUpdateLangVariable (VariableName, Data, DataSize);
3384 if (EFI_ERROR (Status)) {
3385 //
3386 // The auto update operation failed, directly return to avoid inconsistency between PlatformLang and Lang.
3387 //
3388 goto Done;
3389 }
3390 }
3391
3392 if (mVariableModuleGlobal->VariableGlobal.AuthSupport) {
3393 Status = AuthVariableLibProcessVariable (VariableName, VendorGuid, Data, DataSize, Attributes);
3394 } else {
3395 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, &Variable, NULL);
3396 }
3397
3398 Done:
3399 InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);
3400 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
3401
3402 if (!AtRuntime ()) {
3403 if (!EFI_ERROR (Status)) {
3404 SecureBootHook (
3405 VariableName,
3406 VendorGuid
3407 );
3408 }
3409 }
3410
3411 return Status;
3412 }
3413
3414 /**
3415
3416 This code returns information about the EFI variables.
3417
3418 Caution: This function may receive untrusted input.
3419 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3420
3421 @param Attributes Attributes bitmask to specify the type of variables
3422 on which to return information.
3423 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
3424 for the EFI variables associated with the attributes specified.
3425 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
3426 for EFI variables associated with the attributes specified.
3427 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
3428 associated with the attributes specified.
3429
3430 @return EFI_SUCCESS Query successfully.
3431
3432 **/
3433 EFI_STATUS
3434 EFIAPI
3435 VariableServiceQueryVariableInfoInternal (
3436 IN UINT32 Attributes,
3437 OUT UINT64 *MaximumVariableStorageSize,
3438 OUT UINT64 *RemainingVariableStorageSize,
3439 OUT UINT64 *MaximumVariableSize
3440 )
3441 {
3442 VARIABLE_HEADER *Variable;
3443 VARIABLE_HEADER *NextVariable;
3444 UINT64 VariableSize;
3445 VARIABLE_STORE_HEADER *VariableStoreHeader;
3446 UINT64 CommonVariableTotalSize;
3447 UINT64 HwErrVariableTotalSize;
3448 EFI_STATUS Status;
3449 VARIABLE_POINTER_TRACK VariablePtrTrack;
3450
3451 CommonVariableTotalSize = 0;
3452 HwErrVariableTotalSize = 0;
3453
3454 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
3455 //
3456 // Query is Volatile related.
3457 //
3458 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
3459 } else {
3460 //
3461 // Query is Non-Volatile related.
3462 //
3463 VariableStoreHeader = mNvVariableCache;
3464 }
3465
3466 //
3467 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
3468 // with the storage size (excluding the storage header size).
3469 //
3470 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
3471
3472 //
3473 // Harware error record variable needs larger size.
3474 //
3475 if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
3476 *MaximumVariableStorageSize = PcdGet32 (PcdHwErrStorageSize);
3477 *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - GetVariableHeaderSize ();
3478 } else {
3479 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
3480 if (AtRuntime ()) {
3481 *MaximumVariableStorageSize = mVariableModuleGlobal->CommonRuntimeVariableSpace;
3482 } else {
3483 *MaximumVariableStorageSize = mVariableModuleGlobal->CommonVariableSpace;
3484 }
3485 }
3486
3487 //
3488 // Let *MaximumVariableSize be Max(Auth|Volatile)VariableSize with the exception of the variable header size.
3489 //
3490 if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
3491 *MaximumVariableSize = mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize ();
3492 } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
3493 *MaximumVariableSize = mVariableModuleGlobal->MaxVariableSize - GetVariableHeaderSize ();
3494 } else {
3495 *MaximumVariableSize = mVariableModuleGlobal->MaxVolatileVariableSize - GetVariableHeaderSize ();
3496 }
3497 }
3498
3499 //
3500 // Point to the starting address of the variables.
3501 //
3502 Variable = GetStartPointer (VariableStoreHeader);
3503
3504 //
3505 // Now walk through the related variable store.
3506 //
3507 while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
3508 NextVariable = GetNextVariablePtr (Variable);
3509 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;
3510
3511 if (AtRuntime ()) {
3512 //
3513 // We don't take the state of the variables in mind
3514 // when calculating RemainingVariableStorageSize,
3515 // since the space occupied by variables not marked with
3516 // VAR_ADDED is not allowed to be reclaimed in Runtime.
3517 //
3518 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
3519 HwErrVariableTotalSize += VariableSize;
3520 } else {
3521 CommonVariableTotalSize += VariableSize;
3522 }
3523 } else {
3524 //
3525 // Only care about Variables with State VAR_ADDED, because
3526 // the space not marked as VAR_ADDED is reclaimable now.
3527 //
3528 if (Variable->State == VAR_ADDED) {
3529 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
3530 HwErrVariableTotalSize += VariableSize;
3531 } else {
3532 CommonVariableTotalSize += VariableSize;
3533 }
3534 } else if (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
3535 //
3536 // If it is a IN_DELETED_TRANSITION variable,
3537 // and there is not also a same ADDED one at the same time,
3538 // this IN_DELETED_TRANSITION variable is valid.
3539 //
3540 VariablePtrTrack.StartPtr = GetStartPointer (VariableStoreHeader);
3541 VariablePtrTrack.EndPtr = GetEndPointer (VariableStoreHeader);
3542 Status = FindVariableEx (
3543 GetVariableNamePtr (Variable),
3544 GetVendorGuidPtr (Variable),
3545 FALSE,
3546 &VariablePtrTrack
3547 );
3548 if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr->State != VAR_ADDED) {
3549 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
3550 HwErrVariableTotalSize += VariableSize;
3551 } else {
3552 CommonVariableTotalSize += VariableSize;
3553 }
3554 }
3555 }
3556 }
3557
3558 //
3559 // Go to the next one.
3560 //
3561 Variable = NextVariable;
3562 }
3563
3564 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){
3565 *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;
3566 } else {
3567 if (*MaximumVariableStorageSize < CommonVariableTotalSize) {
3568 *RemainingVariableStorageSize = 0;
3569 } else {
3570 *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;
3571 }
3572 }
3573
3574 if (*RemainingVariableStorageSize < GetVariableHeaderSize ()) {
3575 *MaximumVariableSize = 0;
3576 } else if ((*RemainingVariableStorageSize - GetVariableHeaderSize ()) < *MaximumVariableSize) {
3577 *MaximumVariableSize = *RemainingVariableStorageSize - GetVariableHeaderSize ();
3578 }
3579
3580 return EFI_SUCCESS;
3581 }
3582
3583 /**
3584
3585 This code returns information about the EFI variables.
3586
3587 Caution: This function may receive untrusted input.
3588 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3589
3590 @param Attributes Attributes bitmask to specify the type of variables
3591 on which to return information.
3592 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
3593 for the EFI variables associated with the attributes specified.
3594 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
3595 for EFI variables associated with the attributes specified.
3596 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
3597 associated with the attributes specified.
3598
3599 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
3600 @return EFI_SUCCESS Query successfully.
3601 @return EFI_UNSUPPORTED The attribute is not supported on this platform.
3602
3603 **/
3604 EFI_STATUS
3605 EFIAPI
3606 VariableServiceQueryVariableInfo (
3607 IN UINT32 Attributes,
3608 OUT UINT64 *MaximumVariableStorageSize,
3609 OUT UINT64 *RemainingVariableStorageSize,
3610 OUT UINT64 *MaximumVariableSize
3611 )
3612 {
3613 EFI_STATUS Status;
3614
3615 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
3616 return EFI_INVALID_PARAMETER;
3617 }
3618
3619 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
3620 //
3621 // Deprecated attribute, make this check as highest priority.
3622 //
3623 return EFI_UNSUPPORTED;
3624 }
3625
3626 if ((Attributes & EFI_VARIABLE_ATTRIBUTES_MASK) == 0) {
3627 //
3628 // Make sure the Attributes combination is supported by the platform.
3629 //
3630 return EFI_UNSUPPORTED;
3631 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
3632 //
3633 // Make sure if runtime bit is set, boot service bit is set also.
3634 //
3635 return EFI_INVALID_PARAMETER;
3636 } else if (AtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {
3637 //
3638 // Make sure RT Attribute is set if we are in Runtime phase.
3639 //
3640 return EFI_INVALID_PARAMETER;
3641 } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
3642 //
3643 // Make sure Hw Attribute is set with NV.
3644 //
3645 return EFI_INVALID_PARAMETER;
3646 } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
3647 if (!mVariableModuleGlobal->VariableGlobal.AuthSupport) {
3648 //
3649 // Not support authenticated variable write.
3650 //
3651 return EFI_UNSUPPORTED;
3652 }
3653 } else if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
3654 if (PcdGet32 (PcdHwErrStorageSize) == 0) {
3655 //
3656 // Not support harware error record variable variable.
3657 //
3658 return EFI_UNSUPPORTED;
3659 }
3660 }
3661
3662 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
3663
3664 Status = VariableServiceQueryVariableInfoInternal (
3665 Attributes,
3666 MaximumVariableStorageSize,
3667 RemainingVariableStorageSize,
3668 MaximumVariableSize
3669 );
3670
3671 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
3672 return Status;
3673 }
3674
3675 /**
3676 This function reclaims variable storage if free size is below the threshold.
3677
3678 Caution: This function may be invoked at SMM mode.
3679 Care must be taken to make sure not security issue.
3680
3681 **/
3682 VOID
3683 ReclaimForOS(
3684 VOID
3685 )
3686 {
3687 EFI_STATUS Status;
3688 UINTN RemainingCommonRuntimeVariableSpace;
3689 UINTN RemainingHwErrVariableSpace;
3690 STATIC BOOLEAN Reclaimed;
3691
3692 //
3693 // This function will be called only once at EndOfDxe or ReadyToBoot event.
3694 //
3695 if (Reclaimed) {
3696 return;
3697 }
3698 Reclaimed = TRUE;
3699
3700 Status = EFI_SUCCESS;
3701
3702 if (mVariableModuleGlobal->CommonRuntimeVariableSpace < mVariableModuleGlobal->CommonVariableTotalSize) {
3703 RemainingCommonRuntimeVariableSpace = 0;
3704 } else {
3705 RemainingCommonRuntimeVariableSpace = mVariableModuleGlobal->CommonRuntimeVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;
3706 }
3707
3708 RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;
3709
3710 //
3711 // Check if the free area is below a threshold.
3712 //
3713 if (((RemainingCommonRuntimeVariableSpace < mVariableModuleGlobal->MaxVariableSize) ||
3714 (RemainingCommonRuntimeVariableSpace < mVariableModuleGlobal->MaxAuthVariableSize)) ||
3715 ((PcdGet32 (PcdHwErrStorageSize) != 0) &&
3716 (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize)))){
3717 Status = Reclaim (
3718 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
3719 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
3720 FALSE,
3721 NULL,
3722 NULL,
3723 0
3724 );
3725 ASSERT_EFI_ERROR (Status);
3726 }
3727 }
3728
3729 /**
3730 Get non-volatile maximum variable size.
3731
3732 @return Non-volatile maximum variable size.
3733
3734 **/
3735 UINTN
3736 GetNonVolatileMaxVariableSize (
3737 VOID
3738 )
3739 {
3740 if (PcdGet32 (PcdHwErrStorageSize) != 0) {
3741 return MAX (MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize)),
3742 PcdGet32 (PcdMaxHardwareErrorVariableSize));
3743 } else {
3744 return MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxAuthVariableSize));
3745 }
3746 }
3747
3748 /**
3749 Get maximum variable size, covering both non-volatile and volatile variables.
3750
3751 @return Maximum variable size.
3752
3753 **/
3754 UINTN
3755 GetMaxVariableSize (
3756 VOID
3757 )
3758 {
3759 UINTN MaxVariableSize;
3760
3761 MaxVariableSize = GetNonVolatileMaxVariableSize();
3762 //
3763 // The condition below fails implicitly if PcdMaxVolatileVariableSize equals
3764 // the default zero value.
3765 //
3766 if (MaxVariableSize < PcdGet32 (PcdMaxVolatileVariableSize)) {
3767 MaxVariableSize = PcdGet32 (PcdMaxVolatileVariableSize);
3768 }
3769 return MaxVariableSize;
3770 }
3771
3772 /**
3773 Init real non-volatile variable store.
3774
3775 @param[out] VariableStoreBase Output pointer to real non-volatile variable store base.
3776
3777 @retval EFI_SUCCESS Function successfully executed.
3778 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
3779 @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
3780
3781 **/
3782 EFI_STATUS
3783 InitRealNonVolatileVariableStore (
3784 OUT EFI_PHYSICAL_ADDRESS *VariableStoreBase
3785 )
3786 {
3787 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
3788 VARIABLE_STORE_HEADER *VariableStore;
3789 UINT32 VariableStoreLength;
3790 EFI_HOB_GUID_TYPE *GuidHob;
3791 EFI_PHYSICAL_ADDRESS NvStorageBase;
3792 UINT8 *NvStorageData;
3793 UINT32 NvStorageSize;
3794 FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;
3795 UINT32 BackUpOffset;
3796 UINT32 BackUpSize;
3797 UINT32 HwErrStorageSize;
3798 UINT32 MaxUserNvVariableSpaceSize;
3799 UINT32 BoottimeReservedNvVariableSpaceSize;
3800 EFI_STATUS Status;
3801 VOID *FtwProtocol;
3802
3803 mVariableModuleGlobal->FvbInstance = NULL;
3804
3805 //
3806 // Allocate runtime memory used for a memory copy of the FLASH region.
3807 // Keep the memory and the FLASH in sync as updates occur.
3808 //
3809 NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);
3810 NvStorageData = AllocateRuntimeZeroPool (NvStorageSize);
3811 if (NvStorageData == NULL) {
3812 return EFI_OUT_OF_RESOURCES;
3813 }
3814
3815 NvStorageBase = NV_STORAGE_VARIABLE_BASE;
3816 ASSERT (NvStorageBase != 0);
3817
3818 //
3819 // Copy NV storage data to the memory buffer.
3820 //
3821 CopyMem (NvStorageData, (UINT8 *) (UINTN) NvStorageBase, NvStorageSize);
3822
3823 Status = GetFtwProtocol ((VOID **)&FtwProtocol);
3824 //
3825 // If FTW protocol has been installed, no need to check FTW last write data hob.
3826 //
3827 if (EFI_ERROR (Status)) {
3828 //
3829 // Check the FTW last write data hob.
3830 //
3831 GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);
3832 if (GuidHob != NULL) {
3833 FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob);
3834 if (FtwLastWriteData->TargetAddress == NvStorageBase) {
3835 DEBUG ((EFI_D_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress));
3836 //
3837 // Copy the backed up NV storage data to the memory buffer from spare block.
3838 //
3839 CopyMem (NvStorageData, (UINT8 *) (UINTN) (FtwLastWriteData->SpareAddress), NvStorageSize);
3840 } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) &&
3841 (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {
3842 //
3843 // Flash NV storage from the Offset is backed up in spare block.
3844 //
3845 BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase);
3846 BackUpSize = NvStorageSize - BackUpOffset;
3847 DEBUG ((EFI_D_INFO, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN) FtwLastWriteData->SpareAddress));
3848 //
3849 // Copy the partial backed up NV storage data to the memory buffer from spare block.
3850 //
3851 CopyMem (NvStorageData + BackUpOffset, (UINT8 *) (UINTN) FtwLastWriteData->SpareAddress, BackUpSize);
3852 }
3853 }
3854 }
3855
3856 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) NvStorageData;
3857
3858 //
3859 // Check if the Firmware Volume is not corrupted
3860 //
3861 if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {
3862 FreePool (NvStorageData);
3863 DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n"));
3864 return EFI_VOLUME_CORRUPTED;
3865 }
3866
3867 VariableStore = (VARIABLE_STORE_HEADER *) ((UINTN) FvHeader + FvHeader->HeaderLength);
3868 VariableStoreLength = NvStorageSize - FvHeader->HeaderLength;
3869 ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);
3870 ASSERT (VariableStore->Size == VariableStoreLength);
3871
3872 //
3873 // Check if the Variable Store header is not corrupted
3874 //
3875 if (GetVariableStoreStatus (VariableStore) != EfiValid) {
3876 FreePool (NvStorageData);
3877 DEBUG((EFI_D_ERROR, "Variable Store header is corrupted\n"));
3878 return EFI_VOLUME_CORRUPTED;
3879 }
3880
3881 mNvFvHeaderCache = FvHeader;
3882
3883 *VariableStoreBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore;
3884
3885 HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize);
3886 MaxUserNvVariableSpaceSize = PcdGet32 (PcdMaxUserNvVariableSpaceSize);
3887 BoottimeReservedNvVariableSpaceSize = PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize);
3888
3889 //
3890 // Note that in EdkII variable driver implementation, Hardware Error Record type variable
3891 // is stored with common variable in the same NV region. So the platform integrator should
3892 // ensure that the value of PcdHwErrStorageSize is less than the value of
3893 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
3894 //
3895 ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));
3896 //
3897 // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of
3898 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
3899 //
3900 ASSERT (MaxUserNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));
3901 //
3902 // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of
3903 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).
3904 //
3905 ASSERT (BoottimeReservedNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));
3906
3907 mVariableModuleGlobal->CommonVariableSpace = ((UINTN) VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize);
3908 mVariableModuleGlobal->CommonMaxUserVariableSpace = ((MaxUserNvVariableSpaceSize != 0) ? MaxUserNvVariableSpaceSize : mVariableModuleGlobal->CommonVariableSpace);
3909 mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace - BoottimeReservedNvVariableSpaceSize;
3910
3911 DEBUG ((EFI_D_INFO, "Variable driver common space: 0x%x 0x%x 0x%x\n", mVariableModuleGlobal->CommonVariableSpace, mVariableModuleGlobal->CommonMaxUserVariableSpace, mVariableModuleGlobal->CommonRuntimeVariableSpace));
3912
3913 //
3914 // The max NV variable size should be < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
3915 //
3916 ASSERT (GetNonVolatileMaxVariableSize () < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));
3917
3918 return EFI_SUCCESS;
3919 }
3920
3921 /**
3922 Init emulated non-volatile variable store.
3923
3924 @param[out] VariableStoreBase Output pointer to emulated non-volatile variable store base.
3925
3926 @retval EFI_SUCCESS Function successfully executed.
3927 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
3928
3929 **/
3930 EFI_STATUS
3931 InitEmuNonVolatileVariableStore (
3932 EFI_PHYSICAL_ADDRESS *VariableStoreBase
3933 )
3934 {
3935 VARIABLE_STORE_HEADER *VariableStore;
3936 UINT32 VariableStoreLength;
3937 BOOLEAN FullyInitializeStore;
3938 UINT32 HwErrStorageSize;
3939
3940 FullyInitializeStore = TRUE;
3941
3942 VariableStoreLength = PcdGet32 (PcdVariableStoreSize);
3943 ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);
3944
3945 //
3946 // Allocate memory for variable store.
3947 //
3948 if (PcdGet64 (PcdEmuVariableNvStoreReserved) == 0) {
3949 VariableStore = (VARIABLE_STORE_HEADER *) AllocateRuntimePool (VariableStoreLength);
3950 if (VariableStore == NULL) {
3951 return EFI_OUT_OF_RESOURCES;
3952 }
3953 } else {
3954 //
3955 // A memory location has been reserved for the NV variable store. Certain
3956 // platforms may be able to preserve a memory range across system resets,
3957 // thereby providing better NV variable emulation.
3958 //
3959 VariableStore =
3960 (VARIABLE_STORE_HEADER *)(VOID*)(UINTN)
3961 PcdGet64 (PcdEmuVariableNvStoreReserved);
3962 if ((VariableStore->Size == VariableStoreLength) &&
3963 (CompareGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid) ||
3964 CompareGuid (&VariableStore->Signature, &gEfiVariableGuid)) &&
3965 (VariableStore->Format == VARIABLE_STORE_FORMATTED) &&
3966 (VariableStore->State == VARIABLE_STORE_HEALTHY)) {
3967 DEBUG((
3968 DEBUG_INFO,
3969 "Variable Store reserved at %p appears to be valid\n",
3970 VariableStore
3971 ));
3972 FullyInitializeStore = FALSE;
3973 }
3974 }
3975
3976 if (FullyInitializeStore) {
3977 SetMem (VariableStore, VariableStoreLength, 0xff);
3978 //
3979 // Use gEfiAuthenticatedVariableGuid for potential auth variable support.
3980 //
3981 CopyGuid (&VariableStore->Signature, &gEfiAuthenticatedVariableGuid);
3982 VariableStore->Size = VariableStoreLength;
3983 VariableStore->Format = VARIABLE_STORE_FORMATTED;
3984 VariableStore->State = VARIABLE_STORE_HEALTHY;
3985 VariableStore->Reserved = 0;
3986 VariableStore->Reserved1 = 0;
3987 }
3988
3989 *VariableStoreBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore;
3990
3991 HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize);
3992
3993 //
3994 // Note that in EdkII variable driver implementation, Hardware Error Record type variable
3995 // is stored with common variable in the same NV region. So the platform integrator should
3996 // ensure that the value of PcdHwErrStorageSize is less than the value of
3997 // (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).
3998 //
3999 ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));
4000
4001 mVariableModuleGlobal->CommonVariableSpace = ((UINTN) VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize);
4002 mVariableModuleGlobal->CommonMaxUserVariableSpace = mVariableModuleGlobal->CommonVariableSpace;
4003 mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace;
4004
4005 return EFI_SUCCESS;
4006 }
4007
4008 /**
4009 Init non-volatile variable store.
4010
4011 @retval EFI_SUCCESS Function successfully executed.
4012 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
4013 @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.
4014
4015 **/
4016 EFI_STATUS
4017 InitNonVolatileVariableStore (
4018 VOID
4019 )
4020 {
4021 VARIABLE_HEADER *Variable;
4022 VARIABLE_HEADER *NextVariable;
4023 EFI_PHYSICAL_ADDRESS VariableStoreBase;
4024 UINTN VariableSize;
4025 EFI_STATUS Status;
4026
4027 if (PcdGetBool (PcdEmuVariableNvModeEnable)) {
4028 Status = InitEmuNonVolatileVariableStore (&VariableStoreBase);
4029 if (EFI_ERROR (Status)) {
4030 return Status;
4031 }
4032 mVariableModuleGlobal->VariableGlobal.EmuNvMode = TRUE;
4033 DEBUG ((DEBUG_INFO, "Variable driver will work at emulated non-volatile variable mode!\n"));
4034 } else {
4035 Status = InitRealNonVolatileVariableStore (&VariableStoreBase);
4036 if (EFI_ERROR (Status)) {
4037 return Status;
4038 }
4039 mVariableModuleGlobal->VariableGlobal.EmuNvMode = FALSE;
4040 }
4041
4042 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;
4043 mNvVariableCache = (VARIABLE_STORE_HEADER *) (UINTN) VariableStoreBase;
4044 mVariableModuleGlobal->VariableGlobal.AuthFormat = (BOOLEAN)(CompareGuid (&mNvVariableCache->Signature, &gEfiAuthenticatedVariableGuid));
4045
4046 mVariableModuleGlobal->MaxVariableSize = PcdGet32 (PcdMaxVariableSize);
4047 mVariableModuleGlobal->MaxAuthVariableSize = ((PcdGet32 (PcdMaxAuthVariableSize) != 0) ? PcdGet32 (PcdMaxAuthVariableSize) : mVariableModuleGlobal->MaxVariableSize);
4048
4049 //
4050 // Parse non-volatile variable data and get last variable offset.
4051 //
4052 Variable = GetStartPointer (mNvVariableCache);
4053 while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {
4054 NextVariable = GetNextVariablePtr (Variable);
4055 VariableSize = (UINTN) NextVariable - (UINTN) Variable;
4056 if ((Variable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
4057 mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
4058 } else {
4059 mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
4060 }
4061
4062 Variable = NextVariable;
4063 }
4064 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) Variable - (UINTN) mNvVariableCache;
4065
4066 return EFI_SUCCESS;
4067 }
4068
4069 /**
4070 Flush the HOB variable to flash.
4071
4072 @param[in] VariableName Name of variable has been updated or deleted.
4073 @param[in] VendorGuid Guid of variable has been updated or deleted.
4074
4075 **/
4076 VOID
4077 FlushHobVariableToFlash (
4078 IN CHAR16 *VariableName,
4079 IN EFI_GUID *VendorGuid
4080 )
4081 {
4082 EFI_STATUS Status;
4083 VARIABLE_STORE_HEADER *VariableStoreHeader;
4084 VARIABLE_HEADER *Variable;
4085 VOID *VariableData;
4086 VARIABLE_POINTER_TRACK VariablePtrTrack;
4087 BOOLEAN ErrorFlag;
4088
4089 ErrorFlag = FALSE;
4090
4091 //
4092 // Flush the HOB variable to flash.
4093 //
4094 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {
4095 VariableStoreHeader = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;
4096 //
4097 // Set HobVariableBase to 0, it can avoid SetVariable to call back.
4098 //
4099 mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;
4100 for ( Variable = GetStartPointer (VariableStoreHeader)
4101 ; IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))
4102 ; Variable = GetNextVariablePtr (Variable)
4103 ) {
4104 if (Variable->State != VAR_ADDED) {
4105 //
4106 // The HOB variable has been set to DELETED state in local.
4107 //
4108 continue;
4109 }
4110 ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0);
4111 if (VendorGuid == NULL || VariableName == NULL ||
4112 !CompareGuid (VendorGuid, GetVendorGuidPtr (Variable)) ||
4113 StrCmp (VariableName, GetVariableNamePtr (Variable)) != 0) {
4114 VariableData = GetVariableDataPtr (Variable);
4115 FindVariable (GetVariableNamePtr (Variable), GetVendorGuidPtr (Variable), &VariablePtrTrack, &mVariableModuleGlobal->VariableGlobal, FALSE);
4116 Status = UpdateVariable (
4117 GetVariableNamePtr (Variable),
4118 GetVendorGuidPtr (Variable),
4119 VariableData,
4120 DataSizeOfVariable (Variable),
4121 Variable->Attributes,
4122 0,
4123 0,
4124 &VariablePtrTrack,
4125 NULL
4126 );
4127 DEBUG ((EFI_D_INFO, "Variable driver flush the HOB variable to flash: %g %s %r\n", GetVendorGuidPtr (Variable), GetVariableNamePtr (Variable), Status));
4128 } else {
4129 //
4130 // The updated or deleted variable is matched with this HOB variable.
4131 // Don't break here because we will try to set other HOB variables
4132 // since this variable could be set successfully.
4133 //
4134 Status = EFI_SUCCESS;
4135 }
4136 if (!EFI_ERROR (Status)) {
4137 //
4138 // If set variable successful, or the updated or deleted variable is matched with the HOB variable,
4139 // set the HOB variable to DELETED state in local.
4140 //
4141 DEBUG ((EFI_D_INFO, "Variable driver set the HOB variable to DELETED state in local: %g %s\n", GetVendorGuidPtr (Variable), GetVariableNamePtr (Variable)));
4142 Variable->State &= VAR_DELETED;
4143 } else {
4144 ErrorFlag = TRUE;
4145 }
4146 }
4147 if (ErrorFlag) {
4148 //
4149 // We still have HOB variable(s) not flushed in flash.
4150 //
4151 mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStoreHeader;
4152 } else {
4153 //
4154 // All HOB variables have been flushed in flash.
4155 //
4156 DEBUG ((EFI_D_INFO, "Variable driver: all HOB variables have been flushed in flash.\n"));
4157 if (!AtRuntime ()) {
4158 FreePool ((VOID *) VariableStoreHeader);
4159 }
4160 }
4161 }
4162
4163 }
4164
4165 /**
4166 Initializes variable write service.
4167
4168 @retval EFI_SUCCESS Function successfully executed.
4169 @retval Others Fail to initialize the variable service.
4170
4171 **/
4172 EFI_STATUS
4173 VariableWriteServiceInitialize (
4174 VOID
4175 )
4176 {
4177 EFI_STATUS Status;
4178 UINTN Index;
4179 UINT8 Data;
4180 VARIABLE_ENTRY_PROPERTY *VariableEntry;
4181
4182 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
4183
4184 //
4185 // Check if the free area is really free.
4186 //
4187 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < mNvVariableCache->Size; Index++) {
4188 Data = ((UINT8 *) mNvVariableCache)[Index];
4189 if (Data != 0xff) {
4190 //
4191 // There must be something wrong in variable store, do reclaim operation.
4192 //
4193 Status = Reclaim (
4194 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
4195 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
4196 FALSE,
4197 NULL,
4198 NULL,
4199 0
4200 );
4201 if (EFI_ERROR (Status)) {
4202 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
4203 return Status;
4204 }
4205 break;
4206 }
4207 }
4208
4209 FlushHobVariableToFlash (NULL, NULL);
4210
4211 Status = EFI_SUCCESS;
4212 ZeroMem (&mAuthContextOut, sizeof (mAuthContextOut));
4213 if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
4214 //
4215 // Authenticated variable initialize.
4216 //
4217 mAuthContextIn.StructSize = sizeof (AUTH_VAR_LIB_CONTEXT_IN);
4218 mAuthContextIn.MaxAuthVariableSize = mVariableModuleGlobal->MaxAuthVariableSize - GetVariableHeaderSize ();
4219 Status = AuthVariableLibInitialize (&mAuthContextIn, &mAuthContextOut);
4220 if (!EFI_ERROR (Status)) {
4221 DEBUG ((EFI_D_INFO, "Variable driver will work with auth variable support!\n"));
4222 mVariableModuleGlobal->VariableGlobal.AuthSupport = TRUE;
4223 if (mAuthContextOut.AuthVarEntry != NULL) {
4224 for (Index = 0; Index < mAuthContextOut.AuthVarEntryCount; Index++) {
4225 VariableEntry = &mAuthContextOut.AuthVarEntry[Index];
4226 Status = VarCheckLibVariablePropertySet (
4227 VariableEntry->Name,
4228 VariableEntry->Guid,
4229 &VariableEntry->VariableProperty
4230 );
4231 ASSERT_EFI_ERROR (Status);
4232 }
4233 }
4234 } else if (Status == EFI_UNSUPPORTED) {
4235 DEBUG ((EFI_D_INFO, "NOTICE - AuthVariableLibInitialize() returns %r!\n", Status));
4236 DEBUG ((EFI_D_INFO, "Variable driver will continue to work without auth variable support!\n"));
4237 mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE;
4238 Status = EFI_SUCCESS;
4239 }
4240 }
4241
4242 if (!EFI_ERROR (Status)) {
4243 for (Index = 0; Index < ARRAY_SIZE (mVariableEntryProperty); Index++) {
4244 VariableEntry = &mVariableEntryProperty[Index];
4245 Status = VarCheckLibVariablePropertySet (VariableEntry->Name, VariableEntry->Guid, &VariableEntry->VariableProperty);
4246 ASSERT_EFI_ERROR (Status);
4247 }
4248 }
4249
4250 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
4251
4252 //
4253 // Initialize MOR Lock variable.
4254 //
4255 MorLockInit ();
4256
4257 return Status;
4258 }
4259
4260 /**
4261 Convert normal variable storage to the allocated auth variable storage.
4262
4263 @param[in] NormalVarStorage Pointer to the normal variable storage header
4264
4265 @retval the allocated auth variable storage
4266 **/
4267 VOID *
4268 ConvertNormalVarStorageToAuthVarStorage (
4269 VARIABLE_STORE_HEADER *NormalVarStorage
4270 )
4271 {
4272 VARIABLE_HEADER *StartPtr;
4273 UINT8 *NextPtr;
4274 VARIABLE_HEADER *EndPtr;
4275 UINTN AuthVarStroageSize;
4276 AUTHENTICATED_VARIABLE_HEADER *AuthStartPtr;
4277 VARIABLE_STORE_HEADER *AuthVarStorage;
4278
4279 AuthVarStroageSize = sizeof (VARIABLE_STORE_HEADER);
4280 //
4281 // Set AuthFormat as FALSE for normal variable storage
4282 //
4283 mVariableModuleGlobal->VariableGlobal.AuthFormat = FALSE;
4284
4285 //
4286 // Calculate Auth Variable Storage Size
4287 //
4288 StartPtr = GetStartPointer (NormalVarStorage);
4289 EndPtr = GetEndPointer (NormalVarStorage);
4290 while (StartPtr < EndPtr) {
4291 if (StartPtr->State == VAR_ADDED) {
4292 AuthVarStroageSize = HEADER_ALIGN (AuthVarStroageSize);
4293 AuthVarStroageSize += sizeof (AUTHENTICATED_VARIABLE_HEADER);
4294 AuthVarStroageSize += StartPtr->NameSize + GET_PAD_SIZE (StartPtr->NameSize);
4295 AuthVarStroageSize += StartPtr->DataSize + GET_PAD_SIZE (StartPtr->DataSize);
4296 }
4297 StartPtr = GetNextVariablePtr (StartPtr);
4298 }
4299
4300 //
4301 // Allocate Runtime memory for Auth Variable Storage
4302 //
4303 AuthVarStorage = AllocateRuntimeZeroPool (AuthVarStroageSize);
4304 ASSERT (AuthVarStorage != NULL);
4305 if (AuthVarStorage == NULL) {
4306 return NULL;
4307 }
4308
4309 //
4310 // Copy Variable from Normal storage to Auth storage
4311 //
4312 StartPtr = GetStartPointer (NormalVarStorage);
4313 EndPtr = GetEndPointer (NormalVarStorage);
4314 AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *) GetStartPointer (AuthVarStorage);
4315 while (StartPtr < EndPtr) {
4316 if (StartPtr->State == VAR_ADDED) {
4317 AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *) HEADER_ALIGN (AuthStartPtr);
4318 //
4319 // Copy Variable Header
4320 //
4321 AuthStartPtr->StartId = StartPtr->StartId;
4322 AuthStartPtr->State = StartPtr->State;
4323 AuthStartPtr->Attributes = StartPtr->Attributes;
4324 AuthStartPtr->NameSize = StartPtr->NameSize;
4325 AuthStartPtr->DataSize = StartPtr->DataSize;
4326 CopyGuid (&AuthStartPtr->VendorGuid, &StartPtr->VendorGuid);
4327 //
4328 // Copy Variable Name
4329 //
4330 NextPtr = (UINT8 *) (AuthStartPtr + 1);
4331 CopyMem (NextPtr, GetVariableNamePtr (StartPtr), AuthStartPtr->NameSize);
4332 //
4333 // Copy Variable Data
4334 //
4335 NextPtr = NextPtr + AuthStartPtr->NameSize + GET_PAD_SIZE (AuthStartPtr->NameSize);
4336 CopyMem (NextPtr, GetVariableDataPtr (StartPtr), AuthStartPtr->DataSize);
4337 //
4338 // Go to next variable
4339 //
4340 AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *) (NextPtr + AuthStartPtr->DataSize + GET_PAD_SIZE (AuthStartPtr->DataSize));
4341 }
4342 StartPtr = GetNextVariablePtr (StartPtr);
4343 }
4344 //
4345 // Update Auth Storage Header
4346 //
4347 AuthVarStorage->Format = NormalVarStorage->Format;
4348 AuthVarStorage->State = NormalVarStorage->State;
4349 AuthVarStorage->Size = (UINT32)((UINTN)AuthStartPtr - (UINTN)AuthVarStorage);
4350 CopyGuid (&AuthVarStorage->Signature, &gEfiAuthenticatedVariableGuid);
4351 ASSERT (AuthVarStorage->Size <= AuthVarStroageSize);
4352
4353 //
4354 // Restore AuthFormat
4355 //
4356 mVariableModuleGlobal->VariableGlobal.AuthFormat = TRUE;
4357 return AuthVarStorage;
4358 }
4359
4360 /**
4361 Get HOB variable store.
4362
4363 @param[in] VariableGuid NV variable store signature.
4364
4365 @retval EFI_SUCCESS Function successfully executed.
4366 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
4367
4368 **/
4369 EFI_STATUS
4370 GetHobVariableStore (
4371 IN EFI_GUID *VariableGuid
4372 )
4373 {
4374 VARIABLE_STORE_HEADER *VariableStoreHeader;
4375 UINT64 VariableStoreLength;
4376 EFI_HOB_GUID_TYPE *GuidHob;
4377 BOOLEAN NeedConvertNormalToAuth;
4378
4379 //
4380 // Make sure there is no more than one Variable HOB.
4381 //
4382 DEBUG_CODE (
4383 GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
4384 if (GuidHob != NULL) {
4385 if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
4386 DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n"));
4387 ASSERT (FALSE);
4388 } else if (GetFirstGuidHob (&gEfiVariableGuid) != NULL) {
4389 DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable HOBs\n"));
4390 ASSERT (FALSE);
4391 }
4392 } else {
4393 GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
4394 if (GuidHob != NULL) {
4395 if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
4396 DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n"));
4397 ASSERT (FALSE);
4398 }
4399 }
4400 }
4401 );
4402
4403 //
4404 // Combinations supported:
4405 // 1. Normal NV variable store +
4406 // Normal HOB variable store
4407 // 2. Auth NV variable store +
4408 // Auth HOB variable store
4409 // 3. Auth NV variable store +
4410 // Normal HOB variable store (code will convert it to Auth Format)
4411 //
4412 NeedConvertNormalToAuth = FALSE;
4413 GuidHob = GetFirstGuidHob (VariableGuid);
4414 if (GuidHob == NULL && VariableGuid == &gEfiAuthenticatedVariableGuid) {
4415 //
4416 // Try getting it from normal variable HOB
4417 //
4418 GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
4419 NeedConvertNormalToAuth = TRUE;
4420 }
4421 if (GuidHob != NULL) {
4422 VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob);
4423 VariableStoreLength = GuidHob->Header.HobLength - sizeof (EFI_HOB_GUID_TYPE);
4424 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
4425 if (!NeedConvertNormalToAuth) {
4426 mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateRuntimeCopyPool ((UINTN) VariableStoreLength, (VOID *) VariableStoreHeader);
4427 } else {
4428 mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) ConvertNormalVarStorageToAuthVarStorage ((VOID *) VariableStoreHeader);
4429 }
4430 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) {
4431 return EFI_OUT_OF_RESOURCES;
4432 }
4433 } else {
4434 DEBUG ((EFI_D_ERROR, "HOB Variable Store header is corrupted!\n"));
4435 }
4436 }
4437
4438 return EFI_SUCCESS;
4439 }
4440
4441 /**
4442 Initializes variable store area for non-volatile and volatile variable.
4443
4444 @retval EFI_SUCCESS Function successfully executed.
4445 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
4446
4447 **/
4448 EFI_STATUS
4449 VariableCommonInitialize (
4450 VOID
4451 )
4452 {
4453 EFI_STATUS Status;
4454 VARIABLE_STORE_HEADER *VolatileVariableStore;
4455 UINTN ScratchSize;
4456 EFI_GUID *VariableGuid;
4457
4458 //
4459 // Allocate runtime memory for variable driver global structure.
4460 //
4461 mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL));
4462 if (mVariableModuleGlobal == NULL) {
4463 return EFI_OUT_OF_RESOURCES;
4464 }
4465
4466 InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);
4467
4468 //
4469 // Init non-volatile variable store.
4470 //
4471 Status = InitNonVolatileVariableStore ();
4472 if (EFI_ERROR (Status)) {
4473 FreePool (mVariableModuleGlobal);
4474 return Status;
4475 }
4476
4477 //
4478 // mVariableModuleGlobal->VariableGlobal.AuthFormat
4479 // has been initialized in InitNonVolatileVariableStore().
4480 //
4481 if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
4482 DEBUG ((EFI_D_INFO, "Variable driver will work with auth variable format!\n"));
4483 //
4484 // Set AuthSupport to FALSE first, VariableWriteServiceInitialize() will initialize it.
4485 //
4486 mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE;
4487 VariableGuid = &gEfiAuthenticatedVariableGuid;
4488 } else {
4489 DEBUG ((EFI_D_INFO, "Variable driver will work without auth variable support!\n"));
4490 mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE;
4491 VariableGuid = &gEfiVariableGuid;
4492 }
4493
4494 //
4495 // Get HOB variable store.
4496 //
4497 Status = GetHobVariableStore (VariableGuid);
4498 if (EFI_ERROR (Status)) {
4499 if (mNvFvHeaderCache != NULL) {
4500 FreePool (mNvFvHeaderCache);
4501 }
4502 FreePool (mVariableModuleGlobal);
4503 return Status;
4504 }
4505
4506 mVariableModuleGlobal->MaxVolatileVariableSize = ((PcdGet32 (PcdMaxVolatileVariableSize) != 0) ?
4507 PcdGet32 (PcdMaxVolatileVariableSize) :
4508 mVariableModuleGlobal->MaxVariableSize
4509 );
4510 //
4511 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
4512 //
4513 ScratchSize = GetMaxVariableSize ();
4514 mVariableModuleGlobal->ScratchBufferSize = ScratchSize;
4515 VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);
4516 if (VolatileVariableStore == NULL) {
4517 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {
4518 FreePool ((VOID *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase);
4519 }
4520 if (mNvFvHeaderCache != NULL) {
4521 FreePool (mNvFvHeaderCache);
4522 }
4523 FreePool (mVariableModuleGlobal);
4524 return EFI_OUT_OF_RESOURCES;
4525 }
4526
4527 SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);
4528
4529 //
4530 // Initialize Variable Specific Data.
4531 //
4532 mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;
4533 mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;
4534
4535 CopyGuid (&VolatileVariableStore->Signature, VariableGuid);
4536 VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize);
4537 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;
4538 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;
4539 VolatileVariableStore->Reserved = 0;
4540 VolatileVariableStore->Reserved1 = 0;
4541
4542 return EFI_SUCCESS;
4543 }
4544
4545
4546 /**
4547 Get the proper fvb handle and/or fvb protocol by the given Flash address.
4548
4549 @param[in] Address The Flash address.
4550 @param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle.
4551 @param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol.
4552
4553 **/
4554 EFI_STATUS
4555 GetFvbInfoByAddress (
4556 IN EFI_PHYSICAL_ADDRESS Address,
4557 OUT EFI_HANDLE *FvbHandle OPTIONAL,
4558 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvbProtocol OPTIONAL
4559 )
4560 {
4561 EFI_STATUS Status;
4562 EFI_HANDLE *HandleBuffer;
4563 UINTN HandleCount;
4564 UINTN Index;
4565 EFI_PHYSICAL_ADDRESS FvbBaseAddress;
4566 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
4567 EFI_FVB_ATTRIBUTES_2 Attributes;
4568 UINTN BlockSize;
4569 UINTN NumberOfBlocks;
4570
4571 HandleBuffer = NULL;
4572 //
4573 // Get all FVB handles.
4574 //
4575 Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);
4576 if (EFI_ERROR (Status)) {
4577 return EFI_NOT_FOUND;
4578 }
4579
4580 //
4581 // Get the FVB to access variable store.
4582 //
4583 Fvb = NULL;
4584 for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {
4585 Status = GetFvbByHandle (HandleBuffer[Index], &Fvb);
4586 if (EFI_ERROR (Status)) {
4587 Status = EFI_NOT_FOUND;
4588 break;
4589 }
4590
4591 //
4592 // Ensure this FVB protocol supported Write operation.
4593 //
4594 Status = Fvb->GetAttributes (Fvb, &Attributes);
4595 if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
4596 continue;
4597 }
4598
4599 //
4600 // Compare the address and select the right one.
4601 //
4602 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
4603 if (EFI_ERROR (Status)) {
4604 continue;
4605 }
4606
4607 //
4608 // Assume one FVB has one type of BlockSize.
4609 //
4610 Status = Fvb->GetBlockSize (Fvb, 0, &BlockSize, &NumberOfBlocks);
4611 if (EFI_ERROR (Status)) {
4612 continue;
4613 }
4614
4615 if ((Address >= FvbBaseAddress) && (Address < (FvbBaseAddress + BlockSize * NumberOfBlocks))) {
4616 if (FvbHandle != NULL) {
4617 *FvbHandle = HandleBuffer[Index];
4618 }
4619 if (FvbProtocol != NULL) {
4620 *FvbProtocol = Fvb;
4621 }
4622 Status = EFI_SUCCESS;
4623 break;
4624 }
4625 }
4626 FreePool (HandleBuffer);
4627
4628 if (Fvb == NULL) {
4629 Status = EFI_NOT_FOUND;
4630 }
4631
4632 return Status;
4633 }
4634