]> git.proxmox.com Git - mirror_edk2.git/blob - SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c
Support Variable driver (VariableAuthenticatedPei/VariableAuthenticatedRuntimeDxe...
[mirror_edk2.git] / SecurityPkg / VariableAuthenticated / RuntimeDxe / Variable.c
1 /** @file
2 The common variable operation routines shared by DXE_RINTIME variable
3 module and DXE_SMM variable module.
4
5 Copyright (c) 2009 - 2011, 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 VariableName Name of the variable to be found
722 @param VendorGuid Vendor GUID to be found.
723 @param PtrTrack Variable Track Pointer structure that contains Variable Information.
724
725 @retval EFI_SUCCESS Variable found successfully
726 @retval EFI_NOT_FOUND Variable not found
727 **/
728 EFI_STATUS
729 FindVariableEx (
730 IN CHAR16 *VariableName,
731 IN EFI_GUID *VendorGuid,
732 IN OUT VARIABLE_POINTER_TRACK *PtrTrack
733 )
734 {
735 VARIABLE_HEADER *InDeletedVariable;
736 VOID *Point;
737
738 //
739 // Find the variable by walk through HOB, volatile and non-volatile variable store.
740 //
741 InDeletedVariable = NULL;
742
743 for ( PtrTrack->CurrPtr = PtrTrack->StartPtr
744 ; (PtrTrack->CurrPtr < PtrTrack->EndPtr) && IsValidVariableHeader (PtrTrack->CurrPtr)
745 ; PtrTrack->CurrPtr = GetNextVariablePtr (PtrTrack->CurrPtr)
746 ) {
747 if (PtrTrack->CurrPtr->State == VAR_ADDED ||
748 PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)
749 ) {
750 if (!AtRuntime () || ((PtrTrack->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {
751 if (VariableName[0] == 0) {
752 if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
753 InDeletedVariable = PtrTrack->CurrPtr;
754 } else {
755 return EFI_SUCCESS;
756 }
757 } else {
758 if (CompareGuid (VendorGuid, &PtrTrack->CurrPtr->VendorGuid)) {
759 Point = (VOID *) GetVariableNamePtr (PtrTrack->CurrPtr);
760
761 ASSERT (NameSizeOfVariable (PtrTrack->CurrPtr) != 0);
762 if (CompareMem (VariableName, Point, NameSizeOfVariable (PtrTrack->CurrPtr)) == 0) {
763 if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
764 InDeletedVariable = PtrTrack->CurrPtr;
765 } else {
766 return EFI_SUCCESS;
767 }
768 }
769 }
770 }
771 }
772 }
773 }
774
775 PtrTrack->CurrPtr = InDeletedVariable;
776 return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;
777 }
778
779
780 /**
781 Finds variable in storage blocks of volatile and non-volatile storage areas.
782
783 This code finds variable in storage blocks of volatile and non-volatile storage areas.
784 If VariableName is an empty string, then we just return the first
785 qualified variable without comparing VariableName and VendorGuid.
786 Otherwise, VariableName and VendorGuid are compared.
787
788 @param VariableName Name of the variable to be found.
789 @param VendorGuid Vendor GUID to be found.
790 @param PtrTrack VARIABLE_POINTER_TRACK structure for output,
791 including the range searched and the target position.
792 @param Global Pointer to VARIABLE_GLOBAL structure, including
793 base of volatile variable storage area, base of
794 NV variable storage area, and a lock.
795
796 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
797 VendorGuid is NULL.
798 @retval EFI_SUCCESS Variable successfully found.
799 @retval EFI_NOT_FOUND Variable not found
800
801 **/
802 EFI_STATUS
803 FindVariable (
804 IN CHAR16 *VariableName,
805 IN EFI_GUID *VendorGuid,
806 OUT VARIABLE_POINTER_TRACK *PtrTrack,
807 IN VARIABLE_GLOBAL *Global
808 )
809 {
810 EFI_STATUS Status;
811 VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];
812 VARIABLE_STORE_TYPE Type;
813
814 if (VariableName[0] != 0 && VendorGuid == NULL) {
815 return EFI_INVALID_PARAMETER;
816 }
817
818 //
819 // 0: Volatile, 1: HOB, 2: Non-Volatile.
820 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
821 // make use of this mapping to implement search algorithm.
822 //
823 VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) Global->VolatileVariableBase;
824 VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *) (UINTN) Global->HobVariableBase;
825 VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache;
826
827 //
828 // Find the variable by walk through HOB, volatile and non-volatile variable store.
829 //
830 for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {
831 if (VariableStoreHeader[Type] == NULL) {
832 continue;
833 }
834
835 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Type]);
836 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Type]);
837 PtrTrack->Volatile = (BOOLEAN) (Type == VariableStoreTypeVolatile);
838
839 Status = FindVariableEx (VariableName, VendorGuid, PtrTrack);
840 if (!EFI_ERROR (Status)) {
841 return Status;
842 }
843 }
844 return EFI_NOT_FOUND;
845 }
846
847 /**
848 Get index from supported language codes according to language string.
849
850 This code is used to get corresponding index in supported language codes. It can handle
851 RFC4646 and ISO639 language tags.
852 In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.
853 In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.
854
855 For example:
856 SupportedLang = "engfraengfra"
857 Lang = "eng"
858 Iso639Language = TRUE
859 The return value is "0".
860 Another example:
861 SupportedLang = "en;fr;en-US;fr-FR"
862 Lang = "fr-FR"
863 Iso639Language = FALSE
864 The return value is "3".
865
866 @param SupportedLang Platform supported language codes.
867 @param Lang Configured language.
868 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
869
870 @retval The index of language in the language codes.
871
872 **/
873 UINTN
874 GetIndexFromSupportedLangCodes(
875 IN CHAR8 *SupportedLang,
876 IN CHAR8 *Lang,
877 IN BOOLEAN Iso639Language
878 )
879 {
880 UINTN Index;
881 UINTN CompareLength;
882 UINTN LanguageLength;
883
884 if (Iso639Language) {
885 CompareLength = ISO_639_2_ENTRY_SIZE;
886 for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {
887 if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {
888 //
889 // Successfully find the index of Lang string in SupportedLang string.
890 //
891 Index = Index / CompareLength;
892 return Index;
893 }
894 }
895 ASSERT (FALSE);
896 return 0;
897 } else {
898 //
899 // Compare RFC4646 language code
900 //
901 Index = 0;
902 for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++);
903
904 for (Index = 0; *SupportedLang != '\0'; Index++, SupportedLang += CompareLength) {
905 //
906 // Skip ';' characters in SupportedLang
907 //
908 for (; *SupportedLang != '\0' && *SupportedLang == ';'; SupportedLang++);
909 //
910 // Determine the length of the next language code in SupportedLang
911 //
912 for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++);
913
914 if ((CompareLength == LanguageLength) &&
915 (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0)) {
916 //
917 // Successfully find the index of Lang string in SupportedLang string.
918 //
919 return Index;
920 }
921 }
922 ASSERT (FALSE);
923 return 0;
924 }
925 }
926
927 /**
928 Get language string from supported language codes according to index.
929
930 This code is used to get corresponding language strings in supported language codes. It can handle
931 RFC4646 and ISO639 language tags.
932 In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.
933 In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.
934
935 For example:
936 SupportedLang = "engfraengfra"
937 Index = "1"
938 Iso639Language = TRUE
939 The return value is "fra".
940 Another example:
941 SupportedLang = "en;fr;en-US;fr-FR"
942 Index = "1"
943 Iso639Language = FALSE
944 The return value is "fr".
945
946 @param SupportedLang Platform supported language codes.
947 @param Index The index in supported language codes.
948 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
949
950 @retval The language string in the language codes.
951
952 **/
953 CHAR8 *
954 GetLangFromSupportedLangCodes (
955 IN CHAR8 *SupportedLang,
956 IN UINTN Index,
957 IN BOOLEAN Iso639Language
958 )
959 {
960 UINTN SubIndex;
961 UINTN CompareLength;
962 CHAR8 *Supported;
963
964 SubIndex = 0;
965 Supported = SupportedLang;
966 if (Iso639Language) {
967 //
968 // According to the index of Lang string in SupportedLang string to get the language.
969 // This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation.
970 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
971 //
972 CompareLength = ISO_639_2_ENTRY_SIZE;
973 mVariableModuleGlobal->Lang[CompareLength] = '\0';
974 return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength);
975
976 } else {
977 while (TRUE) {
978 //
979 // Take semicolon as delimitation, sequentially traverse supported language codes.
980 //
981 for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {
982 Supported++;
983 }
984 if ((*Supported == '\0') && (SubIndex != Index)) {
985 //
986 // Have completed the traverse, but not find corrsponding string.
987 // This case is not allowed to happen.
988 //
989 ASSERT(FALSE);
990 return NULL;
991 }
992 if (SubIndex == Index) {
993 //
994 // According to the index of Lang string in SupportedLang string to get the language.
995 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
996 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
997 //
998 mVariableModuleGlobal->PlatformLang[CompareLength] = '\0';
999 return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - CompareLength, CompareLength);
1000 }
1001 SubIndex++;
1002
1003 //
1004 // Skip ';' characters in Supported
1005 //
1006 for (; *Supported != '\0' && *Supported == ';'; Supported++);
1007 }
1008 }
1009 }
1010
1011 /**
1012 Returns a pointer to an allocated buffer that contains the best matching language
1013 from a set of supported languages.
1014
1015 This function supports both ISO 639-2 and RFC 4646 language codes, but language
1016 code types may not be mixed in a single call to this function. This function
1017 supports a variable argument list that allows the caller to pass in a prioritized
1018 list of language codes to test against all the language codes in SupportedLanguages.
1019
1020 If SupportedLanguages is NULL, then ASSERT().
1021
1022 @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that
1023 contains a set of language codes in the format
1024 specified by Iso639Language.
1025 @param[in] Iso639Language If TRUE, then all language codes are assumed to be
1026 in ISO 639-2 format. If FALSE, then all language
1027 codes are assumed to be in RFC 4646 language format
1028 @param[in] ... A variable argument list that contains pointers to
1029 Null-terminated ASCII strings that contain one or more
1030 language codes in the format specified by Iso639Language.
1031 The first language code from each of these language
1032 code lists is used to determine if it is an exact or
1033 close match to any of the language codes in
1034 SupportedLanguages. Close matches only apply to RFC 4646
1035 language codes, and the matching algorithm from RFC 4647
1036 is used to determine if a close match is present. If
1037 an exact or close match is found, then the matching
1038 language code from SupportedLanguages is returned. If
1039 no matches are found, then the next variable argument
1040 parameter is evaluated. The variable argument list
1041 is terminated by a NULL.
1042
1043 @retval NULL The best matching language could not be found in SupportedLanguages.
1044 @retval NULL There are not enough resources available to return the best matching
1045 language.
1046 @retval Other A pointer to a Null-terminated ASCII string that is the best matching
1047 language in SupportedLanguages.
1048
1049 **/
1050 CHAR8 *
1051 EFIAPI
1052 VariableGetBestLanguage (
1053 IN CONST CHAR8 *SupportedLanguages,
1054 IN BOOLEAN Iso639Language,
1055 ...
1056 )
1057 {
1058 VA_LIST Args;
1059 CHAR8 *Language;
1060 UINTN CompareLength;
1061 UINTN LanguageLength;
1062 CONST CHAR8 *Supported;
1063 CHAR8 *Buffer;
1064
1065 if (SupportedLanguages == NULL) {
1066 return NULL;
1067 }
1068
1069 VA_START (Args, Iso639Language);
1070 while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {
1071 //
1072 // Default to ISO 639-2 mode
1073 //
1074 CompareLength = 3;
1075 LanguageLength = MIN (3, AsciiStrLen (Language));
1076
1077 //
1078 // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
1079 //
1080 if (!Iso639Language) {
1081 for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++);
1082 }
1083
1084 //
1085 // Trim back the length of Language used until it is empty
1086 //
1087 while (LanguageLength > 0) {
1088 //
1089 // Loop through all language codes in SupportedLanguages
1090 //
1091 for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {
1092 //
1093 // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
1094 //
1095 if (!Iso639Language) {
1096 //
1097 // Skip ';' characters in Supported
1098 //
1099 for (; *Supported != '\0' && *Supported == ';'; Supported++);
1100 //
1101 // Determine the length of the next language code in Supported
1102 //
1103 for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++);
1104 //
1105 // If Language is longer than the Supported, then skip to the next language
1106 //
1107 if (LanguageLength > CompareLength) {
1108 continue;
1109 }
1110 }
1111 //
1112 // See if the first LanguageLength characters in Supported match Language
1113 //
1114 if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {
1115 VA_END (Args);
1116
1117 Buffer = Iso639Language ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang;
1118 Buffer[CompareLength] = '\0';
1119 return CopyMem (Buffer, Supported, CompareLength);
1120 }
1121 }
1122
1123 if (Iso639Language) {
1124 //
1125 // If ISO 639 mode, then each language can only be tested once
1126 //
1127 LanguageLength = 0;
1128 } else {
1129 //
1130 // If RFC 4646 mode, then trim Language from the right to the next '-' character
1131 //
1132 for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--);
1133 }
1134 }
1135 }
1136 VA_END (Args);
1137
1138 //
1139 // No matches were found
1140 //
1141 return NULL;
1142 }
1143
1144 /**
1145 Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.
1146
1147 When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.
1148
1149 According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,
1150 and are read-only. Therefore, in variable driver, only store the original value for other use.
1151
1152 @param[in] VariableName Name of variable.
1153
1154 @param[in] Data Variable data.
1155
1156 @param[in] DataSize Size of data. 0 means delete.
1157
1158 **/
1159 VOID
1160 AutoUpdateLangVariable(
1161 IN CHAR16 *VariableName,
1162 IN VOID *Data,
1163 IN UINTN DataSize
1164 )
1165 {
1166 EFI_STATUS Status;
1167 CHAR8 *BestPlatformLang;
1168 CHAR8 *BestLang;
1169 UINTN Index;
1170 UINT32 Attributes;
1171 VARIABLE_POINTER_TRACK Variable;
1172 BOOLEAN SetLanguageCodes;
1173
1174 //
1175 // Don't do updates for delete operation
1176 //
1177 if (DataSize == 0) {
1178 return;
1179 }
1180
1181 SetLanguageCodes = FALSE;
1182
1183 if (StrCmp (VariableName, L"PlatformLangCodes") == 0) {
1184 //
1185 // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.
1186 //
1187 if (AtRuntime ()) {
1188 return;
1189 }
1190
1191 SetLanguageCodes = TRUE;
1192
1193 //
1194 // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
1195 // Therefore, in variable driver, only store the original value for other use.
1196 //
1197 if (mVariableModuleGlobal->PlatformLangCodes != NULL) {
1198 FreePool (mVariableModuleGlobal->PlatformLangCodes);
1199 }
1200 mVariableModuleGlobal->PlatformLangCodes = AllocateRuntimeCopyPool (DataSize, Data);
1201 ASSERT (mVariableModuleGlobal->PlatformLangCodes != NULL);
1202
1203 //
1204 // PlatformLang holds a single language from PlatformLangCodes,
1205 // so the size of PlatformLangCodes is enough for the PlatformLang.
1206 //
1207 if (mVariableModuleGlobal->PlatformLang != NULL) {
1208 FreePool (mVariableModuleGlobal->PlatformLang);
1209 }
1210 mVariableModuleGlobal->PlatformLang = AllocateRuntimePool (DataSize);
1211 ASSERT (mVariableModuleGlobal->PlatformLang != NULL);
1212
1213 } else if (StrCmp (VariableName, L"LangCodes") == 0) {
1214 //
1215 // LangCodes is a volatile variable, so it can not be updated at runtime.
1216 //
1217 if (AtRuntime ()) {
1218 return;
1219 }
1220
1221 SetLanguageCodes = TRUE;
1222
1223 //
1224 // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
1225 // Therefore, in variable driver, only store the original value for other use.
1226 //
1227 if (mVariableModuleGlobal->LangCodes != NULL) {
1228 FreePool (mVariableModuleGlobal->LangCodes);
1229 }
1230 mVariableModuleGlobal->LangCodes = AllocateRuntimeCopyPool (DataSize, Data);
1231 ASSERT (mVariableModuleGlobal->LangCodes != NULL);
1232 }
1233
1234 if (SetLanguageCodes
1235 && (mVariableModuleGlobal->PlatformLangCodes != NULL)
1236 && (mVariableModuleGlobal->LangCodes != NULL)) {
1237 //
1238 // Update Lang if PlatformLang is already set
1239 // Update PlatformLang if Lang is already set
1240 //
1241 Status = FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);
1242 if (!EFI_ERROR (Status)) {
1243 //
1244 // Update Lang
1245 //
1246 VariableName = L"PlatformLang";
1247 Data = GetVariableDataPtr (Variable.CurrPtr);
1248 DataSize = Variable.CurrPtr->DataSize;
1249 } else {
1250 Status = FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);
1251 if (!EFI_ERROR (Status)) {
1252 //
1253 // Update PlatformLang
1254 //
1255 VariableName = L"Lang";
1256 Data = GetVariableDataPtr (Variable.CurrPtr);
1257 DataSize = Variable.CurrPtr->DataSize;
1258 } else {
1259 //
1260 // Neither PlatformLang nor Lang is set, directly return
1261 //
1262 return;
1263 }
1264 }
1265 }
1266
1267 //
1268 // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
1269 //
1270 Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
1271
1272 if (StrCmp (VariableName, L"PlatformLang") == 0) {
1273 //
1274 // Update Lang when PlatformLangCodes/LangCodes were set.
1275 //
1276 if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {
1277 //
1278 // When setting PlatformLang, firstly get most matched language string from supported language codes.
1279 //
1280 BestPlatformLang = VariableGetBestLanguage (mVariableModuleGlobal->PlatformLangCodes, FALSE, Data, NULL);
1281 if (BestPlatformLang != NULL) {
1282 //
1283 // Get the corresponding index in language codes.
1284 //
1285 Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, BestPlatformLang, FALSE);
1286
1287 //
1288 // Get the corresponding ISO639 language tag according to RFC4646 language tag.
1289 //
1290 BestLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, Index, TRUE);
1291
1292 //
1293 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
1294 //
1295 FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);
1296
1297 Status = UpdateVariable (L"Lang", &gEfiGlobalVariableGuid, BestLang,
1298 ISO_639_2_ENTRY_SIZE + 1, Attributes, 0, 0, &Variable, NULL);
1299
1300 DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang));
1301
1302 ASSERT_EFI_ERROR(Status);
1303 }
1304 }
1305
1306 } else if (StrCmp (VariableName, L"Lang") == 0) {
1307 //
1308 // Update PlatformLang when PlatformLangCodes/LangCodes were set.
1309 //
1310 if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {
1311 //
1312 // When setting Lang, firstly get most matched language string from supported language codes.
1313 //
1314 BestLang = VariableGetBestLanguage (mVariableModuleGlobal->LangCodes, TRUE, Data, NULL);
1315 if (BestLang != NULL) {
1316 //
1317 // Get the corresponding index in language codes.
1318 //
1319 Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, BestLang, TRUE);
1320
1321 //
1322 // Get the corresponding RFC4646 language tag according to ISO639 language tag.
1323 //
1324 BestPlatformLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, Index, FALSE);
1325
1326 //
1327 // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
1328 //
1329 FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);
1330
1331 Status = UpdateVariable (L"PlatformLang", &gEfiGlobalVariableGuid, BestPlatformLang,
1332 AsciiStrSize (BestPlatformLang), Attributes, 0, 0, &Variable, NULL);
1333
1334 DEBUG ((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a\n", BestLang, BestPlatformLang));
1335 ASSERT_EFI_ERROR (Status);
1336 }
1337 }
1338 }
1339 }
1340
1341 /**
1342 Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,
1343 index of associated public key is needed.
1344
1345 @param[in] VariableName Name of variable.
1346 @param[in] VendorGuid Guid of variable.
1347 @param[in] Data Variable data.
1348 @param[in] DataSize Size of data. 0 means delete.
1349 @param[in] Attributes Attributes of the variable.
1350 @param[in] KeyIndex Index of associated public key.
1351 @param[in] MonotonicCount Value of associated monotonic count.
1352 @param[in] CacheVariable The variable information which is used to keep track of variable usage.
1353 @param[in] TimeStamp Value of associated TimeStamp.
1354
1355 @retval EFI_SUCCESS The update operation is success.
1356 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
1357
1358 **/
1359 EFI_STATUS
1360 UpdateVariable (
1361 IN CHAR16 *VariableName,
1362 IN EFI_GUID *VendorGuid,
1363 IN VOID *Data,
1364 IN UINTN DataSize,
1365 IN UINT32 Attributes OPTIONAL,
1366 IN UINT32 KeyIndex OPTIONAL,
1367 IN UINT64 MonotonicCount OPTIONAL,
1368 IN VARIABLE_POINTER_TRACK *CacheVariable,
1369 IN EFI_TIME *TimeStamp OPTIONAL
1370 )
1371 {
1372 EFI_STATUS Status;
1373 VARIABLE_HEADER *NextVariable;
1374 UINTN ScratchSize;
1375 UINTN ScratchDataSize;
1376 UINTN NonVolatileVarableStoreSize;
1377 UINTN VarNameOffset;
1378 UINTN VarDataOffset;
1379 UINTN VarNameSize;
1380 UINTN VarSize;
1381 BOOLEAN Volatile;
1382 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
1383 UINT8 State;
1384 BOOLEAN Reclaimed;
1385 VARIABLE_POINTER_TRACK *Variable;
1386 VARIABLE_POINTER_TRACK NvVariable;
1387 VARIABLE_STORE_HEADER *VariableStoreHeader;
1388 UINTN CacheOffset;
1389 UINTN BufSize;
1390 UINTN DataOffset;
1391 UINTN RevBufSize;
1392
1393 if (mVariableModuleGlobal->FvbInstance == NULL) {
1394 //
1395 // The FVB protocol is not installed, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.
1396 //
1397 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
1398 //
1399 // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
1400 //
1401 return EFI_NOT_AVAILABLE_YET;
1402 } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
1403 //
1404 // Trying to update volatile authenticated variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL
1405 // The authenticated variable perhaps is not initialized, just return here.
1406 //
1407 return EFI_NOT_AVAILABLE_YET;
1408 }
1409 }
1410
1411 if ((CacheVariable->CurrPtr == NULL) || CacheVariable->Volatile) {
1412 Variable = CacheVariable;
1413 } else {
1414 //
1415 // Update/Delete existing NV variable.
1416 // CacheVariable points to the variable in the memory copy of Flash area
1417 // Now let Variable points to the same variable in Flash area.
1418 //
1419 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);
1420 Variable = &NvVariable;
1421 Variable->StartPtr = GetStartPointer (VariableStoreHeader);
1422 Variable->EndPtr = GetEndPointer (VariableStoreHeader);
1423 Variable->CurrPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->CurrPtr - (UINTN)CacheVariable->StartPtr));
1424 Variable->Volatile = FALSE;
1425 }
1426
1427 Fvb = mVariableModuleGlobal->FvbInstance;
1428 Reclaimed = FALSE;
1429
1430 //
1431 // Tricky part: Use scratch data area at the end of volatile variable store
1432 // as a temporary storage.
1433 //
1434 NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));
1435 ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));
1436 ScratchDataSize = ScratchSize - sizeof (VARIABLE_HEADER) - StrSize (VariableName) - GET_PAD_SIZE (StrSize (VariableName));
1437
1438 if (Variable->CurrPtr != NULL) {
1439 //
1440 // Update/Delete existing variable.
1441 //
1442 if (AtRuntime ()) {
1443 //
1444 // If AtRuntime and the variable is Volatile and Runtime Access,
1445 // the volatile is ReadOnly, and SetVariable should be aborted and
1446 // return EFI_WRITE_PROTECTED.
1447 //
1448 if (Variable->Volatile) {
1449 Status = EFI_WRITE_PROTECTED;
1450 goto Done;
1451 }
1452 //
1453 // Only variable that have NV attributes can be updated/deleted in Runtime.
1454 //
1455 if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
1456 Status = EFI_INVALID_PARAMETER;
1457 goto Done;
1458 }
1459 }
1460
1461 //
1462 // Setting a data variable with no access, or zero DataSize attributes
1463 // causes it to be deleted.
1464 // When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero will
1465 // not delete the variable.
1466 //
1467 if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0))|| ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)) {
1468 State = Variable->CurrPtr->State;
1469 State &= VAR_DELETED;
1470
1471 Status = UpdateVariableStore (
1472 &mVariableModuleGlobal->VariableGlobal,
1473 Variable->Volatile,
1474 FALSE,
1475 Fvb,
1476 (UINTN) &Variable->CurrPtr->State,
1477 sizeof (UINT8),
1478 &State
1479 );
1480 if (!EFI_ERROR (Status)) {
1481 UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE);
1482 if (!Variable->Volatile) {
1483 CacheVariable->CurrPtr->State = State;
1484 }
1485 }
1486 goto Done;
1487 }
1488 //
1489 // If the variable is marked valid, and the same data has been passed in,
1490 // then return to the caller immediately.
1491 //
1492 if (DataSizeOfVariable (Variable->CurrPtr) == DataSize &&
1493 (CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0) &&
1494 ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0)) {
1495
1496 UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE);
1497 Status = EFI_SUCCESS;
1498 goto Done;
1499 } else if ((Variable->CurrPtr->State == VAR_ADDED) ||
1500 (Variable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {
1501
1502 //
1503 // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable
1504 //
1505 if ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) {
1506
1507 BufSize = Variable->CurrPtr->DataSize + DataSize;
1508 RevBufSize = MIN (PcdGet32 (PcdMaxAppendVariableSize), ScratchDataSize);
1509
1510 if (BufSize > RevBufSize) {
1511 //
1512 // If variable size (previous + current) is bigger than reserved buffer in runtime,
1513 // return EFI_OUT_OF_RESOURCES.
1514 //
1515 return EFI_OUT_OF_RESOURCES;
1516 }
1517
1518 SetMem (mStorageArea, PcdGet32 (PcdMaxAppendVariableSize), 0xff);
1519 //
1520 // Cache the previous variable data into StorageArea.
1521 //
1522 DataOffset = sizeof (VARIABLE_HEADER) + Variable->CurrPtr->NameSize + GET_PAD_SIZE (Variable->CurrPtr->NameSize);
1523 CopyMem (mStorageArea, (UINT8*)((UINTN)Variable->CurrPtr + DataOffset), Variable->CurrPtr->DataSize);
1524
1525 //
1526 // Append the new data to the end of previous data.
1527 //
1528 CopyMem ((UINT8*)((UINTN)mStorageArea + Variable->CurrPtr->DataSize), Data, DataSize);
1529
1530 //
1531 // Override Data and DataSize which are used for combined data area including previous and new data.
1532 //
1533 Data = mStorageArea;
1534 DataSize = BufSize;
1535 }
1536
1537 //
1538 // Mark the old variable as in delete transition.
1539 //
1540 State = Variable->CurrPtr->State;
1541 State &= VAR_IN_DELETED_TRANSITION;
1542
1543 Status = UpdateVariableStore (
1544 &mVariableModuleGlobal->VariableGlobal,
1545 Variable->Volatile,
1546 FALSE,
1547 Fvb,
1548 (UINTN) &Variable->CurrPtr->State,
1549 sizeof (UINT8),
1550 &State
1551 );
1552 if (EFI_ERROR (Status)) {
1553 goto Done;
1554 }
1555 if (!Variable->Volatile) {
1556 CacheVariable->CurrPtr->State = State;
1557 }
1558 }
1559 } else {
1560 //
1561 // Not found existing variable. Create a new variable.
1562 //
1563
1564 //
1565 // EFI_VARIABLE_APPEND_WRITE attribute only set for existing variable
1566 //
1567 if ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) {
1568 Status = EFI_INVALID_PARAMETER;
1569 goto Done;
1570 }
1571
1572 //
1573 // Make sure we are trying to create a new variable.
1574 // Setting a data variable with zero DataSize or no access attributes means to delete it.
1575 //
1576 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
1577 Status = EFI_NOT_FOUND;
1578 goto Done;
1579 }
1580
1581 //
1582 // Only variable have NV|RT attribute can be created in Runtime.
1583 //
1584 if (AtRuntime () &&
1585 (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {
1586 Status = EFI_INVALID_PARAMETER;
1587 goto Done;
1588 }
1589 }
1590
1591 //
1592 // Function part - create a new variable and copy the data.
1593 // Both update a variable and create a variable will come here.
1594
1595 SetMem (NextVariable, ScratchSize, 0xff);
1596
1597 NextVariable->StartId = VARIABLE_DATA;
1598 //
1599 // NextVariable->State = VAR_ADDED;
1600 //
1601 NextVariable->Reserved = 0;
1602 NextVariable->PubKeyIndex = KeyIndex;
1603 NextVariable->MonotonicCount = MonotonicCount;
1604 SetMem (&NextVariable->TimeStamp, sizeof (EFI_TIME), 0);
1605
1606 if (((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) &&
1607 TimeStamp != NULL) {
1608 if ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) {
1609 CopyMem (&NextVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
1610 } else {
1611 //
1612 // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only
1613 // when the new TimeStamp value is later than the current timestamp associated
1614 // with the variable, we need associate the new timestamp with the updated value.
1615 //
1616 if (CompareTimeStamp (&Variable->CurrPtr->TimeStamp, TimeStamp)) {
1617 CopyMem (&NextVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));
1618 }
1619 }
1620 }
1621
1622 //
1623 // The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the returned
1624 // Attributes bitmask parameter of a GetVariable() call.
1625 //
1626 NextVariable->Attributes = Attributes & (~EFI_VARIABLE_APPEND_WRITE);
1627
1628 VarNameOffset = sizeof (VARIABLE_HEADER);
1629 VarNameSize = StrSize (VariableName);
1630 CopyMem (
1631 (UINT8 *) ((UINTN) NextVariable + VarNameOffset),
1632 VariableName,
1633 VarNameSize
1634 );
1635 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);
1636 CopyMem (
1637 (UINT8 *) ((UINTN) NextVariable + VarDataOffset),
1638 Data,
1639 DataSize
1640 );
1641 CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));
1642 //
1643 // There will be pad bytes after Data, the NextVariable->NameSize and
1644 // NextVariable->DataSize should not include pad size so that variable
1645 // service can get actual size in GetVariable.
1646 //
1647 NextVariable->NameSize = (UINT32)VarNameSize;
1648 NextVariable->DataSize = (UINT32)DataSize;
1649
1650 //
1651 // The actual size of the variable that stores in storage should
1652 // include pad size.
1653 //
1654 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
1655 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
1656 //
1657 // Create a nonvolatile variable.
1658 //
1659 Volatile = FALSE;
1660 NonVolatileVarableStoreSize = ((VARIABLE_STORE_HEADER *)(UINTN)(mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase))->Size;
1661 if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)
1662 && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))
1663 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0)
1664 && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize)))) {
1665 if (AtRuntime ()) {
1666 Status = EFI_OUT_OF_RESOURCES;
1667 goto Done;
1668 }
1669 //
1670 // Perform garbage collection & reclaim operation.
1671 //
1672 Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
1673 &mVariableModuleGlobal->NonVolatileLastVariableOffset, FALSE, Variable->CurrPtr);
1674 if (EFI_ERROR (Status)) {
1675 goto Done;
1676 }
1677 //
1678 // If still no enough space, return out of resources.
1679 //
1680 if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)
1681 && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))
1682 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0)
1683 && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize)))) {
1684 Status = EFI_OUT_OF_RESOURCES;
1685 goto Done;
1686 }
1687 Reclaimed = TRUE;
1688 }
1689 //
1690 // Four steps
1691 // 1. Write variable header
1692 // 2. Set variable state to header valid
1693 // 3. Write variable data
1694 // 4. Set variable state to valid
1695 //
1696 //
1697 // Step 1:
1698 //
1699 CacheOffset = mVariableModuleGlobal->NonVolatileLastVariableOffset;
1700 Status = UpdateVariableStore (
1701 &mVariableModuleGlobal->VariableGlobal,
1702 FALSE,
1703 TRUE,
1704 Fvb,
1705 mVariableModuleGlobal->NonVolatileLastVariableOffset,
1706 sizeof (VARIABLE_HEADER),
1707 (UINT8 *) NextVariable
1708 );
1709
1710 if (EFI_ERROR (Status)) {
1711 goto Done;
1712 }
1713
1714 //
1715 // Step 2:
1716 //
1717 NextVariable->State = VAR_HEADER_VALID_ONLY;
1718 Status = UpdateVariableStore (
1719 &mVariableModuleGlobal->VariableGlobal,
1720 FALSE,
1721 TRUE,
1722 Fvb,
1723 mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),
1724 sizeof (UINT8),
1725 &NextVariable->State
1726 );
1727
1728 if (EFI_ERROR (Status)) {
1729 goto Done;
1730 }
1731 //
1732 // Step 3:
1733 //
1734 Status = UpdateVariableStore (
1735 &mVariableModuleGlobal->VariableGlobal,
1736 FALSE,
1737 TRUE,
1738 Fvb,
1739 mVariableModuleGlobal->NonVolatileLastVariableOffset + sizeof (VARIABLE_HEADER),
1740 (UINT32) VarSize - sizeof (VARIABLE_HEADER),
1741 (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)
1742 );
1743
1744 if (EFI_ERROR (Status)) {
1745 goto Done;
1746 }
1747 //
1748 // Step 4:
1749 //
1750 NextVariable->State = VAR_ADDED;
1751 Status = UpdateVariableStore (
1752 &mVariableModuleGlobal->VariableGlobal,
1753 FALSE,
1754 TRUE,
1755 Fvb,
1756 mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),
1757 sizeof (UINT8),
1758 &NextVariable->State
1759 );
1760
1761 if (EFI_ERROR (Status)) {
1762 goto Done;
1763 }
1764
1765 mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);
1766
1767 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
1768 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);
1769 } else {
1770 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);
1771 }
1772 //
1773 // update the memory copy of Flash region.
1774 //
1775 CopyMem ((UINT8 *)mNvVariableCache + CacheOffset, (UINT8 *)NextVariable, VarSize);
1776 } else {
1777 //
1778 // Create a volatile variable.
1779 //
1780 Volatile = TRUE;
1781
1782 if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >
1783 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) {
1784 //
1785 // Perform garbage collection & reclaim operation.
1786 //
1787 Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase,
1788 &mVariableModuleGlobal->VolatileLastVariableOffset, TRUE, Variable->CurrPtr);
1789 if (EFI_ERROR (Status)) {
1790 goto Done;
1791 }
1792 //
1793 // If still no enough space, return out of resources.
1794 //
1795 if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >
1796 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size
1797 ) {
1798 Status = EFI_OUT_OF_RESOURCES;
1799 goto Done;
1800 }
1801 Reclaimed = TRUE;
1802 }
1803
1804 NextVariable->State = VAR_ADDED;
1805 Status = UpdateVariableStore (
1806 &mVariableModuleGlobal->VariableGlobal,
1807 TRUE,
1808 TRUE,
1809 Fvb,
1810 mVariableModuleGlobal->VolatileLastVariableOffset,
1811 (UINT32) VarSize,
1812 (UINT8 *) NextVariable
1813 );
1814
1815 if (EFI_ERROR (Status)) {
1816 goto Done;
1817 }
1818
1819 mVariableModuleGlobal->VolatileLastVariableOffset += HEADER_ALIGN (VarSize);
1820 }
1821
1822 //
1823 // Mark the old variable as deleted.
1824 //
1825 if (!Reclaimed && !EFI_ERROR (Status) && Variable->CurrPtr != NULL) {
1826 State = Variable->CurrPtr->State;
1827 State &= VAR_DELETED;
1828
1829 Status = UpdateVariableStore (
1830 &mVariableModuleGlobal->VariableGlobal,
1831 Variable->Volatile,
1832 FALSE,
1833 Fvb,
1834 (UINTN) &Variable->CurrPtr->State,
1835 sizeof (UINT8),
1836 &State
1837 );
1838 if (!EFI_ERROR (Status) && !Variable->Volatile) {
1839 CacheVariable->CurrPtr->State = State;
1840 }
1841 }
1842
1843 if (!EFI_ERROR (Status)) {
1844 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);
1845 }
1846
1847 Done:
1848 return Status;
1849 }
1850
1851 /**
1852
1853 This code finds variable in storage blocks (Volatile or Non-Volatile).
1854
1855 @param VariableName Name of Variable to be found.
1856 @param VendorGuid Variable vendor GUID.
1857 @param Attributes Attribute value of the variable found.
1858 @param DataSize Size of Data found. If size is less than the
1859 data, this value contains the required size.
1860 @param Data Data pointer.
1861
1862 @return EFI_INVALID_PARAMETER Invalid parameter.
1863 @return EFI_SUCCESS Find the specified variable.
1864 @return EFI_NOT_FOUND Not found.
1865 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
1866
1867 **/
1868 EFI_STATUS
1869 EFIAPI
1870 VariableServiceGetVariable (
1871 IN CHAR16 *VariableName,
1872 IN EFI_GUID *VendorGuid,
1873 OUT UINT32 *Attributes OPTIONAL,
1874 IN OUT UINTN *DataSize,
1875 OUT VOID *Data
1876 )
1877 {
1878 EFI_STATUS Status;
1879 VARIABLE_POINTER_TRACK Variable;
1880 UINTN VarDataSize;
1881
1882 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
1883 return EFI_INVALID_PARAMETER;
1884 }
1885
1886 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1887
1888 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);
1889 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
1890 goto Done;
1891 }
1892
1893 //
1894 // Get data size
1895 //
1896 VarDataSize = DataSizeOfVariable (Variable.CurrPtr);
1897 ASSERT (VarDataSize != 0);
1898
1899 if (*DataSize >= VarDataSize) {
1900 if (Data == NULL) {
1901 Status = EFI_INVALID_PARAMETER;
1902 goto Done;
1903 }
1904
1905 CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);
1906 if (Attributes != NULL) {
1907 *Attributes = Variable.CurrPtr->Attributes;
1908 }
1909
1910 *DataSize = VarDataSize;
1911 UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);
1912
1913 Status = EFI_SUCCESS;
1914 goto Done;
1915 } else {
1916 *DataSize = VarDataSize;
1917 Status = EFI_BUFFER_TOO_SMALL;
1918 goto Done;
1919 }
1920
1921 Done:
1922 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1923 return Status;
1924 }
1925
1926
1927
1928 /**
1929
1930 This code Finds the Next available variable.
1931
1932 @param VariableNameSize Size of the variable name.
1933 @param VariableName Pointer to variable name.
1934 @param VendorGuid Variable Vendor Guid.
1935
1936 @return EFI_INVALID_PARAMETER Invalid parameter.
1937 @return EFI_SUCCESS Find the specified variable.
1938 @return EFI_NOT_FOUND Not found.
1939 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.
1940
1941 **/
1942 EFI_STATUS
1943 EFIAPI
1944 VariableServiceGetNextVariableName (
1945 IN OUT UINTN *VariableNameSize,
1946 IN OUT CHAR16 *VariableName,
1947 IN OUT EFI_GUID *VendorGuid
1948 )
1949 {
1950 VARIABLE_STORE_TYPE Type;
1951 VARIABLE_POINTER_TRACK Variable;
1952 VARIABLE_POINTER_TRACK VariableInHob;
1953 UINTN VarNameSize;
1954 EFI_STATUS Status;
1955 VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];
1956
1957 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
1958 return EFI_INVALID_PARAMETER;
1959 }
1960
1961 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
1962
1963 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);
1964 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
1965 goto Done;
1966 }
1967
1968 if (VariableName[0] != 0) {
1969 //
1970 // If variable name is not NULL, get next variable.
1971 //
1972 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
1973 }
1974
1975 //
1976 // 0: Volatile, 1: HOB, 2: Non-Volatile.
1977 // The index and attributes mapping must be kept in this order as FindVariable
1978 // makes use of this mapping to implement search algorithm.
1979 //
1980 VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;
1981 VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;
1982 VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache;
1983
1984 while (TRUE) {
1985 //
1986 // Switch from Volatile to HOB, to Non-Volatile.
1987 //
1988 while ((Variable.CurrPtr >= Variable.EndPtr) ||
1989 (Variable.CurrPtr == NULL) ||
1990 !IsValidVariableHeader (Variable.CurrPtr)
1991 ) {
1992 //
1993 // Find current storage index
1994 //
1995 for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {
1996 if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) {
1997 break;
1998 }
1999 }
2000 ASSERT (Type < VariableStoreTypeMax);
2001 //
2002 // Switch to next storage
2003 //
2004 for (Type++; Type < VariableStoreTypeMax; Type++) {
2005 if (VariableStoreHeader[Type] != NULL) {
2006 break;
2007 }
2008 }
2009 //
2010 // Capture the case that
2011 // 1. current storage is the last one, or
2012 // 2. no further storage
2013 //
2014 if (Type == VariableStoreTypeMax) {
2015 Status = EFI_NOT_FOUND;
2016 goto Done;
2017 }
2018 Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]);
2019 Variable.EndPtr = GetEndPointer (VariableStoreHeader[Type]);
2020 Variable.CurrPtr = Variable.StartPtr;
2021 }
2022
2023 //
2024 // Variable is found
2025 //
2026 if (Variable.CurrPtr->State == VAR_ADDED) {
2027 if ((AtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) == 0) {
2028
2029 //
2030 // Don't return NV variable when HOB overrides it
2031 //
2032 if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) && (VariableStoreHeader[VariableStoreTypeNv] != NULL) &&
2033 (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv]))
2034 ) {
2035 VariableInHob.StartPtr = GetStartPointer (VariableStoreHeader[VariableStoreTypeHob]);
2036 VariableInHob.EndPtr = GetEndPointer (VariableStoreHeader[VariableStoreTypeHob]);
2037 Status = FindVariableEx (
2038 GetVariableNamePtr (Variable.CurrPtr),
2039 &Variable.CurrPtr->VendorGuid,
2040 &VariableInHob
2041 );
2042 if (!EFI_ERROR (Status)) {
2043 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
2044 continue;
2045 }
2046 }
2047
2048 VarNameSize = NameSizeOfVariable (Variable.CurrPtr);
2049 ASSERT (VarNameSize != 0);
2050
2051 if (VarNameSize <= *VariableNameSize) {
2052 CopyMem (VariableName, GetVariableNamePtr (Variable.CurrPtr), VarNameSize);
2053 CopyMem (VendorGuid, &Variable.CurrPtr->VendorGuid, sizeof (EFI_GUID));
2054 Status = EFI_SUCCESS;
2055 } else {
2056 Status = EFI_BUFFER_TOO_SMALL;
2057 }
2058
2059 *VariableNameSize = VarNameSize;
2060 goto Done;
2061 }
2062 }
2063
2064 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
2065 }
2066
2067 Done:
2068 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
2069 return Status;
2070 }
2071
2072 /**
2073
2074 This code sets variable in storage blocks (Volatile or Non-Volatile).
2075
2076 @param VariableName Name of Variable to be found.
2077 @param VendorGuid Variable vendor GUID.
2078 @param Attributes Attribute value of the variable found
2079 @param DataSize Size of Data found. If size is less than the
2080 data, this value contains the required size.
2081 @param Data Data pointer.
2082
2083 @return EFI_INVALID_PARAMETER Invalid parameter.
2084 @return EFI_SUCCESS Set successfully.
2085 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.
2086 @return EFI_NOT_FOUND Not found.
2087 @return EFI_WRITE_PROTECTED Variable is read-only.
2088
2089 **/
2090 EFI_STATUS
2091 EFIAPI
2092 VariableServiceSetVariable (
2093 IN CHAR16 *VariableName,
2094 IN EFI_GUID *VendorGuid,
2095 IN UINT32 Attributes,
2096 IN UINTN DataSize,
2097 IN VOID *Data
2098 )
2099 {
2100 VARIABLE_POINTER_TRACK Variable;
2101 EFI_STATUS Status;
2102 VARIABLE_HEADER *NextVariable;
2103 EFI_PHYSICAL_ADDRESS Point;
2104 UINTN PayloadSize;
2105
2106 //
2107 // Check input parameters.
2108 //
2109 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
2110 return EFI_INVALID_PARAMETER;
2111 }
2112
2113 if (DataSize != 0 && Data == NULL) {
2114 return EFI_INVALID_PARAMETER;
2115 }
2116
2117 //
2118 // Make sure if runtime bit is set, boot service bit is set also.
2119 //
2120 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
2121 return EFI_INVALID_PARAMETER;
2122 }
2123
2124 //
2125 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute
2126 // cannot be set both.
2127 //
2128 if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) \
2129 && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {
2130 return EFI_INVALID_PARAMETER;
2131 }
2132
2133 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) {
2134 if (DataSize < AUTHINFO_SIZE) {
2135 //
2136 // Try to write Authencated Variable without AuthInfo.
2137 //
2138 return EFI_SECURITY_VIOLATION;
2139 }
2140 PayloadSize = DataSize - AUTHINFO_SIZE;
2141 } else {
2142 PayloadSize = DataSize;
2143 }
2144 //
2145 // The size of the VariableName, including the Unicode Null in bytes plus
2146 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
2147 // bytes for HwErrRec, and PcdGet32 (PcdMaxVariableSize) bytes for the others.
2148 //
2149 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
2150 if ((PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize)) ||
2151 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize))) {
2152 return EFI_INVALID_PARAMETER;
2153 }
2154 //
2155 // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX".
2156 //
2157 if (StrnCmp(VariableName, L"HwErrRec", StrLen(L"HwErrRec")) != 0) {
2158 return EFI_INVALID_PARAMETER;
2159 }
2160 } else {
2161 //
2162 // The size of the VariableName, including the Unicode Null in bytes plus
2163 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxVariableSize) bytes.
2164 //
2165 if ((PayloadSize > PcdGet32 (PcdMaxVariableSize)) ||
2166 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxVariableSize))) {
2167 return EFI_INVALID_PARAMETER;
2168 }
2169 }
2170
2171 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
2172
2173 //
2174 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.
2175 //
2176 if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {
2177 Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;
2178 //
2179 // Parse non-volatile variable data and get last variable offset.
2180 //
2181 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point);
2182 while ((NextVariable < GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point))
2183 && IsValidVariableHeader (NextVariable)) {
2184 NextVariable = GetNextVariablePtr (NextVariable);
2185 }
2186 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;
2187 }
2188
2189 //
2190 // Check whether the input variable is already existed.
2191 //
2192 FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);
2193
2194 //
2195 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.
2196 //
2197 AutoUpdateLangVariable (VariableName, Data, DataSize);
2198 //
2199 // Process PK, KEK, Sigdb seperately.
2200 //
2201 if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){
2202 Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, TRUE);
2203 } else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) {
2204 Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, FALSE);
2205 } else if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == 0)) {
2206 Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);
2207 } else {
2208 Status = ProcessVariable (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);
2209 }
2210
2211 InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);
2212 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
2213
2214 return Status;
2215 }
2216
2217 /**
2218
2219 This code returns information about the EFI variables.
2220
2221 @param Attributes Attributes bitmask to specify the type of variables
2222 on which to return information.
2223 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
2224 for the EFI variables associated with the attributes specified.
2225 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
2226 for EFI variables associated with the attributes specified.
2227 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
2228 associated with the attributes specified.
2229
2230 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
2231 @return EFI_SUCCESS Query successfully.
2232 @return EFI_UNSUPPORTED The attribute is not supported on this platform.
2233
2234 **/
2235 EFI_STATUS
2236 EFIAPI
2237 VariableServiceQueryVariableInfo (
2238 IN UINT32 Attributes,
2239 OUT UINT64 *MaximumVariableStorageSize,
2240 OUT UINT64 *RemainingVariableStorageSize,
2241 OUT UINT64 *MaximumVariableSize
2242 )
2243 {
2244 VARIABLE_HEADER *Variable;
2245 VARIABLE_HEADER *NextVariable;
2246 UINT64 VariableSize;
2247 VARIABLE_STORE_HEADER *VariableStoreHeader;
2248 UINT64 CommonVariableTotalSize;
2249 UINT64 HwErrVariableTotalSize;
2250
2251 CommonVariableTotalSize = 0;
2252 HwErrVariableTotalSize = 0;
2253
2254 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
2255 return EFI_INVALID_PARAMETER;
2256 }
2257
2258 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {
2259 //
2260 // Make sure the Attributes combination is supported by the platform.
2261 //
2262 return EFI_UNSUPPORTED;
2263 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
2264 //
2265 // Make sure if runtime bit is set, boot service bit is set also.
2266 //
2267 return EFI_INVALID_PARAMETER;
2268 } else if (AtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {
2269 //
2270 // Make sure RT Attribute is set if we are in Runtime phase.
2271 //
2272 return EFI_INVALID_PARAMETER;
2273 } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
2274 //
2275 // Make sure Hw Attribute is set with NV.
2276 //
2277 return EFI_INVALID_PARAMETER;
2278 }
2279
2280 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
2281
2282 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
2283 //
2284 // Query is Volatile related.
2285 //
2286 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
2287 } else {
2288 //
2289 // Query is Non-Volatile related.
2290 //
2291 VariableStoreHeader = mNvVariableCache;
2292 }
2293
2294 //
2295 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
2296 // with the storage size (excluding the storage header size).
2297 //
2298 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
2299
2300 //
2301 // Harware error record variable needs larger size.
2302 //
2303 if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
2304 *MaximumVariableStorageSize = PcdGet32 (PcdHwErrStorageSize);
2305 *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);
2306 } else {
2307 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
2308 ASSERT (PcdGet32 (PcdHwErrStorageSize) < VariableStoreHeader->Size);
2309 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize);
2310 }
2311
2312 //
2313 // Let *MaximumVariableSize be PcdGet32 (PcdMaxVariableSize) with the exception of the variable header size.
2314 //
2315 *MaximumVariableSize = PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);
2316 }
2317
2318 //
2319 // Point to the starting address of the variables.
2320 //
2321 Variable = GetStartPointer (VariableStoreHeader);
2322
2323 //
2324 // Now walk through the related variable store.
2325 //
2326 while ((Variable < GetEndPointer (VariableStoreHeader)) && IsValidVariableHeader (Variable)) {
2327 NextVariable = GetNextVariablePtr (Variable);
2328 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;
2329
2330 if (AtRuntime ()) {
2331 //
2332 // We don't take the state of the variables in mind
2333 // when calculating RemainingVariableStorageSize,
2334 // since the space occupied by variables not marked with
2335 // VAR_ADDED is not allowed to be reclaimed in Runtime.
2336 //
2337 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
2338 HwErrVariableTotalSize += VariableSize;
2339 } else {
2340 CommonVariableTotalSize += VariableSize;
2341 }
2342 } else {
2343 //
2344 // Only care about Variables with State VAR_ADDED, because
2345 // the space not marked as VAR_ADDED is reclaimable now.
2346 //
2347 if (Variable->State == VAR_ADDED) {
2348 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
2349 HwErrVariableTotalSize += VariableSize;
2350 } else {
2351 CommonVariableTotalSize += VariableSize;
2352 }
2353 }
2354 }
2355
2356 //
2357 // Go to the next one.
2358 //
2359 Variable = NextVariable;
2360 }
2361
2362 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){
2363 *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;
2364 }else {
2365 *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;
2366 }
2367
2368 if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {
2369 *MaximumVariableSize = 0;
2370 } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {
2371 *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);
2372 }
2373
2374 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
2375 return EFI_SUCCESS;
2376 }
2377
2378
2379 /**
2380 This function reclaims variable storage if free size is below the threshold.
2381
2382 **/
2383 VOID
2384 ReclaimForOS(
2385 VOID
2386 )
2387 {
2388 EFI_STATUS Status;
2389 UINTN CommonVariableSpace;
2390 UINTN RemainingCommonVariableSpace;
2391 UINTN RemainingHwErrVariableSpace;
2392
2393 Status = EFI_SUCCESS;
2394
2395 CommonVariableSpace = ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize); //Allowable max size of common variable storage space
2396
2397 RemainingCommonVariableSpace = CommonVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;
2398
2399 RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;
2400 //
2401 // Check if the free area is blow a threshold.
2402 //
2403 if ((RemainingCommonVariableSpace < PcdGet32 (PcdMaxVariableSize))
2404 || ((PcdGet32 (PcdHwErrStorageSize) != 0) &&
2405 (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize)))){
2406 Status = Reclaim (
2407 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
2408 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
2409 FALSE,
2410 NULL
2411 );
2412 ASSERT_EFI_ERROR (Status);
2413 }
2414 }
2415
2416
2417 /**
2418 Initializes variable write service after FVB was ready.
2419
2420 @retval EFI_SUCCESS Function successfully executed.
2421 @retval Others Fail to initialize the variable service.
2422
2423 **/
2424 EFI_STATUS
2425 VariableWriteServiceInitialize (
2426 VOID
2427 )
2428 {
2429 EFI_STATUS Status;
2430 VARIABLE_STORE_HEADER *VariableStoreHeader;
2431 UINTN Index;
2432 UINT8 Data;
2433 EFI_PHYSICAL_ADDRESS VariableStoreBase;
2434 VARIABLE_HEADER *Variable;
2435 VOID *VariableData;
2436
2437 VariableStoreBase = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;
2438 VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;
2439
2440 //
2441 // Check if the free area is really free.
2442 //
2443 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {
2444 Data = ((UINT8 *) mNvVariableCache)[Index];
2445 if (Data != 0xff) {
2446 //
2447 // There must be something wrong in variable store, do reclaim operation.
2448 //
2449 Status = Reclaim (
2450 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
2451 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
2452 FALSE,
2453 NULL
2454 );
2455 if (EFI_ERROR (Status)) {
2456 return Status;
2457 }
2458 break;
2459 }
2460 }
2461
2462
2463 //
2464 // Flush the HOB variable to flash and invalidate HOB variable.
2465 //
2466 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {
2467 //
2468 // Clear the HobVariableBase to avoid SetVariable() updating the variable in HOB
2469 //
2470 VariableStoreHeader = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;
2471 mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;
2472
2473 for ( Variable = GetStartPointer (VariableStoreHeader)
2474 ; (Variable < GetEndPointer (VariableStoreHeader) && IsValidVariableHeader (Variable))
2475 ; Variable = GetNextVariablePtr (Variable)
2476 ) {
2477 ASSERT (Variable->State == VAR_ADDED);
2478 ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0);
2479 VariableData = GetVariableDataPtr (Variable);
2480 Status = VariableServiceSetVariable (
2481 GetVariableNamePtr (Variable),
2482 &Variable->VendorGuid,
2483 Variable->Attributes,
2484 Variable->DataSize,
2485 VariableData
2486 );
2487 ASSERT_EFI_ERROR (Status);
2488 }
2489 }
2490
2491 //
2492 // Authenticated variable initialize.
2493 //
2494 Status = AutenticatedVariableServiceInitialize ();
2495
2496 return Status;
2497 }
2498
2499
2500 /**
2501 Initializes variable store area for non-volatile and volatile variable.
2502
2503 @retval EFI_SUCCESS Function successfully executed.
2504 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
2505
2506 **/
2507 EFI_STATUS
2508 VariableCommonInitialize (
2509 VOID
2510 )
2511 {
2512 EFI_STATUS Status;
2513 VARIABLE_STORE_HEADER *VolatileVariableStore;
2514 VARIABLE_STORE_HEADER *VariableStoreHeader;
2515 VARIABLE_HEADER *NextVariable;
2516 EFI_PHYSICAL_ADDRESS TempVariableStoreHeader;
2517 EFI_PHYSICAL_ADDRESS VariableStoreBase;
2518 UINT64 VariableStoreLength;
2519 UINTN ScratchSize;
2520 UINTN VariableSize;
2521 EFI_HOB_GUID_TYPE *GuidHob;
2522
2523 //
2524 // Allocate runtime memory for variable driver global structure.
2525 //
2526 mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL));
2527 if (mVariableModuleGlobal == NULL) {
2528 return EFI_OUT_OF_RESOURCES;
2529 }
2530
2531 InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);
2532
2533 //
2534 // Note that in EdkII variable driver implementation, Hardware Error Record type variable
2535 // is stored with common variable in the same NV region. So the platform integrator should
2536 // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of
2537 // PcdFlashNvStorageVariableSize.
2538 //
2539 ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));
2540
2541 //
2542 // Get HOB variable store.
2543 //
2544 GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
2545 if (GuidHob != NULL) {
2546 VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob);
2547 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
2548 mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStoreHeader;
2549 } else {
2550 DEBUG ((EFI_D_ERROR, "HOB Variable Store header is corrupted!\n"));
2551 }
2552 }
2553
2554 //
2555 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
2556 //
2557 ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));
2558 VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);
2559 if (VolatileVariableStore == NULL) {
2560 FreePool (mVariableModuleGlobal);
2561 return EFI_OUT_OF_RESOURCES;
2562 }
2563
2564 SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);
2565
2566 //
2567 // Initialize Variable Specific Data.
2568 //
2569 mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;
2570 mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;
2571 mVariableModuleGlobal->FvbInstance = NULL;
2572
2573 CopyGuid (&VolatileVariableStore->Signature, &gEfiAuthenticatedVariableGuid);
2574 VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize);
2575 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;
2576 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;
2577 VolatileVariableStore->Reserved = 0;
2578 VolatileVariableStore->Reserved1 = 0;
2579
2580 //
2581 // Get non-volatile variable store.
2582 //
2583
2584 TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);
2585 if (TempVariableStoreHeader == 0) {
2586 TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);
2587 }
2588 VariableStoreBase = TempVariableStoreHeader + \
2589 (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);
2590 VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \
2591 (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);
2592
2593 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;
2594 VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;
2595 if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {
2596 Status = EFI_VOLUME_CORRUPTED;
2597 DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));
2598 goto Done;
2599 }
2600 ASSERT(VariableStoreHeader->Size == VariableStoreLength);
2601
2602 //
2603 // Parse non-volatile variable data and get last variable offset.
2604 //
2605 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);
2606 while (IsValidVariableHeader (NextVariable)) {
2607 VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);
2608 if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
2609 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);
2610 } else {
2611 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);
2612 }
2613
2614 NextVariable = GetNextVariablePtr (NextVariable);
2615 }
2616
2617 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;
2618
2619 //
2620 // Allocate runtime memory used for a memory copy of the FLASH region.
2621 // Keep the memory and the FLASH in sync as updates occur
2622 //
2623 mNvVariableCache = AllocateRuntimeZeroPool ((UINTN)VariableStoreLength);
2624 if (mNvVariableCache == NULL) {
2625 Status = EFI_OUT_OF_RESOURCES;
2626 goto Done;
2627 }
2628 CopyMem (mNvVariableCache, (CHAR8 *)(UINTN)VariableStoreBase, (UINTN)VariableStoreLength);
2629 Status = EFI_SUCCESS;
2630
2631 Done:
2632 if (EFI_ERROR (Status)) {
2633 FreePool (mVariableModuleGlobal);
2634 FreePool (VolatileVariableStore);
2635 }
2636
2637 return Status;
2638 }
2639
2640
2641 /**
2642 Get the proper fvb handle and/or fvb protocol by the given Flash address.
2643
2644 @param[in] Address The Flash address.
2645 @param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle.
2646 @param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol.
2647
2648 **/
2649 EFI_STATUS
2650 GetFvbInfoByAddress (
2651 IN EFI_PHYSICAL_ADDRESS Address,
2652 OUT EFI_HANDLE *FvbHandle OPTIONAL,
2653 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvbProtocol OPTIONAL
2654 )
2655 {
2656 EFI_STATUS Status;
2657 EFI_HANDLE *HandleBuffer;
2658 UINTN HandleCount;
2659 UINTN Index;
2660 EFI_PHYSICAL_ADDRESS FvbBaseAddress;
2661 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
2662 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
2663 EFI_FVB_ATTRIBUTES_2 Attributes;
2664
2665 //
2666 // Get all FVB handles.
2667 //
2668 Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);
2669 if (EFI_ERROR (Status)) {
2670 return EFI_NOT_FOUND;
2671 }
2672
2673 //
2674 // Get the FVB to access variable store.
2675 //
2676 Fvb = NULL;
2677 for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {
2678 Status = GetFvbByHandle (HandleBuffer[Index], &Fvb);
2679 if (EFI_ERROR (Status)) {
2680 Status = EFI_NOT_FOUND;
2681 break;
2682 }
2683
2684 //
2685 // Ensure this FVB protocol supported Write operation.
2686 //
2687 Status = Fvb->GetAttributes (Fvb, &Attributes);
2688 if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
2689 continue;
2690 }
2691
2692 //
2693 // Compare the address and select the right one.
2694 //
2695 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
2696 if (EFI_ERROR (Status)) {
2697 continue;
2698 }
2699
2700 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);
2701 if ((Address >= FvbBaseAddress) && (Address < (FvbBaseAddress + FwVolHeader->FvLength))) {
2702 if (FvbHandle != NULL) {
2703 *FvbHandle = HandleBuffer[Index];
2704 }
2705 if (FvbProtocol != NULL) {
2706 *FvbProtocol = Fvb;
2707 }
2708 Status = EFI_SUCCESS;
2709 break;
2710 }
2711 }
2712 FreePool (HandleBuffer);
2713
2714 if (Fvb == NULL) {
2715 Status = EFI_NOT_FOUND;
2716 }
2717
2718 return Status;
2719 }
2720