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