]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c
49358de0138cafe3f33a39a8cf9f822e09709710
[mirror_edk2.git] / SecurityPkg / VariableAuthenticated / RuntimeDxe / Variable.c
1 /** @file
2 The common variable operation routines shared by DXE_RUNTIME variable
3 module and DXE_SMM variable module.
4
5 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 Check if a Unicode character is a hexadecimal character.
1889
1890 This function checks if a Unicode character is a
1891 hexadecimal character. The valid hexadecimal character is
1892 L'0' to L'9', L'a' to L'f', or L'A' to L'F'.
1893
1894
1895 @param Char The character to check against.
1896
1897 @retval TRUE If the Char is a hexadecmial character.
1898 @retval FALSE If the Char is not a hexadecmial character.
1899
1900 **/
1901 BOOLEAN
1902 EFIAPI
1903 IsHexaDecimalDigitCharacter (
1904 IN CHAR16 Char
1905 )
1906 {
1907 return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f'));
1908 }
1909
1910 /**
1911
1912 This code checks if variable is hardware error record variable or not.
1913
1914 According to UEFI spec, hardware error record variable should use the EFI_HARDWARE_ERROR_VARIABLE VendorGuid
1915 and have the L"HwErrRec####" name convention, #### is a printed hex value and no 0x or h is included in the hex value.
1916
1917 @param VariableName Pointer to variable name.
1918 @param VendorGuid Variable Vendor Guid.
1919
1920 @retval TRUE Variable is hardware error record variable.
1921 @retval FALSE Variable is not hardware error record variable.
1922
1923 **/
1924 BOOLEAN
1925 EFIAPI
1926 IsHwErrRecVariable (
1927 IN CHAR16 *VariableName,
1928 IN EFI_GUID *VendorGuid
1929 )
1930 {
1931 if (!CompareGuid (VendorGuid, &gEfiHardwareErrorVariableGuid) ||
1932 (StrLen (VariableName) != StrLen (L"HwErrRec####")) ||
1933 (StrnCmp(VariableName, L"HwErrRec", StrLen (L"HwErrRec")) != 0) ||
1934 !IsHexaDecimalDigitCharacter (VariableName[0x8]) ||
1935 !IsHexaDecimalDigitCharacter (VariableName[0x9]) ||
1936 !IsHexaDecimalDigitCharacter (VariableName[0xA]) ||
1937 !IsHexaDecimalDigitCharacter (VariableName[0xB])) {
1938 return FALSE;
1939 }
1940
1941 return TRUE;
1942 }
1943
1944 /**
1945
1946 This code finds variable in storage blocks (Volatile or Non-Volatile).
1947
1948 @param VariableName Name of Variable to be found.
1949 @param VendorGuid Variable vendor GUID.
1950 @param Attributes Attribute value of the variable found.
1951 @param DataSize Size of Data found. If size is less than the
1952 data, this value contains the required size.
1953 @param Data Data pointer.
1954
1955 @return EFI_INVALID_PARAMETER Invalid parameter.
1956 @return EFI_SUCCESS Find the specified variable.
1957 @return EFI_NOT_FOUND Not found.
1958 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
1959
1960 **/
1961 EFI_STATUS
1962 EFIAPI
1963 VariableServiceGetVariable (
1964 IN CHAR16 *VariableName,
1965 IN EFI_GUID *VendorGuid,
1966 OUT UINT32 *Attributes OPTIONAL,
1967 IN OUT UINTN *DataSize,
1968 OUT VOID *Data
1969 )
1970 {
1971 EFI_STATUS Status;
1972 VARIABLE_POINTER_TRACK Variable;
1973 UINTN VarDataSize;
1974
1975 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
1976 return EFI_INVALID_PARAMETER;
1977 }
1978
1979 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1980
1981 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
1982 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
1983 goto Done;
1984 }
1985
1986 //
1987 // Get data size
1988 //
1989 VarDataSize = DataSizeOfVariable (Variable.CurrPtr);
1990 ASSERT (VarDataSize != 0);
1991
1992 if (*DataSize >= VarDataSize) {
1993 if (Data == NULL) {
1994 Status = EFI_INVALID_PARAMETER;
1995 goto Done;
1996 }
1997
1998 CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);
1999 if (Attributes != NULL) {
2000 *Attributes = Variable.CurrPtr->Attributes;
2001 }
2002
2003 *DataSize = VarDataSize;
2004 UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);
2005
2006 Status = EFI_SUCCESS;
2007 goto Done;
2008 } else {
2009 *DataSize = VarDataSize;
2010 Status = EFI_BUFFER_TOO_SMALL;
2011 goto Done;
2012 }
2013
2014 Done:
2015 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
2016 return Status;
2017 }
2018
2019
2020
2021 /**
2022
2023 This code Finds the Next available variable.
2024
2025 @param VariableNameSize Size of the variable name.
2026 @param VariableName Pointer to variable name.
2027 @param VendorGuid Variable Vendor Guid.
2028
2029 @return EFI_INVALID_PARAMETER Invalid parameter.
2030 @return EFI_SUCCESS Find the specified variable.
2031 @return EFI_NOT_FOUND Not found.
2032 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
2033
2034 **/
2035 EFI_STATUS
2036 EFIAPI
2037 VariableServiceGetNextVariableName (
2038 IN OUT UINTN *VariableNameSize,
2039 IN OUT CHAR16 *VariableName,
2040 IN OUT EFI_GUID *VendorGuid
2041 )
2042 {
2043 VARIABLE_STORE_TYPE Type;
2044 VARIABLE_POINTER_TRACK Variable;
2045 VARIABLE_POINTER_TRACK VariableInHob;
2046 UINTN VarNameSize;
2047 EFI_STATUS Status;
2048 VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];
2049
2050 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
2051 return EFI_INVALID_PARAMETER;
2052 }
2053
2054 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
2055
2056 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);
2057 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
2058 goto Done;
2059 }
2060
2061 if (VariableName[0] != 0) {
2062 //
2063 // If variable name is not NULL, get next variable.
2064 //
2065 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
2066 }
2067
2068 //
2069 // 0: Volatile, 1: HOB, 2: Non-Volatile.
2070 // The index and attributes mapping must be kept in this order as FindVariable
2071 // makes use of this mapping to implement search algorithm.
2072 //
2073 VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
2074 VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;
2075 VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache;
2076
2077 while (TRUE) {
2078 //
2079 // Switch from Volatile to HOB, to Non-Volatile.
2080 //
2081 while ((Variable.CurrPtr >= Variable.EndPtr) ||
2082 (Variable.CurrPtr == NULL) ||
2083 !IsValidVariableHeader (Variable.CurrPtr)
2084 ) {
2085 //
2086 // Find current storage index
2087 //
2088 for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {
2089 if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) {
2090 break;
2091 }
2092 }
2093 ASSERT (Type < VariableStoreTypeMax);
2094 //
2095 // Switch to next storage
2096 //
2097 for (Type++; Type < VariableStoreTypeMax; Type++) {
2098 if (VariableStoreHeader[Type] != NULL) {
2099 break;
2100 }
2101 }
2102 //
2103 // Capture the case that
2104 // 1. current storage is the last one, or
2105 // 2. no further storage
2106 //
2107 if (Type == VariableStoreTypeMax) {
2108 Status = EFI_NOT_FOUND;
2109 goto Done;
2110 }
2111 Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]);
2112 Variable.EndPtr = GetEndPointer (VariableStoreHeader[Type]);
2113 Variable.CurrPtr = Variable.StartPtr;
2114 }
2115
2116 //
2117 // Variable is found
2118 //
2119 if (Variable.CurrPtr->State == VAR_ADDED) {
2120 if ((AtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) == 0) {
2121
2122 //
2123 // Don't return NV variable when HOB overrides it
2124 //
2125 if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) && (VariableStoreHeader[VariableStoreTypeNv] != NULL) &&
2126 (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv]))
2127 ) {
2128 VariableInHob.StartPtr = GetStartPointer (VariableStoreHeader[VariableStoreTypeHob]);
2129 VariableInHob.EndPtr = GetEndPointer (VariableStoreHeader[VariableStoreTypeHob]);
2130 Status = FindVariableEx (
2131 GetVariableNamePtr (Variable.CurrPtr),
2132 &Variable.CurrPtr->VendorGuid,
2133 FALSE,
2134 &VariableInHob
2135 );
2136 if (!EFI_ERROR (Status)) {
2137 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
2138 continue;
2139 }
2140 }
2141
2142 VarNameSize = NameSizeOfVariable (Variable.CurrPtr);
2143 ASSERT (VarNameSize != 0);
2144
2145 if (VarNameSize <= *VariableNameSize) {
2146 CopyMem (VariableName, GetVariableNamePtr (Variable.CurrPtr), VarNameSize);
2147 CopyMem (VendorGuid, &Variable.CurrPtr->VendorGuid, sizeof (EFI_GUID));
2148 Status = EFI_SUCCESS;
2149 } else {
2150 Status = EFI_BUFFER_TOO_SMALL;
2151 }
2152
2153 *VariableNameSize = VarNameSize;
2154 goto Done;
2155 }
2156 }
2157
2158 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
2159 }
2160
2161 Done:
2162 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
2163 return Status;
2164 }
2165
2166 /**
2167
2168 This code sets variable in storage blocks (Volatile or Non-Volatile).
2169
2170 @param VariableName Name of Variable to be found.
2171 @param VendorGuid Variable vendor GUID.
2172 @param Attributes Attribute value of the variable found
2173 @param DataSize Size of Data found. If size is less than the
2174 data, this value contains the required size.
2175 @param Data Data pointer.
2176
2177 @return EFI_INVALID_PARAMETER Invalid parameter.
2178 @return EFI_SUCCESS Set successfully.
2179 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
2180 @return EFI_NOT_FOUND Not found.
2181 @return EFI_WRITE_PROTECTED Variable is read-only.
2182
2183 **/
2184 EFI_STATUS
2185 EFIAPI
2186 VariableServiceSetVariable (
2187 IN CHAR16 *VariableName,
2188 IN EFI_GUID *VendorGuid,
2189 IN UINT32 Attributes,
2190 IN UINTN DataSize,
2191 IN VOID *Data
2192 )
2193 {
2194 VARIABLE_POINTER_TRACK Variable;
2195 EFI_STATUS Status;
2196 VARIABLE_HEADER *NextVariable;
2197 EFI_PHYSICAL_ADDRESS Point;
2198 UINTN PayloadSize;
2199
2200 //
2201 // Check input parameters.
2202 //
2203 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
2204 return EFI_INVALID_PARAMETER;
2205 }
2206
2207 if (DataSize != 0 && Data == NULL) {
2208 return EFI_INVALID_PARAMETER;
2209 }
2210
2211 //
2212 // Make sure if runtime bit is set, boot service bit is set also.
2213 //
2214 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
2215 return EFI_INVALID_PARAMETER;
2216 }
2217
2218 //
2219 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute
2220 // cannot be set both.
2221 //
2222 if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
2223 && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {
2224 return EFI_INVALID_PARAMETER;
2225 }
2226
2227 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) {
2228 if (DataSize < AUTHINFO_SIZE) {
2229 //
2230 // Try to write Authenticated Variable without AuthInfo.
2231 //
2232 return EFI_SECURITY_VIOLATION;
2233 }
2234 PayloadSize = DataSize - AUTHINFO_SIZE;
2235 } else if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
2236 //
2237 // Sanity check for EFI_VARIABLE_AUTHENTICATION_2 descriptor.
2238 //
2239 if (DataSize < OFFSET_OF_AUTHINFO2_CERT_DATA ||
2240 ((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->AuthInfo.Hdr.dwLength > DataSize - (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo)) ||
2241 ((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->AuthInfo.Hdr.dwLength < OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)) {
2242 return EFI_SECURITY_VIOLATION;
2243 }
2244 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
2245 } else {
2246 PayloadSize = DataSize;
2247 }
2248
2249 //
2250 // The size of the VariableName, including the Unicode Null in bytes plus
2251 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
2252 // bytes for HwErrRec, and PcdGet32 (PcdMaxVariableSize) bytes for the others.
2253 //
2254 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
2255 if ((PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize)) ||
2256 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize))) {
2257 return EFI_INVALID_PARAMETER;
2258 }
2259 if (!IsHwErrRecVariable(VariableName, VendorGuid)) {
2260 return EFI_INVALID_PARAMETER;
2261 }
2262 } else {
2263 //
2264 // The size of the VariableName, including the Unicode Null in bytes plus
2265 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxVariableSize) bytes.
2266 //
2267 if ((PayloadSize > PcdGet32 (PcdMaxVariableSize)) ||
2268 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxVariableSize))) {
2269 return EFI_INVALID_PARAMETER;
2270 }
2271 }
2272
2273 if (AtRuntime ()) {
2274 //
2275 // HwErrRecSupport Global Variable identifies the level of hardware error record persistence
2276 // support implemented by the platform. This variable is only modified by firmware and is read-only to the OS.
2277 //
2278 if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, L"HwErrRecSupport") == 0)) {
2279 return EFI_WRITE_PROTECTED;
2280 }
2281 }
2282
2283 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
2284
2285 //
2286 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.
2287 //
2288 if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {
2289 Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;
2290 //
2291 // Parse non-volatile variable data and get last variable offset.
2292 //
2293 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point);
2294 while ((NextVariable < GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point))
2295 && IsValidVariableHeader (NextVariable)) {
2296 NextVariable = GetNextVariablePtr (NextVariable);
2297 }
2298 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;
2299 }
2300
2301 //
2302 // Check whether the input variable is already existed.
2303 //
2304 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, TRUE);
2305 if (!EFI_ERROR (Status)) {
2306 if (((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) && AtRuntime ()) {
2307 return EFI_WRITE_PROTECTED;
2308 }
2309 }
2310
2311 //
2312 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.
2313 //
2314 AutoUpdateLangVariable (VariableName, Data, DataSize);
2315 //
2316 // Process PK, KEK, Sigdb seperately.
2317 //
2318 if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){
2319 Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, TRUE);
2320 } else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) {
2321 Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, FALSE);
2322 } else if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&
2323 ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0))) {
2324 Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);
2325 } else {
2326 Status = ProcessVariable (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);
2327 }
2328
2329 InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);
2330 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
2331
2332 return Status;
2333 }
2334
2335 /**
2336
2337 This code returns information about the EFI variables.
2338
2339 @param Attributes Attributes bitmask to specify the type of variables
2340 on which to return information.
2341 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
2342 for the EFI variables associated with the attributes specified.
2343 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
2344 for EFI variables associated with the attributes specified.
2345 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
2346 associated with the attributes specified.
2347
2348 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
2349 @return EFI_SUCCESS Query successfully.
2350 @return EFI_UNSUPPORTED The attribute is not supported on this platform.
2351
2352 **/
2353 EFI_STATUS
2354 EFIAPI
2355 VariableServiceQueryVariableInfo (
2356 IN UINT32 Attributes,
2357 OUT UINT64 *MaximumVariableStorageSize,
2358 OUT UINT64 *RemainingVariableStorageSize,
2359 OUT UINT64 *MaximumVariableSize
2360 )
2361 {
2362 VARIABLE_HEADER *Variable;
2363 VARIABLE_HEADER *NextVariable;
2364 UINT64 VariableSize;
2365 VARIABLE_STORE_HEADER *VariableStoreHeader;
2366 UINT64 CommonVariableTotalSize;
2367 UINT64 HwErrVariableTotalSize;
2368
2369 CommonVariableTotalSize = 0;
2370 HwErrVariableTotalSize = 0;
2371
2372 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
2373 return EFI_INVALID_PARAMETER;
2374 }
2375
2376 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {
2377 //
2378 // Make sure the Attributes combination is supported by the platform.
2379 //
2380 return EFI_UNSUPPORTED;
2381 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
2382 //
2383 // Make sure if runtime bit is set, boot service bit is set also.
2384 //
2385 return EFI_INVALID_PARAMETER;
2386 } else if (AtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {
2387 //
2388 // Make sure RT Attribute is set if we are in Runtime phase.
2389 //
2390 return EFI_INVALID_PARAMETER;
2391 } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
2392 //
2393 // Make sure Hw Attribute is set with NV.
2394 //
2395 return EFI_INVALID_PARAMETER;
2396 }
2397
2398 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
2399
2400 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
2401 //
2402 // Query is Volatile related.
2403 //
2404 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
2405 } else {
2406 //
2407 // Query is Non-Volatile related.
2408 //
2409 VariableStoreHeader = mNvVariableCache;
2410 }
2411
2412 //
2413 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
2414 // with the storage size (excluding the storage header size).
2415 //
2416 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
2417
2418 //
2419 // Harware error record variable needs larger size.
2420 //
2421 if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
2422 *MaximumVariableStorageSize = PcdGet32 (PcdHwErrStorageSize);
2423 *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);
2424 } else {
2425 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
2426 ASSERT (PcdGet32 (PcdHwErrStorageSize) < VariableStoreHeader->Size);
2427 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize);
2428 }
2429
2430 //
2431 // Let *MaximumVariableSize be PcdGet32 (PcdMaxVariableSize) with the exception of the variable header size.
2432 //
2433 *MaximumVariableSize = PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);
2434 }
2435
2436 //
2437 // Point to the starting address of the variables.
2438 //
2439 Variable = GetStartPointer (VariableStoreHeader);
2440
2441 //
2442 // Now walk through the related variable store.
2443 //
2444 while ((Variable < GetEndPointer (VariableStoreHeader)) && IsValidVariableHeader (Variable)) {
2445 NextVariable = GetNextVariablePtr (Variable);
2446 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;
2447
2448 if (AtRuntime ()) {
2449 //
2450 // We don't take the state of the variables in mind
2451 // when calculating RemainingVariableStorageSize,
2452 // since the space occupied by variables not marked with
2453 // VAR_ADDED is not allowed to be reclaimed in Runtime.
2454 //
2455 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
2456 HwErrVariableTotalSize += VariableSize;
2457 } else {
2458 CommonVariableTotalSize += VariableSize;
2459 }
2460 } else {
2461 //
2462 // Only care about Variables with State VAR_ADDED, because
2463 // the space not marked as VAR_ADDED is reclaimable now.
2464 //
2465 if (Variable->State == VAR_ADDED) {
2466 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
2467 HwErrVariableTotalSize += VariableSize;
2468 } else {
2469 CommonVariableTotalSize += VariableSize;
2470 }
2471 }
2472 }
2473
2474 //
2475 // Go to the next one.
2476 //
2477 Variable = NextVariable;
2478 }
2479
2480 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){
2481 *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;
2482 }else {
2483 *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;
2484 }
2485
2486 if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {
2487 *MaximumVariableSize = 0;
2488 } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {
2489 *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);
2490 }
2491
2492 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
2493 return EFI_SUCCESS;
2494 }
2495
2496
2497 /**
2498 This function reclaims variable storage if free size is below the threshold.
2499
2500 **/
2501 VOID
2502 ReclaimForOS(
2503 VOID
2504 )
2505 {
2506 EFI_STATUS Status;
2507 UINTN CommonVariableSpace;
2508 UINTN RemainingCommonVariableSpace;
2509 UINTN RemainingHwErrVariableSpace;
2510
2511 Status = EFI_SUCCESS;
2512
2513 CommonVariableSpace = ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize); //Allowable max size of common variable storage space
2514
2515 RemainingCommonVariableSpace = CommonVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;
2516
2517 RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;
2518 //
2519 // Check if the free area is blow a threshold.
2520 //
2521 if ((RemainingCommonVariableSpace < PcdGet32 (PcdMaxVariableSize))
2522 || ((PcdGet32 (PcdHwErrStorageSize) != 0) &&
2523 (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize)))){
2524 Status = Reclaim (
2525 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
2526 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
2527 FALSE,
2528 NULL
2529 );
2530 ASSERT_EFI_ERROR (Status);
2531 }
2532 }
2533
2534
2535 /**
2536 Initializes variable write service after FVB was ready.
2537
2538 @retval EFI_SUCCESS Function successfully executed.
2539 @retval Others Fail to initialize the variable service.
2540
2541 **/
2542 EFI_STATUS
2543 VariableWriteServiceInitialize (
2544 VOID
2545 )
2546 {
2547 EFI_STATUS Status;
2548 VARIABLE_STORE_HEADER *VariableStoreHeader;
2549 UINTN Index;
2550 UINT8 Data;
2551 EFI_PHYSICAL_ADDRESS VariableStoreBase;
2552 VARIABLE_HEADER *Variable;
2553 VOID *VariableData;
2554
2555 VariableStoreBase = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;
2556 VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;
2557
2558 //
2559 // Check if the free area is really free.
2560 //
2561 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {
2562 Data = ((UINT8 *) mNvVariableCache)[Index];
2563 if (Data != 0xff) {
2564 //
2565 // There must be something wrong in variable store, do reclaim operation.
2566 //
2567 Status = Reclaim (
2568 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
2569 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
2570 FALSE,
2571 NULL
2572 );
2573 if (EFI_ERROR (Status)) {
2574 return Status;
2575 }
2576 break;
2577 }
2578 }
2579
2580
2581 //
2582 // Flush the HOB variable to flash and invalidate HOB variable.
2583 //
2584 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {
2585 //
2586 // Clear the HobVariableBase to avoid SetVariable() updating the variable in HOB
2587 //
2588 VariableStoreHeader = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;
2589 mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;
2590
2591 for ( Variable = GetStartPointer (VariableStoreHeader)
2592 ; (Variable < GetEndPointer (VariableStoreHeader) && IsValidVariableHeader (Variable))
2593 ; Variable = GetNextVariablePtr (Variable)
2594 ) {
2595 ASSERT (Variable->State == VAR_ADDED);
2596 ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0);
2597 VariableData = GetVariableDataPtr (Variable);
2598 Status = VariableServiceSetVariable (
2599 GetVariableNamePtr (Variable),
2600 &Variable->VendorGuid,
2601 Variable->Attributes,
2602 Variable->DataSize,
2603 VariableData
2604 );
2605 ASSERT_EFI_ERROR (Status);
2606 }
2607 }
2608
2609 //
2610 // Authenticated variable initialize.
2611 //
2612 Status = AutenticatedVariableServiceInitialize ();
2613
2614 return Status;
2615 }
2616
2617
2618 /**
2619 Initializes variable store area for non-volatile and volatile variable.
2620
2621 @retval EFI_SUCCESS Function successfully executed.
2622 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
2623
2624 **/
2625 EFI_STATUS
2626 VariableCommonInitialize (
2627 VOID
2628 )
2629 {
2630 EFI_STATUS Status;
2631 VARIABLE_STORE_HEADER *VolatileVariableStore;
2632 VARIABLE_STORE_HEADER *VariableStoreHeader;
2633 VARIABLE_HEADER *NextVariable;
2634 EFI_PHYSICAL_ADDRESS TempVariableStoreHeader;
2635 EFI_PHYSICAL_ADDRESS VariableStoreBase;
2636 UINT64 VariableStoreLength;
2637 UINTN ScratchSize;
2638 UINTN VariableSize;
2639 EFI_HOB_GUID_TYPE *GuidHob;
2640
2641 //
2642 // Allocate runtime memory for variable driver global structure.
2643 //
2644 mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL));
2645 if (mVariableModuleGlobal == NULL) {
2646 return EFI_OUT_OF_RESOURCES;
2647 }
2648
2649 InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);
2650
2651 //
2652 // Note that in EdkII variable driver implementation, Hardware Error Record type variable
2653 // is stored with common variable in the same NV region. So the platform integrator should
2654 // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of
2655 // PcdFlashNvStorageVariableSize.
2656 //
2657 ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));
2658
2659 //
2660 // Get HOB variable store.
2661 //
2662 GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
2663 if (GuidHob != NULL) {
2664 VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob);
2665 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
2666 mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStoreHeader;
2667 } else {
2668 DEBUG ((EFI_D_ERROR, "HOB Variable Store header is corrupted!\n"));
2669 }
2670 }
2671
2672 //
2673 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
2674 //
2675 ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));
2676 VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);
2677 if (VolatileVariableStore == NULL) {
2678 FreePool (mVariableModuleGlobal);
2679 return EFI_OUT_OF_RESOURCES;
2680 }
2681
2682 SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);
2683
2684 //
2685 // Initialize Variable Specific Data.
2686 //
2687 mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;
2688 mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;
2689 mVariableModuleGlobal->FvbInstance = NULL;
2690
2691 CopyGuid (&VolatileVariableStore->Signature, &gEfiAuthenticatedVariableGuid);
2692 VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize);
2693 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;
2694 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;
2695 VolatileVariableStore->Reserved = 0;
2696 VolatileVariableStore->Reserved1 = 0;
2697
2698 //
2699 // Get non-volatile variable store.
2700 //
2701
2702 TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);
2703 if (TempVariableStoreHeader == 0) {
2704 TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);
2705 }
2706
2707 //
2708 // Check if the Firmware Volume is not corrupted
2709 //
2710 if ((((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader))->Signature != EFI_FVH_SIGNATURE) ||
2711 (!CompareGuid (&gEfiSystemNvDataFvGuid, &((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader))->FileSystemGuid))) {
2712 Status = EFI_VOLUME_CORRUPTED;
2713 DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n"));
2714 goto Done;
2715 }
2716
2717 VariableStoreBase = TempVariableStoreHeader + \
2718 (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);
2719 VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \
2720 (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);
2721
2722 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;
2723 VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;
2724 if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {
2725 Status = EFI_VOLUME_CORRUPTED;
2726 DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));
2727 goto Done;
2728 }
2729 ASSERT(VariableStoreHeader->Size == VariableStoreLength);
2730
2731 //
2732 // Parse non-volatile variable data and get last variable offset.
2733 //
2734 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);
2735 while (IsValidVariableHeader (NextVariable)) {
2736 VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);
2737 if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
2738 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);
2739 } else {
2740 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);
2741 }
2742
2743 NextVariable = GetNextVariablePtr (NextVariable);
2744 }
2745
2746 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;
2747
2748 //
2749 // Allocate runtime memory used for a memory copy of the FLASH region.
2750 // Keep the memory and the FLASH in sync as updates occur
2751 //
2752 mNvVariableCache = AllocateRuntimeZeroPool ((UINTN)VariableStoreLength);
2753 if (mNvVariableCache == NULL) {
2754 Status = EFI_OUT_OF_RESOURCES;
2755 goto Done;
2756 }
2757 CopyMem (mNvVariableCache, (CHAR8 *)(UINTN)VariableStoreBase, (UINTN)VariableStoreLength);
2758 Status = EFI_SUCCESS;
2759
2760 Done:
2761 if (EFI_ERROR (Status)) {
2762 FreePool (mVariableModuleGlobal);
2763 FreePool (VolatileVariableStore);
2764 }
2765
2766 return Status;
2767 }
2768
2769
2770 /**
2771 Get the proper fvb handle and/or fvb protocol by the given Flash address.
2772
2773 @param[in] Address The Flash address.
2774 @param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle.
2775 @param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol.
2776
2777 **/
2778 EFI_STATUS
2779 GetFvbInfoByAddress (
2780 IN EFI_PHYSICAL_ADDRESS Address,
2781 OUT EFI_HANDLE *FvbHandle OPTIONAL,
2782 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvbProtocol OPTIONAL
2783 )
2784 {
2785 EFI_STATUS Status;
2786 EFI_HANDLE *HandleBuffer;
2787 UINTN HandleCount;
2788 UINTN Index;
2789 EFI_PHYSICAL_ADDRESS FvbBaseAddress;
2790 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
2791 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
2792 EFI_FVB_ATTRIBUTES_2 Attributes;
2793
2794 //
2795 // Get all FVB handles.
2796 //
2797 Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);
2798 if (EFI_ERROR (Status)) {
2799 return EFI_NOT_FOUND;
2800 }
2801
2802 //
2803 // Get the FVB to access variable store.
2804 //
2805 Fvb = NULL;
2806 for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {
2807 Status = GetFvbByHandle (HandleBuffer[Index], &Fvb);
2808 if (EFI_ERROR (Status)) {
2809 Status = EFI_NOT_FOUND;
2810 break;
2811 }
2812
2813 //
2814 // Ensure this FVB protocol supported Write operation.
2815 //
2816 Status = Fvb->GetAttributes (Fvb, &Attributes);
2817 if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
2818 continue;
2819 }
2820
2821 //
2822 // Compare the address and select the right one.
2823 //
2824 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
2825 if (EFI_ERROR (Status)) {
2826 continue;
2827 }
2828
2829 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
2830 if ((Address >= FvbBaseAddress) && (Address < (FvbBaseAddress + FwVolHeader->FvLength))) {
2831 if (FvbHandle != NULL) {
2832 *FvbHandle = HandleBuffer[Index];
2833 }
2834 if (FvbProtocol != NULL) {
2835 *FvbProtocol = Fvb;
2836 }
2837 Status = EFI_SUCCESS;
2838 break;
2839 }
2840 }
2841 FreePool (HandleBuffer);
2842
2843 if (Fvb == NULL) {
2844 Status = EFI_NOT_FOUND;
2845 }
2846
2847 return Status;
2848 }
2849