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