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