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