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