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