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