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