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