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