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