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