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