]> 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 return EFI_INVALID_PARAMETER;
2680 } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
2681 if (!mVariableModuleGlobal->VariableGlobal.AuthSupport) {
2682 //
2683 // Not support authenticated variable write.
2684 //
2685 return EFI_INVALID_PARAMETER;
2686 }
2687 } else if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
2688 if (PcdGet32 (PcdHwErrStorageSize) == 0) {
2689 //
2690 // Not support harware error record variable variable.
2691 //
2692 return EFI_INVALID_PARAMETER;
2693 }
2694 }
2695
2696 //
2697 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute
2698 // cannot be set both.
2699 //
2700 if ( ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)
2701 && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS))
2702 {
2703 return EFI_UNSUPPORTED;
2704 }
2705
2706 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) {
2707 //
2708 // If DataSize == AUTHINFO_SIZE and then PayloadSize is 0.
2709 // Maybe it's the delete operation of common authenticated variable at user physical presence.
2710 //
2711 if (DataSize != AUTHINFO_SIZE) {
2712 return EFI_UNSUPPORTED;
2713 }
2714
2715 PayloadSize = DataSize - AUTHINFO_SIZE;
2716 } else if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {
2717 //
2718 // Sanity check for EFI_VARIABLE_AUTHENTICATION_2 descriptor.
2719 //
2720 if ((DataSize < OFFSET_OF_AUTHINFO2_CERT_DATA) ||
2721 (((EFI_VARIABLE_AUTHENTICATION_2 *)Data)->AuthInfo.Hdr.dwLength > DataSize - (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo))) ||
2722 (((EFI_VARIABLE_AUTHENTICATION_2 *)Data)->AuthInfo.Hdr.dwLength < OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)))
2723 {
2724 return EFI_SECURITY_VIOLATION;
2725 }
2726
2727 //
2728 // The VariableSpeculationBarrier() call here is to ensure the above sanity
2729 // check for the EFI_VARIABLE_AUTHENTICATION_2 descriptor has been completed
2730 // before the execution of subsequent codes.
2731 //
2732 VariableSpeculationBarrier ();
2733 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);
2734 } else {
2735 PayloadSize = DataSize;
2736 }
2737
2738 if ((UINTN)(~0) - PayloadSize < StrSize (VariableName)) {
2739 //
2740 // Prevent whole variable size overflow
2741 //
2742 return EFI_INVALID_PARAMETER;
2743 }
2744
2745 //
2746 // The size of the VariableName, including the Unicode Null in bytes plus
2747 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
2748 // bytes for HwErrRec#### variable.
2749 //
2750 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
2751 if (StrSize (VariableName) + PayloadSize >
2752 PcdGet32 (PcdMaxHardwareErrorVariableSize) - GetVariableHeaderSize (AuthFormat))
2753 {
2754 return EFI_INVALID_PARAMETER;
2755 }
2756 } else {
2757 //
2758 // The size of the VariableName, including the Unicode Null in bytes plus
2759 // the DataSize is limited to maximum size of Max(Auth|Volatile)VariableSize bytes.
2760 //
2761 if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
2762 if (StrSize (VariableName) + PayloadSize >
2763 mVariableModuleGlobal->MaxAuthVariableSize -
2764 GetVariableHeaderSize (AuthFormat))
2765 {
2766 DEBUG ((
2767 DEBUG_ERROR,
2768 "%a: Failed to set variable '%s' with Guid %g\n",
2769 __FUNCTION__,
2770 VariableName,
2771 VendorGuid
2772 ));
2773 DEBUG ((
2774 DEBUG_ERROR,
2775 "NameSize(0x%x) + PayloadSize(0x%x) > "
2776 "MaxAuthVariableSize(0x%x) - HeaderSize(0x%x)\n",
2777 StrSize (VariableName),
2778 PayloadSize,
2779 mVariableModuleGlobal->MaxAuthVariableSize,
2780 GetVariableHeaderSize (AuthFormat)
2781 ));
2782 return EFI_INVALID_PARAMETER;
2783 }
2784 } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
2785 if (StrSize (VariableName) + PayloadSize >
2786 mVariableModuleGlobal->MaxVariableSize - GetVariableHeaderSize (AuthFormat))
2787 {
2788 DEBUG ((
2789 DEBUG_ERROR,
2790 "%a: Failed to set variable '%s' with Guid %g\n",
2791 __FUNCTION__,
2792 VariableName,
2793 VendorGuid
2794 ));
2795 DEBUG ((
2796 DEBUG_ERROR,
2797 "NameSize(0x%x) + PayloadSize(0x%x) > "
2798 "MaxVariableSize(0x%x) - HeaderSize(0x%x)\n",
2799 StrSize (VariableName),
2800 PayloadSize,
2801 mVariableModuleGlobal->MaxVariableSize,
2802 GetVariableHeaderSize (AuthFormat)
2803 ));
2804 return EFI_INVALID_PARAMETER;
2805 }
2806 } else {
2807 if (StrSize (VariableName) + PayloadSize >
2808 mVariableModuleGlobal->MaxVolatileVariableSize - GetVariableHeaderSize (AuthFormat))
2809 {
2810 DEBUG ((
2811 DEBUG_ERROR,
2812 "%a: Failed to set variable '%s' with Guid %g\n",
2813 __FUNCTION__,
2814 VariableName,
2815 VendorGuid
2816 ));
2817 DEBUG ((
2818 DEBUG_ERROR,
2819 "NameSize(0x%x) + PayloadSize(0x%x) > "
2820 "MaxVolatileVariableSize(0x%x) - HeaderSize(0x%x)\n",
2821 StrSize (VariableName),
2822 PayloadSize,
2823 mVariableModuleGlobal->MaxVolatileVariableSize,
2824 GetVariableHeaderSize (AuthFormat)
2825 ));
2826 return EFI_INVALID_PARAMETER;
2827 }
2828 }
2829 }
2830
2831 //
2832 // Special Handling for MOR Lock variable.
2833 //
2834 Status = SetVariableCheckHandlerMor (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *)((UINTN)Data + DataSize - PayloadSize));
2835 if (Status == EFI_ALREADY_STARTED) {
2836 //
2837 // EFI_ALREADY_STARTED means the SetVariable() action is handled inside of SetVariableCheckHandlerMor().
2838 // Variable driver can just return SUCCESS.
2839 //
2840 return EFI_SUCCESS;
2841 }
2842
2843 if (EFI_ERROR (Status)) {
2844 return Status;
2845 }
2846
2847 Status = VarCheckLibSetVariableCheck (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *)((UINTN)Data + DataSize - PayloadSize), mRequestSource);
2848 if (EFI_ERROR (Status)) {
2849 return Status;
2850 }
2851
2852 AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
2853
2854 //
2855 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.
2856 //
2857 if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {
2858 Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;
2859 //
2860 // Parse non-volatile variable data and get last variable offset.
2861 //
2862 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)Point);
2863 while (IsValidVariableHeader (NextVariable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)Point))) {
2864 NextVariable = GetNextVariablePtr (NextVariable, AuthFormat);
2865 }
2866
2867 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN)NextVariable - (UINTN)Point;
2868 }
2869
2870 //
2871 // Check whether the input variable is already existed.
2872 //
2873 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, TRUE);
2874 if (!EFI_ERROR (Status)) {
2875 if (((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) && AtRuntime ()) {
2876 Status = EFI_WRITE_PROTECTED;
2877 goto Done;
2878 }
2879
2880 if ((Attributes != 0) && ((Attributes & (~EFI_VARIABLE_APPEND_WRITE)) != Variable.CurrPtr->Attributes)) {
2881 //
2882 // If a preexisting variable is rewritten with different attributes, SetVariable() shall not
2883 // modify the variable and shall return EFI_INVALID_PARAMETER. Two exceptions to this rule:
2884 // 1. No access attributes specified
2885 // 2. The only attribute differing is EFI_VARIABLE_APPEND_WRITE
2886 //
2887 Status = EFI_INVALID_PARAMETER;
2888 DEBUG ((DEBUG_INFO, "[Variable]: Rewritten a preexisting variable(0x%08x) with different attributes(0x%08x) - %g:%s\n", Variable.CurrPtr->Attributes, Attributes, VendorGuid, VariableName));
2889 goto Done;
2890 }
2891 }
2892
2893 if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate)) {
2894 //
2895 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.
2896 //
2897 Status = AutoUpdateLangVariable (VariableName, Data, DataSize);
2898 if (EFI_ERROR (Status)) {
2899 //
2900 // The auto update operation failed, directly return to avoid inconsistency between PlatformLang and Lang.
2901 //
2902 goto Done;
2903 }
2904 }
2905
2906 if (mVariableModuleGlobal->VariableGlobal.AuthSupport) {
2907 Status = AuthVariableLibProcessVariable (VariableName, VendorGuid, Data, DataSize, Attributes);
2908 } else {
2909 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, 0, 0, &Variable, NULL);
2910 }
2911
2912 Done:
2913 InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);
2914 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
2915
2916 if (!AtRuntime ()) {
2917 if (!EFI_ERROR (Status)) {
2918 SecureBootHook (
2919 VariableName,
2920 VendorGuid
2921 );
2922 }
2923 }
2924
2925 return Status;
2926 }
2927
2928 /**
2929
2930 This code returns information about the EFI variables.
2931
2932 Caution: This function may receive untrusted input.
2933 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
2934
2935 @param Attributes Attributes bitmask to specify the type of variables
2936 on which to return information.
2937 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
2938 for the EFI variables associated with the attributes specified.
2939 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
2940 for EFI variables associated with the attributes specified.
2941 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
2942 associated with the attributes specified.
2943
2944 @return EFI_SUCCESS Query successfully.
2945
2946 **/
2947 EFI_STATUS
2948 EFIAPI
2949 VariableServiceQueryVariableInfoInternal (
2950 IN UINT32 Attributes,
2951 OUT UINT64 *MaximumVariableStorageSize,
2952 OUT UINT64 *RemainingVariableStorageSize,
2953 OUT UINT64 *MaximumVariableSize
2954 )
2955 {
2956 VARIABLE_HEADER *Variable;
2957 VARIABLE_HEADER *NextVariable;
2958 UINT64 VariableSize;
2959 VARIABLE_STORE_HEADER *VariableStoreHeader;
2960 UINT64 CommonVariableTotalSize;
2961 UINT64 HwErrVariableTotalSize;
2962 EFI_STATUS Status;
2963 VARIABLE_POINTER_TRACK VariablePtrTrack;
2964
2965 CommonVariableTotalSize = 0;
2966 HwErrVariableTotalSize = 0;
2967
2968 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
2969 //
2970 // Query is Volatile related.
2971 //
2972 VariableStoreHeader = (VARIABLE_STORE_HEADER *)((UINTN)mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);
2973 } else {
2974 //
2975 // Query is Non-Volatile related.
2976 //
2977 VariableStoreHeader = mNvVariableCache;
2978 }
2979
2980 //
2981 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
2982 // with the storage size (excluding the storage header size).
2983 //
2984 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
2985
2986 //
2987 // Harware error record variable needs larger size.
2988 //
2989 if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
2990 *MaximumVariableStorageSize = PcdGet32 (PcdHwErrStorageSize);
2991 *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) -
2992 GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);
2993 } else {
2994 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
2995 if (AtRuntime ()) {
2996 *MaximumVariableStorageSize = mVariableModuleGlobal->CommonRuntimeVariableSpace;
2997 } else {
2998 *MaximumVariableStorageSize = mVariableModuleGlobal->CommonVariableSpace;
2999 }
3000 }
3001
3002 //
3003 // Let *MaximumVariableSize be Max(Auth|Volatile)VariableSize with the exception of the variable header size.
3004 //
3005 if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
3006 *MaximumVariableSize = mVariableModuleGlobal->MaxAuthVariableSize -
3007 GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);
3008 } else if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
3009 *MaximumVariableSize = mVariableModuleGlobal->MaxVariableSize -
3010 GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);
3011 } else {
3012 *MaximumVariableSize = mVariableModuleGlobal->MaxVolatileVariableSize -
3013 GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);
3014 }
3015 }
3016
3017 //
3018 // Point to the starting address of the variables.
3019 //
3020 Variable = GetStartPointer (VariableStoreHeader);
3021
3022 //
3023 // Now walk through the related variable store.
3024 //
3025 while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {
3026 NextVariable = GetNextVariablePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat);
3027 VariableSize = (UINT64)(UINTN)NextVariable - (UINT64)(UINTN)Variable;
3028
3029 if (AtRuntime ()) {
3030 //
3031 // We don't take the state of the variables in mind
3032 // when calculating RemainingVariableStorageSize,
3033 // since the space occupied by variables not marked with
3034 // VAR_ADDED is not allowed to be reclaimed in Runtime.
3035 //
3036 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
3037 HwErrVariableTotalSize += VariableSize;
3038 } else {
3039 CommonVariableTotalSize += VariableSize;
3040 }
3041 } else {
3042 //
3043 // Only care about Variables with State VAR_ADDED, because
3044 // the space not marked as VAR_ADDED is reclaimable now.
3045 //
3046 if (Variable->State == VAR_ADDED) {
3047 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
3048 HwErrVariableTotalSize += VariableSize;
3049 } else {
3050 CommonVariableTotalSize += VariableSize;
3051 }
3052 } else if (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
3053 //
3054 // If it is a IN_DELETED_TRANSITION variable,
3055 // and there is not also a same ADDED one at the same time,
3056 // this IN_DELETED_TRANSITION variable is valid.
3057 //
3058 VariablePtrTrack.StartPtr = GetStartPointer (VariableStoreHeader);
3059 VariablePtrTrack.EndPtr = GetEndPointer (VariableStoreHeader);
3060 Status = FindVariableEx (
3061 GetVariableNamePtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat),
3062 GetVendorGuidPtr (Variable, mVariableModuleGlobal->VariableGlobal.AuthFormat),
3063 FALSE,
3064 &VariablePtrTrack,
3065 mVariableModuleGlobal->VariableGlobal.AuthFormat
3066 );
3067 if (!EFI_ERROR (Status) && (VariablePtrTrack.CurrPtr->State != VAR_ADDED)) {
3068 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
3069 HwErrVariableTotalSize += VariableSize;
3070 } else {
3071 CommonVariableTotalSize += VariableSize;
3072 }
3073 }
3074 }
3075 }
3076
3077 //
3078 // Go to the next one.
3079 //
3080 Variable = NextVariable;
3081 }
3082
3083 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
3084 *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;
3085 } else {
3086 if (*MaximumVariableStorageSize < CommonVariableTotalSize) {
3087 *RemainingVariableStorageSize = 0;
3088 } else {
3089 *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;
3090 }
3091 }
3092
3093 if (*RemainingVariableStorageSize < GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat)) {
3094 *MaximumVariableSize = 0;
3095 } else if ((*RemainingVariableStorageSize - GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat)) <
3096 *MaximumVariableSize
3097 )
3098 {
3099 *MaximumVariableSize = *RemainingVariableStorageSize -
3100 GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);
3101 }
3102
3103 return EFI_SUCCESS;
3104 }
3105
3106 /**
3107
3108 This code returns information about the EFI variables.
3109
3110 Caution: This function may receive untrusted input.
3111 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.
3112
3113 @param Attributes Attributes bitmask to specify the type of variables
3114 on which to return information.
3115 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available
3116 for the EFI variables associated with the attributes specified.
3117 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available
3118 for EFI variables associated with the attributes specified.
3119 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables
3120 associated with the attributes specified.
3121
3122 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
3123 @return EFI_SUCCESS Query successfully.
3124 @return EFI_UNSUPPORTED The attribute is not supported on this platform.
3125
3126 **/
3127 EFI_STATUS
3128 EFIAPI
3129 VariableServiceQueryVariableInfo (
3130 IN UINT32 Attributes,
3131 OUT UINT64 *MaximumVariableStorageSize,
3132 OUT UINT64 *RemainingVariableStorageSize,
3133 OUT UINT64 *MaximumVariableSize
3134 )
3135 {
3136 EFI_STATUS Status;
3137
3138 if ((MaximumVariableStorageSize == NULL) || (RemainingVariableStorageSize == NULL) || (MaximumVariableSize == NULL) || (Attributes == 0)) {
3139 return EFI_INVALID_PARAMETER;
3140 }
3141
3142 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
3143 //
3144 // Deprecated attribute, make this check as highest priority.
3145 //
3146 return EFI_UNSUPPORTED;
3147 }
3148
3149 if ((Attributes & EFI_VARIABLE_ATTRIBUTES_MASK) == 0) {
3150 //
3151 // Make sure the Attributes combination is supported by the platform.
3152 //
3153 return EFI_UNSUPPORTED;
3154 } else if ((Attributes & EFI_VARIABLE_ATTRIBUTES_MASK) == EFI_VARIABLE_NON_VOLATILE) {
3155 //
3156 // Only EFI_VARIABLE_NON_VOLATILE attribute is invalid
3157 //
3158 return EFI_INVALID_PARAMETER;
3159 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
3160 //
3161 // Make sure if runtime bit is set, boot service bit is set also.
3162 //
3163 return EFI_INVALID_PARAMETER;
3164 } else if (AtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {
3165 //
3166 // Make sure RT Attribute is set if we are in Runtime phase.
3167 //
3168 return EFI_INVALID_PARAMETER;
3169 } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
3170 //
3171 // Make sure Hw Attribute is set with NV.
3172 //
3173 return EFI_INVALID_PARAMETER;
3174 } else if ((Attributes & VARIABLE_ATTRIBUTE_AT_AW) != 0) {
3175 if (!mVariableModuleGlobal->VariableGlobal.AuthSupport) {
3176 //
3177 // Not support authenticated variable write.
3178 //
3179 return EFI_UNSUPPORTED;
3180 }
3181 } else if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
3182 if (PcdGet32 (PcdHwErrStorageSize) == 0) {
3183 //
3184 // Not support harware error record variable variable.
3185 //
3186 return EFI_UNSUPPORTED;
3187 }
3188 }
3189
3190 AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
3191
3192 Status = VariableServiceQueryVariableInfoInternal (
3193 Attributes,
3194 MaximumVariableStorageSize,
3195 RemainingVariableStorageSize,
3196 MaximumVariableSize
3197 );
3198
3199 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
3200 return Status;
3201 }
3202
3203 /**
3204 This function reclaims variable storage if free size is below the threshold.
3205
3206 Caution: This function may be invoked at SMM mode.
3207 Care must be taken to make sure not security issue.
3208
3209 **/
3210 VOID
3211 ReclaimForOS (
3212 VOID
3213 )
3214 {
3215 EFI_STATUS Status;
3216 UINTN RemainingCommonRuntimeVariableSpace;
3217 UINTN RemainingHwErrVariableSpace;
3218 STATIC BOOLEAN Reclaimed;
3219
3220 //
3221 // This function will be called only once at EndOfDxe or ReadyToBoot event.
3222 //
3223 if (Reclaimed) {
3224 return;
3225 }
3226
3227 Reclaimed = TRUE;
3228
3229 Status = EFI_SUCCESS;
3230
3231 if (mVariableModuleGlobal->CommonRuntimeVariableSpace < mVariableModuleGlobal->CommonVariableTotalSize) {
3232 RemainingCommonRuntimeVariableSpace = 0;
3233 } else {
3234 RemainingCommonRuntimeVariableSpace = mVariableModuleGlobal->CommonRuntimeVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;
3235 }
3236
3237 RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;
3238
3239 //
3240 // Check if the free area is below a threshold.
3241 //
3242 if (((RemainingCommonRuntimeVariableSpace < mVariableModuleGlobal->MaxVariableSize) ||
3243 (RemainingCommonRuntimeVariableSpace < mVariableModuleGlobal->MaxAuthVariableSize)) ||
3244 ((PcdGet32 (PcdHwErrStorageSize) != 0) &&
3245 (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize))))
3246 {
3247 Status = Reclaim (
3248 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
3249 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
3250 FALSE,
3251 NULL,
3252 NULL,
3253 0
3254 );
3255 ASSERT_EFI_ERROR (Status);
3256 }
3257 }
3258
3259 /**
3260 Get maximum variable size, covering both non-volatile and volatile variables.
3261
3262 @return Maximum variable size.
3263
3264 **/
3265 UINTN
3266 GetMaxVariableSize (
3267 VOID
3268 )
3269 {
3270 UINTN MaxVariableSize;
3271
3272 MaxVariableSize = GetNonVolatileMaxVariableSize ();
3273 //
3274 // The condition below fails implicitly if PcdMaxVolatileVariableSize equals
3275 // the default zero value.
3276 //
3277 if (MaxVariableSize < PcdGet32 (PcdMaxVolatileVariableSize)) {
3278 MaxVariableSize = PcdGet32 (PcdMaxVolatileVariableSize);
3279 }
3280
3281 return MaxVariableSize;
3282 }
3283
3284 /**
3285 Flush the HOB variable to flash.
3286
3287 @param[in] VariableName Name of variable has been updated or deleted.
3288 @param[in] VendorGuid Guid of variable has been updated or deleted.
3289
3290 **/
3291 VOID
3292 FlushHobVariableToFlash (
3293 IN CHAR16 *VariableName,
3294 IN EFI_GUID *VendorGuid
3295 )
3296 {
3297 EFI_STATUS Status;
3298 VARIABLE_STORE_HEADER *VariableStoreHeader;
3299 VARIABLE_HEADER *Variable;
3300 VOID *VariableData;
3301 VARIABLE_POINTER_TRACK VariablePtrTrack;
3302 BOOLEAN ErrorFlag;
3303 BOOLEAN AuthFormat;
3304
3305 ErrorFlag = FALSE;
3306 AuthFormat = mVariableModuleGlobal->VariableGlobal.AuthFormat;
3307
3308 //
3309 // Flush the HOB variable to flash.
3310 //
3311 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {
3312 VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase;
3313 //
3314 // Set HobVariableBase to 0, it can avoid SetVariable to call back.
3315 //
3316 mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;
3317 for ( Variable = GetStartPointer (VariableStoreHeader)
3318 ; IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))
3319 ; Variable = GetNextVariablePtr (Variable, AuthFormat)
3320 )
3321 {
3322 if (Variable->State != VAR_ADDED) {
3323 //
3324 // The HOB variable has been set to DELETED state in local.
3325 //
3326 continue;
3327 }
3328
3329 ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0);
3330 if ((VendorGuid == NULL) || (VariableName == NULL) ||
3331 !CompareGuid (VendorGuid, GetVendorGuidPtr (Variable, AuthFormat)) ||
3332 (StrCmp (VariableName, GetVariableNamePtr (Variable, AuthFormat)) != 0))
3333 {
3334 VariableData = GetVariableDataPtr (Variable, AuthFormat);
3335 FindVariable (
3336 GetVariableNamePtr (Variable, AuthFormat),
3337 GetVendorGuidPtr (Variable, AuthFormat),
3338 &VariablePtrTrack,
3339 &mVariableModuleGlobal->VariableGlobal,
3340 FALSE
3341 );
3342 Status = UpdateVariable (
3343 GetVariableNamePtr (Variable, AuthFormat),
3344 GetVendorGuidPtr (Variable, AuthFormat),
3345 VariableData,
3346 DataSizeOfVariable (Variable, AuthFormat),
3347 Variable->Attributes,
3348 0,
3349 0,
3350 &VariablePtrTrack,
3351 NULL
3352 );
3353 DEBUG ((
3354 DEBUG_INFO,
3355 "Variable driver flush the HOB variable to flash: %g %s %r\n",
3356 GetVendorGuidPtr (Variable, AuthFormat),
3357 GetVariableNamePtr (Variable, AuthFormat),
3358 Status
3359 ));
3360 } else {
3361 //
3362 // The updated or deleted variable is matched with this HOB variable.
3363 // Don't break here because we will try to set other HOB variables
3364 // since this variable could be set successfully.
3365 //
3366 Status = EFI_SUCCESS;
3367 }
3368
3369 if (!EFI_ERROR (Status)) {
3370 //
3371 // If set variable successful, or the updated or deleted variable is matched with the HOB variable,
3372 // set the HOB variable to DELETED state in local.
3373 //
3374 DEBUG ((
3375 DEBUG_INFO,
3376 "Variable driver set the HOB variable to DELETED state in local: %g %s\n",
3377 GetVendorGuidPtr (Variable, AuthFormat),
3378 GetVariableNamePtr (Variable, AuthFormat)
3379 ));
3380 Variable->State &= VAR_DELETED;
3381 } else {
3382 ErrorFlag = TRUE;
3383 }
3384 }
3385
3386 if (mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache.Store != NULL) {
3387 Status = SynchronizeRuntimeVariableCache (
3388 &mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache,
3389 0,
3390 mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.VariableRuntimeHobCache.Store->Size
3391 );
3392 ASSERT_EFI_ERROR (Status);
3393 }
3394
3395 if (ErrorFlag) {
3396 //
3397 // We still have HOB variable(s) not flushed in flash.
3398 //
3399 mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)VariableStoreHeader;
3400 } else {
3401 //
3402 // All HOB variables have been flushed in flash.
3403 //
3404 DEBUG ((DEBUG_INFO, "Variable driver: all HOB variables have been flushed in flash.\n"));
3405 if (mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.HobFlushComplete != NULL) {
3406 *(mVariableModuleGlobal->VariableGlobal.VariableRuntimeCacheContext.HobFlushComplete) = TRUE;
3407 }
3408
3409 if (!AtRuntime ()) {
3410 FreePool ((VOID *)VariableStoreHeader);
3411 }
3412 }
3413 }
3414 }
3415
3416 /**
3417 Initializes variable write service.
3418
3419 @retval EFI_SUCCESS Function successfully executed.
3420 @retval Others Fail to initialize the variable service.
3421
3422 **/
3423 EFI_STATUS
3424 VariableWriteServiceInitialize (
3425 VOID
3426 )
3427 {
3428 EFI_STATUS Status;
3429 UINTN Index;
3430 UINT8 Data;
3431 VARIABLE_ENTRY_PROPERTY *VariableEntry;
3432
3433 AcquireLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
3434
3435 //
3436 // Check if the free area is really free.
3437 //
3438 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < mNvVariableCache->Size; Index++) {
3439 Data = ((UINT8 *)mNvVariableCache)[Index];
3440 if (Data != 0xff) {
3441 //
3442 // There must be something wrong in variable store, do reclaim operation.
3443 //
3444 Status = Reclaim (
3445 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,
3446 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
3447 FALSE,
3448 NULL,
3449 NULL,
3450 0
3451 );
3452 if (EFI_ERROR (Status)) {
3453 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
3454 return Status;
3455 }
3456
3457 break;
3458 }
3459 }
3460
3461 FlushHobVariableToFlash (NULL, NULL);
3462
3463 Status = EFI_SUCCESS;
3464 ZeroMem (&mAuthContextOut, sizeof (mAuthContextOut));
3465 if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
3466 //
3467 // Authenticated variable initialize.
3468 //
3469 mAuthContextIn.StructSize = sizeof (AUTH_VAR_LIB_CONTEXT_IN);
3470 mAuthContextIn.MaxAuthVariableSize = mVariableModuleGlobal->MaxAuthVariableSize -
3471 GetVariableHeaderSize (mVariableModuleGlobal->VariableGlobal.AuthFormat);
3472 Status = AuthVariableLibInitialize (&mAuthContextIn, &mAuthContextOut);
3473 if (!EFI_ERROR (Status)) {
3474 DEBUG ((DEBUG_INFO, "Variable driver will work with auth variable support!\n"));
3475 mVariableModuleGlobal->VariableGlobal.AuthSupport = TRUE;
3476 if (mAuthContextOut.AuthVarEntry != NULL) {
3477 for (Index = 0; Index < mAuthContextOut.AuthVarEntryCount; Index++) {
3478 VariableEntry = &mAuthContextOut.AuthVarEntry[Index];
3479 Status = VarCheckLibVariablePropertySet (
3480 VariableEntry->Name,
3481 VariableEntry->Guid,
3482 &VariableEntry->VariableProperty
3483 );
3484 ASSERT_EFI_ERROR (Status);
3485 }
3486 }
3487 } else if (Status == EFI_UNSUPPORTED) {
3488 DEBUG ((DEBUG_INFO, "NOTICE - AuthVariableLibInitialize() returns %r!\n", Status));
3489 DEBUG ((DEBUG_INFO, "Variable driver will continue to work without auth variable support!\n"));
3490 mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE;
3491 Status = EFI_SUCCESS;
3492 }
3493 }
3494
3495 if (!EFI_ERROR (Status)) {
3496 for (Index = 0; Index < ARRAY_SIZE (mVariableEntryProperty); Index++) {
3497 VariableEntry = &mVariableEntryProperty[Index];
3498 Status = VarCheckLibVariablePropertySet (VariableEntry->Name, VariableEntry->Guid, &VariableEntry->VariableProperty);
3499 ASSERT_EFI_ERROR (Status);
3500 }
3501 }
3502
3503 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);
3504
3505 //
3506 // Initialize MOR Lock variable.
3507 //
3508 MorLockInit ();
3509
3510 return Status;
3511 }
3512
3513 /**
3514 Convert normal variable storage to the allocated auth variable storage.
3515
3516 @param[in] NormalVarStorage Pointer to the normal variable storage header
3517
3518 @retval the allocated auth variable storage
3519 **/
3520 VOID *
3521 ConvertNormalVarStorageToAuthVarStorage (
3522 VARIABLE_STORE_HEADER *NormalVarStorage
3523 )
3524 {
3525 VARIABLE_HEADER *StartPtr;
3526 UINT8 *NextPtr;
3527 VARIABLE_HEADER *EndPtr;
3528 UINTN AuthVarStroageSize;
3529 AUTHENTICATED_VARIABLE_HEADER *AuthStartPtr;
3530 VARIABLE_STORE_HEADER *AuthVarStorage;
3531
3532 AuthVarStroageSize = sizeof (VARIABLE_STORE_HEADER);
3533 //
3534 // Set AuthFormat as FALSE for normal variable storage
3535 //
3536 mVariableModuleGlobal->VariableGlobal.AuthFormat = FALSE;
3537
3538 //
3539 // Calculate Auth Variable Storage Size
3540 //
3541 StartPtr = GetStartPointer (NormalVarStorage);
3542 EndPtr = GetEndPointer (NormalVarStorage);
3543 while (StartPtr < EndPtr) {
3544 if (StartPtr->State == VAR_ADDED) {
3545 AuthVarStroageSize = HEADER_ALIGN (AuthVarStroageSize);
3546 AuthVarStroageSize += sizeof (AUTHENTICATED_VARIABLE_HEADER);
3547 AuthVarStroageSize += StartPtr->NameSize + GET_PAD_SIZE (StartPtr->NameSize);
3548 AuthVarStroageSize += StartPtr->DataSize + GET_PAD_SIZE (StartPtr->DataSize);
3549 }
3550
3551 StartPtr = GetNextVariablePtr (StartPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
3552 }
3553
3554 //
3555 // Allocate Runtime memory for Auth Variable Storage
3556 //
3557 AuthVarStorage = AllocateRuntimeZeroPool (AuthVarStroageSize);
3558 ASSERT (AuthVarStorage != NULL);
3559 if (AuthVarStorage == NULL) {
3560 return NULL;
3561 }
3562
3563 //
3564 // Copy Variable from Normal storage to Auth storage
3565 //
3566 StartPtr = GetStartPointer (NormalVarStorage);
3567 EndPtr = GetEndPointer (NormalVarStorage);
3568 AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *)GetStartPointer (AuthVarStorage);
3569 while (StartPtr < EndPtr) {
3570 if (StartPtr->State == VAR_ADDED) {
3571 AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *)HEADER_ALIGN (AuthStartPtr);
3572 //
3573 // Copy Variable Header
3574 //
3575 AuthStartPtr->StartId = StartPtr->StartId;
3576 AuthStartPtr->State = StartPtr->State;
3577 AuthStartPtr->Attributes = StartPtr->Attributes;
3578 AuthStartPtr->NameSize = StartPtr->NameSize;
3579 AuthStartPtr->DataSize = StartPtr->DataSize;
3580 CopyGuid (&AuthStartPtr->VendorGuid, &StartPtr->VendorGuid);
3581 //
3582 // Copy Variable Name
3583 //
3584 NextPtr = (UINT8 *)(AuthStartPtr + 1);
3585 CopyMem (
3586 NextPtr,
3587 GetVariableNamePtr (StartPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat),
3588 AuthStartPtr->NameSize
3589 );
3590 //
3591 // Copy Variable Data
3592 //
3593 NextPtr = NextPtr + AuthStartPtr->NameSize + GET_PAD_SIZE (AuthStartPtr->NameSize);
3594 CopyMem (NextPtr, GetVariableDataPtr (StartPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat), AuthStartPtr->DataSize);
3595 //
3596 // Go to next variable
3597 //
3598 AuthStartPtr = (AUTHENTICATED_VARIABLE_HEADER *)(NextPtr + AuthStartPtr->DataSize + GET_PAD_SIZE (AuthStartPtr->DataSize));
3599 }
3600
3601 StartPtr = GetNextVariablePtr (StartPtr, mVariableModuleGlobal->VariableGlobal.AuthFormat);
3602 }
3603
3604 //
3605 // Update Auth Storage Header
3606 //
3607 AuthVarStorage->Format = NormalVarStorage->Format;
3608 AuthVarStorage->State = NormalVarStorage->State;
3609 AuthVarStorage->Size = (UINT32)((UINTN)AuthStartPtr - (UINTN)AuthVarStorage);
3610 CopyGuid (&AuthVarStorage->Signature, &gEfiAuthenticatedVariableGuid);
3611 ASSERT (AuthVarStorage->Size <= AuthVarStroageSize);
3612
3613 //
3614 // Restore AuthFormat
3615 //
3616 mVariableModuleGlobal->VariableGlobal.AuthFormat = TRUE;
3617 return AuthVarStorage;
3618 }
3619
3620 /**
3621 Get HOB variable store.
3622
3623 @param[in] VariableGuid NV variable store signature.
3624
3625 @retval EFI_SUCCESS Function successfully executed.
3626 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
3627
3628 **/
3629 EFI_STATUS
3630 GetHobVariableStore (
3631 IN EFI_GUID *VariableGuid
3632 )
3633 {
3634 VARIABLE_STORE_HEADER *VariableStoreHeader;
3635 UINT64 VariableStoreLength;
3636 EFI_HOB_GUID_TYPE *GuidHob;
3637 BOOLEAN NeedConvertNormalToAuth;
3638
3639 //
3640 // Make sure there is no more than one Variable HOB.
3641 //
3642 DEBUG_CODE_BEGIN ();
3643 GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);
3644 if (GuidHob != NULL) {
3645 if ((GetNextGuidHob (&gEfiAuthenticatedVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
3646 DEBUG ((DEBUG_ERROR, "ERROR: Found two Auth Variable HOBs\n"));
3647 ASSERT (FALSE);
3648 } else if (GetFirstGuidHob (&gEfiVariableGuid) != NULL) {
3649 DEBUG ((DEBUG_ERROR, "ERROR: Found one Auth + one Normal Variable HOBs\n"));
3650 ASSERT (FALSE);
3651 }
3652 } else {
3653 GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
3654 if (GuidHob != NULL) {
3655 if ((GetNextGuidHob (&gEfiVariableGuid, GET_NEXT_HOB (GuidHob)) != NULL)) {
3656 DEBUG ((DEBUG_ERROR, "ERROR: Found two Normal Variable HOBs\n"));
3657 ASSERT (FALSE);
3658 }
3659 }
3660 }
3661
3662 DEBUG_CODE_END ();
3663
3664 //
3665 // Combinations supported:
3666 // 1. Normal NV variable store +
3667 // Normal HOB variable store
3668 // 2. Auth NV variable store +
3669 // Auth HOB variable store
3670 // 3. Auth NV variable store +
3671 // Normal HOB variable store (code will convert it to Auth Format)
3672 //
3673 NeedConvertNormalToAuth = FALSE;
3674 GuidHob = GetFirstGuidHob (VariableGuid);
3675 if ((GuidHob == NULL) && (VariableGuid == &gEfiAuthenticatedVariableGuid)) {
3676 //
3677 // Try getting it from normal variable HOB
3678 //
3679 GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
3680 NeedConvertNormalToAuth = TRUE;
3681 }
3682
3683 if (GuidHob != NULL) {
3684 VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob);
3685 VariableStoreLength = GuidHob->Header.HobLength - sizeof (EFI_HOB_GUID_TYPE);
3686 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
3687 if (!NeedConvertNormalToAuth) {
3688 mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateRuntimeCopyPool ((UINTN)VariableStoreLength, (VOID *)VariableStoreHeader);
3689 } else {
3690 mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)ConvertNormalVarStorageToAuthVarStorage ((VOID *)VariableStoreHeader);
3691 }
3692
3693 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) {
3694 return EFI_OUT_OF_RESOURCES;
3695 }
3696 } else {
3697 DEBUG ((DEBUG_ERROR, "HOB Variable Store header is corrupted!\n"));
3698 }
3699 }
3700
3701 return EFI_SUCCESS;
3702 }
3703
3704 /**
3705 Initializes variable store area for non-volatile and volatile variable.
3706
3707 @retval EFI_SUCCESS Function successfully executed.
3708 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
3709
3710 **/
3711 EFI_STATUS
3712 VariableCommonInitialize (
3713 VOID
3714 )
3715 {
3716 EFI_STATUS Status;
3717 VARIABLE_STORE_HEADER *VolatileVariableStore;
3718 UINTN ScratchSize;
3719 EFI_GUID *VariableGuid;
3720
3721 //
3722 // Allocate runtime memory for variable driver global structure.
3723 //
3724 mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL));
3725 if (mVariableModuleGlobal == NULL) {
3726 return EFI_OUT_OF_RESOURCES;
3727 }
3728
3729 InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);
3730
3731 //
3732 // Init non-volatile variable store.
3733 //
3734 Status = InitNonVolatileVariableStore ();
3735 if (EFI_ERROR (Status)) {
3736 FreePool (mVariableModuleGlobal);
3737 return Status;
3738 }
3739
3740 //
3741 // mVariableModuleGlobal->VariableGlobal.AuthFormat
3742 // has been initialized in InitNonVolatileVariableStore().
3743 //
3744 if (mVariableModuleGlobal->VariableGlobal.AuthFormat) {
3745 DEBUG ((DEBUG_INFO, "Variable driver will work with auth variable format!\n"));
3746 //
3747 // Set AuthSupport to FALSE first, VariableWriteServiceInitialize() will initialize it.
3748 //
3749 mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE;
3750 VariableGuid = &gEfiAuthenticatedVariableGuid;
3751 } else {
3752 DEBUG ((DEBUG_INFO, "Variable driver will work without auth variable support!\n"));
3753 mVariableModuleGlobal->VariableGlobal.AuthSupport = FALSE;
3754 VariableGuid = &gEfiVariableGuid;
3755 }
3756
3757 //
3758 // Get HOB variable store.
3759 //
3760 Status = GetHobVariableStore (VariableGuid);
3761 if (EFI_ERROR (Status)) {
3762 if (mNvFvHeaderCache != NULL) {
3763 FreePool (mNvFvHeaderCache);
3764 }
3765
3766 FreePool (mVariableModuleGlobal);
3767 return Status;
3768 }
3769
3770 mVariableModuleGlobal->MaxVolatileVariableSize = ((PcdGet32 (PcdMaxVolatileVariableSize) != 0) ?
3771 PcdGet32 (PcdMaxVolatileVariableSize) :
3772 mVariableModuleGlobal->MaxVariableSize
3773 );
3774 //
3775 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.
3776 //
3777 ScratchSize = GetMaxVariableSize ();
3778 mVariableModuleGlobal->ScratchBufferSize = ScratchSize;
3779 VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);
3780 if (VolatileVariableStore == NULL) {
3781 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {
3782 FreePool ((VOID *)(UINTN)mVariableModuleGlobal->VariableGlobal.HobVariableBase);
3783 }
3784
3785 if (mNvFvHeaderCache != NULL) {
3786 FreePool (mNvFvHeaderCache);
3787 }
3788
3789 FreePool (mVariableModuleGlobal);
3790 return EFI_OUT_OF_RESOURCES;
3791 }
3792
3793 SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);
3794
3795 //
3796 // Initialize Variable Specific Data.
3797 //
3798 mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS)(UINTN)VolatileVariableStore;
3799 mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN)GetStartPointer (VolatileVariableStore) - (UINTN)VolatileVariableStore;
3800
3801 CopyGuid (&VolatileVariableStore->Signature, VariableGuid);
3802 VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize);
3803 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;
3804 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;
3805 VolatileVariableStore->Reserved = 0;
3806 VolatileVariableStore->Reserved1 = 0;
3807
3808 return EFI_SUCCESS;
3809 }
3810
3811 /**
3812 Get the proper fvb handle and/or fvb protocol by the given Flash address.
3813
3814 @param[in] Address The Flash address.
3815 @param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle.
3816 @param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol.
3817
3818 **/
3819 EFI_STATUS
3820 GetFvbInfoByAddress (
3821 IN EFI_PHYSICAL_ADDRESS Address,
3822 OUT EFI_HANDLE *FvbHandle OPTIONAL,
3823 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvbProtocol OPTIONAL
3824 )
3825 {
3826 EFI_STATUS Status;
3827 EFI_HANDLE *HandleBuffer;
3828 UINTN HandleCount;
3829 UINTN Index;
3830 EFI_PHYSICAL_ADDRESS FvbBaseAddress;
3831 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
3832 EFI_FVB_ATTRIBUTES_2 Attributes;
3833 UINTN BlockSize;
3834 UINTN NumberOfBlocks;
3835
3836 HandleBuffer = NULL;
3837 //
3838 // Get all FVB handles.
3839 //
3840 Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);
3841 if (EFI_ERROR (Status)) {
3842 return EFI_NOT_FOUND;
3843 }
3844
3845 //
3846 // Get the FVB to access variable store.
3847 //
3848 Fvb = NULL;
3849 for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {
3850 Status = GetFvbByHandle (HandleBuffer[Index], &Fvb);
3851 if (EFI_ERROR (Status)) {
3852 Status = EFI_NOT_FOUND;
3853 break;
3854 }
3855
3856 //
3857 // Ensure this FVB protocol supported Write operation.
3858 //
3859 Status = Fvb->GetAttributes (Fvb, &Attributes);
3860 if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
3861 continue;
3862 }
3863
3864 //
3865 // Compare the address and select the right one.
3866 //
3867 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);
3868 if (EFI_ERROR (Status)) {
3869 continue;
3870 }
3871
3872 //
3873 // Assume one FVB has one type of BlockSize.
3874 //
3875 Status = Fvb->GetBlockSize (Fvb, 0, &BlockSize, &NumberOfBlocks);
3876 if (EFI_ERROR (Status)) {
3877 continue;
3878 }
3879
3880 if ((Address >= FvbBaseAddress) && (Address < (FvbBaseAddress + BlockSize * NumberOfBlocks))) {
3881 if (FvbHandle != NULL) {
3882 *FvbHandle = HandleBuffer[Index];
3883 }
3884
3885 if (FvbProtocol != NULL) {
3886 *FvbProtocol = Fvb;
3887 }
3888
3889 Status = EFI_SUCCESS;
3890 break;
3891 }
3892 }
3893
3894 FreePool (HandleBuffer);
3895
3896 if (Fvb == NULL) {
3897 Status = EFI_NOT_FOUND;
3898 }
3899
3900 return Status;
3901 }