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