]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
Nt32Pkg: Forbid creation of non-spec variables in EFI_GLOBAL_VARIABLE namespace.
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / Variable.c
CommitLineData
052ad7e1 1/** @file\r
504214c4 2\r
021a1af9 3 The common variable operation routines shared by DXE_RUNTIME variable \r
8a2d4996 4 module and DXE_SMM variable module.\r
052ad7e1 5 \r
23b06935 6Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>\r
e5eed7d3 7This program and the accompanying materials \r
504214c4
LG
8are licensed and made available under the terms and conditions of the BSD License \r
9which accompanies this distribution. The full text of the license may be found at \r
10http://opensource.org/licenses/bsd-license.php \r
11\r
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
8d3a5c82 14\r
052ad7e1 15**/\r
8d3a5c82 16\r
8d3a5c82 17#include "Variable.h"\r
33a5a666 18\r
7800593d 19VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;\r
8d3a5c82 20\r
7c80e839 21///\r
8a2d4996 22/// Define a memory cache that improves the search performance for a variable.\r
7c80e839 23///\r
ff843847 24VARIABLE_STORE_HEADER *mNvVariableCache = NULL;\r
aa79b0b3 25\r
8a2d4996 26///\r
27/// The memory entry used for variable statistics data.\r
28///\r
ff843847
RN
29VARIABLE_INFO_ENTRY *gVariableInfo = NULL;\r
30\r
31///\r
32/// The list to store the variables which cannot be set after the EFI_END_OF_DXE_EVENT_GROUP_GUID\r
33/// or EVT_GROUP_READY_TO_BOOT event.\r
34///\r
35LIST_ENTRY mLockedVariableList = INITIALIZE_LIST_HEAD_VARIABLE (mLockedVariableList);\r
36\r
37///\r
38/// The flag to indicate whether the platform has left the DXE phase of execution.\r
39///\r
40BOOLEAN mEndOfDxe = FALSE;\r
41\r
42///\r
43/// The flag to indicate whether the variable storage locking is enabled.\r
44///\r
45BOOLEAN mEnableLocking = TRUE;\r
8d3a5c82 46\r
33a5a666 47\r
052ad7e1
A
48/**\r
49 Routine used to track statistical information about variable usage. \r
50 The data is stored in the EFI system table so it can be accessed later.\r
51 VariableInfo.efi can dump out the table. Only Boot Services variable \r
52 accesses are tracked by this code. The PcdVariableCollectStatistics\r
53 build flag controls if this feature is enabled. \r
54\r
55 A read that hits in the cache will have Read and Cache true for \r
56 the transaction. Data is allocated by this routine, but never\r
57 freed.\r
58\r
8a2d4996 59 @param[in] VariableName Name of the Variable to track.\r
60 @param[in] VendorGuid Guid of the Variable to track.\r
61 @param[in] Volatile TRUE if volatile FALSE if non-volatile.\r
62 @param[in] Read TRUE if GetVariable() was called.\r
63 @param[in] Write TRUE if SetVariable() was called.\r
64 @param[in] Delete TRUE if deleted via SetVariable().\r
052ad7e1
A
65 @param[in] Cache TRUE for a cache hit.\r
66\r
67**/\r
33a5a666
A
68VOID\r
69UpdateVariableInfo (\r
70 IN CHAR16 *VariableName,\r
71 IN EFI_GUID *VendorGuid,\r
72 IN BOOLEAN Volatile,\r
73 IN BOOLEAN Read,\r
74 IN BOOLEAN Write,\r
75 IN BOOLEAN Delete,\r
76 IN BOOLEAN Cache\r
77 )\r
78{\r
79 VARIABLE_INFO_ENTRY *Entry;\r
80\r
81 if (FeaturePcdGet (PcdVariableCollectStatistics)) {\r
82\r
8a2d4996 83 if (AtRuntime ()) {\r
84 // Don't collect statistics at runtime.\r
33a5a666
A
85 return;\r
86 }\r
87\r
88 if (gVariableInfo == NULL) {\r
052ad7e1 89 //\r
8a2d4996 90 // On the first call allocate a entry and place a pointer to it in\r
91 // the EFI System Table.\r
052ad7e1 92 //\r
33a5a666 93 gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
052ad7e1
A
94 ASSERT (gVariableInfo != NULL);\r
95\r
33a5a666 96 CopyGuid (&gVariableInfo->VendorGuid, VendorGuid);\r
bcd7070d 97 gVariableInfo->Name = AllocatePool (StrSize (VariableName));\r
e6c4ef13 98 ASSERT (gVariableInfo->Name != NULL);\r
33a5a666
A
99 StrCpy (gVariableInfo->Name, VariableName);\r
100 gVariableInfo->Volatile = Volatile;\r
33a5a666
A
101 }\r
102\r
103 \r
104 for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) {\r
105 if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {\r
106 if (StrCmp (VariableName, Entry->Name) == 0) {\r
107 if (Read) {\r
108 Entry->ReadCount++;\r
109 }\r
110 if (Write) {\r
111 Entry->WriteCount++;\r
112 }\r
113 if (Delete) {\r
114 Entry->DeleteCount++;\r
115 }\r
116 if (Cache) {\r
117 Entry->CacheCount++;\r
118 }\r
119\r
120 return;\r
121 }\r
122 }\r
123\r
124 if (Entry->Next == NULL) {\r
052ad7e1
A
125 //\r
126 // If the entry is not in the table add it.\r
8a2d4996 127 // Next iteration of the loop will fill in the data.\r
052ad7e1 128 //\r
33a5a666 129 Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
052ad7e1 130 ASSERT (Entry->Next != NULL);\r
33a5a666
A
131\r
132 CopyGuid (&Entry->Next->VendorGuid, VendorGuid);\r
bcd7070d 133 Entry->Next->Name = AllocatePool (StrSize (VariableName));\r
e6c4ef13 134 ASSERT (Entry->Next->Name != NULL);\r
33a5a666
A
135 StrCpy (Entry->Next->Name, VariableName);\r
136 Entry->Next->Volatile = Volatile;\r
137 }\r
138\r
139 }\r
140 }\r
141}\r
142\r
143\r
7c80e839 144/**\r
8d3a5c82 145\r
146 This code checks if variable header is valid or not.\r
147\r
7c80e839 148 @param Variable Pointer to the Variable Header.\r
8d3a5c82 149\r
7c80e839 150 @retval TRUE Variable header is valid.\r
151 @retval FALSE Variable header is not valid.\r
8d3a5c82 152\r
7c80e839 153**/\r
154BOOLEAN\r
155IsValidVariableHeader (\r
156 IN VARIABLE_HEADER *Variable\r
157 )\r
8d3a5c82 158{\r
fdb7765f 159 if (Variable == NULL || Variable->StartId != VARIABLE_DATA) {\r
8d3a5c82 160 return FALSE;\r
161 }\r
162\r
163 return TRUE;\r
164}\r
165\r
052ad7e1 166\r
7c80e839 167/**\r
168\r
169 This function writes data to the FWH at the correct LBA even if the LBAs\r
170 are fragmented.\r
171\r
8a2d4996 172 @param Global Pointer to VARAIBLE_GLOBAL structure.\r
173 @param Volatile Point out the Variable is Volatile or Non-Volatile.\r
174 @param SetByIndex TRUE if target pointer is given as index.\r
175 FALSE if target pointer is absolute.\r
176 @param Fvb Pointer to the writable FVB protocol.\r
7c80e839 177 @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER\r
8a2d4996 178 structure.\r
179 @param DataSize Size of data to be written.\r
180 @param Buffer Pointer to the buffer from which data is written.\r
7c80e839 181\r
8a2d4996 182 @retval EFI_INVALID_PARAMETER Parameters not valid.\r
183 @retval EFI_SUCCESS Variable store successfully updated.\r
7c80e839 184\r
185**/\r
8d3a5c82 186EFI_STATUS\r
8d3a5c82 187UpdateVariableStore (\r
8a9e0b72 188 IN VARIABLE_GLOBAL *Global,\r
189 IN BOOLEAN Volatile,\r
190 IN BOOLEAN SetByIndex,\r
191 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,\r
192 IN UINTN DataPtrIndex,\r
193 IN UINT32 DataSize,\r
194 IN UINT8 *Buffer\r
8d3a5c82 195 )\r
8d3a5c82 196{\r
197 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
198 UINTN BlockIndex2;\r
199 UINTN LinearOffset;\r
200 UINTN CurrWriteSize;\r
201 UINTN CurrWritePtr;\r
202 UINT8 *CurrBuffer;\r
203 EFI_LBA LbaNumber;\r
204 UINTN Size;\r
205 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
206 VARIABLE_STORE_HEADER *VolatileBase;\r
207 EFI_PHYSICAL_ADDRESS FvVolHdr;\r
208 EFI_PHYSICAL_ADDRESS DataPtr;\r
209 EFI_STATUS Status;\r
210\r
211 FwVolHeader = NULL;\r
212 DataPtr = DataPtrIndex;\r
213\r
214 //\r
8a2d4996 215 // Check if the Data is Volatile.\r
8d3a5c82 216 //\r
217 if (!Volatile) {\r
b59ad751 218 ASSERT (Fvb != NULL);\r
8a9e0b72 219 Status = Fvb->GetPhysicalAddress(Fvb, &FvVolHdr);\r
220 ASSERT_EFI_ERROR (Status);\r
221\r
8d3a5c82 222 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);\r
223 //\r
224 // Data Pointer should point to the actual Address where data is to be\r
8a2d4996 225 // written.\r
8d3a5c82 226 //\r
227 if (SetByIndex) {\r
052ad7e1 228 DataPtr += mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
8d3a5c82 229 }\r
230\r
231 if ((DataPtr + DataSize) >= ((EFI_PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) FwVolHeader + FwVolHeader->FvLength))) {\r
232 return EFI_INVALID_PARAMETER;\r
233 }\r
234 } else {\r
235 //\r
236 // Data Pointer should point to the actual Address where data is to be\r
8a2d4996 237 // written.\r
8d3a5c82 238 //\r
052ad7e1 239 VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
8d3a5c82 240 if (SetByIndex) {\r
052ad7e1 241 DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
8d3a5c82 242 }\r
243\r
244 if ((DataPtr + DataSize) >= ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) {\r
245 return EFI_INVALID_PARAMETER;\r
246 }\r
c6492839 247 \r
248 //\r
249 // If Volatile Variable just do a simple mem copy.\r
250 // \r
251 CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize);\r
8d3a5c82 252 return EFI_SUCCESS;\r
253 }\r
c6492839 254 \r
8d3a5c82 255 //\r
8a2d4996 256 // If we are here we are dealing with Non-Volatile Variables.\r
8d3a5c82 257 //\r
258 LinearOffset = (UINTN) FwVolHeader;\r
259 CurrWritePtr = (UINTN) DataPtr;\r
260 CurrWriteSize = DataSize;\r
261 CurrBuffer = Buffer;\r
262 LbaNumber = 0;\r
263\r
264 if (CurrWritePtr < LinearOffset) {\r
265 return EFI_INVALID_PARAMETER;\r
266 }\r
267\r
268 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
269 for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {\r
270 //\r
271 // Check to see if the Variable Writes are spanning through multiple\r
272 // blocks.\r
273 //\r
274 if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) {\r
275 if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {\r
8a9e0b72 276 Status = Fvb->Write (\r
277 Fvb,\r
8d3a5c82 278 LbaNumber,\r
279 (UINTN) (CurrWritePtr - LinearOffset),\r
280 &CurrWriteSize,\r
281 CurrBuffer\r
282 );\r
8a9e0b72 283 return Status;\r
8d3a5c82 284 } else {\r
285 Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);\r
8a9e0b72 286 Status = Fvb->Write (\r
287 Fvb,\r
8d3a5c82 288 LbaNumber,\r
289 (UINTN) (CurrWritePtr - LinearOffset),\r
290 &Size,\r
291 CurrBuffer\r
292 );\r
293 if (EFI_ERROR (Status)) {\r
294 return Status;\r
295 }\r
296\r
297 CurrWritePtr = LinearOffset + PtrBlockMapEntry->Length;\r
298 CurrBuffer = CurrBuffer + Size;\r
299 CurrWriteSize = CurrWriteSize - Size;\r
300 }\r
301 }\r
302\r
303 LinearOffset += PtrBlockMapEntry->Length;\r
304 LbaNumber++;\r
305 }\r
306 }\r
307\r
308 return EFI_SUCCESS;\r
309}\r
310\r
052ad7e1 311\r
7c80e839 312/**\r
8d3a5c82 313\r
314 This code gets the current status of Variable Store.\r
315\r
7c80e839 316 @param VarStoreHeader Pointer to the Variable Store Header.\r
8d3a5c82 317\r
8a2d4996 318 @retval EfiRaw Variable store status is raw.\r
319 @retval EfiValid Variable store status is valid.\r
320 @retval EfiInvalid Variable store status is invalid.\r
8d3a5c82 321\r
7c80e839 322**/\r
323VARIABLE_STORE_STATUS\r
324GetVariableStoreStatus (\r
325 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
326 )\r
8d3a5c82 327{\r
3709c4cd 328 if (CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid) &&\r
8d3a5c82 329 VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&\r
330 VarStoreHeader->State == VARIABLE_STORE_HEALTHY\r
331 ) {\r
332\r
333 return EfiValid;\r
3709c4cd 334 } else if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff &&\r
335 ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff &&\r
336 ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff &&\r
337 ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff &&\r
338 VarStoreHeader->Size == 0xffffffff &&\r
339 VarStoreHeader->Format == 0xff &&\r
340 VarStoreHeader->State == 0xff\r
8d3a5c82 341 ) {\r
342\r
343 return EfiRaw;\r
344 } else {\r
345 return EfiInvalid;\r
346 }\r
347}\r
348\r
130e2569 349\r
7c80e839 350/**\r
130e2569 351\r
352 This code gets the size of name of variable.\r
353\r
8a2d4996 354 @param Variable Pointer to the Variable Header.\r
130e2569 355\r
8a2d4996 356 @return UINTN Size of variable in bytes.\r
130e2569 357\r
7c80e839 358**/\r
359UINTN\r
360NameSizeOfVariable (\r
361 IN VARIABLE_HEADER *Variable\r
362 )\r
130e2569 363{\r
364 if (Variable->State == (UINT8) (-1) ||\r
7c80e839 365 Variable->DataSize == (UINT32) (-1) ||\r
366 Variable->NameSize == (UINT32) (-1) ||\r
367 Variable->Attributes == (UINT32) (-1)) {\r
130e2569 368 return 0;\r
369 }\r
370 return (UINTN) Variable->NameSize;\r
371}\r
372\r
7c80e839 373/**\r
130e2569 374\r
7c80e839 375 This code gets the size of variable data.\r
130e2569 376\r
8a2d4996 377 @param Variable Pointer to the Variable Header.\r
130e2569 378\r
8a2d4996 379 @return Size of variable in bytes.\r
130e2569 380\r
7c80e839 381**/\r
382UINTN\r
383DataSizeOfVariable (\r
384 IN VARIABLE_HEADER *Variable\r
385 )\r
130e2569 386{\r
7c80e839 387 if (Variable->State == (UINT8) (-1) ||\r
388 Variable->DataSize == (UINT32) (-1) ||\r
389 Variable->NameSize == (UINT32) (-1) ||\r
390 Variable->Attributes == (UINT32) (-1)) {\r
130e2569 391 return 0;\r
392 }\r
393 return (UINTN) Variable->DataSize;\r
394}\r
395\r
7c80e839 396/**\r
130e2569 397\r
398 This code gets the pointer to the variable name.\r
399\r
8a2d4996 400 @param Variable Pointer to the Variable Header.\r
130e2569 401\r
8a2d4996 402 @return Pointer to Variable Name which is Unicode encoding.\r
130e2569 403\r
7c80e839 404**/\r
405CHAR16 *\r
406GetVariableNamePtr (\r
407 IN VARIABLE_HEADER *Variable\r
408 )\r
130e2569 409{\r
410\r
411 return (CHAR16 *) (Variable + 1);\r
412}\r
413\r
7c80e839 414/**\r
8d3a5c82 415\r
416 This code gets the pointer to the variable data.\r
417\r
8a2d4996 418 @param Variable Pointer to the Variable Header.\r
8d3a5c82 419\r
8a2d4996 420 @return Pointer to Variable Data.\r
8d3a5c82 421\r
7c80e839 422**/\r
423UINT8 *\r
424GetVariableDataPtr (\r
425 IN VARIABLE_HEADER *Variable\r
426 )\r
8d3a5c82 427{\r
130e2569 428 UINTN Value;\r
429 \r
8d3a5c82 430 //\r
8a2d4996 431 // Be careful about pad size for alignment.\r
8d3a5c82 432 //\r
130e2569 433 Value = (UINTN) GetVariableNamePtr (Variable);\r
434 Value += NameSizeOfVariable (Variable);\r
435 Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));\r
436\r
437 return (UINT8 *) Value;\r
8d3a5c82 438}\r
439\r
052ad7e1 440\r
7c80e839 441/**\r
8d3a5c82 442\r
443 This code gets the pointer to the next variable header.\r
444\r
8a2d4996 445 @param Variable Pointer to the Variable Header.\r
8d3a5c82 446\r
8a2d4996 447 @return Pointer to next variable header.\r
8d3a5c82 448\r
7c80e839 449**/\r
450VARIABLE_HEADER *\r
451GetNextVariablePtr (\r
452 IN VARIABLE_HEADER *Variable\r
453 )\r
8d3a5c82 454{\r
130e2569 455 UINTN Value;\r
456\r
8d3a5c82 457 if (!IsValidVariableHeader (Variable)) {\r
458 return NULL;\r
459 }\r
130e2569 460\r
461 Value = (UINTN) GetVariableDataPtr (Variable);\r
462 Value += DataSizeOfVariable (Variable);\r
463 Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));\r
464\r
8d3a5c82 465 //\r
8a2d4996 466 // Be careful about pad size for alignment.\r
8d3a5c82 467 //\r
130e2569 468 return (VARIABLE_HEADER *) HEADER_ALIGN (Value);\r
8d3a5c82 469}\r
470\r
7c80e839 471/**\r
9cad030b 472\r
7c80e839 473 Gets the pointer to the first variable header in given variable store area.\r
9cad030b 474\r
7c80e839 475 @param VarStoreHeader Pointer to the Variable Store Header.\r
9cad030b 476\r
8a2d4996 477 @return Pointer to the first variable header.\r
9cad030b 478\r
7c80e839 479**/\r
480VARIABLE_HEADER *\r
481GetStartPointer (\r
482 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
483 )\r
9cad030b 484{\r
485 //\r
8a2d4996 486 // The end of variable store.\r
9cad030b 487 //\r
488 return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);\r
489}\r
052ad7e1 490\r
7c80e839 491/**\r
8d3a5c82 492\r
7c80e839 493 Gets the pointer to the end of the variable storage area.\r
8d3a5c82 494\r
7c80e839 495 This function gets pointer to the end of the variable storage\r
496 area, according to the input variable store header.\r
8d3a5c82 497\r
8a2d4996 498 @param VarStoreHeader Pointer to the Variable Store Header.\r
8d3a5c82 499\r
8a2d4996 500 @return Pointer to the end of the variable storage area. \r
8d3a5c82 501\r
7c80e839 502**/\r
503VARIABLE_HEADER *\r
504GetEndPointer (\r
505 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
506 )\r
8d3a5c82 507{\r
508 //\r
509 // The end of variable store\r
510 //\r
9cad030b 511 return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);\r
8d3a5c82 512}\r
513\r
052ad7e1 514\r
7c80e839 515/**\r
516\r
517 Variable store garbage collection and reclaim operation.\r
518\r
8a2d4996 519 @param VariableBase Base address of variable store.\r
520 @param LastVariableOffset Offset of last variable.\r
521 @param IsVolatile The variable store is volatile or not;\r
522 if it is non-volatile, need FTW.\r
23b06935 523 @param UpdatingPtrTrack Pointer to updating variable pointer track structure.\r
335e2681 524 @param ReclaimAnyway If TRUE, do reclaim anyway.\r
7c80e839 525\r
526 @return EFI_OUT_OF_RESOURCES\r
527 @return EFI_SUCCESS\r
528 @return Others\r
529\r
530**/\r
8d3a5c82 531EFI_STATUS\r
8d3a5c82 532Reclaim (\r
533 IN EFI_PHYSICAL_ADDRESS VariableBase,\r
534 OUT UINTN *LastVariableOffset,\r
814bae52 535 IN BOOLEAN IsVolatile,\r
23b06935 536 IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack,\r
335e2681 537 IN BOOLEAN ReclaimAnyway\r
8d3a5c82 538 )\r
8d3a5c82 539{\r
540 VARIABLE_HEADER *Variable;\r
814bae52 541 VARIABLE_HEADER *AddedVariable;\r
8d3a5c82 542 VARIABLE_HEADER *NextVariable;\r
814bae52 543 VARIABLE_HEADER *NextAddedVariable;\r
8d3a5c82 544 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
545 UINT8 *ValidBuffer;\r
814bae52 546 UINTN MaximumBufferSize;\r
8d3a5c82 547 UINTN VariableSize;\r
49e70927 548 UINTN VariableNameSize;\r
549 UINTN UpdatingVariableNameSize;\r
814bae52 550 UINTN NameSize;\r
8d3a5c82 551 UINT8 *CurrPtr;\r
814bae52 552 VOID *Point0;\r
553 VOID *Point1;\r
554 BOOLEAN FoundAdded;\r
8d3a5c82 555 EFI_STATUS Status;\r
49e70927 556 CHAR16 *VariableNamePtr;\r
557 CHAR16 *UpdatingVariableNamePtr;\r
8f3a9e58
SZ
558 UINTN CommonVariableTotalSize;\r
559 UINTN HwErrVariableTotalSize;\r
335e2681 560 BOOLEAN NeedDoReclaim;\r
23b06935
SZ
561 VARIABLE_HEADER *UpdatingVariable;\r
562\r
563 UpdatingVariable = NULL;\r
564 if (UpdatingPtrTrack != NULL) {\r
565 UpdatingVariable = UpdatingPtrTrack->CurrPtr;\r
566 }\r
8d3a5c82 567\r
335e2681 568 NeedDoReclaim = FALSE;\r
8d3a5c82 569 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);\r
8f3a9e58
SZ
570\r
571 CommonVariableTotalSize = 0;\r
572 HwErrVariableTotalSize = 0;\r
8d3a5c82 573\r
574 //\r
575 // Start Pointers for the variable.\r
576 //\r
814bae52 577 Variable = GetStartPointer (VariableStoreHeader);\r
578 MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);\r
8d3a5c82 579\r
580 while (IsValidVariableHeader (Variable)) {\r
581 NextVariable = GetNextVariablePtr (Variable);\r
814bae52 582 if (Variable->State == VAR_ADDED || \r
583 Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
584 ) {\r
8d3a5c82 585 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
814bae52 586 MaximumBufferSize += VariableSize;\r
335e2681
SZ
587 } else {\r
588 NeedDoReclaim = TRUE;\r
8d3a5c82 589 }\r
590\r
591 Variable = NextVariable;\r
592 }\r
593\r
335e2681
SZ
594 if (!ReclaimAnyway && !NeedDoReclaim) {\r
595 DEBUG ((EFI_D_INFO, "Variable driver: no DELETED variable found, so no variable space could be reclaimed.\n"));\r
596 return EFI_SUCCESS;\r
597 }\r
598\r
814bae52 599 //\r
600 // Reserve the 1 Bytes with Oxff to identify the \r
601 // end of the variable buffer. \r
602 // \r
603 MaximumBufferSize += 1;\r
604 ValidBuffer = AllocatePool (MaximumBufferSize);\r
8d3a5c82 605 if (ValidBuffer == NULL) {\r
606 return EFI_OUT_OF_RESOURCES;\r
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
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
814bae52 619 // \r
620 Variable = GetStartPointer (VariableStoreHeader);\r
8d3a5c82 621 while (IsValidVariableHeader (Variable)) {\r
622 NextVariable = GetNextVariablePtr (Variable);\r
623 if (Variable->State == VAR_ADDED) {\r
5ead4a07 624 if (UpdatingVariable != NULL) {\r
625 if (UpdatingVariable == Variable) {\r
626 Variable = NextVariable;\r
627 continue;\r
628 }\r
49e70927 629\r
630 VariableNameSize = NameSizeOfVariable(Variable);\r
631 UpdatingVariableNameSize = NameSizeOfVariable(UpdatingVariable);\r
632\r
633 VariableNamePtr = GetVariableNamePtr (Variable);\r
634 UpdatingVariableNamePtr = GetVariableNamePtr (UpdatingVariable);\r
5ead4a07 635 if (CompareGuid (&Variable->VendorGuid, &UpdatingVariable->VendorGuid) &&\r
49e70927 636 VariableNameSize == UpdatingVariableNameSize &&\r
637 CompareMem (VariableNamePtr, UpdatingVariableNamePtr, VariableNameSize) == 0 ) {\r
5ead4a07 638 Variable = NextVariable;\r
639 continue;\r
640 }\r
641 }\r
8d3a5c82 642 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
643 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
644 CurrPtr += VariableSize;\r
2fcdca1d 645 if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
8f3a9e58 646 HwErrVariableTotalSize += VariableSize;\r
2fcdca1d 647 } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
8f3a9e58 648 CommonVariableTotalSize += VariableSize;\r
2fcdca1d 649 }\r
8d3a5c82 650 }\r
8d3a5c82 651 Variable = NextVariable;\r
652 }\r
5ead4a07 653\r
654 //\r
8a2d4996 655 // Reinstall the variable being updated if it is not NULL.\r
5ead4a07 656 //\r
657 if (UpdatingVariable != NULL) {\r
658 VariableSize = (UINTN)(GetNextVariablePtr (UpdatingVariable)) - (UINTN)UpdatingVariable;\r
659 CopyMem (CurrPtr, (UINT8 *) UpdatingVariable, VariableSize);\r
23b06935
SZ
660 UpdatingPtrTrack->CurrPtr = (VARIABLE_HEADER *)((UINTN)UpdatingPtrTrack->StartPtr + ((UINTN)CurrPtr - (UINTN)GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer)));\r
661 UpdatingPtrTrack->InDeletedTransitionPtr = NULL;\r
5ead4a07 662 CurrPtr += VariableSize;\r
2fcdca1d 663 if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
8f3a9e58 664 HwErrVariableTotalSize += VariableSize;\r
2fcdca1d 665 } else if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
8f3a9e58 666 CommonVariableTotalSize += VariableSize;\r
2fcdca1d 667 }\r
5ead4a07 668 }\r
669\r
814bae52 670 //\r
8a2d4996 671 // Reinstall all in delete transition variables.\r
814bae52 672 // \r
673 Variable = GetStartPointer (VariableStoreHeader);\r
674 while (IsValidVariableHeader (Variable)) {\r
675 NextVariable = GetNextVariablePtr (Variable);\r
5ead4a07 676 if (Variable != UpdatingVariable && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
814bae52 677\r
678 //\r
679 // Buffer has cached all ADDED variable. \r
680 // Per IN_DELETED variable, we have to guarantee that\r
681 // no ADDED one in previous buffer. \r
682 // \r
683 \r
684 FoundAdded = FALSE;\r
685 AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
686 while (IsValidVariableHeader (AddedVariable)) {\r
687 NextAddedVariable = GetNextVariablePtr (AddedVariable);\r
688 NameSize = NameSizeOfVariable (AddedVariable);\r
689 if (CompareGuid (&AddedVariable->VendorGuid, &Variable->VendorGuid) &&\r
690 NameSize == NameSizeOfVariable (Variable)\r
691 ) {\r
692 Point0 = (VOID *) GetVariableNamePtr (AddedVariable);\r
693 Point1 = (VOID *) GetVariableNamePtr (Variable);\r
23b06935 694 if (CompareMem (Point0, Point1, NameSize) == 0) {\r
814bae52 695 FoundAdded = TRUE;\r
696 break;\r
697 }\r
698 }\r
699 AddedVariable = NextAddedVariable;\r
700 }\r
701 if (!FoundAdded) {\r
5ead4a07 702 //\r
8a2d4996 703 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.\r
5ead4a07 704 //\r
814bae52 705 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
706 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
5ead4a07 707 ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;\r
814bae52 708 CurrPtr += VariableSize;\r
2fcdca1d 709 if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
8f3a9e58 710 HwErrVariableTotalSize += VariableSize;\r
2fcdca1d 711 } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
8f3a9e58 712 CommonVariableTotalSize += VariableSize;\r
2fcdca1d 713 }\r
814bae52 714 }\r
715 }\r
716\r
717 Variable = NextVariable;\r
718 }\r
8d3a5c82 719\r
720 if (IsVolatile) {\r
721 //\r
8a2d4996 722 // If volatile variable store, just copy valid buffer.\r
8d3a5c82 723 //\r
724 SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);\r
814bae52 725 CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - (UINT8 *) ValidBuffer));\r
8a2d4996 726 Status = EFI_SUCCESS;\r
8d3a5c82 727 } else {\r
728 //\r
729 // If non-volatile variable store, perform FTW here.\r
730 //\r
731 Status = FtwVariableSpace (\r
732 VariableBase,\r
733 ValidBuffer,\r
814bae52 734 (UINTN) (CurrPtr - (UINT8 *) ValidBuffer)\r
8d3a5c82 735 );\r
8a2d4996 736 CopyMem (mNvVariableCache, (CHAR8 *)(UINTN)VariableBase, VariableStoreHeader->Size);\r
8d3a5c82 737 }\r
814bae52 738 if (!EFI_ERROR (Status)) {\r
739 *LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer);\r
8f3a9e58
SZ
740 if (!IsVolatile) {\r
741 mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;\r
742 mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;\r
743 }\r
814bae52 744 } else {\r
8f3a9e58
SZ
745 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);\r
746 while (IsValidVariableHeader (NextVariable)) {\r
747 VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);\r
748 if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
749 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);\r
750 } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
751 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);\r
752 }\r
753\r
754 NextVariable = GetNextVariablePtr (NextVariable);\r
755 }\r
756 *LastVariableOffset = (UINTN) NextVariable - (UINTN) VariableBase;\r
8d3a5c82 757 }\r
758\r
814bae52 759 FreePool (ValidBuffer);\r
760\r
8d3a5c82 761 return Status;\r
762}\r
763\r
0f7aff72
RN
764/**\r
765 Find the variable in the specified variable store.\r
766\r
767 @param VariableName Name of the variable to be found\r
768 @param VendorGuid Vendor GUID to be found.\r
9622df63
SZ
769 @param IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute\r
770 check at runtime when searching variable.\r
0f7aff72
RN
771 @param PtrTrack Variable Track Pointer structure that contains Variable Information.\r
772\r
773 @retval EFI_SUCCESS Variable found successfully\r
774 @retval EFI_NOT_FOUND Variable not found\r
775**/\r
776EFI_STATUS\r
777FindVariableEx (\r
778 IN CHAR16 *VariableName,\r
779 IN EFI_GUID *VendorGuid,\r
9622df63 780 IN BOOLEAN IgnoreRtCheck,\r
0f7aff72
RN
781 IN OUT VARIABLE_POINTER_TRACK *PtrTrack\r
782 )\r
783{\r
784 VARIABLE_HEADER *InDeletedVariable;\r
785 VOID *Point;\r
786\r
23b06935
SZ
787 PtrTrack->InDeletedTransitionPtr = NULL;\r
788\r
0f7aff72
RN
789 //\r
790 // Find the variable by walk through HOB, volatile and non-volatile variable store.\r
791 //\r
792 InDeletedVariable = NULL;\r
793\r
794 for ( PtrTrack->CurrPtr = PtrTrack->StartPtr\r
795 ; (PtrTrack->CurrPtr < PtrTrack->EndPtr) && IsValidVariableHeader (PtrTrack->CurrPtr)\r
796 ; PtrTrack->CurrPtr = GetNextVariablePtr (PtrTrack->CurrPtr)\r
797 ) {\r
798 if (PtrTrack->CurrPtr->State == VAR_ADDED || \r
799 PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
800 ) {\r
9622df63 801 if (IgnoreRtCheck || !AtRuntime () || ((PtrTrack->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {\r
0f7aff72
RN
802 if (VariableName[0] == 0) {\r
803 if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
804 InDeletedVariable = PtrTrack->CurrPtr;\r
805 } else {\r
23b06935 806 PtrTrack->InDeletedTransitionPtr = InDeletedVariable;\r
0f7aff72
RN
807 return EFI_SUCCESS;\r
808 }\r
809 } else {\r
810 if (CompareGuid (VendorGuid, &PtrTrack->CurrPtr->VendorGuid)) {\r
811 Point = (VOID *) GetVariableNamePtr (PtrTrack->CurrPtr);\r
812\r
813 ASSERT (NameSizeOfVariable (PtrTrack->CurrPtr) != 0);\r
814 if (CompareMem (VariableName, Point, NameSizeOfVariable (PtrTrack->CurrPtr)) == 0) {\r
815 if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
816 InDeletedVariable = PtrTrack->CurrPtr;\r
817 } else {\r
23b06935 818 PtrTrack->InDeletedTransitionPtr = InDeletedVariable;\r
0f7aff72
RN
819 return EFI_SUCCESS;\r
820 }\r
821 }\r
822 }\r
823 }\r
824 }\r
825 }\r
826 }\r
827\r
828 PtrTrack->CurrPtr = InDeletedVariable;\r
829 return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;\r
830}\r
831\r
33a5a666 832\r
7c80e839 833/**\r
834 Finds variable in storage blocks of volatile and non-volatile storage areas.\r
835\r
836 This code finds variable in storage blocks of volatile and non-volatile storage areas.\r
837 If VariableName is an empty string, then we just return the first\r
838 qualified variable without comparing VariableName and VendorGuid.\r
9622df63
SZ
839 If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check\r
840 at runtime when searching existing variable, only VariableName and VendorGuid are compared.\r
841 Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime.\r
7c80e839 842\r
8a2d4996 843 @param VariableName Name of the variable to be found.\r
7c80e839 844 @param VendorGuid Vendor GUID to be found.\r
845 @param PtrTrack VARIABLE_POINTER_TRACK structure for output,\r
846 including the range searched and the target position.\r
847 @param Global Pointer to VARIABLE_GLOBAL structure, including\r
848 base of volatile variable storage area, base of\r
849 NV variable storage area, and a lock.\r
9622df63
SZ
850 @param IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute\r
851 check at runtime when searching variable.\r
7c80e839 852\r
853 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while\r
8a2d4996 854 VendorGuid is NULL.\r
855 @retval EFI_SUCCESS Variable successfully found.\r
255a3f33 856 @retval EFI_NOT_FOUND Variable not found\r
33a5a666 857\r
7c80e839 858**/\r
8d3a5c82 859EFI_STATUS\r
8d3a5c82 860FindVariable (\r
861 IN CHAR16 *VariableName,\r
862 IN EFI_GUID *VendorGuid,\r
863 OUT VARIABLE_POINTER_TRACK *PtrTrack,\r
9622df63
SZ
864 IN VARIABLE_GLOBAL *Global,\r
865 IN BOOLEAN IgnoreRtCheck\r
8d3a5c82 866 )\r
8d3a5c82 867{\r
0f7aff72
RN
868 EFI_STATUS Status;\r
869 VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];\r
870 VARIABLE_STORE_TYPE Type;\r
871\r
872 if (VariableName[0] != 0 && VendorGuid == NULL) {\r
873 return EFI_INVALID_PARAMETER;\r
874 }\r
8d3a5c82 875\r
8d3a5c82 876 //\r
0f7aff72 877 // 0: Volatile, 1: HOB, 2: Non-Volatile.\r
36873a61 878 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName\r
8a2d4996 879 // make use of this mapping to implement search algorithm.\r
8d3a5c82 880 //\r
0f7aff72
RN
881 VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) Global->VolatileVariableBase;\r
882 VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *) (UINTN) Global->HobVariableBase;\r
883 VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache;\r
8d3a5c82 884\r
885 //\r
0f7aff72 886 // Find the variable by walk through HOB, volatile and non-volatile variable store.\r
8d3a5c82 887 //\r
0f7aff72
RN
888 for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {\r
889 if (VariableStoreHeader[Type] == NULL) {\r
890 continue;\r
891 }\r
814bae52 892\r
0f7aff72
RN
893 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Type]);\r
894 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Type]);\r
895 PtrTrack->Volatile = (BOOLEAN) (Type == VariableStoreTypeVolatile);\r
8d3a5c82 896\r
9622df63 897 Status = FindVariableEx (VariableName, VendorGuid, IgnoreRtCheck, PtrTrack);\r
0f7aff72
RN
898 if (!EFI_ERROR (Status)) {\r
899 return Status;\r
814bae52 900 }\r
8d3a5c82 901 }\r
8d3a5c82 902 return EFI_NOT_FOUND;\r
903}\r
904\r
7c80e839 905/**\r
72399dae 906 Get index from supported language codes according to language string.\r
907\r
908 This code is used to get corresponding index in supported language codes. It can handle\r
0254efc0 909 RFC4646 and ISO639 language tags.\r
72399dae 910 In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.\r
0254efc0 911 In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.\r
72399dae 912\r
913 For example:\r
914 SupportedLang = "engfraengfra"\r
915 Lang = "eng"\r
916 Iso639Language = TRUE\r
917 The return value is "0".\r
918 Another example:\r
919 SupportedLang = "en;fr;en-US;fr-FR"\r
920 Lang = "fr-FR"\r
921 Iso639Language = FALSE\r
922 The return value is "3".\r
923\r
924 @param SupportedLang Platform supported language codes.\r
925 @param Lang Configured language.\r
0254efc0 926 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
72399dae 927\r
8a2d4996 928 @retval The index of language in the language codes.\r
8d3a5c82 929\r
7c80e839 930**/\r
72399dae 931UINTN\r
72399dae 932GetIndexFromSupportedLangCodes(\r
933 IN CHAR8 *SupportedLang,\r
934 IN CHAR8 *Lang,\r
935 IN BOOLEAN Iso639Language\r
936 ) \r
8d3a5c82 937{\r
72399dae 938 UINTN Index;\r
255a3f33
RN
939 UINTN CompareLength;\r
940 UINTN LanguageLength;\r
72399dae 941\r
72399dae 942 if (Iso639Language) {\r
255a3f33 943 CompareLength = ISO_639_2_ENTRY_SIZE;\r
72399dae 944 for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {\r
945 if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {\r
946 //\r
947 // Successfully find the index of Lang string in SupportedLang string.\r
948 //\r
949 Index = Index / CompareLength;\r
950 return Index;\r
951 }\r
952 }\r
953 ASSERT (FALSE);\r
954 return 0;\r
955 } else {\r
956 //\r
0254efc0 957 // Compare RFC4646 language code\r
72399dae 958 //\r
255a3f33
RN
959 Index = 0;\r
960 for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++);\r
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
255a3f33
RN
966 for (; *SupportedLang != '\0' && *SupportedLang == ';'; SupportedLang++);\r
967 //\r
968 // Determine the length of the next language code in SupportedLang\r
969 //\r
970 for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++);\r
971 \r
972 if ((CompareLength == LanguageLength) && \r
973 (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0)) {\r
72399dae 974 //\r
975 // Successfully find the index of Lang string in SupportedLang string.\r
976 //\r
977 return Index;\r
978 }\r
72399dae 979 }\r
980 ASSERT (FALSE);\r
981 return 0;\r
8d3a5c82 982 }\r
72399dae 983}\r
33a5a666 984\r
72399dae 985/**\r
986 Get language string from supported language codes according to index.\r
987\r
8a2d4996 988 This code is used to get corresponding language strings in supported language codes. It can handle\r
0254efc0 989 RFC4646 and ISO639 language tags.\r
72399dae 990 In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.\r
0254efc0 991 In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.\r
72399dae 992\r
993 For example:\r
994 SupportedLang = "engfraengfra"\r
995 Index = "1"\r
996 Iso639Language = TRUE\r
997 The return value is "fra".\r
998 Another example:\r
999 SupportedLang = "en;fr;en-US;fr-FR"\r
1000 Index = "1"\r
1001 Iso639Language = FALSE\r
1002 The return value is "fr".\r
1003\r
1004 @param SupportedLang Platform supported language codes.\r
8a2d4996 1005 @param Index The index in supported language codes.\r
0254efc0 1006 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
72399dae 1007\r
8a2d4996 1008 @retval The language string in the language codes.\r
8d3a5c82 1009\r
72399dae 1010**/\r
1011CHAR8 *\r
72399dae 1012GetLangFromSupportedLangCodes (\r
1013 IN CHAR8 *SupportedLang,\r
1014 IN UINTN Index,\r
1015 IN BOOLEAN Iso639Language\r
1016)\r
1017{\r
1018 UINTN SubIndex;\r
255a3f33 1019 UINTN CompareLength;\r
72399dae 1020 CHAR8 *Supported;\r
8d3a5c82 1021\r
72399dae 1022 SubIndex = 0;\r
1023 Supported = SupportedLang;\r
1024 if (Iso639Language) {\r
1025 //\r
8a2d4996 1026 // According to the index of Lang string in SupportedLang string to get the language.\r
1027 // This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation.\r
72399dae 1028 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
1029 //\r
255a3f33
RN
1030 CompareLength = ISO_639_2_ENTRY_SIZE;\r
1031 mVariableModuleGlobal->Lang[CompareLength] = '\0';\r
72399dae 1032 return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength);\r
f68af18e 1033\r
8d3a5c82 1034 } else {\r
72399dae 1035 while (TRUE) {\r
1036 //\r
8a2d4996 1037 // Take semicolon as delimitation, sequentially traverse supported language codes.\r
72399dae 1038 //\r
1039 for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {\r
1040 Supported++;\r
1041 }\r
1042 if ((*Supported == '\0') && (SubIndex != Index)) {\r
1043 //\r
1044 // Have completed the traverse, but not find corrsponding string.\r
1045 // This case is not allowed to happen.\r
1046 //\r
1047 ASSERT(FALSE);\r
1048 return NULL;\r
1049 }\r
1050 if (SubIndex == Index) {\r
1051 //\r
8a2d4996 1052 // According to the index of Lang string in SupportedLang string to get the language.\r
72399dae 1053 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.\r
1054 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
1055 //\r
255a3f33 1056 mVariableModuleGlobal->PlatformLang[CompareLength] = '\0';\r
72399dae 1057 return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - CompareLength, CompareLength);\r
1058 }\r
1059 SubIndex++;\r
8a2d4996 1060\r
5c033766
RN
1061 //\r
1062 // Skip ';' characters in Supported\r
1063 //\r
1064 for (; *Supported != '\0' && *Supported == ';'; Supported++);\r
72399dae 1065 }\r
8d3a5c82 1066 }\r
8d3a5c82 1067}\r
1068\r
255a3f33
RN
1069/**\r
1070 Returns a pointer to an allocated buffer that contains the best matching language \r
1071 from a set of supported languages. \r
1072 \r
1073 This function supports both ISO 639-2 and RFC 4646 language codes, but language \r
1074 code types may not be mixed in a single call to this function. This function\r
1075 supports a variable argument list that allows the caller to pass in a prioritized\r
1076 list of language codes to test against all the language codes in SupportedLanguages.\r
1077\r
1078 If SupportedLanguages is NULL, then ASSERT().\r
1079\r
1080 @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that\r
1081 contains a set of language codes in the format \r
1082 specified by Iso639Language.\r
1083 @param[in] Iso639Language If TRUE, then all language codes are assumed to be\r
1084 in ISO 639-2 format. If FALSE, then all language\r
1085 codes are assumed to be in RFC 4646 language format\r
1086 @param[in] ... A variable argument list that contains pointers to \r
1087 Null-terminated ASCII strings that contain one or more\r
1088 language codes in the format specified by Iso639Language.\r
1089 The first language code from each of these language\r
1090 code lists is used to determine if it is an exact or\r
1091 close match to any of the language codes in \r
1092 SupportedLanguages. Close matches only apply to RFC 4646\r
1093 language codes, and the matching algorithm from RFC 4647\r
1094 is used to determine if a close match is present. If \r
1095 an exact or close match is found, then the matching\r
1096 language code from SupportedLanguages is returned. If\r
1097 no matches are found, then the next variable argument\r
1098 parameter is evaluated. The variable argument list \r
1099 is terminated by a NULL.\r
1100\r
1101 @retval NULL The best matching language could not be found in SupportedLanguages.\r
1102 @retval NULL There are not enough resources available to return the best matching \r
1103 language.\r
1104 @retval Other A pointer to a Null-terminated ASCII string that is the best matching \r
1105 language in SupportedLanguages.\r
1106\r
1107**/\r
1108CHAR8 *\r
e1adae60 1109EFIAPI\r
255a3f33
RN
1110VariableGetBestLanguage (\r
1111 IN CONST CHAR8 *SupportedLanguages, \r
1112 IN BOOLEAN Iso639Language,\r
1113 ...\r
1114 )\r
1115{\r
1116 VA_LIST Args;\r
1117 CHAR8 *Language;\r
1118 UINTN CompareLength;\r
1119 UINTN LanguageLength;\r
1120 CONST CHAR8 *Supported;\r
1121 CHAR8 *Buffer;\r
1122\r
1123 ASSERT (SupportedLanguages != NULL);\r
1124\r
1125 VA_START (Args, Iso639Language);\r
1126 while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {\r
1127 //\r
1128 // Default to ISO 639-2 mode\r
1129 //\r
1130 CompareLength = 3;\r
1131 LanguageLength = MIN (3, AsciiStrLen (Language));\r
1132\r
1133 //\r
1134 // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language\r
1135 //\r
1136 if (!Iso639Language) {\r
1137 for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++);\r
1138 }\r
1139\r
1140 //\r
1141 // Trim back the length of Language used until it is empty\r
1142 //\r
1143 while (LanguageLength > 0) {\r
1144 //\r
1145 // Loop through all language codes in SupportedLanguages\r
1146 //\r
1147 for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {\r
1148 //\r
1149 // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages\r
1150 //\r
1151 if (!Iso639Language) {\r
1152 //\r
1153 // Skip ';' characters in Supported\r
1154 //\r
1155 for (; *Supported != '\0' && *Supported == ';'; Supported++);\r
1156 //\r
1157 // Determine the length of the next language code in Supported\r
1158 //\r
1159 for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++);\r
1160 //\r
1161 // If Language is longer than the Supported, then skip to the next language\r
1162 //\r
1163 if (LanguageLength > CompareLength) {\r
1164 continue;\r
1165 }\r
1166 }\r
1167 //\r
1168 // See if the first LanguageLength characters in Supported match Language\r
1169 //\r
1170 if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {\r
1171 VA_END (Args);\r
1172\r
1173 Buffer = Iso639Language ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang;\r
1174 Buffer[CompareLength] = '\0';\r
1175 return CopyMem (Buffer, Supported, CompareLength);\r
1176 }\r
1177 }\r
1178\r
1179 if (Iso639Language) {\r
1180 //\r
1181 // If ISO 639 mode, then each language can only be tested once\r
1182 //\r
1183 LanguageLength = 0;\r
1184 } else {\r
1185 //\r
1186 // If RFC 4646 mode, then trim Language from the right to the next '-' character \r
1187 //\r
1188 for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--);\r
1189 }\r
1190 }\r
1191 }\r
1192 VA_END (Args);\r
1193\r
1194 //\r
1195 // No matches were found \r
1196 //\r
1197 return NULL;\r
1198}\r
1199\r
72399dae 1200/**\r
1201 Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.\r
052ad7e1 1202\r
72399dae 1203 When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.\r
052ad7e1 1204\r
72399dae 1205 According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,\r
1206 and are read-only. Therefore, in variable driver, only store the original value for other use.\r
8d3a5c82 1207\r
8a2d4996 1208 @param[in] VariableName Name of variable.\r
8d3a5c82 1209\r
8a2d4996 1210 @param[in] Data Variable data.\r
8d3a5c82 1211\r
8a2d4996 1212 @param[in] DataSize Size of data. 0 means delete.\r
72399dae 1213\r
7c80e839 1214**/\r
255a3f33 1215VOID\r
d6550260 1216AutoUpdateLangVariable (\r
72399dae 1217 IN CHAR16 *VariableName,\r
1218 IN VOID *Data,\r
1219 IN UINTN DataSize\r
052ad7e1 1220 )\r
8d3a5c82 1221{\r
255a3f33
RN
1222 EFI_STATUS Status;\r
1223 CHAR8 *BestPlatformLang;\r
1224 CHAR8 *BestLang;\r
1225 UINTN Index;\r
1226 UINT32 Attributes;\r
72399dae 1227 VARIABLE_POINTER_TRACK Variable;\r
255a3f33 1228 BOOLEAN SetLanguageCodes;\r
8d3a5c82 1229\r
72399dae 1230 //\r
255a3f33 1231 // Don't do updates for delete operation\r
72399dae 1232 //\r
255a3f33
RN
1233 if (DataSize == 0) {\r
1234 return;\r
1235 }\r
1236\r
1237 SetLanguageCodes = FALSE;\r
8d3a5c82 1238\r
72399dae 1239 if (StrCmp (VariableName, L"PlatformLangCodes") == 0) {\r
255a3f33
RN
1240 //\r
1241 // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.\r
1242 //\r
8a2d4996 1243 if (AtRuntime ()) {\r
255a3f33
RN
1244 return;\r
1245 }\r
1246\r
1247 SetLanguageCodes = TRUE;\r
1248\r
72399dae 1249 //\r
1250 // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only\r
1251 // Therefore, in variable driver, only store the original value for other use.\r
1252 //\r
255a3f33
RN
1253 if (mVariableModuleGlobal->PlatformLangCodes != NULL) {\r
1254 FreePool (mVariableModuleGlobal->PlatformLangCodes);\r
1255 }\r
1256 mVariableModuleGlobal->PlatformLangCodes = AllocateRuntimeCopyPool (DataSize, Data);\r
1257 ASSERT (mVariableModuleGlobal->PlatformLangCodes != NULL);\r
1258\r
72399dae 1259 //\r
255a3f33
RN
1260 // PlatformLang holds a single language from PlatformLangCodes, \r
1261 // so the size of PlatformLangCodes is enough for the PlatformLang.\r
72399dae 1262 //\r
255a3f33
RN
1263 if (mVariableModuleGlobal->PlatformLang != NULL) {\r
1264 FreePool (mVariableModuleGlobal->PlatformLang);\r
1265 }\r
1266 mVariableModuleGlobal->PlatformLang = AllocateRuntimePool (DataSize);\r
1267 ASSERT (mVariableModuleGlobal->PlatformLang != NULL);\r
fdb7765f 1268\r
255a3f33 1269 } else if (StrCmp (VariableName, L"LangCodes") == 0) {\r
72399dae 1270 //\r
255a3f33 1271 // LangCodes is a volatile variable, so it can not be updated at runtime.\r
72399dae 1272 //\r
8a2d4996 1273 if (AtRuntime ()) {\r
255a3f33
RN
1274 return;\r
1275 }\r
1276\r
1277 SetLanguageCodes = TRUE;\r
8d3a5c82 1278\r
8d3a5c82 1279 //\r
255a3f33
RN
1280 // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only\r
1281 // Therefore, in variable driver, only store the original value for other use.\r
8d3a5c82 1282 //\r
255a3f33
RN
1283 if (mVariableModuleGlobal->LangCodes != NULL) {\r
1284 FreePool (mVariableModuleGlobal->LangCodes);\r
1285 }\r
1286 mVariableModuleGlobal->LangCodes = AllocateRuntimeCopyPool (DataSize, Data);\r
1287 ASSERT (mVariableModuleGlobal->LangCodes != NULL);\r
1288 }\r
8d3a5c82 1289\r
255a3f33
RN
1290 if (SetLanguageCodes \r
1291 && (mVariableModuleGlobal->PlatformLangCodes != NULL)\r
1292 && (mVariableModuleGlobal->LangCodes != NULL)) {\r
8d3a5c82 1293 //\r
255a3f33
RN
1294 // Update Lang if PlatformLang is already set\r
1295 // Update PlatformLang if Lang is already set\r
8d3a5c82 1296 //\r
9622df63 1297 Status = FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
255a3f33
RN
1298 if (!EFI_ERROR (Status)) {\r
1299 //\r
1300 // Update Lang\r
1301 //\r
1302 VariableName = L"PlatformLang";\r
1303 Data = GetVariableDataPtr (Variable.CurrPtr);\r
1304 DataSize = Variable.CurrPtr->DataSize;\r
1305 } else {\r
9622df63 1306 Status = FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
255a3f33
RN
1307 if (!EFI_ERROR (Status)) {\r
1308 //\r
1309 // Update PlatformLang\r
1310 //\r
1311 VariableName = L"Lang";\r
1312 Data = GetVariableDataPtr (Variable.CurrPtr);\r
1313 DataSize = Variable.CurrPtr->DataSize;\r
1314 } else {\r
1315 //\r
1316 // Neither PlatformLang nor Lang is set, directly return\r
1317 //\r
1318 return;\r
1319 }\r
1320 }\r
1321 }\r
1322 \r
1323 //\r
1324 // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.\r
1325 //\r
1326 Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;\r
8d3a5c82 1327\r
255a3f33 1328 if (StrCmp (VariableName, L"PlatformLang") == 0) {\r
8d3a5c82 1329 //\r
255a3f33 1330 // Update Lang when PlatformLangCodes/LangCodes were set.\r
8d3a5c82 1331 //\r
255a3f33
RN
1332 if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {\r
1333 //\r
1334 // When setting PlatformLang, firstly get most matched language string from supported language codes.\r
1335 //\r
1336 BestPlatformLang = VariableGetBestLanguage (mVariableModuleGlobal->PlatformLangCodes, FALSE, Data, NULL);\r
1337 if (BestPlatformLang != NULL) {\r
1338 //\r
1339 // Get the corresponding index in language codes.\r
1340 //\r
1341 Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, BestPlatformLang, FALSE);\r
fdb7765f 1342\r
255a3f33
RN
1343 //\r
1344 // Get the corresponding ISO639 language tag according to RFC4646 language tag.\r
1345 //\r
1346 BestLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, Index, TRUE);\r
8d3a5c82 1347\r
255a3f33
RN
1348 //\r
1349 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.\r
1350 //\r
23b06935 1351 FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
8d3a5c82 1352\r
8a2d4996 1353 Status = UpdateVariable (L"Lang", &gEfiGlobalVariableGuid, BestLang,\r
1354 ISO_639_2_ENTRY_SIZE + 1, Attributes, &Variable);\r
8d3a5c82 1355\r
255a3f33 1356 DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang));\r
72399dae 1357\r
255a3f33
RN
1358 ASSERT_EFI_ERROR(Status);\r
1359 }\r
1360 }\r
72399dae 1361\r
255a3f33 1362 } else if (StrCmp (VariableName, L"Lang") == 0) {\r
72399dae 1363 //\r
255a3f33 1364 // Update PlatformLang when PlatformLangCodes/LangCodes were set.\r
72399dae 1365 //\r
255a3f33
RN
1366 if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {\r
1367 //\r
1368 // When setting Lang, firstly get most matched language string from supported language codes.\r
1369 //\r
1370 BestLang = VariableGetBestLanguage (mVariableModuleGlobal->LangCodes, TRUE, Data, NULL);\r
1371 if (BestLang != NULL) {\r
1372 //\r
1373 // Get the corresponding index in language codes.\r
1374 //\r
1375 Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, BestLang, TRUE);\r
72399dae 1376\r
255a3f33
RN
1377 //\r
1378 // Get the corresponding RFC4646 language tag according to ISO639 language tag.\r
1379 //\r
1380 BestPlatformLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, Index, FALSE);\r
1381\r
1382 //\r
1383 // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.\r
1384 //\r
9622df63 1385 FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
72399dae 1386\r
255a3f33
RN
1387 Status = UpdateVariable (L"PlatformLang", &gEfiGlobalVariableGuid, BestPlatformLang, \r
1388 AsciiStrSize (BestPlatformLang), Attributes, &Variable);\r
72399dae 1389\r
255a3f33
RN
1390 DEBUG ((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a\n", BestLang, BestPlatformLang));\r
1391 ASSERT_EFI_ERROR (Status);\r
1392 }\r
1393 }\r
72399dae 1394 }\r
8d3a5c82 1395}\r
1396\r
7c80e839 1397/**\r
72399dae 1398 Update the variable region with Variable information. These are the same \r
1399 arguments as the EFI Variable services.\r
052ad7e1 1400\r
8a2d4996 1401 @param[in] VariableName Name of variable.\r
1402 @param[in] VendorGuid Guid of variable.\r
1403 @param[in] Data Variable data.\r
1404 @param[in] DataSize Size of data. 0 means delete.\r
1405 @param[in] Attributes Attribues of the variable.\r
23b06935 1406 @param[in, out] CacheVariable The variable information which is used to keep track of variable usage.\r
8a2d4996 1407 \r
72399dae 1408 @retval EFI_SUCCESS The update operation is success.\r
72399dae 1409 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.\r
8d3a5c82 1410\r
7c80e839 1411**/\r
052ad7e1 1412EFI_STATUS\r
72399dae 1413UpdateVariable (\r
8a2d4996 1414 IN CHAR16 *VariableName,\r
1415 IN EFI_GUID *VendorGuid,\r
1416 IN VOID *Data,\r
1417 IN UINTN DataSize,\r
1418 IN UINT32 Attributes OPTIONAL,\r
23b06935 1419 IN OUT VARIABLE_POINTER_TRACK *CacheVariable\r
052ad7e1 1420 )\r
8d3a5c82 1421{\r
8a9e0b72 1422 EFI_STATUS Status;\r
1423 VARIABLE_HEADER *NextVariable;\r
72399dae 1424 UINTN ScratchSize;\r
1425 UINTN NonVolatileVarableStoreSize;\r
8a9e0b72 1426 UINTN VarNameOffset;\r
1427 UINTN VarDataOffset;\r
72399dae 1428 UINTN VarNameSize;\r
8a9e0b72 1429 UINTN VarSize;\r
72399dae 1430 BOOLEAN Volatile;\r
1431 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
8a9e0b72 1432 UINT8 State;\r
8a2d4996 1433 VARIABLE_POINTER_TRACK *Variable;\r
1434 VARIABLE_POINTER_TRACK NvVariable;\r
1435 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
1436 UINTN CacheOffset;\r
fdb7765f 1437\r
5456306f 1438 if ((mVariableModuleGlobal->FvbInstance == NULL) && ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0)) {\r
1439 //\r
1440 // The FVB protocol is not ready. Trying to update NV variable prior to the installation\r
1441 // of EFI_VARIABLE_WRITE_ARCH_PROTOCOL.\r
1442 //\r
1443 return EFI_NOT_AVAILABLE_YET; \r
1444 }\r
1445\r
1446 if ((CacheVariable->CurrPtr == NULL) || CacheVariable->Volatile) {\r
8a2d4996 1447 Variable = CacheVariable;\r
1448 } else {\r
8a2d4996 1449 //\r
5456306f 1450 // Update/Delete existing NV variable.\r
8a2d4996 1451 // CacheVariable points to the variable in the memory copy of Flash area\r
1452 // Now let Variable points to the same variable in Flash area.\r
1453 //\r
1454 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
1455 Variable = &NvVariable; \r
1456 Variable->StartPtr = GetStartPointer (VariableStoreHeader);\r
1457 Variable->EndPtr = GetEndPointer (VariableStoreHeader);\r
5456306f 1458 Variable->CurrPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->CurrPtr - (UINTN)CacheVariable->StartPtr));\r
23b06935
SZ
1459 if (CacheVariable->InDeletedTransitionPtr != NULL) {\r
1460 Variable->InDeletedTransitionPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->InDeletedTransitionPtr - (UINTN)CacheVariable->StartPtr));\r
1461 } else {\r
1462 Variable->InDeletedTransitionPtr = NULL;\r
1463 }\r
5456306f 1464 Variable->Volatile = FALSE;\r
1465 } \r
1466\r
1467 Fvb = mVariableModuleGlobal->FvbInstance;\r
fdb7765f 1468\r
72399dae 1469 if (Variable->CurrPtr != NULL) {\r
8d3a5c82 1470 //\r
8a2d4996 1471 // Update/Delete existing variable.\r
8d3a5c82 1472 //\r
8a2d4996 1473 if (AtRuntime ()) { \r
c6492839 1474 //\r
8a2d4996 1475 // If AtRuntime and the variable is Volatile and Runtime Access, \r
c6492839 1476 // the volatile is ReadOnly, and SetVariable should be aborted and \r
1477 // return EFI_WRITE_PROTECTED.\r
1478 //\r
72399dae 1479 if (Variable->Volatile) {\r
c6492839 1480 Status = EFI_WRITE_PROTECTED;\r
1481 goto Done;\r
1482 }\r
1483 //\r
9622df63 1484 // Only variable that have NV|RT attributes can be updated/deleted in Runtime.\r
c6492839 1485 //\r
9622df63 1486 if (((Variable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)) {\r
c6492839 1487 Status = EFI_INVALID_PARAMETER;\r
1488 goto Done; \r
1489 }\r
1490 }\r
8a2d4996 1491\r
8d3a5c82 1492 //\r
c6492839 1493 // Setting a data variable with no access, or zero DataSize attributes\r
8a2d4996 1494 // causes it to be deleted.\r
8d3a5c82 1495 //\r
c6492839 1496 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) { \r
23b06935
SZ
1497 if (Variable->InDeletedTransitionPtr != NULL) {\r
1498 //\r
1499 // Both ADDED and IN_DELETED_TRANSITION variable are present,\r
1500 // set IN_DELETED_TRANSITION one to DELETED state first.\r
1501 //\r
1502 State = Variable->InDeletedTransitionPtr->State;\r
1503 State &= VAR_DELETED;\r
1504 Status = UpdateVariableStore (\r
1505 &mVariableModuleGlobal->VariableGlobal,\r
1506 Variable->Volatile,\r
1507 FALSE,\r
1508 Fvb,\r
1509 (UINTN) &Variable->InDeletedTransitionPtr->State,\r
1510 sizeof (UINT8),\r
1511 &State\r
1512 );\r
1513 if (!EFI_ERROR (Status)) {\r
1514 if (!Variable->Volatile) {\r
0cc565de 1515 ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
23b06935
SZ
1516 CacheVariable->InDeletedTransitionPtr->State = State;\r
1517 }\r
1518 } else {\r
1519 goto Done;\r
1520 }\r
1521 }\r
1522\r
72399dae 1523 State = Variable->CurrPtr->State;\r
c6492839 1524 State &= VAR_DELETED;\r
1525\r
1526 Status = UpdateVariableStore (\r
052ad7e1 1527 &mVariableModuleGlobal->VariableGlobal,\r
72399dae 1528 Variable->Volatile,\r
c6492839 1529 FALSE,\r
8a9e0b72 1530 Fvb,\r
72399dae 1531 (UINTN) &Variable->CurrPtr->State,\r
c6492839 1532 sizeof (UINT8),\r
1533 &State\r
1534 ); \r
33a5a666 1535 if (!EFI_ERROR (Status)) {\r
8a2d4996 1536 UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE);\r
1537 if (!Variable->Volatile) {\r
1538 CacheVariable->CurrPtr->State = State;\r
335e2681 1539 FlushHobVariableToFlash (VariableName, VendorGuid);\r
8a2d4996 1540 }\r
33a5a666 1541 }\r
c6492839 1542 goto Done; \r
1543 }\r
8d3a5c82 1544 //\r
8a2d4996 1545 // If the variable is marked valid, and the same data has been passed in,\r
c6492839 1546 // then return to the caller immediately.\r
8d3a5c82 1547 //\r
72399dae 1548 if (DataSizeOfVariable (Variable->CurrPtr) == DataSize &&\r
1549 (CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0)) {\r
33a5a666 1550 \r
8a2d4996 1551 UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE);\r
c6492839 1552 Status = EFI_SUCCESS;\r
1553 goto Done;\r
72399dae 1554 } else if ((Variable->CurrPtr->State == VAR_ADDED) ||\r
1555 (Variable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {\r
814bae52 1556\r
c6492839 1557 //\r
8a2d4996 1558 // Mark the old variable as in delete transition.\r
c6492839 1559 //\r
72399dae 1560 State = Variable->CurrPtr->State;\r
c6492839 1561 State &= VAR_IN_DELETED_TRANSITION;\r
1562\r
1563 Status = UpdateVariableStore (\r
052ad7e1 1564 &mVariableModuleGlobal->VariableGlobal,\r
72399dae 1565 Variable->Volatile,\r
c6492839 1566 FALSE,\r
8a9e0b72 1567 Fvb,\r
72399dae 1568 (UINTN) &Variable->CurrPtr->State,\r
c6492839 1569 sizeof (UINT8),\r
1570 &State\r
1571 ); \r
1572 if (EFI_ERROR (Status)) {\r
1573 goto Done; \r
33a5a666 1574 } \r
8a2d4996 1575 if (!Variable->Volatile) {\r
1576 CacheVariable->CurrPtr->State = State;\r
1577 }\r
c6492839 1578 } \r
72399dae 1579 } else {\r
8d3a5c82 1580 //\r
8a2d4996 1581 // Not found existing variable. Create a new variable.\r
c6492839 1582 // \r
1583 \r
8d3a5c82 1584 //\r
c6492839 1585 // Make sure we are trying to create a new variable.\r
8a2d4996 1586 // Setting a data variable with zero DataSize or no access attributes means to delete it. \r
8d3a5c82 1587 //\r
c6492839 1588 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {\r
1589 Status = EFI_NOT_FOUND;\r
1590 goto Done;\r
1591 }\r
1592 \r
8d3a5c82 1593 //\r
8a2d4996 1594 // Only variable have NV|RT attribute can be created in Runtime.\r
c6492839 1595 //\r
8a2d4996 1596 if (AtRuntime () &&\r
45f6c85b 1597 (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {\r
c6492839 1598 Status = EFI_INVALID_PARAMETER;\r
1599 goto Done;\r
1600 } \r
c6492839 1601 }\r
1602\r
1603 //\r
1604 // Function part - create a new variable and copy the data.\r
1605 // Both update a variable and create a variable will come here.\r
8a2d4996 1606\r
c6492839 1607 //\r
1608 // Tricky part: Use scratch data area at the end of volatile variable store\r
1609 // as a temporary storage.\r
1610 //\r
052ad7e1 1611 NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));\r
188e4e84 1612 ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
c6492839 1613\r
2fcdca1d 1614 SetMem (NextVariable, ScratchSize, 0xff);\r
c6492839 1615\r
1616 NextVariable->StartId = VARIABLE_DATA;\r
1617 NextVariable->Attributes = Attributes;\r
1618 //\r
1619 // NextVariable->State = VAR_ADDED;\r
1620 //\r
8a2d4996 1621 NextVariable->Reserved = 0;\r
1622 VarNameOffset = sizeof (VARIABLE_HEADER);\r
1623 VarNameSize = StrSize (VariableName);\r
c6492839 1624 CopyMem (\r
1625 (UINT8 *) ((UINTN) NextVariable + VarNameOffset),\r
1626 VariableName,\r
1627 VarNameSize\r
1628 );\r
1629 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);\r
1630 CopyMem (\r
1631 (UINT8 *) ((UINTN) NextVariable + VarDataOffset),\r
1632 Data,\r
1633 DataSize\r
1634 );\r
1635 CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));\r
1636 //\r
1637 // There will be pad bytes after Data, the NextVariable->NameSize and\r
1638 // NextVariable->DataSize should not include pad size so that variable\r
8a2d4996 1639 // service can get actual size in GetVariable.\r
c6492839 1640 //\r
1641 NextVariable->NameSize = (UINT32)VarNameSize;\r
1642 NextVariable->DataSize = (UINT32)DataSize;\r
1643\r
1644 //\r
1645 // The actual size of the variable that stores in storage should\r
1646 // include pad size.\r
1647 //\r
1648 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);\r
45f6c85b 1649 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
8d3a5c82 1650 //\r
8a2d4996 1651 // Create a nonvolatile variable.\r
8d3a5c82 1652 //\r
fd51bf70 1653 Volatile = FALSE;\r
2fcdca1d 1654 NonVolatileVarableStoreSize = ((VARIABLE_STORE_HEADER *)(UINTN)(mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase))->Size;\r
1655 if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \r
188e4e84 1656 && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))\r
2fcdca1d 1657 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
188e4e84 1658 && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize)))) {\r
8a2d4996 1659 if (AtRuntime ()) {\r
c6492839 1660 Status = EFI_OUT_OF_RESOURCES;\r
1661 goto Done;\r
1662 }\r
1663 //\r
8a2d4996 1664 // Perform garbage collection & reclaim operation.\r
c6492839 1665 //\r
72399dae 1666 Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, \r
23b06935 1667 &mVariableModuleGlobal->NonVolatileLastVariableOffset, FALSE, Variable, FALSE);\r
8d3a5c82 1668 if (EFI_ERROR (Status)) {\r
1669 goto Done;\r
1670 }\r
8d3a5c82 1671 //\r
8a2d4996 1672 // If still no enough space, return out of resources.\r
8d3a5c82 1673 //\r
2fcdca1d 1674 if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \r
188e4e84 1675 && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))\r
2fcdca1d 1676 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
188e4e84 1677 && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize)))) {\r
c6492839 1678 Status = EFI_OUT_OF_RESOURCES;\r
8d3a5c82 1679 goto Done;\r
8d3a5c82 1680 }\r
23b06935
SZ
1681 if (Variable->CurrPtr != NULL) {\r
1682 CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN) CacheVariable->StartPtr + ((UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr));\r
1683 CacheVariable->InDeletedTransitionPtr = NULL;\r
1684 }\r
8d3a5c82 1685 }\r
1686 //\r
8a2d4996 1687 // Four steps\r
c6492839 1688 // 1. Write variable header\r
130e2569 1689 // 2. Set variable state to header valid \r
1690 // 3. Write variable data\r
1691 // 4. Set variable state to valid\r
8d3a5c82 1692 //\r
8d3a5c82 1693 //\r
c6492839 1694 // Step 1:\r
8d3a5c82 1695 //\r
8a2d4996 1696 CacheOffset = mVariableModuleGlobal->NonVolatileLastVariableOffset;\r
c6492839 1697 Status = UpdateVariableStore (\r
052ad7e1 1698 &mVariableModuleGlobal->VariableGlobal,\r
c6492839 1699 FALSE,\r
1700 TRUE,\r
8a9e0b72 1701 Fvb,\r
72399dae 1702 mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
c6492839 1703 sizeof (VARIABLE_HEADER),\r
1704 (UINT8 *) NextVariable\r
1705 );\r
1706\r
1707 if (EFI_ERROR (Status)) {\r
1708 goto Done;\r
1709 }\r
130e2569 1710\r
8d3a5c82 1711 //\r
c6492839 1712 // Step 2:\r
8d3a5c82 1713 //\r
130e2569 1714 NextVariable->State = VAR_HEADER_VALID_ONLY;\r
1715 Status = UpdateVariableStore (\r
1716 &mVariableModuleGlobal->VariableGlobal,\r
1717 FALSE,\r
1718 TRUE,\r
8a9e0b72 1719 Fvb,\r
8a2d4996 1720 mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
1721 sizeof (UINT8),\r
1722 &NextVariable->State\r
130e2569 1723 );\r
1724\r
1725 if (EFI_ERROR (Status)) {\r
1726 goto Done;\r
1727 }\r
1728 //\r
1729 // Step 3:\r
1730 //\r
c6492839 1731 Status = UpdateVariableStore (\r
052ad7e1 1732 &mVariableModuleGlobal->VariableGlobal,\r
c6492839 1733 FALSE,\r
1734 TRUE,\r
8a9e0b72 1735 Fvb,\r
72399dae 1736 mVariableModuleGlobal->NonVolatileLastVariableOffset + sizeof (VARIABLE_HEADER),\r
c6492839 1737 (UINT32) VarSize - sizeof (VARIABLE_HEADER),\r
1738 (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)\r
1739 );\r
1740\r
1741 if (EFI_ERROR (Status)) {\r
1742 goto Done;\r
1743 }\r
8d3a5c82 1744 //\r
130e2569 1745 // Step 4:\r
8d3a5c82 1746 //\r
c6492839 1747 NextVariable->State = VAR_ADDED;\r
1748 Status = UpdateVariableStore (\r
052ad7e1 1749 &mVariableModuleGlobal->VariableGlobal,\r
c6492839 1750 FALSE,\r
1751 TRUE,\r
8a9e0b72 1752 Fvb,\r
8a2d4996 1753 mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
1754 sizeof (UINT8),\r
1755 &NextVariable->State\r
c6492839 1756 );\r
1757\r
1758 if (EFI_ERROR (Status)) {\r
1759 goto Done;\r
1760 }\r
8d3a5c82 1761\r
72399dae 1762 mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
8d3a5c82 1763\r
2fcdca1d 1764 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {\r
1765 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);\r
1766 } else {\r
1767 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);\r
1768 }\r
8a2d4996 1769 //\r
1770 // update the memory copy of Flash region.\r
1771 //\r
1772 CopyMem ((UINT8 *)mNvVariableCache + CacheOffset, (UINT8 *)NextVariable, VarSize);\r
c6492839 1773 } else {\r
1774 //\r
8a2d4996 1775 // Create a volatile variable.\r
c6492839 1776 // \r
fd51bf70 1777 Volatile = TRUE;\r
c6492839 1778\r
72399dae 1779 if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >\r
052ad7e1 1780 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) {\r
8d3a5c82 1781 //\r
8a2d4996 1782 // Perform garbage collection & reclaim operation.\r
8d3a5c82 1783 //\r
72399dae 1784 Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase, \r
23b06935 1785 &mVariableModuleGlobal->VolatileLastVariableOffset, TRUE, Variable, FALSE);\r
8d3a5c82 1786 if (EFI_ERROR (Status)) {\r
1787 goto Done;\r
1788 }\r
1789 //\r
8a2d4996 1790 // If still no enough space, return out of resources.\r
8d3a5c82 1791 //\r
72399dae 1792 if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >\r
052ad7e1 1793 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size\r
8d3a5c82 1794 ) {\r
c6492839 1795 Status = EFI_OUT_OF_RESOURCES;\r
8d3a5c82 1796 goto Done;\r
1797 }\r
23b06935
SZ
1798 if (Variable->CurrPtr != NULL) {\r
1799 CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN) CacheVariable->StartPtr + ((UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr));\r
1800 CacheVariable->InDeletedTransitionPtr = NULL;\r
1801 }\r
8d3a5c82 1802 }\r
8d3a5c82 1803\r
c6492839 1804 NextVariable->State = VAR_ADDED;\r
1805 Status = UpdateVariableStore (\r
052ad7e1 1806 &mVariableModuleGlobal->VariableGlobal,\r
c6492839 1807 TRUE,\r
1808 TRUE,\r
8a9e0b72 1809 Fvb,\r
72399dae 1810 mVariableModuleGlobal->VolatileLastVariableOffset,\r
c6492839 1811 (UINT32) VarSize,\r
1812 (UINT8 *) NextVariable\r
1813 );\r
1814\r
1815 if (EFI_ERROR (Status)) {\r
1816 goto Done;\r
8d3a5c82 1817 }\r
c6492839 1818\r
72399dae 1819 mVariableModuleGlobal->VolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
c6492839 1820 }\r
72399dae 1821\r
c6492839 1822 //\r
8a2d4996 1823 // Mark the old variable as deleted.\r
c6492839 1824 //\r
23b06935
SZ
1825 if (!EFI_ERROR (Status) && Variable->CurrPtr != NULL) {\r
1826 if (Variable->InDeletedTransitionPtr != NULL) {\r
1827 //\r
1828 // Both ADDED and IN_DELETED_TRANSITION old variable are present,\r
1829 // set IN_DELETED_TRANSITION one to DELETED state first.\r
1830 //\r
1831 State = Variable->InDeletedTransitionPtr->State;\r
1832 State &= VAR_DELETED;\r
1833 Status = UpdateVariableStore (\r
1834 &mVariableModuleGlobal->VariableGlobal,\r
1835 Variable->Volatile,\r
1836 FALSE,\r
1837 Fvb,\r
1838 (UINTN) &Variable->InDeletedTransitionPtr->State,\r
1839 sizeof (UINT8),\r
1840 &State\r
1841 );\r
1842 if (!EFI_ERROR (Status)) {\r
1843 if (!Variable->Volatile) {\r
0cc565de 1844 ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
23b06935
SZ
1845 CacheVariable->InDeletedTransitionPtr->State = State;\r
1846 }\r
1847 } else {\r
1848 goto Done;\r
1849 }\r
1850 }\r
1851\r
72399dae 1852 State = Variable->CurrPtr->State;\r
c6492839 1853 State &= VAR_DELETED;\r
1854\r
1855 Status = UpdateVariableStore (\r
72399dae 1856 &mVariableModuleGlobal->VariableGlobal,\r
1857 Variable->Volatile,\r
1858 FALSE,\r
1859 Fvb,\r
1860 (UINTN) &Variable->CurrPtr->State,\r
1861 sizeof (UINT8),\r
1862 &State\r
1863 );\r
8a2d4996 1864 if (!EFI_ERROR (Status) && !Variable->Volatile) { \r
1865 CacheVariable->CurrPtr->State = State;\r
1866 }\r
72399dae 1867 }\r
1868\r
1869 if (!EFI_ERROR (Status)) {\r
1870 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
335e2681
SZ
1871 if (!Volatile) {\r
1872 FlushHobVariableToFlash (VariableName, VendorGuid);\r
1873 }\r
72399dae 1874 }\r
1875\r
1876Done:\r
1877 return Status;\r
1878}\r
1879\r
a5f15e30
SZ
1880/**\r
1881 Check if a Unicode character is a hexadecimal character.\r
1882\r
1883 This function checks if a Unicode character is a \r
1884 hexadecimal character. The valid hexadecimal character is \r
1885 L'0' to L'9', L'a' to L'f', or L'A' to L'F'.\r
1886\r
1887\r
1888 @param Char The character to check against.\r
1889\r
1890 @retval TRUE If the Char is a hexadecmial character.\r
1891 @retval FALSE If the Char is not a hexadecmial character.\r
1892\r
1893**/\r
1894BOOLEAN\r
1895EFIAPI\r
1896IsHexaDecimalDigitCharacter (\r
1897 IN CHAR16 Char\r
1898 )\r
1899{\r
1900 return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f'));\r
1901}\r
1902\r
1903/**\r
1904\r
1905 This code checks if variable is hardware error record variable or not.\r
1906\r
1907 According to UEFI spec, hardware error record variable should use the EFI_HARDWARE_ERROR_VARIABLE VendorGuid\r
1908 and have the L"HwErrRec####" name convention, #### is a printed hex value and no 0x or h is included in the hex value.\r
1909\r
1910 @param VariableName Pointer to variable name.\r
1911 @param VendorGuid Variable Vendor Guid.\r
1912\r
1913 @retval TRUE Variable is hardware error record variable.\r
1914 @retval FALSE Variable is not hardware error record variable.\r
1915\r
1916**/\r
1917BOOLEAN\r
1918EFIAPI\r
1919IsHwErrRecVariable (\r
1920 IN CHAR16 *VariableName,\r
1921 IN EFI_GUID *VendorGuid\r
1922 )\r
1923{\r
1924 if (!CompareGuid (VendorGuid, &gEfiHardwareErrorVariableGuid) ||\r
1925 (StrLen (VariableName) != StrLen (L"HwErrRec####")) ||\r
1926 (StrnCmp(VariableName, L"HwErrRec", StrLen (L"HwErrRec")) != 0) ||\r
1927 !IsHexaDecimalDigitCharacter (VariableName[0x8]) ||\r
1928 !IsHexaDecimalDigitCharacter (VariableName[0x9]) ||\r
1929 !IsHexaDecimalDigitCharacter (VariableName[0xA]) ||\r
1930 !IsHexaDecimalDigitCharacter (VariableName[0xB])) {\r
1931 return FALSE;\r
1932 }\r
1933\r
1934 return TRUE;\r
1935}\r
1936\r
ff843847
RN
1937/**\r
1938 Mark a variable that will become read-only after leaving the DXE phase of execution.\r
1939\r
1940 @param[in] This The VARIABLE_LOCK_PROTOCOL instance.\r
1941 @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.\r
1942 @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.\r
1943\r
1944 @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked\r
1945 as pending to be read-only.\r
1946 @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.\r
1947 Or VariableName is an empty string.\r
1948 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has\r
1949 already been signaled.\r
1950 @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.\r
1951**/\r
1952EFI_STATUS\r
1953EFIAPI\r
1954VariableLockRequestToLock (\r
1955 IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,\r
1956 IN CHAR16 *VariableName,\r
1957 IN EFI_GUID *VendorGuid\r
1958 )\r
1959{\r
1960 VARIABLE_ENTRY *Entry;\r
1961\r
1962 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
1963 return EFI_INVALID_PARAMETER;\r
1964 }\r
1965\r
1966 if (mEndOfDxe) {\r
1967 return EFI_ACCESS_DENIED;\r
1968 }\r
1969\r
1970 Entry = AllocateRuntimePool (sizeof (*Entry) + StrSize (VariableName));\r
1971 if (Entry == NULL) {\r
1972 return EFI_OUT_OF_RESOURCES;\r
1973 }\r
1974\r
1975 DEBUG ((EFI_D_INFO, "[Variable] Lock: %g:%s\n", VendorGuid, VariableName));\r
1976\r
1977 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
1978\r
1979 Entry->Name = (CHAR16 *) (Entry + 1);\r
1980 StrCpy (Entry->Name, VariableName);\r
1981 CopyGuid (&Entry->Guid, VendorGuid);\r
1982 InsertTailList (&mLockedVariableList, &Entry->Link);\r
1983\r
1984 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
1985\r
1986 return EFI_SUCCESS;\r
1987}\r
1988\r
72399dae 1989/**\r
1990\r
1991 This code finds variable in storage blocks (Volatile or Non-Volatile).\r
1992\r
1993 @param VariableName Name of Variable to be found.\r
1994 @param VendorGuid Variable vendor GUID.\r
1995 @param Attributes Attribute value of the variable found.\r
1996 @param DataSize Size of Data found. If size is less than the\r
1997 data, this value contains the required size.\r
1998 @param Data Data pointer.\r
1999 \r
8a2d4996 2000 @return EFI_INVALID_PARAMETER Invalid parameter.\r
2001 @return EFI_SUCCESS Find the specified variable.\r
2002 @return EFI_NOT_FOUND Not found.\r
2003 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
72399dae 2004\r
2005**/\r
2006EFI_STATUS\r
2007EFIAPI\r
8a2d4996 2008VariableServiceGetVariable (\r
72399dae 2009 IN CHAR16 *VariableName,\r
2010 IN EFI_GUID *VendorGuid,\r
2011 OUT UINT32 *Attributes OPTIONAL,\r
2012 IN OUT UINTN *DataSize,\r
2013 OUT VOID *Data\r
2014 )\r
2015{\r
2016 EFI_STATUS Status;\r
2017 VARIABLE_POINTER_TRACK Variable;\r
2018 UINTN VarDataSize;\r
2019\r
2020 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
2021 return EFI_INVALID_PARAMETER;\r
2022 }\r
2023\r
2024 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
72399dae 2025 \r
9622df63 2026 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
72399dae 2027 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
2028 goto Done;\r
2029 }\r
2030\r
2031 //\r
2032 // Get data size\r
2033 //\r
2034 VarDataSize = DataSizeOfVariable (Variable.CurrPtr);\r
2035 ASSERT (VarDataSize != 0);\r
2036\r
2037 if (*DataSize >= VarDataSize) {\r
2038 if (Data == NULL) {\r
2039 Status = EFI_INVALID_PARAMETER;\r
2040 goto Done;\r
33a5a666 2041 }\r
72399dae 2042\r
2043 CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);\r
2044 if (Attributes != NULL) {\r
2045 *Attributes = Variable.CurrPtr->Attributes;\r
2046 }\r
2047\r
2048 *DataSize = VarDataSize;\r
2049 UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);\r
72399dae 2050 \r
2051 Status = EFI_SUCCESS;\r
2052 goto Done;\r
2053 } else {\r
2054 *DataSize = VarDataSize;\r
2055 Status = EFI_BUFFER_TOO_SMALL;\r
2056 goto Done;\r
8d3a5c82 2057 }\r
2058\r
72399dae 2059Done:\r
2060 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2061 return Status;\r
2062}\r
2063\r
2064\r
2065\r
2066/**\r
2067\r
2068 This code Finds the Next available variable.\r
2069\r
8a2d4996 2070 @param VariableNameSize Size of the variable name.\r
2071 @param VariableName Pointer to variable name.\r
2072 @param VendorGuid Variable Vendor Guid.\r
72399dae 2073\r
8a2d4996 2074 @return EFI_INVALID_PARAMETER Invalid parameter.\r
2075 @return EFI_SUCCESS Find the specified variable.\r
2076 @return EFI_NOT_FOUND Not found.\r
2077 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
72399dae 2078\r
2079**/\r
2080EFI_STATUS\r
2081EFIAPI\r
8a2d4996 2082VariableServiceGetNextVariableName (\r
72399dae 2083 IN OUT UINTN *VariableNameSize,\r
2084 IN OUT CHAR16 *VariableName,\r
2085 IN OUT EFI_GUID *VendorGuid\r
2086 )\r
2087{\r
0f7aff72 2088 VARIABLE_STORE_TYPE Type;\r
72399dae 2089 VARIABLE_POINTER_TRACK Variable;\r
0f7aff72 2090 VARIABLE_POINTER_TRACK VariableInHob;\r
23b06935 2091 VARIABLE_POINTER_TRACK VariablePtrTrack;\r
72399dae 2092 UINTN VarNameSize;\r
2093 EFI_STATUS Status;\r
0f7aff72 2094 VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];\r
72399dae 2095\r
2096 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
2097 return EFI_INVALID_PARAMETER;\r
2098 }\r
2099\r
2100 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2101\r
9622df63 2102 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
72399dae 2103 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
2104 goto Done;\r
2105 }\r
2106\r
2107 if (VariableName[0] != 0) {\r
2108 //\r
8a2d4996 2109 // If variable name is not NULL, get next variable.\r
72399dae 2110 //\r
2111 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
2112 }\r
2113\r
0f7aff72
RN
2114 //\r
2115 // 0: Volatile, 1: HOB, 2: Non-Volatile.\r
2116 // The index and attributes mapping must be kept in this order as FindVariable\r
2117 // makes use of this mapping to implement search algorithm.\r
2118 //\r
2119 VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
2120 VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;\r
2121 VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache;\r
2122\r
72399dae 2123 while (TRUE) {\r
2124 //\r
0f7aff72 2125 // Switch from Volatile to HOB, to Non-Volatile.\r
72399dae 2126 //\r
0f7aff72
RN
2127 while ((Variable.CurrPtr >= Variable.EndPtr) ||\r
2128 (Variable.CurrPtr == NULL) ||\r
2129 !IsValidVariableHeader (Variable.CurrPtr)\r
2130 ) {\r
2131 //\r
2132 // Find current storage index\r
2133 //\r
2134 for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {\r
2135 if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) {\r
2136 break;\r
2137 }\r
2138 }\r
2139 ASSERT (Type < VariableStoreTypeMax);\r
2140 //\r
2141 // Switch to next storage\r
2142 //\r
2143 for (Type++; Type < VariableStoreTypeMax; Type++) {\r
2144 if (VariableStoreHeader[Type] != NULL) {\r
2145 break;\r
2146 }\r
2147 }\r
2148 //\r
2149 // Capture the case that \r
2150 // 1. current storage is the last one, or\r
2151 // 2. no further storage\r
2152 //\r
2153 if (Type == VariableStoreTypeMax) {\r
72399dae 2154 Status = EFI_NOT_FOUND;\r
2155 goto Done;\r
2156 }\r
0f7aff72
RN
2157 Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]);\r
2158 Variable.EndPtr = GetEndPointer (VariableStoreHeader[Type]);\r
2159 Variable.CurrPtr = Variable.StartPtr;\r
72399dae 2160 }\r
0f7aff72 2161\r
72399dae 2162 //\r
2163 // Variable is found\r
2164 //\r
23b06935
SZ
2165 if (Variable.CurrPtr->State == VAR_ADDED || Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
2166 if (!AtRuntime () || ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {\r
2167 if (Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
2168 //\r
2169 // If it is a IN_DELETED_TRANSITION variable,\r
2170 // and there is also a same ADDED one at the same time,\r
2171 // don't return it.\r
2172 //\r
2173 VariablePtrTrack.StartPtr = Variable.StartPtr;\r
2174 VariablePtrTrack.EndPtr = Variable.EndPtr;\r
2175 Status = FindVariableEx (\r
2176 GetVariableNamePtr (Variable.CurrPtr),\r
2177 &Variable.CurrPtr->VendorGuid,\r
2178 FALSE,\r
2179 &VariablePtrTrack\r
2180 );\r
2181 if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr->State == VAR_ADDED) {\r
2182 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
2183 continue;\r
2184 }\r
2185 }\r
0f7aff72
RN
2186\r
2187 //\r
2188 // Don't return NV variable when HOB overrides it\r
2189 //\r
2190 if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) && (VariableStoreHeader[VariableStoreTypeNv] != NULL) && \r
2191 (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv]))\r
2192 ) {\r
2193 VariableInHob.StartPtr = GetStartPointer (VariableStoreHeader[VariableStoreTypeHob]);\r
2194 VariableInHob.EndPtr = GetEndPointer (VariableStoreHeader[VariableStoreTypeHob]);\r
2195 Status = FindVariableEx (\r
2196 GetVariableNamePtr (Variable.CurrPtr),\r
2197 &Variable.CurrPtr->VendorGuid,\r
9622df63 2198 FALSE,\r
0f7aff72
RN
2199 &VariableInHob\r
2200 );\r
2201 if (!EFI_ERROR (Status)) {\r
2202 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
2203 continue;\r
2204 }\r
2205 }\r
2206\r
72399dae 2207 VarNameSize = NameSizeOfVariable (Variable.CurrPtr);\r
2208 ASSERT (VarNameSize != 0);\r
2209\r
2210 if (VarNameSize <= *VariableNameSize) {\r
0f7aff72
RN
2211 CopyMem (VariableName, GetVariableNamePtr (Variable.CurrPtr), VarNameSize);\r
2212 CopyMem (VendorGuid, &Variable.CurrPtr->VendorGuid, sizeof (EFI_GUID));\r
72399dae 2213 Status = EFI_SUCCESS;\r
2214 } else {\r
2215 Status = EFI_BUFFER_TOO_SMALL;\r
2216 }\r
2217\r
2218 *VariableNameSize = VarNameSize;\r
2219 goto Done;\r
2220 }\r
2221 }\r
2222\r
2223 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
2224 }\r
33a5a666 2225\r
8d3a5c82 2226Done:\r
72399dae 2227 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2228 return Status;\r
2229}\r
2230\r
2231/**\r
2232\r
2233 This code sets variable in storage blocks (Volatile or Non-Volatile).\r
2234\r
8a2d4996 2235 @param VariableName Name of Variable to be found.\r
2236 @param VendorGuid Variable vendor GUID.\r
72399dae 2237 @param Attributes Attribute value of the variable found\r
2238 @param DataSize Size of Data found. If size is less than the\r
2239 data, this value contains the required size.\r
8a2d4996 2240 @param Data Data pointer.\r
72399dae 2241\r
8a2d4996 2242 @return EFI_INVALID_PARAMETER Invalid parameter.\r
2243 @return EFI_SUCCESS Set successfully.\r
2244 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.\r
2245 @return EFI_NOT_FOUND Not found.\r
2246 @return EFI_WRITE_PROTECTED Variable is read-only.\r
72399dae 2247\r
2248**/\r
2249EFI_STATUS\r
2250EFIAPI\r
8a2d4996 2251VariableServiceSetVariable (\r
72399dae 2252 IN CHAR16 *VariableName,\r
2253 IN EFI_GUID *VendorGuid,\r
2254 IN UINT32 Attributes,\r
2255 IN UINTN DataSize,\r
2256 IN VOID *Data\r
2257 )\r
2258{\r
2259 VARIABLE_POINTER_TRACK Variable;\r
2260 EFI_STATUS Status;\r
2261 VARIABLE_HEADER *NextVariable;\r
2262 EFI_PHYSICAL_ADDRESS Point;\r
ff843847
RN
2263 LIST_ENTRY *Link;\r
2264 VARIABLE_ENTRY *Entry;\r
72399dae 2265\r
2266 //\r
8a2d4996 2267 // Check input parameters.\r
72399dae 2268 //\r
2269 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
2270 return EFI_INVALID_PARAMETER;\r
8a2d4996 2271 } \r
48a0e6bf 2272\r
2273 if (DataSize != 0 && Data == NULL) {\r
2274 return EFI_INVALID_PARAMETER;\r
2275 }\r
2276\r
8e38f18e 2277 //\r
6e67fec0 2278 // Not support authenticated or append variable write yet.\r
8e38f18e 2279 //\r
6e67fec0 2280 if ((Attributes & (EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS | EFI_VARIABLE_APPEND_WRITE)) != 0) {\r
8e38f18e 2281 return EFI_INVALID_PARAMETER;\r
2282 }\r
2283\r
72399dae 2284 //\r
8a2d4996 2285 // Make sure if runtime bit is set, boot service bit is set also.\r
72399dae 2286 //\r
2287 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
2288 return EFI_INVALID_PARAMETER;\r
2289 }\r
2290\r
56251c66 2291 if ((UINTN)(~0) - DataSize < StrSize(VariableName)){\r
2292 //\r
2293 // Prevent whole variable size overflow \r
2294 // \r
2295 return EFI_INVALID_PARAMETER;\r
2296 }\r
2297\r
72399dae 2298 //\r
2299 // The size of the VariableName, including the Unicode Null in bytes plus\r
188e4e84 2300 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)\r
2301 // bytes for HwErrRec, and PcdGet32 (PcdMaxVariableSize) bytes for the others.\r
72399dae 2302 //\r
2303 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
56251c66 2304 if ( StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER)) {\r
72399dae 2305 return EFI_INVALID_PARAMETER;\r
2306 }\r
a5f15e30 2307 if (!IsHwErrRecVariable(VariableName, VendorGuid)) {\r
72399dae 2308 return EFI_INVALID_PARAMETER;\r
2309 }\r
2310 } else {\r
2311 //\r
2312 // The size of the VariableName, including the Unicode Null in bytes plus\r
188e4e84 2313 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxVariableSize) bytes.\r
72399dae 2314 //\r
56251c66 2315 if (StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER)) {\r
72399dae 2316 return EFI_INVALID_PARAMETER;\r
2317 } \r
021a1af9
SZ
2318 }\r
2319\r
72399dae 2320 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2321\r
2322 //\r
8a2d4996 2323 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.\r
72399dae 2324 //\r
2325 if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {\r
8a2d4996 2326 Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
72399dae 2327 //\r
8a2d4996 2328 // Parse non-volatile variable data and get last variable offset.\r
72399dae 2329 //\r
2330 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point);\r
2331 while ((NextVariable < GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point)) \r
2332 && IsValidVariableHeader (NextVariable)) {\r
2333 NextVariable = GetNextVariablePtr (NextVariable);\r
2334 }\r
2335 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;\r
2336 }\r
2337\r
ff843847
RN
2338 if (mEndOfDxe && mEnableLocking) {\r
2339 //\r
2340 // Treat the variables listed in the forbidden variable list as read-only after leaving DXE phase.\r
2341 //\r
2342 for ( Link = GetFirstNode (&mLockedVariableList)\r
2343 ; !IsNull (&mLockedVariableList, Link)\r
2344 ; Link = GetNextNode (&mLockedVariableList, Link)\r
2345 ) {\r
2346 Entry = BASE_CR (Link, VARIABLE_ENTRY, Link);\r
2347 if (CompareGuid (&Entry->Guid, VendorGuid) && (StrCmp (Entry->Name, VariableName) == 0)) {\r
2348 Status = EFI_WRITE_PROTECTED;\r
2349 DEBUG ((EFI_D_INFO, "[Variable]: Changing readonly variable after leaving DXE phase - %g:%s\n", VendorGuid, VariableName));\r
2350 goto Done;\r
2351 }\r
2352 }\r
2353 }\r
2354\r
72399dae 2355 //\r
8a2d4996 2356 // Check whether the input variable is already existed.\r
72399dae 2357 //\r
9622df63
SZ
2358 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, TRUE);\r
2359 if (!EFI_ERROR (Status)) {\r
2360 if (((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) && AtRuntime ()) {\r
ff843847
RN
2361 Status = EFI_WRITE_PROTECTED;\r
2362 goto Done;\r
9622df63 2363 }\r
6e67fec0
SZ
2364 if (Attributes != 0 && Attributes != Variable.CurrPtr->Attributes) {\r
2365 //\r
2366 // If a preexisting variable is rewritten with different attributes, SetVariable() shall not\r
2367 // modify the variable and shall return EFI_INVALID_PARAMETER. Two exceptions to this rule:\r
2368 // 1. No access attributes specified\r
2369 // 2. The only attribute differing is EFI_VARIABLE_APPEND_WRITE\r
2370 //\r
2371 Status = EFI_INVALID_PARAMETER;\r
2372 goto Done;\r
2373 }\r
9622df63 2374 }\r
72399dae 2375\r
2376 //\r
8a2d4996 2377 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.\r
72399dae 2378 //\r
2379 AutoUpdateLangVariable (VariableName, Data, DataSize);\r
2380\r
2381 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, &Variable);\r
2382\r
ff843847 2383Done:\r
fdb7765f 2384 InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);\r
052ad7e1 2385 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
fdb7765f 2386\r
8d3a5c82 2387 return Status;\r
2388}\r
2389\r
7c80e839 2390/**\r
8d3a5c82 2391\r
2392 This code returns information about the EFI variables.\r
2393\r
7c80e839 2394 @param Attributes Attributes bitmask to specify the type of variables\r
2395 on which to return information.\r
2396 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
2397 for the EFI variables associated with the attributes specified.\r
2398 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
2399 for EFI variables associated with the attributes specified.\r
2400 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables\r
2401 associated with the attributes specified.\r
8d3a5c82 2402\r
7c80e839 2403 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.\r
2404 @return EFI_SUCCESS Query successfully.\r
2405 @return EFI_UNSUPPORTED The attribute is not supported on this platform.\r
8d3a5c82 2406\r
7c80e839 2407**/\r
052ad7e1
A
2408EFI_STATUS\r
2409EFIAPI\r
8a2d4996 2410VariableServiceQueryVariableInfo (\r
052ad7e1
A
2411 IN UINT32 Attributes,\r
2412 OUT UINT64 *MaximumVariableStorageSize,\r
2413 OUT UINT64 *RemainingVariableStorageSize,\r
2414 OUT UINT64 *MaximumVariableSize\r
2415 )\r
8d3a5c82 2416{\r
2417 VARIABLE_HEADER *Variable;\r
2418 VARIABLE_HEADER *NextVariable;\r
2419 UINT64 VariableSize;\r
2420 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
2fcdca1d 2421 UINT64 CommonVariableTotalSize;\r
2422 UINT64 HwErrVariableTotalSize;\r
2423\r
2424 CommonVariableTotalSize = 0;\r
2425 HwErrVariableTotalSize = 0;\r
8d3a5c82 2426\r
c6492839 2427 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
8d3a5c82 2428 return EFI_INVALID_PARAMETER;\r
2429 }\r
2fcdca1d 2430\r
c6492839 2431 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {\r
8d3a5c82 2432 //\r
2433 // Make sure the Attributes combination is supported by the platform.\r
2434 //\r
c6492839 2435 return EFI_UNSUPPORTED; \r
8d3a5c82 2436 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
2437 //\r
2438 // Make sure if runtime bit is set, boot service bit is set also.\r
2439 //\r
2440 return EFI_INVALID_PARAMETER;\r
8a2d4996 2441 } else if (AtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {\r
8d3a5c82 2442 //\r
2443 // Make sure RT Attribute is set if we are in Runtime phase.\r
2444 //\r
2445 return EFI_INVALID_PARAMETER;\r
2fcdca1d 2446 } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2447 //\r
2448 // Make sure Hw Attribute is set with NV.\r
2449 //\r
2450 return EFI_INVALID_PARAMETER;\r
8e38f18e 2451 } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
2452 //\r
2453 // Not support authentiated variable write yet.\r
2454 //\r
2455 return EFI_UNSUPPORTED;\r
8d3a5c82 2456 }\r
2457\r
052ad7e1 2458 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
8d3a5c82 2459\r
2460 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
2461 //\r
2462 // Query is Volatile related.\r
2463 //\r
052ad7e1 2464 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
8d3a5c82 2465 } else {\r
2466 //\r
2467 // Query is Non-Volatile related.\r
2468 //\r
8a2d4996 2469 VariableStoreHeader = mNvVariableCache;\r
8d3a5c82 2470 }\r
2471\r
2472 //\r
2473 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize\r
2474 // with the storage size (excluding the storage header size).\r
2475 //\r
2476 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
c6492839 2477\r
2478 //\r
2479 // Harware error record variable needs larger size.\r
2480 //\r
2fcdca1d 2481 if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
188e4e84 2482 *MaximumVariableStorageSize = PcdGet32 (PcdHwErrStorageSize);\r
2483 *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);\r
2fcdca1d 2484 } else {\r
2485 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
188e4e84 2486 ASSERT (PcdGet32 (PcdHwErrStorageSize) < VariableStoreHeader->Size);\r
2487 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize);\r
2fcdca1d 2488 }\r
2489\r
2490 //\r
188e4e84 2491 // Let *MaximumVariableSize be PcdGet32 (PcdMaxVariableSize) with the exception of the variable header size.\r
2fcdca1d 2492 //\r
188e4e84 2493 *MaximumVariableSize = PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);\r
c6492839 2494 }\r
8d3a5c82 2495\r
2496 //\r
2497 // Point to the starting address of the variables.\r
2498 //\r
9cad030b 2499 Variable = GetStartPointer (VariableStoreHeader);\r
8d3a5c82 2500\r
2501 //\r
2502 // Now walk through the related variable store.\r
2503 //\r
6f90dfbc 2504 while ((Variable < GetEndPointer (VariableStoreHeader)) && IsValidVariableHeader (Variable)) {\r
8d3a5c82 2505 NextVariable = GetNextVariablePtr (Variable);\r
2506 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;\r
2507\r
8a2d4996 2508 if (AtRuntime ()) {\r
8d3a5c82 2509 //\r
8a2d4996 2510 // We don't take the state of the variables in mind\r
8d3a5c82 2511 // when calculating RemainingVariableStorageSize,\r
2512 // since the space occupied by variables not marked with\r
2513 // VAR_ADDED is not allowed to be reclaimed in Runtime.\r
2514 //\r
3b425367 2515 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2fcdca1d 2516 HwErrVariableTotalSize += VariableSize;\r
2517 } else {\r
2518 CommonVariableTotalSize += VariableSize;\r
2519 }\r
8d3a5c82 2520 } else {\r
2521 //\r
8a2d4996 2522 // Only care about Variables with State VAR_ADDED, because\r
8d3a5c82 2523 // the space not marked as VAR_ADDED is reclaimable now.\r
2524 //\r
2525 if (Variable->State == VAR_ADDED) {\r
3b425367 2526 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2fcdca1d 2527 HwErrVariableTotalSize += VariableSize;\r
2528 } else {\r
2529 CommonVariableTotalSize += VariableSize;\r
2530 }\r
8d3a5c82 2531 }\r
2532 }\r
2533\r
2534 //\r
8a2d4996 2535 // Go to the next one.\r
8d3a5c82 2536 //\r
2537 Variable = NextVariable;\r
2538 }\r
2539\r
2fcdca1d 2540 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){\r
2541 *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;\r
2542 }else {\r
2543 *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;\r
2544 }\r
2545\r
c6492839 2546 if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {\r
2547 *MaximumVariableSize = 0;\r
2548 } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {\r
2549 *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);\r
2550 }\r
2551\r
052ad7e1 2552 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
8d3a5c82 2553 return EFI_SUCCESS;\r
2554}\r
2555\r
7c80e839 2556\r
2557/**\r
8a2d4996 2558 This function reclaims variable storage if free size is below the threshold.\r
2559 \r
7c80e839 2560**/\r
7800593d 2561VOID\r
7800593d 2562ReclaimForOS(\r
8a2d4996 2563 VOID\r
7800593d
LG
2564 )\r
2565{\r
9948c0b0 2566 EFI_STATUS Status;\r
2fcdca1d 2567 UINTN CommonVariableSpace;\r
2568 UINTN RemainingCommonVariableSpace;\r
2569 UINTN RemainingHwErrVariableSpace;\r
7800593d 2570\r
7800593d
LG
2571 Status = EFI_SUCCESS; \r
2572\r
2fcdca1d 2573 CommonVariableSpace = ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize); //Allowable max size of common variable storage space\r
2574\r
2575 RemainingCommonVariableSpace = CommonVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;\r
2576\r
2577 RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;\r
7800593d 2578 //\r
9948c0b0 2579 // Check if the free area is blow a threshold.\r
7800593d 2580 //\r
2fcdca1d 2581 if ((RemainingCommonVariableSpace < PcdGet32 (PcdMaxVariableSize))\r
9948c0b0 2582 || ((PcdGet32 (PcdHwErrStorageSize) != 0) && \r
2583 (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize)))){\r
7800593d 2584 Status = Reclaim (\r
2fcdca1d 2585 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
2586 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
2587 FALSE,\r
335e2681
SZ
2588 NULL,\r
2589 FALSE\r
2fcdca1d 2590 );\r
7800593d
LG
2591 ASSERT_EFI_ERROR (Status);\r
2592 }\r
2593}\r
2594\r
3e02ebb2
SZ
2595/**\r
2596 Init non-volatile variable store.\r
2597\r
2598 @retval EFI_SUCCESS Function successfully executed.\r
2599 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r
2600 @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.\r
2601\r
2602**/\r
2603EFI_STATUS\r
2604InitNonVolatileVariableStore (\r
2605 VOID\r
2606 )\r
2607{\r
2608 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
2609 VARIABLE_HEADER *NextVariable;\r
2610 EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
2611 UINT64 VariableStoreLength;\r
2612 UINTN VariableSize;\r
2613 EFI_HOB_GUID_TYPE *GuidHob;\r
2614 EFI_PHYSICAL_ADDRESS NvStorageBase;\r
2615 UINT8 *NvStorageData;\r
2616 UINT32 NvStorageSize;\r
2617 FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;\r
2618 UINT32 BackUpOffset;\r
2619 UINT32 BackUpSize;\r
2620\r
2621 mVariableModuleGlobal->FvbInstance = NULL;\r
2622\r
2623 //\r
2624 // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r
2625 // is stored with common variable in the same NV region. So the platform integrator should\r
2626 // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of\r
2627 // PcdFlashNvStorageVariableSize.\r
2628 //\r
2629 ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));\r
2630\r
2631 //\r
2632 // Allocate runtime memory used for a memory copy of the FLASH region.\r
2633 // Keep the memory and the FLASH in sync as updates occur.\r
2634 //\r
2635 NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);\r
2636 NvStorageData = AllocateRuntimeZeroPool (NvStorageSize);\r
2637 if (NvStorageData == NULL) {\r
2638 return EFI_OUT_OF_RESOURCES;\r
2639 }\r
2640\r
2641 NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
2642 if (NvStorageBase == 0) {\r
2643 NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
2644 }\r
2645 //\r
2646 // Copy NV storage data to the memory buffer.\r
2647 //\r
2648 CopyMem (NvStorageData, (UINT8 *) (UINTN) NvStorageBase, NvStorageSize);\r
2649\r
2650 //\r
2651 // Check the FTW last write data hob.\r
2652 //\r
2653 GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);\r
2654 if (GuidHob != NULL) {\r
2655 FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob);\r
2656 if (FtwLastWriteData->TargetAddress == NvStorageBase) {\r
2657 DEBUG ((EFI_D_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress));\r
2658 //\r
2659 // Copy the backed up NV storage data to the memory buffer from spare block.\r
2660 //\r
2661 CopyMem (NvStorageData, (UINT8 *) (UINTN) (FtwLastWriteData->SpareAddress), NvStorageSize);\r
2662 } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) &&\r
2663 (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {\r
2664 //\r
2665 // Flash NV storage from the offset is backed up in spare block.\r
2666 //\r
2667 BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase);\r
2668 BackUpSize = NvStorageSize - BackUpOffset;\r
2669 DEBUG ((EFI_D_INFO, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN) FtwLastWriteData->SpareAddress));\r
2670 //\r
2671 // Copy the partial backed up NV storage data to the memory buffer from spare block.\r
2672 //\r
2673 CopyMem (NvStorageData + BackUpOffset, (UINT8 *) (UINTN) FtwLastWriteData->SpareAddress, BackUpSize);\r
2674 }\r
2675 }\r
2676\r
2677 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) NvStorageData;\r
2678\r
2679 //\r
2680 // Check if the Firmware Volume is not corrupted\r
2681 //\r
2682 if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {\r
2683 FreePool (NvStorageData);\r
2684 DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n"));\r
2685 return EFI_VOLUME_CORRUPTED;\r
2686 }\r
2687\r
2688 VariableStoreBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) FvHeader + FvHeader->HeaderLength);\r
2689 VariableStoreLength = (UINT64) (NvStorageSize - FvHeader->HeaderLength);\r
2690\r
2691 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
2692 mNvVariableCache = (VARIABLE_STORE_HEADER *) (UINTN) VariableStoreBase;\r
2693 if (GetVariableStoreStatus (mNvVariableCache) != EfiValid) {\r
2694 FreePool (NvStorageData);\r
2695 DEBUG((EFI_D_ERROR, "Variable Store header is corrupted\n"));\r
2696 return EFI_VOLUME_CORRUPTED;\r
2697 }\r
2698 ASSERT(mNvVariableCache->Size == VariableStoreLength);\r
2699\r
2700 //\r
2701 // The max variable or hardware error variable size should be < variable store size.\r
2702 //\r
2703 ASSERT(MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) < VariableStoreLength);\r
2704\r
2705 //\r
2706 // Parse non-volatile variable data and get last variable offset.\r
2707 //\r
2708 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);\r
2709 while (IsValidVariableHeader (NextVariable)) {\r
2710 VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);\r
2711 if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
2712 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);\r
2713 } else {\r
2714 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);\r
2715 }\r
2716\r
2717 NextVariable = GetNextVariablePtr (NextVariable);\r
2718 }\r
2719 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;\r
2720\r
2721 return EFI_SUCCESS;\r
2722}\r
2723\r
335e2681
SZ
2724/**\r
2725 Flush the HOB variable to flash.\r
2726\r
2727 @param[in] VariableName Name of variable has been updated or deleted.\r
2728 @param[in] VendorGuid Guid of variable has been updated or deleted.\r
2729\r
2730**/\r
2731VOID\r
2732FlushHobVariableToFlash (\r
2733 IN CHAR16 *VariableName,\r
2734 IN EFI_GUID *VendorGuid\r
2735 )\r
2736{\r
2737 EFI_STATUS Status;\r
2738 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
2739 VARIABLE_HEADER *Variable;\r
2740 VOID *VariableData;\r
2741 BOOLEAN ErrorFlag;\r
2742\r
2743 ErrorFlag = FALSE;\r
2744\r
2745 //\r
2746 // Flush the HOB variable to flash.\r
2747 //\r
2748 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {\r
2749 VariableStoreHeader = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;\r
2750 //\r
2751 // Set HobVariableBase to 0, it can avoid SetVariable to call back.\r
2752 //\r
2753 mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;\r
2754 for ( Variable = GetStartPointer (VariableStoreHeader)\r
2755 ; (Variable < GetEndPointer (VariableStoreHeader) && IsValidVariableHeader (Variable))\r
2756 ; Variable = GetNextVariablePtr (Variable)\r
2757 ) {\r
2758 if (Variable->State != VAR_ADDED) {\r
2759 //\r
2760 // The HOB variable has been set to DELETED state in local.\r
2761 //\r
2762 continue;\r
2763 }\r
2764 ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0);\r
2765 if (VendorGuid == NULL || VariableName == NULL ||\r
2766 !CompareGuid (VendorGuid, &Variable->VendorGuid) ||\r
2767 StrCmp (VariableName, GetVariableNamePtr (Variable)) != 0) {\r
2768 VariableData = GetVariableDataPtr (Variable);\r
2769 Status = VariableServiceSetVariable (\r
2770 GetVariableNamePtr (Variable),\r
2771 &Variable->VendorGuid,\r
2772 Variable->Attributes,\r
2773 Variable->DataSize,\r
2774 VariableData\r
2775 );\r
2776 DEBUG ((EFI_D_INFO, "Variable driver flush the HOB variable to flash: %g %s %r\n", &Variable->VendorGuid, GetVariableNamePtr (Variable), Status));\r
2777 } else {\r
2778 //\r
2779 // The updated or deleted variable is matched with the HOB variable.\r
2780 // Don't break here because we will try to set other HOB variables\r
2781 // since this variable could be set successfully.\r
2782 //\r
2783 Status = EFI_SUCCESS;\r
2784 }\r
2785 if (!EFI_ERROR (Status)) {\r
2786 //\r
2787 // If set variable successful, or the updated or deleted variable is matched with the HOB variable,\r
2788 // set the HOB variable to DELETED state in local.\r
2789 //\r
2790 DEBUG ((EFI_D_INFO, "Variable driver set the HOB variable to DELETED state in local: %g %s\n", &Variable->VendorGuid, GetVariableNamePtr (Variable)));\r
2791 Variable->State &= VAR_DELETED;\r
2792 } else {\r
2793 ErrorFlag = TRUE;\r
2794 }\r
2795 }\r
2796 if (ErrorFlag) {\r
2797 //\r
2798 // We still have HOB variable(s) not flushed in flash.\r
2799 //\r
2800 mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStoreHeader;\r
2801 } else {\r
2802 //\r
2803 // All HOB variables have been flushed in flash.\r
2804 //\r
2805 DEBUG ((EFI_D_INFO, "Variable driver: all HOB variables have been flushed in flash.\n"));\r
2806 if (!AtRuntime ()) {\r
2807 FreePool ((VOID *) VariableStoreHeader);\r
2808 }\r
2809 }\r
2810 }\r
2811\r
2812}\r
8a2d4996 2813\r
7c80e839 2814/**\r
3e02ebb2 2815 Initializes variable write service after FTW was ready.\r
7c80e839 2816\r
8a2d4996 2817 @retval EFI_SUCCESS Function successfully executed.\r
2818 @retval Others Fail to initialize the variable service.\r
2819\r
2820**/\r
2821EFI_STATUS\r
2822VariableWriteServiceInitialize (\r
2823 VOID\r
2824 )\r
2825{\r
2826 EFI_STATUS Status;\r
2827 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
2828 UINTN Index;\r
2829 UINT8 Data;\r
8a2d4996 2830 EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
3e02ebb2 2831 EFI_PHYSICAL_ADDRESS NvStorageBase;\r
8a2d4996 2832\r
3e02ebb2
SZ
2833 NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
2834 if (NvStorageBase == 0) {\r
2835 NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
2836 }\r
2837 VariableStoreBase = NvStorageBase + (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(NvStorageBase))->HeaderLength);\r
2838\r
2839 //\r
2840 // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready.\r
2841 //\r
2842 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
8a2d4996 2843 VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
0f7aff72 2844 \r
8a2d4996 2845 //\r
2846 // Check if the free area is really free.\r
2847 //\r
0f7aff72 2848 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {\r
8a2d4996 2849 Data = ((UINT8 *) mNvVariableCache)[Index];\r
2850 if (Data != 0xff) {\r
2851 //\r
2852 // There must be something wrong in variable store, do reclaim operation.\r
2853 //\r
2854 Status = Reclaim (\r
2855 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
2856 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
2857 FALSE,\r
335e2681
SZ
2858 NULL,\r
2859 TRUE\r
8a2d4996 2860 );\r
2861 if (EFI_ERROR (Status)) {\r
2862 return Status;\r
2863 }\r
2864 break;\r
2865 }\r
2866 }\r
2867\r
335e2681 2868 FlushHobVariableToFlash (NULL, NULL);\r
0f7aff72 2869\r
8a2d4996 2870 return EFI_SUCCESS;\r
2871}\r
2872\r
2873\r
2874/**\r
2875 Initializes variable store area for non-volatile and volatile variable.\r
7c80e839 2876\r
2877 @retval EFI_SUCCESS Function successfully executed.\r
2878 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r
2879\r
2880**/\r
8d3a5c82 2881EFI_STATUS\r
8d3a5c82 2882VariableCommonInitialize (\r
8a2d4996 2883 VOID\r
8d3a5c82 2884 )\r
8d3a5c82 2885{\r
2886 EFI_STATUS Status;\r
8d3a5c82 2887 VARIABLE_STORE_HEADER *VolatileVariableStore;\r
2888 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
052ad7e1 2889 UINT64 VariableStoreLength;\r
2fcdca1d 2890 UINTN ScratchSize;\r
0f7aff72 2891 EFI_HOB_GUID_TYPE *GuidHob;\r
8d3a5c82 2892\r
7800593d
LG
2893 //\r
2894 // Allocate runtime memory for variable driver global structure.\r
2895 //\r
72399dae 2896 mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL));\r
7800593d
LG
2897 if (mVariableModuleGlobal == NULL) {\r
2898 return EFI_OUT_OF_RESOURCES;\r
2899 }\r
8d3a5c82 2900\r
8a2d4996 2901 InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);\r
8d3a5c82 2902\r
0f7aff72
RN
2903 //\r
2904 // Get HOB variable store.\r
2905 //\r
2906 GuidHob = GetFirstGuidHob (&gEfiVariableGuid);\r
2907 if (GuidHob != NULL) {\r
f68af18e 2908 VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob);\r
335e2681 2909 VariableStoreLength = (UINT64) (GuidHob->Header.HobLength - sizeof (EFI_HOB_GUID_TYPE));\r
f68af18e 2910 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
335e2681
SZ
2911 mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateRuntimeCopyPool ((UINTN) VariableStoreLength, (VOID *) VariableStoreHeader);\r
2912 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) {\r
3e02ebb2 2913 FreePool (mVariableModuleGlobal);\r
335e2681
SZ
2914 return EFI_OUT_OF_RESOURCES;\r
2915 }\r
f68af18e
RN
2916 } else {\r
2917 DEBUG ((EFI_D_ERROR, "HOB Variable Store header is corrupted!\n"));\r
2918 }\r
0f7aff72
RN
2919 }\r
2920\r
8d3a5c82 2921 //\r
2fcdca1d 2922 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.\r
8d3a5c82 2923 //\r
188e4e84 2924 ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
2925 VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);\r
8d3a5c82 2926 if (VolatileVariableStore == NULL) {\r
3e02ebb2
SZ
2927 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {\r
2928 FreePool ((VOID *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase);\r
2929 }\r
8d3a5c82 2930 FreePool (mVariableModuleGlobal);\r
2931 return EFI_OUT_OF_RESOURCES;\r
2932 }\r
2933\r
188e4e84 2934 SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);\r
8d3a5c82 2935\r
2936 //\r
8a2d4996 2937 // Initialize Variable Specific Data.\r
8d3a5c82 2938 //\r
052ad7e1 2939 mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
9cad030b 2940 mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;\r
8d3a5c82 2941\r
3709c4cd 2942 CopyGuid (&VolatileVariableStore->Signature, &gEfiVariableGuid);\r
8a2d4996 2943 VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize);\r
2944 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;\r
2945 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;\r
2946 VolatileVariableStore->Reserved = 0;\r
2947 VolatileVariableStore->Reserved1 = 0;\r
8d3a5c82 2948\r
2949 //\r
3e02ebb2 2950 // Init non-volatile variable store.\r
8a2d4996 2951 //\r
3e02ebb2 2952 Status = InitNonVolatileVariableStore ();\r
8d3a5c82 2953 if (EFI_ERROR (Status)) {\r
3e02ebb2
SZ
2954 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {\r
2955 FreePool ((VOID *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase);\r
2956 }\r
8d3a5c82 2957 FreePool (mVariableModuleGlobal);\r
2958 FreePool (VolatileVariableStore);\r
2959 }\r
2960\r
2961 return Status;\r
2962}\r
052ad7e1 2963\r
052ad7e1 2964\r
aa75dfec 2965/**\r
8a2d4996 2966 Get the proper fvb handle and/or fvb protocol by the given Flash address.\r
aa75dfec 2967\r
8a2d4996 2968 @param[in] Address The Flash address.\r
2969 @param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle.\r
2970 @param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol.\r
aa75dfec 2971\r
aa75dfec 2972**/\r
8a2d4996 2973EFI_STATUS\r
2974GetFvbInfoByAddress (\r
2975 IN EFI_PHYSICAL_ADDRESS Address,\r
2976 OUT EFI_HANDLE *FvbHandle OPTIONAL,\r
2977 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvbProtocol OPTIONAL\r
8a9e0b72 2978 )\r
2979{\r
8a2d4996 2980 EFI_STATUS Status;\r
2981 EFI_HANDLE *HandleBuffer;\r
2982 UINTN HandleCount;\r
2983 UINTN Index;\r
2984 EFI_PHYSICAL_ADDRESS FvbBaseAddress;\r
2985 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
2986 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
2987 EFI_FVB_ATTRIBUTES_2 Attributes;\r
2988 \r
8a9e0b72 2989 //\r
8a2d4996 2990 // Get all FVB handles.\r
8a9e0b72 2991 //\r
8a2d4996 2992 Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);\r
8a9e0b72 2993 if (EFI_ERROR (Status)) {\r
8a2d4996 2994 return EFI_NOT_FOUND;\r
8a9e0b72 2995 }\r
8a2d4996 2996\r
8a9e0b72 2997 //\r
8a2d4996 2998 // Get the FVB to access variable store.\r
8a9e0b72 2999 //\r
8a2d4996 3000 Fvb = NULL;\r
f0480ecf 3001 for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {\r
8a2d4996 3002 Status = GetFvbByHandle (HandleBuffer[Index], &Fvb);\r
8a9e0b72 3003 if (EFI_ERROR (Status)) {\r
3004 Status = EFI_NOT_FOUND;\r
3005 break;\r
3006 }\r
3007\r
3008 //\r
3009 // Ensure this FVB protocol supported Write operation.\r
3010 //\r
3011 Status = Fvb->GetAttributes (Fvb, &Attributes);\r
3012 if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {\r
3013 continue; \r
3014 }\r
8a2d4996 3015 \r
8a9e0b72 3016 //\r
8a2d4996 3017 // Compare the address and select the right one.\r
8a9e0b72 3018 //\r
3019 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
3020 if (EFI_ERROR (Status)) {\r
3021 continue;\r
3022 }\r
3023\r
3024 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
8a2d4996 3025 if ((Address >= FvbBaseAddress) && (Address < (FvbBaseAddress + FwVolHeader->FvLength))) {\r
3026 if (FvbHandle != NULL) {\r
3027 *FvbHandle = HandleBuffer[Index];\r
3028 }\r
3029 if (FvbProtocol != NULL) {\r
3030 *FvbProtocol = Fvb;\r
3031 }\r
3032 Status = EFI_SUCCESS;\r
8a9e0b72 3033 break;\r
3034 }\r
3035 }\r
8a9e0b72 3036 FreePool (HandleBuffer);\r
533020ef 3037\r
8a2d4996 3038 if (Fvb == NULL) {\r
3039 Status = EFI_NOT_FOUND;\r
8a9e0b72 3040 }\r
052ad7e1 3041 \r
8a2d4996 3042 return Status; \r
052ad7e1
A
3043}\r
3044\r