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