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