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