]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
update platformlangcodes and langcodes to adapt new language convert algorithm.
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / Variable.c
CommitLineData
052ad7e1 1/** @file\r
504214c4
LG
2\r
3 Implement all four UEFI Runtime Variable services for the nonvolatile\r
4 and volatile storage space and install variable architecture protocol.\r
052ad7e1 5 \r
892b7f90 6Copyright (c) 2006 - 2009, Intel Corporation \r
504214c4
LG
7All rights reserved. This program and the accompanying materials \r
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
052ad7e1
A
20EFI_EVENT mVirtualAddressChangeEvent = NULL;\r
21EFI_HANDLE mHandle = NULL;\r
8d3a5c82 22\r
7c80e839 23///\r
24/// The current Hii implementation accesses this variable many times on every boot.\r
25/// Other common variables are only accessed once. This is why this cache algorithm\r
26/// only targets a single variable. Probably to get an performance improvement out of\r
27/// a Cache you would need a cache that improves the search performance for a variable.\r
28///\r
aa79b0b3 29VARIABLE_CACHE_ENTRY mVariableCache[] = {\r
30 {\r
31 &gEfiGlobalVariableGuid,\r
32 L"Lang",\r
33 0x00000000,\r
34 0x00,\r
35 NULL\r
36 }\r
37};\r
38\r
45f6c85b 39VARIABLE_INFO_ENTRY *gVariableInfo = NULL;\r
8a9e0b72 40EFI_EVENT mFvbRegistration = NULL;\r
41\r
aa79b0b3 42\r
7c80e839 43/**\r
44 Acquires lock only at boot time. Simply returns at runtime.\r
45\r
46 This is a temperary function which will be removed when\r
47 EfiAcquireLock() in UefiLib can handle the call in UEFI\r
48 Runtimer driver in RT phase.\r
49 It calls EfiAcquireLock() at boot time, and simply returns\r
50 at runtime.\r
51\r
52 @param Lock A pointer to the lock to acquire\r
53\r
54**/\r
8d3a5c82 55VOID\r
56AcquireLockOnlyAtBootTime (\r
57 IN EFI_LOCK *Lock\r
58 )\r
59{\r
60 if (!EfiAtRuntime ()) {\r
61 EfiAcquireLock (Lock);\r
62 }\r
63}\r
64\r
7c80e839 65/**\r
66 Releases lock only at boot time. Simply returns at runtime.\r
67\r
68 This is a temperary function which will be removed when\r
69 EfiReleaseLock() in UefiLib can handle the call in UEFI\r
70 Runtimer driver in RT phase.\r
71 It calls EfiReleaseLock() at boot time, and simply returns\r
72 at runtime.\r
73\r
74 @param Lock A pointer to the lock to release\r
75\r
76**/\r
8d3a5c82 77VOID\r
78ReleaseLockOnlyAtBootTime (\r
79 IN EFI_LOCK *Lock\r
80 )\r
81{\r
82 if (!EfiAtRuntime ()) {\r
83 EfiReleaseLock (Lock);\r
84 }\r
85}\r
86\r
33a5a666 87\r
052ad7e1
A
88/**\r
89 Routine used to track statistical information about variable usage. \r
90 The data is stored in the EFI system table so it can be accessed later.\r
91 VariableInfo.efi can dump out the table. Only Boot Services variable \r
92 accesses are tracked by this code. The PcdVariableCollectStatistics\r
93 build flag controls if this feature is enabled. \r
94\r
95 A read that hits in the cache will have Read and Cache true for \r
96 the transaction. Data is allocated by this routine, but never\r
97 freed.\r
98\r
99 @param[in] VariableName Name of the Variable to track\r
100 @param[in] VendorGuid Guid of the Variable to track\r
101 @param[in] Volatile TRUE if volatile FALSE if non-volatile\r
102 @param[in] Read TRUE if GetVariable() was called\r
103 @param[in] Write TRUE if SetVariable() was called\r
104 @param[in] Delete TRUE if deleted via SetVariable()\r
105 @param[in] Cache TRUE for a cache hit.\r
106\r
107**/\r
33a5a666
A
108VOID\r
109UpdateVariableInfo (\r
110 IN CHAR16 *VariableName,\r
111 IN EFI_GUID *VendorGuid,\r
112 IN BOOLEAN Volatile,\r
113 IN BOOLEAN Read,\r
114 IN BOOLEAN Write,\r
115 IN BOOLEAN Delete,\r
116 IN BOOLEAN Cache\r
117 )\r
118{\r
119 VARIABLE_INFO_ENTRY *Entry;\r
120\r
121 if (FeaturePcdGet (PcdVariableCollectStatistics)) {\r
122\r
123 if (EfiAtRuntime ()) {\r
124 // Don't collect statistics at runtime\r
125 return;\r
126 }\r
127\r
128 if (gVariableInfo == NULL) {\r
052ad7e1
A
129 //\r
130 // on the first call allocate a entry and place a pointer to it in\r
131 // the EFI System Table\r
132 //\r
33a5a666 133 gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
052ad7e1
A
134 ASSERT (gVariableInfo != NULL);\r
135\r
33a5a666
A
136 CopyGuid (&gVariableInfo->VendorGuid, VendorGuid);\r
137 gVariableInfo->Name = AllocatePool (StrLen (VariableName));\r
e6c4ef13 138 ASSERT (gVariableInfo->Name != NULL);\r
33a5a666
A
139 StrCpy (gVariableInfo->Name, VariableName);\r
140 gVariableInfo->Volatile = Volatile;\r
141\r
3709c4cd 142 gBS->InstallConfigurationTable (&gEfiVariableGuid, gVariableInfo);\r
33a5a666
A
143 }\r
144\r
145 \r
146 for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) {\r
147 if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {\r
148 if (StrCmp (VariableName, Entry->Name) == 0) {\r
149 if (Read) {\r
150 Entry->ReadCount++;\r
151 }\r
152 if (Write) {\r
153 Entry->WriteCount++;\r
154 }\r
155 if (Delete) {\r
156 Entry->DeleteCount++;\r
157 }\r
158 if (Cache) {\r
159 Entry->CacheCount++;\r
160 }\r
161\r
162 return;\r
163 }\r
164 }\r
165\r
166 if (Entry->Next == NULL) {\r
052ad7e1
A
167 //\r
168 // If the entry is not in the table add it.\r
169 // Next iteration of the loop will fill in the data\r
170 //\r
33a5a666 171 Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
052ad7e1 172 ASSERT (Entry->Next != NULL);\r
33a5a666
A
173\r
174 CopyGuid (&Entry->Next->VendorGuid, VendorGuid);\r
175 Entry->Next->Name = AllocatePool (StrLen (VariableName));\r
e6c4ef13 176 ASSERT (Entry->Next->Name != NULL);\r
33a5a666
A
177 StrCpy (Entry->Next->Name, VariableName);\r
178 Entry->Next->Volatile = Volatile;\r
179 }\r
180\r
181 }\r
182 }\r
183}\r
184\r
185\r
7c80e839 186/**\r
8d3a5c82 187\r
188 This code checks if variable header is valid or not.\r
189\r
7c80e839 190 @param Variable Pointer to the Variable Header.\r
8d3a5c82 191\r
7c80e839 192 @retval TRUE Variable header is valid.\r
193 @retval FALSE Variable header is not valid.\r
8d3a5c82 194\r
7c80e839 195**/\r
196BOOLEAN\r
197IsValidVariableHeader (\r
198 IN VARIABLE_HEADER *Variable\r
199 )\r
8d3a5c82 200{\r
fdb7765f 201 if (Variable == NULL || Variable->StartId != VARIABLE_DATA) {\r
8d3a5c82 202 return FALSE;\r
203 }\r
204\r
205 return TRUE;\r
206}\r
207\r
052ad7e1 208\r
7c80e839 209/**\r
210\r
211 This function writes data to the FWH at the correct LBA even if the LBAs\r
212 are fragmented.\r
213\r
214 @param Global Pointer to VARAIBLE_GLOBAL structure\r
215 @param Volatile Point out the Variable is Volatile or Non-Volatile\r
216 @param SetByIndex TRUE if target pointer is given as index\r
217 FALSE if target pointer is absolute\r
8a9e0b72 218 @param Fvb Pointer to the writable FVB protocol\r
7c80e839 219 @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER\r
220 structure\r
221 @param DataSize Size of data to be written\r
222 @param Buffer Pointer to the buffer from which data is written\r
223\r
224 @retval EFI_INVALID_PARAMETER Parameters not valid\r
225 @retval EFI_SUCCESS Variable store successfully updated\r
226\r
227**/\r
8d3a5c82 228EFI_STATUS\r
8d3a5c82 229UpdateVariableStore (\r
8a9e0b72 230 IN VARIABLE_GLOBAL *Global,\r
231 IN BOOLEAN Volatile,\r
232 IN BOOLEAN SetByIndex,\r
233 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,\r
234 IN UINTN DataPtrIndex,\r
235 IN UINT32 DataSize,\r
236 IN UINT8 *Buffer\r
8d3a5c82 237 )\r
8d3a5c82 238{\r
239 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
240 UINTN BlockIndex2;\r
241 UINTN LinearOffset;\r
242 UINTN CurrWriteSize;\r
243 UINTN CurrWritePtr;\r
244 UINT8 *CurrBuffer;\r
245 EFI_LBA LbaNumber;\r
246 UINTN Size;\r
247 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
248 VARIABLE_STORE_HEADER *VolatileBase;\r
249 EFI_PHYSICAL_ADDRESS FvVolHdr;\r
250 EFI_PHYSICAL_ADDRESS DataPtr;\r
251 EFI_STATUS Status;\r
252\r
253 FwVolHeader = NULL;\r
254 DataPtr = DataPtrIndex;\r
255\r
256 //\r
257 // Check if the Data is Volatile\r
258 //\r
259 if (!Volatile) {\r
8a9e0b72 260 Status = Fvb->GetPhysicalAddress(Fvb, &FvVolHdr);\r
261 ASSERT_EFI_ERROR (Status);\r
262\r
8d3a5c82 263 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);\r
264 //\r
265 // Data Pointer should point to the actual Address where data is to be\r
266 // written\r
267 //\r
268 if (SetByIndex) {\r
052ad7e1 269 DataPtr += mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
8d3a5c82 270 }\r
271\r
272 if ((DataPtr + DataSize) >= ((EFI_PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) FwVolHeader + FwVolHeader->FvLength))) {\r
273 return EFI_INVALID_PARAMETER;\r
274 }\r
275 } else {\r
276 //\r
277 // Data Pointer should point to the actual Address where data is to be\r
278 // written\r
279 //\r
052ad7e1 280 VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
8d3a5c82 281 if (SetByIndex) {\r
052ad7e1 282 DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
8d3a5c82 283 }\r
284\r
285 if ((DataPtr + DataSize) >= ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) {\r
286 return EFI_INVALID_PARAMETER;\r
287 }\r
c6492839 288 \r
289 //\r
290 // If Volatile Variable just do a simple mem copy.\r
291 // \r
292 CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize);\r
8d3a5c82 293 return EFI_SUCCESS;\r
294 }\r
c6492839 295 \r
8d3a5c82 296 //\r
297 // If we are here we are dealing with Non-Volatile Variables\r
298 //\r
299 LinearOffset = (UINTN) FwVolHeader;\r
300 CurrWritePtr = (UINTN) DataPtr;\r
301 CurrWriteSize = DataSize;\r
302 CurrBuffer = Buffer;\r
303 LbaNumber = 0;\r
304\r
305 if (CurrWritePtr < LinearOffset) {\r
306 return EFI_INVALID_PARAMETER;\r
307 }\r
308\r
309 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
310 for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {\r
311 //\r
312 // Check to see if the Variable Writes are spanning through multiple\r
313 // blocks.\r
314 //\r
315 if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) {\r
316 if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {\r
8a9e0b72 317 Status = Fvb->Write (\r
318 Fvb,\r
8d3a5c82 319 LbaNumber,\r
320 (UINTN) (CurrWritePtr - LinearOffset),\r
321 &CurrWriteSize,\r
322 CurrBuffer\r
323 );\r
8a9e0b72 324 return Status;\r
8d3a5c82 325 } else {\r
326 Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);\r
8a9e0b72 327 Status = Fvb->Write (\r
328 Fvb,\r
8d3a5c82 329 LbaNumber,\r
330 (UINTN) (CurrWritePtr - LinearOffset),\r
331 &Size,\r
332 CurrBuffer\r
333 );\r
334 if (EFI_ERROR (Status)) {\r
335 return Status;\r
336 }\r
337\r
338 CurrWritePtr = LinearOffset + PtrBlockMapEntry->Length;\r
339 CurrBuffer = CurrBuffer + Size;\r
340 CurrWriteSize = CurrWriteSize - Size;\r
341 }\r
342 }\r
343\r
344 LinearOffset += PtrBlockMapEntry->Length;\r
345 LbaNumber++;\r
346 }\r
347 }\r
348\r
349 return EFI_SUCCESS;\r
350}\r
351\r
052ad7e1 352\r
7c80e839 353/**\r
8d3a5c82 354\r
355 This code gets the current status of Variable Store.\r
356\r
7c80e839 357 @param VarStoreHeader Pointer to the Variable Store Header.\r
8d3a5c82 358\r
7c80e839 359 @retval EfiRaw Variable store status is raw\r
360 @retval EfiValid Variable store status is valid\r
361 @retval EfiInvalid Variable store status is invalid\r
8d3a5c82 362\r
7c80e839 363**/\r
364VARIABLE_STORE_STATUS\r
365GetVariableStoreStatus (\r
366 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
367 )\r
8d3a5c82 368{\r
3709c4cd 369 if (CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid) &&\r
8d3a5c82 370 VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&\r
371 VarStoreHeader->State == VARIABLE_STORE_HEALTHY\r
372 ) {\r
373\r
374 return EfiValid;\r
3709c4cd 375 } else if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff &&\r
376 ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff &&\r
377 ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff &&\r
378 ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff &&\r
379 VarStoreHeader->Size == 0xffffffff &&\r
380 VarStoreHeader->Format == 0xff &&\r
381 VarStoreHeader->State == 0xff\r
8d3a5c82 382 ) {\r
383\r
384 return EfiRaw;\r
385 } else {\r
386 return EfiInvalid;\r
387 }\r
388}\r
389\r
130e2569 390\r
7c80e839 391/**\r
130e2569 392\r
393 This code gets the size of name of variable.\r
394\r
7c80e839 395 @param Variable Pointer to the Variable Header\r
130e2569 396\r
7c80e839 397 @return UINTN Size of variable in bytes\r
130e2569 398\r
7c80e839 399**/\r
400UINTN\r
401NameSizeOfVariable (\r
402 IN VARIABLE_HEADER *Variable\r
403 )\r
130e2569 404{\r
405 if (Variable->State == (UINT8) (-1) ||\r
7c80e839 406 Variable->DataSize == (UINT32) (-1) ||\r
407 Variable->NameSize == (UINT32) (-1) ||\r
408 Variable->Attributes == (UINT32) (-1)) {\r
130e2569 409 return 0;\r
410 }\r
411 return (UINTN) Variable->NameSize;\r
412}\r
413\r
7c80e839 414/**\r
130e2569 415\r
7c80e839 416 This code gets the size of variable data.\r
130e2569 417\r
7c80e839 418 @param Variable Pointer to the Variable Header\r
130e2569 419\r
7c80e839 420 @return Size of variable in bytes\r
130e2569 421\r
7c80e839 422**/\r
423UINTN\r
424DataSizeOfVariable (\r
425 IN VARIABLE_HEADER *Variable\r
426 )\r
130e2569 427{\r
7c80e839 428 if (Variable->State == (UINT8) (-1) ||\r
429 Variable->DataSize == (UINT32) (-1) ||\r
430 Variable->NameSize == (UINT32) (-1) ||\r
431 Variable->Attributes == (UINT32) (-1)) {\r
130e2569 432 return 0;\r
433 }\r
434 return (UINTN) Variable->DataSize;\r
435}\r
436\r
7c80e839 437/**\r
130e2569 438\r
439 This code gets the pointer to the variable name.\r
440\r
7c80e839 441 @param Variable Pointer to the Variable Header\r
130e2569 442\r
7c80e839 443 @return Pointer to Variable Name which is Unicode encoding\r
130e2569 444\r
7c80e839 445**/\r
446CHAR16 *\r
447GetVariableNamePtr (\r
448 IN VARIABLE_HEADER *Variable\r
449 )\r
130e2569 450{\r
451\r
452 return (CHAR16 *) (Variable + 1);\r
453}\r
454\r
7c80e839 455/**\r
8d3a5c82 456\r
457 This code gets the pointer to the variable data.\r
458\r
7c80e839 459 @param Variable Pointer to the Variable Header\r
8d3a5c82 460\r
7c80e839 461 @return Pointer to Variable Data\r
8d3a5c82 462\r
7c80e839 463**/\r
464UINT8 *\r
465GetVariableDataPtr (\r
466 IN VARIABLE_HEADER *Variable\r
467 )\r
8d3a5c82 468{\r
130e2569 469 UINTN Value;\r
470 \r
8d3a5c82 471 //\r
472 // Be careful about pad size for alignment\r
473 //\r
130e2569 474 Value = (UINTN) GetVariableNamePtr (Variable);\r
475 Value += NameSizeOfVariable (Variable);\r
476 Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));\r
477\r
478 return (UINT8 *) Value;\r
8d3a5c82 479}\r
480\r
052ad7e1 481\r
7c80e839 482/**\r
8d3a5c82 483\r
484 This code gets the pointer to the next variable header.\r
485\r
7c80e839 486 @param Variable Pointer to the Variable Header\r
8d3a5c82 487\r
7c80e839 488 @return Pointer to next variable header\r
8d3a5c82 489\r
7c80e839 490**/\r
491VARIABLE_HEADER *\r
492GetNextVariablePtr (\r
493 IN VARIABLE_HEADER *Variable\r
494 )\r
8d3a5c82 495{\r
130e2569 496 UINTN Value;\r
497\r
8d3a5c82 498 if (!IsValidVariableHeader (Variable)) {\r
499 return NULL;\r
500 }\r
130e2569 501\r
502 Value = (UINTN) GetVariableDataPtr (Variable);\r
503 Value += DataSizeOfVariable (Variable);\r
504 Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));\r
505\r
8d3a5c82 506 //\r
507 // Be careful about pad size for alignment\r
508 //\r
130e2569 509 return (VARIABLE_HEADER *) HEADER_ALIGN (Value);\r
8d3a5c82 510}\r
511\r
7c80e839 512/**\r
9cad030b 513\r
7c80e839 514 Gets the pointer to the first variable header in given variable store area.\r
9cad030b 515\r
7c80e839 516 @param VarStoreHeader Pointer to the Variable Store Header.\r
9cad030b 517\r
7c80e839 518 @return Pointer to the first variable header\r
9cad030b 519\r
7c80e839 520**/\r
521VARIABLE_HEADER *\r
522GetStartPointer (\r
523 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
524 )\r
9cad030b 525{\r
526 //\r
527 // The end of variable store\r
528 //\r
529 return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);\r
530}\r
052ad7e1 531\r
7c80e839 532/**\r
8d3a5c82 533\r
7c80e839 534 Gets the pointer to the end of the variable storage area.\r
8d3a5c82 535\r
7c80e839 536 This function gets pointer to the end of the variable storage\r
537 area, according to the input variable store header.\r
8d3a5c82 538\r
7c80e839 539 @param VarStoreHeader Pointer to the Variable Store Header\r
8d3a5c82 540\r
7c80e839 541 @return Pointer to the end of the variable storage area \r
8d3a5c82 542\r
7c80e839 543**/\r
544VARIABLE_HEADER *\r
545GetEndPointer (\r
546 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
547 )\r
8d3a5c82 548{\r
549 //\r
550 // The end of variable store\r
551 //\r
9cad030b 552 return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);\r
8d3a5c82 553}\r
554\r
052ad7e1 555\r
7c80e839 556/**\r
557\r
558 Variable store garbage collection and reclaim operation.\r
559\r
560 @param VariableBase Base address of variable store\r
561 @param LastVariableOffset Offset of last variable\r
562 @param IsVolatile The variable store is volatile or not,\r
563 if it is non-volatile, need FTW\r
564 @param UpdatingVariable Pointer to updateing variable.\r
565\r
566 @return EFI_OUT_OF_RESOURCES\r
567 @return EFI_SUCCESS\r
568 @return Others\r
569\r
570**/\r
8d3a5c82 571EFI_STATUS\r
8d3a5c82 572Reclaim (\r
573 IN EFI_PHYSICAL_ADDRESS VariableBase,\r
574 OUT UINTN *LastVariableOffset,\r
814bae52 575 IN BOOLEAN IsVolatile,\r
576 IN VARIABLE_HEADER *UpdatingVariable\r
8d3a5c82 577 )\r
8d3a5c82 578{\r
579 VARIABLE_HEADER *Variable;\r
814bae52 580 VARIABLE_HEADER *AddedVariable;\r
8d3a5c82 581 VARIABLE_HEADER *NextVariable;\r
814bae52 582 VARIABLE_HEADER *NextAddedVariable;\r
8d3a5c82 583 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
584 UINT8 *ValidBuffer;\r
814bae52 585 UINTN MaximumBufferSize;\r
8d3a5c82 586 UINTN VariableSize;\r
49e70927 587 UINTN VariableNameSize;\r
588 UINTN UpdatingVariableNameSize;\r
814bae52 589 UINTN NameSize;\r
8d3a5c82 590 UINT8 *CurrPtr;\r
814bae52 591 VOID *Point0;\r
592 VOID *Point1;\r
593 BOOLEAN FoundAdded;\r
8d3a5c82 594 EFI_STATUS Status;\r
49e70927 595 CHAR16 *VariableNamePtr;\r
596 CHAR16 *UpdatingVariableNamePtr;\r
8d3a5c82 597\r
598 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);\r
2fcdca1d 599 //\r
600 // recaluate the total size of Common/HwErr type variables in non-volatile area.\r
601 //\r
602 if (!IsVolatile) {\r
603 mVariableModuleGlobal->CommonVariableTotalSize = 0;\r
604 mVariableModuleGlobal->HwErrVariableTotalSize = 0;\r
605 }\r
8d3a5c82 606\r
607 //\r
608 // Start Pointers for the variable.\r
609 //\r
814bae52 610 Variable = GetStartPointer (VariableStoreHeader);\r
611 MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);\r
8d3a5c82 612\r
613 while (IsValidVariableHeader (Variable)) {\r
614 NextVariable = GetNextVariablePtr (Variable);\r
814bae52 615 if (Variable->State == VAR_ADDED || \r
616 Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
617 ) {\r
8d3a5c82 618 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
814bae52 619 MaximumBufferSize += VariableSize;\r
8d3a5c82 620 }\r
621\r
622 Variable = NextVariable;\r
623 }\r
624\r
814bae52 625 //\r
626 // Reserve the 1 Bytes with Oxff to identify the \r
627 // end of the variable buffer. \r
628 // \r
629 MaximumBufferSize += 1;\r
630 ValidBuffer = AllocatePool (MaximumBufferSize);\r
8d3a5c82 631 if (ValidBuffer == NULL) {\r
632 return EFI_OUT_OF_RESOURCES;\r
633 }\r
634\r
814bae52 635 SetMem (ValidBuffer, MaximumBufferSize, 0xff);\r
8d3a5c82 636\r
637 //\r
638 // Copy variable store header\r
639 //\r
814bae52 640 CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));\r
641 CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
8d3a5c82 642\r
814bae52 643 //\r
5ead4a07 644 // Reinstall all ADDED variables as long as they are not identical to Updating Variable\r
814bae52 645 // \r
646 Variable = GetStartPointer (VariableStoreHeader);\r
8d3a5c82 647 while (IsValidVariableHeader (Variable)) {\r
648 NextVariable = GetNextVariablePtr (Variable);\r
649 if (Variable->State == VAR_ADDED) {\r
5ead4a07 650 if (UpdatingVariable != NULL) {\r
651 if (UpdatingVariable == Variable) {\r
652 Variable = NextVariable;\r
653 continue;\r
654 }\r
49e70927 655\r
656 VariableNameSize = NameSizeOfVariable(Variable);\r
657 UpdatingVariableNameSize = NameSizeOfVariable(UpdatingVariable);\r
658\r
659 VariableNamePtr = GetVariableNamePtr (Variable);\r
660 UpdatingVariableNamePtr = GetVariableNamePtr (UpdatingVariable);\r
5ead4a07 661 if (CompareGuid (&Variable->VendorGuid, &UpdatingVariable->VendorGuid) &&\r
49e70927 662 VariableNameSize == UpdatingVariableNameSize &&\r
663 CompareMem (VariableNamePtr, UpdatingVariableNamePtr, VariableNameSize) == 0 ) {\r
5ead4a07 664 Variable = NextVariable;\r
665 continue;\r
666 }\r
667 }\r
8d3a5c82 668 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
669 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
670 CurrPtr += VariableSize;\r
2fcdca1d 671 if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
672 mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
673 } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
674 mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
675 }\r
8d3a5c82 676 }\r
8d3a5c82 677 Variable = NextVariable;\r
678 }\r
5ead4a07 679\r
680 //\r
681 // Reinstall the variable being updated if it is not NULL\r
682 //\r
683 if (UpdatingVariable != NULL) {\r
684 VariableSize = (UINTN)(GetNextVariablePtr (UpdatingVariable)) - (UINTN)UpdatingVariable;\r
685 CopyMem (CurrPtr, (UINT8 *) UpdatingVariable, VariableSize);\r
686 CurrPtr += VariableSize;\r
2fcdca1d 687 if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
688 mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
689 } else if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
690 mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
691 }\r
5ead4a07 692 }\r
693\r
814bae52 694 //\r
695 // Reinstall all in delete transition variables\r
696 // \r
697 Variable = GetStartPointer (VariableStoreHeader);\r
698 while (IsValidVariableHeader (Variable)) {\r
699 NextVariable = GetNextVariablePtr (Variable);\r
5ead4a07 700 if (Variable != UpdatingVariable && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
814bae52 701\r
702 //\r
703 // Buffer has cached all ADDED variable. \r
704 // Per IN_DELETED variable, we have to guarantee that\r
705 // no ADDED one in previous buffer. \r
706 // \r
707 \r
708 FoundAdded = FALSE;\r
709 AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
710 while (IsValidVariableHeader (AddedVariable)) {\r
711 NextAddedVariable = GetNextVariablePtr (AddedVariable);\r
712 NameSize = NameSizeOfVariable (AddedVariable);\r
713 if (CompareGuid (&AddedVariable->VendorGuid, &Variable->VendorGuid) &&\r
714 NameSize == NameSizeOfVariable (Variable)\r
715 ) {\r
716 Point0 = (VOID *) GetVariableNamePtr (AddedVariable);\r
717 Point1 = (VOID *) GetVariableNamePtr (Variable);\r
5ead4a07 718 if (CompareMem (Point0, Point1, NameSizeOfVariable (AddedVariable)) == 0) {\r
814bae52 719 FoundAdded = TRUE;\r
720 break;\r
721 }\r
722 }\r
723 AddedVariable = NextAddedVariable;\r
724 }\r
725 if (!FoundAdded) {\r
5ead4a07 726 //\r
727 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED\r
728 //\r
814bae52 729 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
730 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
5ead4a07 731 ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;\r
814bae52 732 CurrPtr += VariableSize;\r
2fcdca1d 733 if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
734 mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
735 } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
736 mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
737 }\r
814bae52 738 }\r
739 }\r
740\r
741 Variable = NextVariable;\r
742 }\r
8d3a5c82 743\r
744 if (IsVolatile) {\r
745 //\r
746 // If volatile variable store, just copy valid buffer\r
747 //\r
748 SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);\r
814bae52 749 CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - (UINT8 *) ValidBuffer));\r
8d3a5c82 750 Status = EFI_SUCCESS;\r
751 } else {\r
752 //\r
753 // If non-volatile variable store, perform FTW here.\r
754 //\r
755 Status = FtwVariableSpace (\r
756 VariableBase,\r
757 ValidBuffer,\r
814bae52 758 (UINTN) (CurrPtr - (UINT8 *) ValidBuffer)\r
8d3a5c82 759 );\r
8d3a5c82 760 }\r
814bae52 761 if (!EFI_ERROR (Status)) {\r
762 *LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer);\r
763 } else {\r
8d3a5c82 764 *LastVariableOffset = 0;\r
765 }\r
766\r
814bae52 767 FreePool (ValidBuffer);\r
768\r
8d3a5c82 769 return Status;\r
770}\r
771\r
33a5a666 772\r
052ad7e1
A
773/**\r
774 Update the Cache with Variable information. These are the same \r
775 arguments as the EFI Variable services.\r
776\r
777 @param[in] VariableName Name of variable\r
778 @param[in] VendorGuid Guid of variable\r
45f6c85b 779 @param[in] Attributes Attribues of the variable\r
052ad7e1
A
780 @param[in] DataSize Size of data. 0 means delete\r
781 @param[in] Data Variable data\r
782\r
783**/\r
33a5a666
A
784VOID\r
785UpdateVariableCache (\r
786 IN CHAR16 *VariableName,\r
787 IN EFI_GUID *VendorGuid,\r
052ad7e1
A
788 IN UINT32 Attributes,\r
789 IN UINTN DataSize,\r
790 IN VOID *Data\r
33a5a666
A
791 )\r
792{\r
793 VARIABLE_CACHE_ENTRY *Entry;\r
794 UINTN Index;\r
795\r
796 if (EfiAtRuntime ()) {\r
892b7f90 797 //\r
33a5a666 798 // Don't use the cache at runtime\r
892b7f90 799 // \r
33a5a666
A
800 return;\r
801 }\r
802\r
803 for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {\r
804 if (CompareGuid (VendorGuid, Entry->Guid)) {\r
805 if (StrCmp (VariableName, Entry->Name) == 0) { \r
806 Entry->Attributes = Attributes;\r
807 if (DataSize == 0) {\r
892b7f90 808 //\r
33a5a666 809 // Delete Case\r
892b7f90 810 //\r
33a5a666
A
811 if (Entry->DataSize != 0) {\r
812 FreePool (Entry->Data);\r
813 }\r
814 Entry->DataSize = DataSize;\r
815 } else if (DataSize == Entry->DataSize) {\r
816 CopyMem (Entry->Data, Data, DataSize);\r
817 } else {\r
818 Entry->Data = AllocatePool (DataSize);\r
892b7f90 819 ASSERT (Entry->Data != NULL);\r
820\r
33a5a666
A
821 Entry->DataSize = DataSize;\r
822 CopyMem (Entry->Data, Data, DataSize);\r
823 }\r
824 }\r
825 }\r
826 }\r
827}\r
828\r
829\r
052ad7e1 830/**\r
7c80e839 831 Search the cache to check if the variable is in it.\r
052ad7e1 832\r
7c80e839 833 This function searches the variable cache. If the variable to find exists, return its data\r
834 and attributes.\r
052ad7e1 835\r
7c80e839 836 @param VariableName A Null-terminated Unicode string that is the name of the vendor's\r
837 variable. Each VariableName is unique for each \r
838 VendorGuid.\r
839 @param VendorGuid A unique identifier for the vendor\r
840 @param Attributes Pointer to the attributes bitmask of the variable for output.\r
841 @param DataSize On input, size of the buffer of Data.\r
842 On output, size of the variable's data.\r
843 @param Data Pointer to the data buffer for output.\r
844\r
845 @retval EFI_SUCCESS VariableGuid & VariableName data was returned.\r
846 @retval EFI_NOT_FOUND No matching variable found in cache.\r
847 @retval EFI_BUFFER_TOO_SMALL *DataSize is smaller than size of the variable's data to return.\r
052ad7e1
A
848\r
849**/\r
33a5a666
A
850EFI_STATUS\r
851FindVariableInCache (\r
852 IN CHAR16 *VariableName,\r
853 IN EFI_GUID *VendorGuid,\r
854 OUT UINT32 *Attributes OPTIONAL,\r
855 IN OUT UINTN *DataSize,\r
856 OUT VOID *Data\r
857 )\r
858{\r
859 VARIABLE_CACHE_ENTRY *Entry;\r
860 UINTN Index;\r
861\r
862 if (EfiAtRuntime ()) {\r
863 // Don't use the cache at runtime\r
864 return EFI_NOT_FOUND;\r
865 }\r
866\r
867 for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {\r
868 if (CompareGuid (VendorGuid, Entry->Guid)) {\r
869 if (StrCmp (VariableName, Entry->Name) == 0) {\r
870 if (Entry->DataSize == 0) {\r
052ad7e1 871 // Variable was deleted so return not found\r
33a5a666 872 return EFI_NOT_FOUND;\r
aa09397b 873 } else if (Entry->DataSize > *DataSize) {\r
052ad7e1 874 // If the buffer is too small return correct size\r
33a5a666
A
875 *DataSize = Entry->DataSize;\r
876 return EFI_BUFFER_TOO_SMALL;\r
877 } else {\r
aa09397b 878 *DataSize = Entry->DataSize;\r
052ad7e1 879 // Return the data\r
33a5a666
A
880 CopyMem (Data, Entry->Data, Entry->DataSize);\r
881 if (Attributes != NULL) {\r
882 *Attributes = Entry->Attributes;\r
883 }\r
884 return EFI_SUCCESS;\r
885 }\r
886 }\r
887 }\r
888 }\r
889 \r
890 return EFI_NOT_FOUND;\r
891}\r
892\r
7c80e839 893/**\r
894 Finds variable in storage blocks of volatile and non-volatile storage areas.\r
895\r
896 This code finds variable in storage blocks of volatile and non-volatile storage areas.\r
897 If VariableName is an empty string, then we just return the first\r
898 qualified variable without comparing VariableName and VendorGuid.\r
899 Otherwise, VariableName and VendorGuid are compared.\r
900\r
901 @param VariableName Name of the variable to be found\r
902 @param VendorGuid Vendor GUID to be found.\r
903 @param PtrTrack VARIABLE_POINTER_TRACK structure for output,\r
904 including the range searched and the target position.\r
905 @param Global Pointer to VARIABLE_GLOBAL structure, including\r
906 base of volatile variable storage area, base of\r
907 NV variable storage area, and a lock.\r
908\r
909 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while\r
910 VendorGuid is NULL\r
911 @retval EFI_SUCCESS Variable successfully found\r
912 @retval EFI_INVALID_PARAMETER Variable not found\r
33a5a666 913\r
7c80e839 914**/\r
8d3a5c82 915EFI_STATUS\r
8d3a5c82 916FindVariable (\r
917 IN CHAR16 *VariableName,\r
918 IN EFI_GUID *VendorGuid,\r
919 OUT VARIABLE_POINTER_TRACK *PtrTrack,\r
920 IN VARIABLE_GLOBAL *Global\r
921 )\r
8d3a5c82 922{\r
814bae52 923 VARIABLE_HEADER *Variable[2];\r
924 VARIABLE_HEADER *InDeletedVariable;\r
925 VARIABLE_STORE_HEADER *VariableStoreHeader[2];\r
926 UINTN InDeletedStorageIndex;\r
927 UINTN Index;\r
928 VOID *Point;\r
8d3a5c82 929\r
8d3a5c82 930 //\r
33a5a666 931 // 0: Volatile, 1: Non-Volatile\r
36873a61 932 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName\r
933 // make use of this mapping to implement search algorithme.\r
8d3a5c82 934 //\r
052ad7e1
A
935 VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
936 VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
8d3a5c82 937\r
938 //\r
939 // Start Pointers for the variable.\r
940 // Actual Data Pointer where data can be written.\r
941 //\r
9cad030b 942 Variable[0] = GetStartPointer (VariableStoreHeader[0]);\r
943 Variable[1] = GetStartPointer (VariableStoreHeader[1]);\r
8d3a5c82 944\r
945 if (VariableName[0] != 0 && VendorGuid == NULL) {\r
946 return EFI_INVALID_PARAMETER;\r
947 }\r
814bae52 948\r
8d3a5c82 949 //\r
33a5a666 950 // Find the variable by walk through volatile and then non-volatile variable store\r
8d3a5c82 951 //\r
814bae52 952 InDeletedVariable = NULL;\r
953 InDeletedStorageIndex = 0;\r
8d3a5c82 954 for (Index = 0; Index < 2; Index++) {\r
79749182 955 while ((Variable[Index] < GetEndPointer (VariableStoreHeader[Index])) && IsValidVariableHeader (Variable[Index])) {\r
814bae52 956 if (Variable[Index]->State == VAR_ADDED || \r
957 Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
958 ) {\r
8ed62a30 959 if (!EfiAtRuntime () || ((Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {\r
8d3a5c82 960 if (VariableName[0] == 0) {\r
814bae52 961 if (Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
962 InDeletedVariable = Variable[Index];\r
963 InDeletedStorageIndex = Index;\r
964 } else {\r
965 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]);\r
966 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]);\r
967 PtrTrack->CurrPtr = Variable[Index];\r
968 PtrTrack->Volatile = (BOOLEAN)(Index == 0);\r
969\r
970 return EFI_SUCCESS;\r
971 }\r
8d3a5c82 972 } else {\r
973 if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) {\r
130e2569 974 Point = (VOID *) GetVariableNamePtr (Variable[Index]);\r
975\r
976 ASSERT (NameSizeOfVariable (Variable[Index]) != 0);\r
c24b392c 977 if (CompareMem (VariableName, Point, NameSizeOfVariable (Variable[Index])) == 0) {\r
814bae52 978 if (Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
979 InDeletedVariable = Variable[Index];\r
980 InDeletedStorageIndex = Index;\r
981 } else {\r
982 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]);\r
983 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]);\r
984 PtrTrack->CurrPtr = Variable[Index];\r
985 PtrTrack->Volatile = (BOOLEAN)(Index == 0);\r
986\r
987 return EFI_SUCCESS;\r
988 }\r
8d3a5c82 989 }\r
990 }\r
991 }\r
992 }\r
993 }\r
994\r
995 Variable[Index] = GetNextVariablePtr (Variable[Index]);\r
996 }\r
814bae52 997 if (InDeletedVariable != NULL) {\r
998 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[InDeletedStorageIndex]);\r
999 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[InDeletedStorageIndex]);\r
1000 PtrTrack->CurrPtr = InDeletedVariable;\r
1001 PtrTrack->Volatile = (BOOLEAN)(InDeletedStorageIndex == 0);\r
1002 return EFI_SUCCESS;\r
1003 }\r
8d3a5c82 1004 }\r
8d3a5c82 1005 PtrTrack->CurrPtr = NULL;\r
1006 return EFI_NOT_FOUND;\r
1007}\r
1008\r
33a5a666 1009\r
7c80e839 1010/**\r
052ad7e1 1011\r
7c80e839 1012 This code finds variable in storage blocks (Volatile or Non-Volatile).\r
c6492839 1013\r
7c80e839 1014 @param VariableName Name of Variable to be found.\r
1015 @param VendorGuid Variable vendor GUID.\r
1016 @param Attributes Attribute value of the variable found.\r
1017 @param DataSize Size of Data found. If size is less than the\r
1018 data, this value contains the required size.\r
1019 @param Data Data pointer.\r
1020 \r
1021 @return EFI_INVALID_PARAMETER Invalid parameter\r
1022 @return EFI_SUCCESS Find the specified variable\r
1023 @return EFI_NOT_FOUND Not found\r
1024 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result\r
8d3a5c82 1025\r
7c80e839 1026**/\r
052ad7e1
A
1027EFI_STATUS\r
1028EFIAPI\r
1029RuntimeServiceGetVariable (\r
1030 IN CHAR16 *VariableName,\r
1031 IN EFI_GUID *VendorGuid,\r
1032 OUT UINT32 *Attributes OPTIONAL,\r
1033 IN OUT UINTN *DataSize,\r
1034 OUT VOID *Data\r
1035 )\r
8d3a5c82 1036{\r
052ad7e1 1037 EFI_STATUS Status;\r
8d3a5c82 1038 VARIABLE_POINTER_TRACK Variable;\r
1039 UINTN VarDataSize;\r
8d3a5c82 1040\r
1041 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
1042 return EFI_INVALID_PARAMETER;\r
1043 }\r
33a5a666 1044\r
fdb7765f 1045 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
1046\r
8d3a5c82 1047 //\r
1048 // Find existing variable\r
1049 //\r
33a5a666
A
1050 Status = FindVariableInCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
1051 if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_SUCCESS)){\r
1052 // Hit in the Cache\r
1053 UpdateVariableInfo (VariableName, VendorGuid, FALSE, TRUE, FALSE, FALSE, TRUE);\r
fdb7765f 1054 goto Done;\r
33a5a666
A
1055 }\r
1056 \r
052ad7e1 1057 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
8d3a5c82 1058 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
1059 goto Done;\r
1060 }\r
33a5a666 1061\r
8d3a5c82 1062 //\r
1063 // Get data size\r
1064 //\r
130e2569 1065 VarDataSize = DataSizeOfVariable (Variable.CurrPtr);\r
fdb7765f 1066 ASSERT (VarDataSize != 0);\r
1067\r
8d3a5c82 1068 if (*DataSize >= VarDataSize) {\r
1069 if (Data == NULL) {\r
1070 Status = EFI_INVALID_PARAMETER;\r
1071 goto Done;\r
1072 }\r
1073\r
1074 CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);\r
1075 if (Attributes != NULL) {\r
1076 *Attributes = Variable.CurrPtr->Attributes;\r
1077 }\r
1078\r
1079 *DataSize = VarDataSize;\r
33a5a666
A
1080 UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);\r
1081 UpdateVariableCache (VariableName, VendorGuid, Variable.CurrPtr->Attributes, VarDataSize, Data);\r
1082 \r
8d3a5c82 1083 Status = EFI_SUCCESS;\r
1084 goto Done;\r
1085 } else {\r
1086 *DataSize = VarDataSize;\r
1087 Status = EFI_BUFFER_TOO_SMALL;\r
1088 goto Done;\r
1089 }\r
1090\r
1091Done:\r
052ad7e1 1092 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
8d3a5c82 1093 return Status;\r
1094}\r
1095\r
052ad7e1
A
1096\r
1097\r
7c80e839 1098/**\r
8d3a5c82 1099\r
7c80e839 1100 This code Finds the Next available variable.\r
8d3a5c82 1101\r
7c80e839 1102 @param VariableNameSize Size of the variable name\r
1103 @param VariableName Pointer to variable name\r
1104 @param VendorGuid Variable Vendor Guid\r
8d3a5c82 1105\r
7c80e839 1106 @return EFI_INVALID_PARAMETER Invalid parameter\r
1107 @return EFI_SUCCESS Find the specified variable\r
1108 @return EFI_NOT_FOUND Not found\r
1109 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result\r
8d3a5c82 1110\r
7c80e839 1111**/\r
052ad7e1
A
1112EFI_STATUS\r
1113EFIAPI\r
1114RuntimeServiceGetNextVariableName (\r
1115 IN OUT UINTN *VariableNameSize,\r
1116 IN OUT CHAR16 *VariableName,\r
1117 IN OUT EFI_GUID *VendorGuid\r
1118 )\r
8d3a5c82 1119{\r
1120 VARIABLE_POINTER_TRACK Variable;\r
1121 UINTN VarNameSize;\r
1122 EFI_STATUS Status;\r
1123\r
1124 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
1125 return EFI_INVALID_PARAMETER;\r
1126 }\r
1127\r
fdb7765f 1128 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
1129\r
052ad7e1 1130 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
8d3a5c82 1131 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
1132 goto Done;\r
1133 }\r
1134\r
1135 if (VariableName[0] != 0) {\r
1136 //\r
1137 // If variable name is not NULL, get next variable\r
1138 //\r
1139 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
1140 }\r
1141\r
1142 while (TRUE) {\r
1143 //\r
1144 // If both volatile and non-volatile variable store are parsed,\r
1145 // return not found\r
1146 //\r
1147 if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) {\r
1148 Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));\r
36873a61 1149 if (!Variable.Volatile) {\r
9cad030b 1150 Variable.StartPtr = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
1151 Variable.EndPtr = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase));\r
8d3a5c82 1152 } else {\r
1153 Status = EFI_NOT_FOUND;\r
1154 goto Done;\r
1155 }\r
1156\r
1157 Variable.CurrPtr = Variable.StartPtr;\r
1158 if (!IsValidVariableHeader (Variable.CurrPtr)) {\r
1159 continue;\r
1160 }\r
1161 }\r
1162 //\r
1163 // Variable is found\r
1164 //\r
1165 if (IsValidVariableHeader (Variable.CurrPtr) && Variable.CurrPtr->State == VAR_ADDED) {\r
c24b392c 1166 if ((EfiAtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) == 0) {\r
130e2569 1167 VarNameSize = NameSizeOfVariable (Variable.CurrPtr);\r
fdb7765f 1168 ASSERT (VarNameSize != 0);\r
1169\r
8d3a5c82 1170 if (VarNameSize <= *VariableNameSize) {\r
1171 CopyMem (\r
1172 VariableName,\r
130e2569 1173 GetVariableNamePtr (Variable.CurrPtr),\r
8d3a5c82 1174 VarNameSize\r
1175 );\r
1176 CopyMem (\r
1177 VendorGuid,\r
1178 &Variable.CurrPtr->VendorGuid,\r
1179 sizeof (EFI_GUID)\r
1180 );\r
1181 Status = EFI_SUCCESS;\r
1182 } else {\r
1183 Status = EFI_BUFFER_TOO_SMALL;\r
1184 }\r
1185\r
1186 *VariableNameSize = VarNameSize;\r
1187 goto Done;\r
1188 }\r
1189 }\r
1190\r
1191 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
1192 }\r
1193\r
1194Done:\r
052ad7e1 1195 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
8d3a5c82 1196 return Status;\r
1197}\r
1198\r
7c80e839 1199/**\r
052ad7e1 1200\r
7c80e839 1201 This code sets variable in storage blocks (Volatile or Non-Volatile).\r
8d3a5c82 1202\r
7c80e839 1203 @param VariableName Name of Variable to be found\r
1204 @param VendorGuid Variable vendor GUID\r
1205 @param Attributes Attribute value of the variable found\r
1206 @param DataSize Size of Data found. If size is less than the\r
1207 data, this value contains the required size.\r
1208 @param Data Data pointer\r
8d3a5c82 1209\r
7c80e839 1210 @return EFI_INVALID_PARAMETER Invalid parameter\r
1211 @return EFI_SUCCESS Set successfully\r
1212 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable\r
1213 @return EFI_NOT_FOUND Not found\r
1214 @return EFI_WRITE_PROTECTED Variable is read-only\r
8d3a5c82 1215\r
7c80e839 1216**/\r
052ad7e1
A
1217EFI_STATUS\r
1218EFIAPI\r
1219RuntimeServiceSetVariable (\r
1220 IN CHAR16 *VariableName,\r
1221 IN EFI_GUID *VendorGuid,\r
1222 IN UINT32 Attributes,\r
1223 IN UINTN DataSize,\r
1224 IN VOID *Data\r
1225 )\r
8d3a5c82 1226{\r
8a9e0b72 1227 VARIABLE_POINTER_TRACK Variable;\r
1228 EFI_STATUS Status;\r
1229 VARIABLE_HEADER *NextVariable;\r
1230 UINTN VarNameSize;\r
1231 UINTN VarNameOffset;\r
1232 UINTN VarDataOffset;\r
1233 UINTN VarSize;\r
1234 UINT8 State;\r
1235 BOOLEAN Reclaimed;\r
1236 UINTN *VolatileOffset;\r
1237 UINTN *NonVolatileOffset;\r
1238 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
1239 BOOLEAN Volatile;\r
1240 EFI_PHYSICAL_ADDRESS Point;\r
2fcdca1d 1241 UINTN ScratchSize;\r
1242 UINTN NonVolatileVarableStoreSize;\r
8d3a5c82 1243\r
c6492839 1244 //\r
1245 // Check input parameters\r
1246 //\r
8d3a5c82 1247 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
1248 return EFI_INVALID_PARAMETER;\r
c6492839 1249 } \r
1250 //\r
1251 // Make sure if runtime bit is set, boot service bit is set also\r
1252 //\r
1253 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
1254 return EFI_INVALID_PARAMETER;\r
8d3a5c82 1255 }\r
fdb7765f 1256\r
c6492839 1257 //\r
1258 // The size of the VariableName, including the Unicode Null in bytes plus\r
e5618791
LG
1259 // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxHardwareErrorVariableSize)\r
1260 // bytes for HwErrRec, and FixedPcdGet32(PcdMaxVariableSize) bytes for the others.\r
c6492839 1261 //\r
1262 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
e5618791
LG
1263 if ((DataSize > FixedPcdGet32(PcdMaxHardwareErrorVariableSize)) || \r
1264 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > FixedPcdGet32(PcdMaxHardwareErrorVariableSize))) {\r
c6492839 1265 return EFI_INVALID_PARAMETER;\r
1266 } \r
1267 } else {\r
1268 //\r
1269 // The size of the VariableName, including the Unicode Null in bytes plus\r
e5618791 1270 // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxVariableSize) bytes.\r
c6492839 1271 //\r
e5618791
LG
1272 if ((DataSize > FixedPcdGet32(PcdMaxVariableSize)) ||\r
1273 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > FixedPcdGet32(PcdMaxVariableSize))) {\r
c6492839 1274 return EFI_INVALID_PARAMETER;\r
1275 } \r
1276 } \r
fdb7765f 1277\r
1278 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
1279\r
1280 Reclaimed = FALSE;\r
8a9e0b72 1281 Fvb = mVariableModuleGlobal->FvbInstance;\r
fdb7765f 1282 VolatileOffset = &mVariableModuleGlobal->VolatileLastVariableOffset;\r
1283\r
1284 //\r
1285 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated;\r
1286 //\r
1287 if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {\r
fdb7765f 1288 Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;;\r
1289 //\r
1290 // Parse non-volatile variable data and get last variable offset\r
1291 //\r
9cad030b 1292 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point);\r
fdb7765f 1293 while (IsValidVariableHeader (NextVariable)) {\r
1294 NextVariable = GetNextVariablePtr (NextVariable);\r
1295 }\r
1296 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;\r
1297 }\r
1298\r
1299 NonVolatileOffset = &mVariableModuleGlobal->NonVolatileLastVariableOffset;\r
1300 \r
1301\r
c6492839 1302 //\r
1303 // Check whether the input variable is already existed\r
1304 //\r
1305 \r
052ad7e1 1306 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
c6492839 1307 if (Status == EFI_SUCCESS && Variable.CurrPtr != NULL) {\r
8d3a5c82 1308 //\r
c6492839 1309 // Update/Delete existing variable\r
8d3a5c82 1310 //\r
fd51bf70 1311 Volatile = Variable.Volatile;\r
c6492839 1312 \r
1313 if (EfiAtRuntime ()) { \r
1314 //\r
1315 // If EfiAtRuntime and the variable is Volatile and Runtime Access, \r
1316 // the volatile is ReadOnly, and SetVariable should be aborted and \r
1317 // return EFI_WRITE_PROTECTED.\r
1318 //\r
1319 if (Variable.Volatile) {\r
1320 Status = EFI_WRITE_PROTECTED;\r
1321 goto Done;\r
1322 }\r
1323 //\r
1324 // Only variable have NV attribute can be updated/deleted in Runtime\r
1325 //\r
c24b392c 1326 if ((Variable.CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
c6492839 1327 Status = EFI_INVALID_PARAMETER;\r
1328 goto Done; \r
1329 }\r
1330 }\r
8d3a5c82 1331 //\r
c6492839 1332 // Setting a data variable with no access, or zero DataSize attributes\r
1333 // specified causes it to be deleted.\r
8d3a5c82 1334 //\r
c6492839 1335 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) { \r
1336 State = Variable.CurrPtr->State;\r
1337 State &= VAR_DELETED;\r
1338\r
1339 Status = UpdateVariableStore (\r
052ad7e1 1340 &mVariableModuleGlobal->VariableGlobal,\r
c6492839 1341 Variable.Volatile,\r
1342 FALSE,\r
8a9e0b72 1343 Fvb,\r
c6492839 1344 (UINTN) &Variable.CurrPtr->State,\r
1345 sizeof (UINT8),\r
1346 &State\r
1347 ); \r
33a5a666 1348 if (!EFI_ERROR (Status)) {\r
fd51bf70 1349 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, FALSE, TRUE, FALSE);\r
33a5a666
A
1350 UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
1351 }\r
c6492839 1352 goto Done; \r
1353 }\r
8d3a5c82 1354 //\r
c6492839 1355 // If the variable is marked valid and the same data has been passed in\r
1356 // then return to the caller immediately.\r
8d3a5c82 1357 //\r
130e2569 1358 if (DataSizeOfVariable (Variable.CurrPtr) == DataSize &&\r
c6492839 1359 (CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize) == 0)) {\r
33a5a666 1360 \r
fd51bf70 1361 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
c6492839 1362 Status = EFI_SUCCESS;\r
1363 goto Done;\r
1364 } else if ((Variable.CurrPtr->State == VAR_ADDED) ||\r
1365 (Variable.CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {\r
814bae52 1366\r
c6492839 1367 //\r
1368 // Mark the old variable as in delete transition\r
1369 //\r
1370 State = Variable.CurrPtr->State;\r
1371 State &= VAR_IN_DELETED_TRANSITION;\r
1372\r
1373 Status = UpdateVariableStore (\r
052ad7e1 1374 &mVariableModuleGlobal->VariableGlobal,\r
c6492839 1375 Variable.Volatile,\r
1376 FALSE,\r
8a9e0b72 1377 Fvb,\r
c6492839 1378 (UINTN) &Variable.CurrPtr->State,\r
1379 sizeof (UINT8),\r
1380 &State\r
1381 ); \r
1382 if (EFI_ERROR (Status)) {\r
1383 goto Done; \r
33a5a666 1384 } \r
c6492839 1385 } \r
1386 } else if (Status == EFI_NOT_FOUND) {\r
8d3a5c82 1387 //\r
c6492839 1388 // Create a new variable\r
1389 // \r
1390 \r
8d3a5c82 1391 //\r
c6492839 1392 // Make sure we are trying to create a new variable.\r
1393 // Setting a data variable with no access, or zero DataSize attributes means to delete it. \r
8d3a5c82 1394 //\r
c6492839 1395 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {\r
1396 Status = EFI_NOT_FOUND;\r
1397 goto Done;\r
1398 }\r
1399 \r
8d3a5c82 1400 //\r
c6492839 1401 // Only variable have NV|RT attribute can be created in Runtime\r
1402 //\r
1403 if (EfiAtRuntime () &&\r
45f6c85b 1404 (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {\r
c6492839 1405 Status = EFI_INVALID_PARAMETER;\r
1406 goto Done;\r
1407 } \r
1408 } else {\r
8d3a5c82 1409 //\r
c6492839 1410 // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable().\r
8d3a5c82 1411 //\r
c6492839 1412 ASSERT (Status == EFI_INVALID_PARAMETER);\r
8d3a5c82 1413 goto Done;\r
c6492839 1414 }\r
1415\r
1416 //\r
1417 // Function part - create a new variable and copy the data.\r
1418 // Both update a variable and create a variable will come here.\r
1419 //\r
1420 // Tricky part: Use scratch data area at the end of volatile variable store\r
1421 // as a temporary storage.\r
1422 //\r
052ad7e1 1423 NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));\r
2fcdca1d 1424 ScratchSize = MAX(FixedPcdGet32(PcdMaxVariableSize), FixedPcdGet32(PcdMaxHardwareErrorVariableSize));\r
c6492839 1425\r
2fcdca1d 1426 SetMem (NextVariable, ScratchSize, 0xff);\r
c6492839 1427\r
1428 NextVariable->StartId = VARIABLE_DATA;\r
1429 NextVariable->Attributes = Attributes;\r
1430 //\r
1431 // NextVariable->State = VAR_ADDED;\r
1432 //\r
1433 NextVariable->Reserved = 0;\r
1434 VarNameOffset = sizeof (VARIABLE_HEADER);\r
1435 VarNameSize = StrSize (VariableName);\r
1436 CopyMem (\r
1437 (UINT8 *) ((UINTN) NextVariable + VarNameOffset),\r
1438 VariableName,\r
1439 VarNameSize\r
1440 );\r
1441 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);\r
1442 CopyMem (\r
1443 (UINT8 *) ((UINTN) NextVariable + VarDataOffset),\r
1444 Data,\r
1445 DataSize\r
1446 );\r
1447 CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));\r
1448 //\r
1449 // There will be pad bytes after Data, the NextVariable->NameSize and\r
1450 // NextVariable->DataSize should not include pad size so that variable\r
1451 // service can get actual size in GetVariable\r
1452 //\r
1453 NextVariable->NameSize = (UINT32)VarNameSize;\r
1454 NextVariable->DataSize = (UINT32)DataSize;\r
1455\r
1456 //\r
1457 // The actual size of the variable that stores in storage should\r
1458 // include pad size.\r
1459 //\r
1460 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);\r
45f6c85b 1461 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
8d3a5c82 1462 //\r
c6492839 1463 // Create a nonvolatile variable\r
8d3a5c82 1464 //\r
fd51bf70 1465 Volatile = FALSE;\r
2fcdca1d 1466 NonVolatileVarableStoreSize = ((VARIABLE_STORE_HEADER *)(UINTN)(mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase))->Size;\r
1467 if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \r
1468 && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > FixedPcdGet32(PcdHwErrStorageSize)))\r
1469 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
1470 && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - FixedPcdGet32(PcdHwErrStorageSize)))) {\r
c6492839 1471 if (EfiAtRuntime ()) {\r
1472 Status = EFI_OUT_OF_RESOURCES;\r
1473 goto Done;\r
1474 }\r
1475 //\r
1476 // Perform garbage collection & reclaim operation\r
1477 //\r
814bae52 1478 Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, NonVolatileOffset, FALSE, Variable.CurrPtr);\r
8d3a5c82 1479 if (EFI_ERROR (Status)) {\r
1480 goto Done;\r
1481 }\r
8d3a5c82 1482 //\r
c6492839 1483 // If still no enough space, return out of resources\r
8d3a5c82 1484 //\r
2fcdca1d 1485 if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \r
1486 && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > FixedPcdGet32(PcdHwErrStorageSize)))\r
1487 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
1488 && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - FixedPcdGet32(PcdHwErrStorageSize)))) {\r
c6492839 1489 Status = EFI_OUT_OF_RESOURCES;\r
8d3a5c82 1490 goto Done;\r
8d3a5c82 1491 }\r
c6492839 1492 \r
1493 Reclaimed = TRUE;\r
8d3a5c82 1494 }\r
1495 //\r
c6492839 1496 // Three steps\r
1497 // 1. Write variable header\r
130e2569 1498 // 2. Set variable state to header valid \r
1499 // 3. Write variable data\r
1500 // 4. Set variable state to valid\r
8d3a5c82 1501 //\r
8d3a5c82 1502 //\r
c6492839 1503 // Step 1:\r
8d3a5c82 1504 //\r
c6492839 1505 Status = UpdateVariableStore (\r
052ad7e1 1506 &mVariableModuleGlobal->VariableGlobal,\r
c6492839 1507 FALSE,\r
1508 TRUE,\r
8a9e0b72 1509 Fvb,\r
c6492839 1510 *NonVolatileOffset,\r
1511 sizeof (VARIABLE_HEADER),\r
1512 (UINT8 *) NextVariable\r
1513 );\r
1514\r
1515 if (EFI_ERROR (Status)) {\r
1516 goto Done;\r
1517 }\r
130e2569 1518\r
8d3a5c82 1519 //\r
c6492839 1520 // Step 2:\r
8d3a5c82 1521 //\r
130e2569 1522 NextVariable->State = VAR_HEADER_VALID_ONLY;\r
1523 Status = UpdateVariableStore (\r
1524 &mVariableModuleGlobal->VariableGlobal,\r
1525 FALSE,\r
1526 TRUE,\r
8a9e0b72 1527 Fvb,\r
130e2569 1528 *NonVolatileOffset,\r
1529 sizeof (VARIABLE_HEADER),\r
1530 (UINT8 *) NextVariable\r
1531 );\r
1532\r
1533 if (EFI_ERROR (Status)) {\r
1534 goto Done;\r
1535 }\r
1536 //\r
1537 // Step 3:\r
1538 //\r
c6492839 1539 Status = UpdateVariableStore (\r
052ad7e1 1540 &mVariableModuleGlobal->VariableGlobal,\r
c6492839 1541 FALSE,\r
1542 TRUE,\r
8a9e0b72 1543 Fvb,\r
c6492839 1544 *NonVolatileOffset + sizeof (VARIABLE_HEADER),\r
1545 (UINT32) VarSize - sizeof (VARIABLE_HEADER),\r
1546 (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)\r
1547 );\r
1548\r
1549 if (EFI_ERROR (Status)) {\r
1550 goto Done;\r
1551 }\r
8d3a5c82 1552 //\r
130e2569 1553 // Step 4:\r
8d3a5c82 1554 //\r
c6492839 1555 NextVariable->State = VAR_ADDED;\r
1556 Status = UpdateVariableStore (\r
052ad7e1 1557 &mVariableModuleGlobal->VariableGlobal,\r
c6492839 1558 FALSE,\r
1559 TRUE,\r
8a9e0b72 1560 Fvb,\r
c6492839 1561 *NonVolatileOffset,\r
1562 sizeof (VARIABLE_HEADER),\r
1563 (UINT8 *) NextVariable\r
1564 );\r
1565\r
1566 if (EFI_ERROR (Status)) {\r
1567 goto Done;\r
1568 }\r
8d3a5c82 1569\r
9cad030b 1570 *NonVolatileOffset = HEADER_ALIGN (*NonVolatileOffset + VarSize);\r
8d3a5c82 1571\r
2fcdca1d 1572 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {\r
1573 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);\r
1574 } else {\r
1575 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);\r
1576 }\r
c6492839 1577 } else {\r
1578 //\r
1579 // Create a volatile variable\r
1580 // \r
fd51bf70 1581 Volatile = TRUE;\r
c6492839 1582\r
1583 if ((UINT32) (VarSize +*VolatileOffset) >\r
052ad7e1 1584 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) {\r
8d3a5c82 1585 //\r
c6492839 1586 // Perform garbage collection & reclaim operation\r
8d3a5c82 1587 //\r
814bae52 1588 Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase, VolatileOffset, TRUE, Variable.CurrPtr);\r
8d3a5c82 1589 if (EFI_ERROR (Status)) {\r
1590 goto Done;\r
1591 }\r
1592 //\r
c6492839 1593 // If still no enough space, return out of resources\r
8d3a5c82 1594 //\r
8d3a5c82 1595 if ((UINT32) (VarSize +*VolatileOffset) >\r
052ad7e1 1596 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size\r
8d3a5c82 1597 ) {\r
c6492839 1598 Status = EFI_OUT_OF_RESOURCES;\r
8d3a5c82 1599 goto Done;\r
1600 }\r
c6492839 1601 \r
1602 Reclaimed = TRUE;\r
8d3a5c82 1603 }\r
8d3a5c82 1604\r
c6492839 1605 NextVariable->State = VAR_ADDED;\r
1606 Status = UpdateVariableStore (\r
052ad7e1 1607 &mVariableModuleGlobal->VariableGlobal,\r
c6492839 1608 TRUE,\r
1609 TRUE,\r
8a9e0b72 1610 Fvb,\r
c6492839 1611 *VolatileOffset,\r
1612 (UINT32) VarSize,\r
1613 (UINT8 *) NextVariable\r
1614 );\r
1615\r
1616 if (EFI_ERROR (Status)) {\r
1617 goto Done;\r
8d3a5c82 1618 }\r
c6492839 1619\r
9cad030b 1620 *VolatileOffset = HEADER_ALIGN (*VolatileOffset + VarSize);\r
c6492839 1621 }\r
1622 //\r
1623 // Mark the old variable as deleted\r
1624 //\r
1625 if (!Reclaimed && !EFI_ERROR (Status) && Variable.CurrPtr != NULL) {\r
1626 State = Variable.CurrPtr->State;\r
1627 State &= VAR_DELETED;\r
1628\r
1629 Status = UpdateVariableStore (\r
052ad7e1 1630 &mVariableModuleGlobal->VariableGlobal,\r
c6492839 1631 Variable.Volatile,\r
1632 FALSE,\r
8a9e0b72 1633 Fvb,\r
c6492839 1634 (UINTN) &Variable.CurrPtr->State,\r
1635 sizeof (UINT8),\r
1636 &State\r
1637 );\r
33a5a666
A
1638 \r
1639 if (!EFI_ERROR (Status)) {\r
fd51bf70 1640 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
33a5a666
A
1641 UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
1642 }\r
c6492839 1643 goto Done; \r
8d3a5c82 1644 }\r
1645\r
1646 Status = EFI_SUCCESS;\r
fd51bf70 1647 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
33a5a666
A
1648 UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
1649\r
8d3a5c82 1650Done:\r
fdb7765f 1651 InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);\r
052ad7e1 1652 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
fdb7765f 1653\r
8d3a5c82 1654 return Status;\r
1655}\r
1656\r
7c80e839 1657/**\r
8d3a5c82 1658\r
1659 This code returns information about the EFI variables.\r
1660\r
7c80e839 1661 @param Attributes Attributes bitmask to specify the type of variables\r
1662 on which to return information.\r
1663 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
1664 for the EFI variables associated with the attributes specified.\r
1665 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
1666 for EFI variables associated with the attributes specified.\r
1667 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables\r
1668 associated with the attributes specified.\r
8d3a5c82 1669\r
7c80e839 1670 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.\r
1671 @return EFI_SUCCESS Query successfully.\r
1672 @return EFI_UNSUPPORTED The attribute is not supported on this platform.\r
8d3a5c82 1673\r
7c80e839 1674**/\r
052ad7e1
A
1675EFI_STATUS\r
1676EFIAPI\r
1677RuntimeServiceQueryVariableInfo (\r
1678 IN UINT32 Attributes,\r
1679 OUT UINT64 *MaximumVariableStorageSize,\r
1680 OUT UINT64 *RemainingVariableStorageSize,\r
1681 OUT UINT64 *MaximumVariableSize\r
1682 )\r
8d3a5c82 1683{\r
1684 VARIABLE_HEADER *Variable;\r
1685 VARIABLE_HEADER *NextVariable;\r
1686 UINT64 VariableSize;\r
1687 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
2fcdca1d 1688 UINT64 CommonVariableTotalSize;\r
1689 UINT64 HwErrVariableTotalSize;\r
1690\r
1691 CommonVariableTotalSize = 0;\r
1692 HwErrVariableTotalSize = 0;\r
8d3a5c82 1693\r
c6492839 1694 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
8d3a5c82 1695 return EFI_INVALID_PARAMETER;\r
1696 }\r
2fcdca1d 1697\r
c6492839 1698 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {\r
8d3a5c82 1699 //\r
1700 // Make sure the Attributes combination is supported by the platform.\r
1701 //\r
c6492839 1702 return EFI_UNSUPPORTED; \r
8d3a5c82 1703 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
1704 //\r
1705 // Make sure if runtime bit is set, boot service bit is set also.\r
1706 //\r
1707 return EFI_INVALID_PARAMETER;\r
45f6c85b 1708 } else if (EfiAtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {\r
8d3a5c82 1709 //\r
1710 // Make sure RT Attribute is set if we are in Runtime phase.\r
1711 //\r
1712 return EFI_INVALID_PARAMETER;\r
2fcdca1d 1713 } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
1714 //\r
1715 // Make sure Hw Attribute is set with NV.\r
1716 //\r
1717 return EFI_INVALID_PARAMETER;\r
8d3a5c82 1718 }\r
1719\r
052ad7e1 1720 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
8d3a5c82 1721\r
1722 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
1723 //\r
1724 // Query is Volatile related.\r
1725 //\r
052ad7e1 1726 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
8d3a5c82 1727 } else {\r
1728 //\r
1729 // Query is Non-Volatile related.\r
1730 //\r
052ad7e1 1731 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
8d3a5c82 1732 }\r
1733\r
1734 //\r
1735 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize\r
1736 // with the storage size (excluding the storage header size).\r
1737 //\r
1738 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
c6492839 1739\r
1740 //\r
1741 // Harware error record variable needs larger size.\r
1742 //\r
2fcdca1d 1743 if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
1744 *MaximumVariableStorageSize = FixedPcdGet32(PcdHwErrStorageSize);\r
e5618791 1745 *MaximumVariableSize = FixedPcdGet32(PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);\r
2fcdca1d 1746 } else {\r
1747 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
1748 ASSERT (FixedPcdGet32(PcdHwErrStorageSize) < VariableStoreHeader->Size);\r
1749 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - FixedPcdGet32(PcdHwErrStorageSize);\r
1750 }\r
1751\r
1752 //\r
1753 // Let *MaximumVariableSize be FixedPcdGet32(PcdMaxVariableSize) with the exception of the variable header size.\r
1754 //\r
1755 *MaximumVariableSize = FixedPcdGet32(PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);\r
c6492839 1756 }\r
8d3a5c82 1757\r
1758 //\r
1759 // Point to the starting address of the variables.\r
1760 //\r
9cad030b 1761 Variable = GetStartPointer (VariableStoreHeader);\r
8d3a5c82 1762\r
1763 //\r
1764 // Now walk through the related variable store.\r
1765 //\r
6f90dfbc 1766 while ((Variable < GetEndPointer (VariableStoreHeader)) && IsValidVariableHeader (Variable)) {\r
8d3a5c82 1767 NextVariable = GetNextVariablePtr (Variable);\r
1768 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;\r
1769\r
1770 if (EfiAtRuntime ()) {\r
1771 //\r
1772 // we don't take the state of the variables in mind\r
1773 // when calculating RemainingVariableStorageSize,\r
1774 // since the space occupied by variables not marked with\r
1775 // VAR_ADDED is not allowed to be reclaimed in Runtime.\r
1776 //\r
2fcdca1d 1777 if ((NextVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
1778 HwErrVariableTotalSize += VariableSize;\r
1779 } else {\r
1780 CommonVariableTotalSize += VariableSize;\r
1781 }\r
8d3a5c82 1782 } else {\r
1783 //\r
1784 // Only care about Variables with State VAR_ADDED,because\r
1785 // the space not marked as VAR_ADDED is reclaimable now.\r
1786 //\r
1787 if (Variable->State == VAR_ADDED) {\r
2fcdca1d 1788 if ((NextVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
1789 HwErrVariableTotalSize += VariableSize;\r
1790 } else {\r
1791 CommonVariableTotalSize += VariableSize;\r
1792 }\r
8d3a5c82 1793 }\r
1794 }\r
1795\r
1796 //\r
1797 // Go to the next one\r
1798 //\r
1799 Variable = NextVariable;\r
1800 }\r
1801\r
2fcdca1d 1802 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){\r
1803 *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;\r
1804 }else {\r
1805 *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;\r
1806 }\r
1807\r
c6492839 1808 if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {\r
1809 *MaximumVariableSize = 0;\r
1810 } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {\r
1811 *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);\r
1812 }\r
1813\r
052ad7e1 1814 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
8d3a5c82 1815 return EFI_SUCCESS;\r
1816}\r
1817\r
7c80e839 1818\r
1819/**\r
1820 Notification function of EVT_GROUP_READY_TO_BOOT event group.\r
1821\r
1822 This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.\r
1823 When the Boot Manager is about to load and execute a boot option, it reclaims variable\r
1824 storage if free size is below the threshold.\r
1825\r
1826 @param Event Event whose notification function is being invoked\r
1827 @param Context Pointer to the notification function's context\r
1828\r
1829**/\r
7800593d
LG
1830VOID\r
1831EFIAPI\r
1832ReclaimForOS(\r
1833 EFI_EVENT Event,\r
1834 VOID *Context\r
1835 )\r
1836{\r
7800593d 1837 EFI_STATUS Status;\r
2fcdca1d 1838 UINTN CommonVariableSpace;\r
1839 UINTN RemainingCommonVariableSpace;\r
1840 UINTN RemainingHwErrVariableSpace;\r
7800593d 1841\r
7800593d
LG
1842 Status = EFI_SUCCESS; \r
1843\r
2fcdca1d 1844 CommonVariableSpace = ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize); //Allowable max size of common variable storage space\r
1845\r
1846 RemainingCommonVariableSpace = CommonVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;\r
1847\r
1848 RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;\r
7800593d
LG
1849 //\r
1850 // Check if the free area is blow a threshold\r
1851 //\r
2fcdca1d 1852 if ((RemainingCommonVariableSpace < PcdGet32 (PcdMaxVariableSize))\r
1853 || (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize))){\r
7800593d 1854 Status = Reclaim (\r
2fcdca1d 1855 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
1856 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
1857 FALSE,\r
1858 NULL\r
1859 );\r
7800593d
LG
1860 ASSERT_EFI_ERROR (Status);\r
1861 }\r
1862}\r
1863\r
7c80e839 1864/**\r
1865 Initializes variable store area for non-volatile and volatile variable.\r
1866\r
7c80e839 1867 @param SystemTable The pointer of EFI_SYSTEM_TABLE.\r
1868\r
1869 @retval EFI_SUCCESS Function successfully executed.\r
1870 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r
1871\r
1872**/\r
8d3a5c82 1873EFI_STATUS\r
8d3a5c82 1874VariableCommonInitialize (\r
8a9e0b72 1875 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol\r
8d3a5c82 1876 )\r
8d3a5c82 1877{\r
1878 EFI_STATUS Status;\r
8d3a5c82 1879 VARIABLE_STORE_HEADER *VolatileVariableStore;\r
1880 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
1881 VARIABLE_HEADER *NextVariable;\r
8a9e0b72 1882 EFI_PHYSICAL_ADDRESS TempVariableStoreHeader;\r
8d3a5c82 1883 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
8a9e0b72 1884 EFI_PHYSICAL_ADDRESS BaseAddress;\r
8d3a5c82 1885 UINT64 Length;\r
1886 UINTN Index;\r
1887 UINT8 Data;\r
8a9e0b72 1888 EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
052ad7e1 1889 UINT64 VariableStoreLength;\r
7800593d 1890 EFI_EVENT ReadyToBootEvent;\r
2fcdca1d 1891 UINTN ScratchSize;\r
8d3a5c82 1892\r
7800593d
LG
1893 Status = EFI_SUCCESS;\r
1894 //\r
1895 // Allocate runtime memory for variable driver global structure.\r
1896 //\r
1897 mVariableModuleGlobal = AllocateRuntimePool (sizeof (VARIABLE_MODULE_GLOBAL));\r
1898 if (mVariableModuleGlobal == NULL) {\r
1899 return EFI_OUT_OF_RESOURCES;\r
1900 }\r
8d3a5c82 1901\r
052ad7e1 1902 EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);\r
fdb7765f 1903 mVariableModuleGlobal->VariableGlobal.ReentrantState = 0;\r
2fcdca1d 1904 mVariableModuleGlobal->CommonVariableTotalSize = 0;\r
1905 mVariableModuleGlobal->HwErrVariableTotalSize = 0;\r
8d3a5c82 1906\r
1907 //\r
2fcdca1d 1908 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.\r
8d3a5c82 1909 //\r
2fcdca1d 1910 ScratchSize = MAX(FixedPcdGet32(PcdMaxVariableSize), FixedPcdGet32(PcdMaxHardwareErrorVariableSize));\r
1911 VolatileVariableStore = AllocateRuntimePool (FixedPcdGet32(PcdVariableStoreSize) + ScratchSize);\r
8d3a5c82 1912 if (VolatileVariableStore == NULL) {\r
1913 FreePool (mVariableModuleGlobal);\r
1914 return EFI_OUT_OF_RESOURCES;\r
1915 }\r
1916\r
2fcdca1d 1917 SetMem (VolatileVariableStore, FixedPcdGet32(PcdVariableStoreSize) + ScratchSize, 0xff);\r
8d3a5c82 1918\r
1919 //\r
1920 // Variable Specific Data\r
1921 //\r
052ad7e1 1922 mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
9cad030b 1923 mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;\r
8a9e0b72 1924 mVariableModuleGlobal->FvbInstance = FvbProtocol;\r
8d3a5c82 1925\r
3709c4cd 1926 CopyGuid (&VolatileVariableStore->Signature, &gEfiVariableGuid);\r
e5618791 1927 VolatileVariableStore->Size = FixedPcdGet32(PcdVariableStoreSize);\r
8d3a5c82 1928 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;\r
1929 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;\r
1930 VolatileVariableStore->Reserved = 0;\r
1931 VolatileVariableStore->Reserved1 = 0;\r
1932\r
1933 //\r
1934 // Get non volatile varaible store\r
1935 //\r
1936\r
8a9e0b72 1937 TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
052ad7e1 1938 VariableStoreBase = TempVariableStoreHeader + \\r
8a9e0b72 1939 (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
052ad7e1 1940 VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \\r
8a9e0b72 1941 (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
8d3a5c82 1942 //\r
1943 // Mark the variable storage region of the FLASH as RUNTIME\r
1944 //\r
052ad7e1
A
1945 BaseAddress = VariableStoreBase & (~EFI_PAGE_MASK);\r
1946 Length = VariableStoreLength + (VariableStoreBase - BaseAddress);\r
8d3a5c82 1947 Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);\r
1948\r
1949 Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);\r
1950 if (EFI_ERROR (Status)) {\r
7800593d 1951 goto Done;\r
8d3a5c82 1952 }\r
1953\r
1954 Status = gDS->SetMemorySpaceAttributes (\r
1955 BaseAddress,\r
1956 Length,\r
1957 GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME\r
1958 );\r
1959 if (EFI_ERROR (Status)) {\r
7800593d 1960 goto Done;\r
8d3a5c82 1961 }\r
1962 //\r
1963 // Get address of non volatile variable store base\r
1964 //\r
052ad7e1 1965 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
8a9e0b72 1966 VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
8d3a5c82 1967 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
1968 if (~VariableStoreHeader->Size == 0) {\r
1969 Status = UpdateVariableStore (\r
052ad7e1 1970 &mVariableModuleGlobal->VariableGlobal,\r
8d3a5c82 1971 FALSE,\r
1972 FALSE,\r
1973 mVariableModuleGlobal->FvbInstance,\r
1974 (UINTN) &VariableStoreHeader->Size,\r
1975 sizeof (UINT32),\r
052ad7e1 1976 (UINT8 *) &VariableStoreLength\r
8d3a5c82 1977 );\r
1978 //\r
1979 // As Variables are stored in NV storage, which are slow devices,such as flash.\r
1980 // Variable operation may skip checking variable program result to improve performance,\r
1981 // We can assume Variable program is OK through some check point.\r
1982 // Variable Store Size Setting should be the first Variable write operation,\r
1983 // We can assume all Read/Write is OK if we can set Variable store size successfully.\r
1984 // If write fail, we will assert here\r
1985 //\r
052ad7e1 1986 ASSERT(VariableStoreHeader->Size == VariableStoreLength);\r
8d3a5c82 1987\r
1988 if (EFI_ERROR (Status)) {\r
7800593d 1989 goto Done;\r
8d3a5c82 1990 }\r
1991 }\r
1992\r
8d3a5c82 1993 //\r
1994 // Parse non-volatile variable data and get last variable offset\r
1995 //\r
8a9e0b72 1996 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);\r
8d3a5c82 1997 Status = EFI_SUCCESS;\r
1998\r
1999 while (IsValidVariableHeader (NextVariable)) {\r
2fcdca1d 2000 UINTN VariableSize = 0;\r
2001 VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);\r
2002 if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
2003 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);\r
2004 } else {\r
2005 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);\r
2006 }\r
2007\r
8d3a5c82 2008 NextVariable = GetNextVariablePtr (NextVariable);\r
2009 }\r
2010\r
8a9e0b72 2011 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;\r
8d3a5c82 2012\r
8d3a5c82 2013 //\r
2014 // Check if the free area is really free.\r
2015 //\r
2016 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {\r
052ad7e1 2017 Data = ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)[Index];\r
8d3a5c82 2018 if (Data != 0xff) {\r
2019 //\r
2020 // There must be something wrong in variable store, do reclaim operation.\r
2021 //\r
2022 Status = Reclaim (\r
052ad7e1 2023 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
8d3a5c82 2024 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
814bae52 2025 FALSE,\r
2026 NULL\r
8d3a5c82 2027 );\r
7800593d
LG
2028\r
2029 if (EFI_ERROR (Status)) {\r
2030 goto Done;\r
2031 }\r
2032\r
8d3a5c82 2033 break;\r
2034 }\r
2035 }\r
7800593d
LG
2036\r
2037 //\r
2038 // Register the event handling function to reclaim variable for OS usage.\r
2039 //\r
2040 Status = EfiCreateEventReadyToBootEx (\r
2041 TPL_NOTIFY, \r
2042 ReclaimForOS, \r
2043 NULL, \r
2044 &ReadyToBootEvent\r
2045 );\r
5bb820af 2046 } else {\r
2047 Status = EFI_VOLUME_CORRUPTED;\r
2048 DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));\r
8d3a5c82 2049 }\r
2050\r
7800593d 2051Done:\r
8d3a5c82 2052 if (EFI_ERROR (Status)) {\r
2053 FreePool (mVariableModuleGlobal);\r
2054 FreePool (VolatileVariableStore);\r
2055 }\r
2056\r
2057 return Status;\r
2058}\r
052ad7e1 2059\r
7c80e839 2060/**\r
2061 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE\r
2062\r
2063 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
2064 It convers pointer to new virtual address.\r
2065\r
2066 @param Event Event whose notification function is being invoked\r
2067 @param Context Pointer to the notification function's context\r
2068\r
2069**/\r
052ad7e1
A
2070VOID\r
2071EFIAPI\r
2072VariableClassAddressChangeEvent (\r
2073 IN EFI_EVENT Event,\r
2074 IN VOID *Context\r
2075 )\r
2076{\r
8a9e0b72 2077 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);\r
2078 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);\r
2079 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);\r
2080 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes);\r
2081 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read);\r
2082 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write);\r
2083 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks);\r
2084 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance);\r
052ad7e1
A
2085 EfiConvertPointer (\r
2086 0x0,\r
2087 (VOID **) &mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase\r
2088 );\r
2089 EfiConvertPointer (\r
2090 0x0,\r
2091 (VOID **) &mVariableModuleGlobal->VariableGlobal.VolatileVariableBase\r
2092 );\r
2093 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal);\r
2094}\r
2095\r
8a9e0b72 2096VOID\r
2097EFIAPI\r
2098FvbNotificationEvent (\r
2099 IN EFI_EVENT Event,\r
2100 IN VOID *Context\r
2101 )\r
2102{\r
2103 EFI_STATUS Status;\r
2104 EFI_HANDLE *HandleBuffer;\r
8a9e0b72 2105 UINTN HandleCount;\r
2106 UINTN Index;\r
2107 EFI_PHYSICAL_ADDRESS FvbBaseAddress;\r
2108 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
2109 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
2110 EFI_FVB_ATTRIBUTES_2 Attributes;\r
2111 EFI_SYSTEM_TABLE *SystemTable;\r
2112 EFI_PHYSICAL_ADDRESS NvStorageVariableBase;\r
2113\r
2114 SystemTable = (EFI_SYSTEM_TABLE *)Context;\r
2115 Fvb = NULL;\r
8a9e0b72 2116 \r
2117 //\r
2118 // Locate all handles of Fvb protocol\r
2119 //\r
2120 Status = gBS->LocateHandleBuffer (\r
2121 ByProtocol,\r
2122 &gEfiFirmwareVolumeBlockProtocolGuid,\r
2123 NULL,\r
2124 &HandleCount,\r
2125 &HandleBuffer\r
2126 );\r
2127 if (EFI_ERROR (Status)) {\r
2128 return ;\r
2129 }\r
2130 \r
2131 //\r
2132 // Get the FVB to access variable store\r
2133 //\r
f0480ecf 2134 for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {\r
8a9e0b72 2135 Status = gBS->HandleProtocol (\r
2136 HandleBuffer[Index],\r
2137 &gEfiFirmwareVolumeBlockProtocolGuid,\r
2138 (VOID **) &Fvb\r
2139 );\r
2140 if (EFI_ERROR (Status)) {\r
2141 Status = EFI_NOT_FOUND;\r
2142 break;\r
2143 }\r
2144\r
2145 //\r
2146 // Ensure this FVB protocol supported Write operation.\r
2147 //\r
2148 Status = Fvb->GetAttributes (Fvb, &Attributes);\r
2149 if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {\r
2150 continue; \r
2151 }\r
2152 //\r
2153 // Compare the address and select the right one\r
2154 //\r
2155 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
2156 if (EFI_ERROR (Status)) {\r
2157 continue;\r
2158 }\r
2159\r
2160 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
2161 NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
2162 if ((NvStorageVariableBase >= FvbBaseAddress) && (NvStorageVariableBase < (FvbBaseAddress + FwVolHeader->FvLength))) {\r
8a9e0b72 2163 Status = EFI_SUCCESS;\r
2164 break;\r
2165 }\r
2166 }\r
2167\r
2168 FreePool (HandleBuffer);\r
f0480ecf 2169 if (!EFI_ERROR (Status) && Fvb != NULL) {\r
533020ef 2170 //\r
2171 // Close the notify event to avoid install gEfiVariableArchProtocolGuid & gEfiVariableWriteArchProtocolGuid again.\r
2172 //\r
2173 Status = gBS->CloseEvent (Event); \r
2174 ASSERT_EFI_ERROR (Status);\r
2175\r
8a9e0b72 2176 Status = VariableCommonInitialize (Fvb);\r
2177 ASSERT_EFI_ERROR (Status);\r
2178 \r
79749182 2179 SystemTable->RuntimeServices->GetVariable = RuntimeServiceGetVariable;\r
8a9e0b72 2180 SystemTable->RuntimeServices->GetNextVariableName = RuntimeServiceGetNextVariableName;\r
79749182 2181 SystemTable->RuntimeServices->SetVariable = RuntimeServiceSetVariable;\r
2182 SystemTable->RuntimeServices->QueryVariableInfo = RuntimeServiceQueryVariableInfo;\r
8a9e0b72 2183 \r
2184 //\r
2185 // Now install the Variable Runtime Architectural Protocol on a new handle\r
2186 //\r
2187 Status = gBS->InstallMultipleProtocolInterfaces (\r
2188 &mHandle,\r
2189 &gEfiVariableArchProtocolGuid, NULL,\r
2190 &gEfiVariableWriteArchProtocolGuid, NULL,\r
2191 NULL\r
2192 );\r
2193 ASSERT_EFI_ERROR (Status);\r
2194 \r
2195 Status = gBS->CreateEventEx (\r
2196 EVT_NOTIFY_SIGNAL,\r
2197 TPL_NOTIFY,\r
2198 VariableClassAddressChangeEvent,\r
2199 NULL,\r
2200 &gEfiEventVirtualAddressChangeGuid,\r
2201 &mVirtualAddressChangeEvent\r
2202 );\r
2203 ASSERT_EFI_ERROR (Status);\r
2204 }\r
2205\r
2206}\r
052ad7e1
A
2207\r
2208/**\r
2209 Variable Driver main entry point. The Variable driver places the 4 EFI\r
2210 runtime services in the EFI System Table and installs arch protocols \r
7c80e839 2211 for variable read and write services being availible. It also registers\r
2212 notification function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
052ad7e1
A
2213\r
2214 @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
2215 @param[in] SystemTable A pointer to the EFI System Table.\r
2216 \r
7c80e839 2217 @retval EFI_SUCCESS Variable service successfully initialized.\r
052ad7e1
A
2218\r
2219**/\r
2220EFI_STATUS\r
2221EFIAPI\r
2222VariableServiceInitialize (\r
2223 IN EFI_HANDLE ImageHandle,\r
2224 IN EFI_SYSTEM_TABLE *SystemTable\r
2225 )\r
2226{\r
052ad7e1 2227 //\r
8a9e0b72 2228 // Register FvbNotificationEvent () notify function.\r
2229 // \r
2230 EfiCreateProtocolNotifyEvent (\r
2231 &gEfiFirmwareVolumeBlockProtocolGuid,\r
2232 TPL_CALLBACK,\r
2233 FvbNotificationEvent,\r
2234 (VOID *)SystemTable,\r
2235 &mFvbRegistration\r
2236 );\r
052ad7e1
A
2237\r
2238 return EFI_SUCCESS;\r
2239}\r
2240\r