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