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