]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
Add ASSERT() check for StringInfoIn structure.
[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
599\r
600 //\r
601 // Start Pointers for the variable.\r
602 //\r
814bae52 603 Variable = GetStartPointer (VariableStoreHeader);\r
604 MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);\r
8d3a5c82 605\r
606 while (IsValidVariableHeader (Variable)) {\r
607 NextVariable = GetNextVariablePtr (Variable);\r
814bae52 608 if (Variable->State == VAR_ADDED || \r
609 Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
610 ) {\r
8d3a5c82 611 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
814bae52 612 MaximumBufferSize += VariableSize;\r
8d3a5c82 613 }\r
614\r
615 Variable = NextVariable;\r
616 }\r
617\r
814bae52 618 //\r
619 // Reserve the 1 Bytes with Oxff to identify the \r
620 // end of the variable buffer. \r
621 // \r
622 MaximumBufferSize += 1;\r
623 ValidBuffer = AllocatePool (MaximumBufferSize);\r
8d3a5c82 624 if (ValidBuffer == NULL) {\r
625 return EFI_OUT_OF_RESOURCES;\r
626 }\r
627\r
814bae52 628 SetMem (ValidBuffer, MaximumBufferSize, 0xff);\r
8d3a5c82 629\r
630 //\r
631 // Copy variable store header\r
632 //\r
814bae52 633 CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));\r
634 CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
8d3a5c82 635\r
814bae52 636 //\r
5ead4a07 637 // Reinstall all ADDED variables as long as they are not identical to Updating Variable\r
814bae52 638 // \r
639 Variable = GetStartPointer (VariableStoreHeader);\r
8d3a5c82 640 while (IsValidVariableHeader (Variable)) {\r
641 NextVariable = GetNextVariablePtr (Variable);\r
642 if (Variable->State == VAR_ADDED) {\r
5ead4a07 643 if (UpdatingVariable != NULL) {\r
644 if (UpdatingVariable == Variable) {\r
645 Variable = NextVariable;\r
646 continue;\r
647 }\r
49e70927 648\r
649 VariableNameSize = NameSizeOfVariable(Variable);\r
650 UpdatingVariableNameSize = NameSizeOfVariable(UpdatingVariable);\r
651\r
652 VariableNamePtr = GetVariableNamePtr (Variable);\r
653 UpdatingVariableNamePtr = GetVariableNamePtr (UpdatingVariable);\r
5ead4a07 654 if (CompareGuid (&Variable->VendorGuid, &UpdatingVariable->VendorGuid) &&\r
49e70927 655 VariableNameSize == UpdatingVariableNameSize &&\r
656 CompareMem (VariableNamePtr, UpdatingVariableNamePtr, VariableNameSize) == 0 ) {\r
5ead4a07 657 Variable = NextVariable;\r
658 continue;\r
659 }\r
660 }\r
8d3a5c82 661 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
662 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
663 CurrPtr += VariableSize;\r
664 }\r
8d3a5c82 665 Variable = NextVariable;\r
666 }\r
5ead4a07 667\r
668 //\r
669 // Reinstall the variable being updated if it is not NULL\r
670 //\r
671 if (UpdatingVariable != NULL) {\r
672 VariableSize = (UINTN)(GetNextVariablePtr (UpdatingVariable)) - (UINTN)UpdatingVariable;\r
673 CopyMem (CurrPtr, (UINT8 *) UpdatingVariable, VariableSize);\r
674 CurrPtr += VariableSize;\r
675 }\r
676\r
814bae52 677 //\r
678 // Reinstall all in delete transition variables\r
679 // \r
680 Variable = GetStartPointer (VariableStoreHeader);\r
681 while (IsValidVariableHeader (Variable)) {\r
682 NextVariable = GetNextVariablePtr (Variable);\r
5ead4a07 683 if (Variable != UpdatingVariable && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
814bae52 684\r
685 //\r
686 // Buffer has cached all ADDED variable. \r
687 // Per IN_DELETED variable, we have to guarantee that\r
688 // no ADDED one in previous buffer. \r
689 // \r
690 \r
691 FoundAdded = FALSE;\r
692 AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
693 while (IsValidVariableHeader (AddedVariable)) {\r
694 NextAddedVariable = GetNextVariablePtr (AddedVariable);\r
695 NameSize = NameSizeOfVariable (AddedVariable);\r
696 if (CompareGuid (&AddedVariable->VendorGuid, &Variable->VendorGuid) &&\r
697 NameSize == NameSizeOfVariable (Variable)\r
698 ) {\r
699 Point0 = (VOID *) GetVariableNamePtr (AddedVariable);\r
700 Point1 = (VOID *) GetVariableNamePtr (Variable);\r
5ead4a07 701 if (CompareMem (Point0, Point1, NameSizeOfVariable (AddedVariable)) == 0) {\r
814bae52 702 FoundAdded = TRUE;\r
703 break;\r
704 }\r
705 }\r
706 AddedVariable = NextAddedVariable;\r
707 }\r
708 if (!FoundAdded) {\r
5ead4a07 709 //\r
710 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED\r
711 //\r
814bae52 712 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
713 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
5ead4a07 714 ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;\r
814bae52 715 CurrPtr += VariableSize;\r
716 }\r
717 }\r
718\r
719 Variable = NextVariable;\r
720 }\r
8d3a5c82 721\r
722 if (IsVolatile) {\r
723 //\r
724 // If volatile variable store, just copy valid buffer\r
725 //\r
726 SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);\r
814bae52 727 CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - (UINT8 *) ValidBuffer));\r
8d3a5c82 728 Status = EFI_SUCCESS;\r
729 } else {\r
730 //\r
731 // If non-volatile variable store, perform FTW here.\r
732 //\r
733 Status = FtwVariableSpace (\r
734 VariableBase,\r
735 ValidBuffer,\r
814bae52 736 (UINTN) (CurrPtr - (UINT8 *) ValidBuffer)\r
8d3a5c82 737 );\r
8d3a5c82 738 }\r
814bae52 739 if (!EFI_ERROR (Status)) {\r
740 *LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer);\r
741 } else {\r
8d3a5c82 742 *LastVariableOffset = 0;\r
743 }\r
744\r
814bae52 745 FreePool (ValidBuffer);\r
746\r
8d3a5c82 747 return Status;\r
748}\r
749\r
33a5a666 750\r
052ad7e1
A
751/**\r
752 Update the Cache with Variable information. These are the same \r
753 arguments as the EFI Variable services.\r
754\r
755 @param[in] VariableName Name of variable\r
756 @param[in] VendorGuid Guid of variable\r
45f6c85b 757 @param[in] Attributes Attribues of the variable\r
052ad7e1
A
758 @param[in] DataSize Size of data. 0 means delete\r
759 @param[in] Data Variable data\r
760\r
761**/\r
33a5a666
A
762VOID\r
763UpdateVariableCache (\r
764 IN CHAR16 *VariableName,\r
765 IN EFI_GUID *VendorGuid,\r
052ad7e1
A
766 IN UINT32 Attributes,\r
767 IN UINTN DataSize,\r
768 IN VOID *Data\r
33a5a666
A
769 )\r
770{\r
771 VARIABLE_CACHE_ENTRY *Entry;\r
772 UINTN Index;\r
773\r
774 if (EfiAtRuntime ()) {\r
892b7f90 775 //\r
33a5a666 776 // Don't use the cache at runtime\r
892b7f90 777 // \r
33a5a666
A
778 return;\r
779 }\r
780\r
781 for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {\r
782 if (CompareGuid (VendorGuid, Entry->Guid)) {\r
783 if (StrCmp (VariableName, Entry->Name) == 0) { \r
784 Entry->Attributes = Attributes;\r
785 if (DataSize == 0) {\r
892b7f90 786 //\r
33a5a666 787 // Delete Case\r
892b7f90 788 //\r
33a5a666
A
789 if (Entry->DataSize != 0) {\r
790 FreePool (Entry->Data);\r
791 }\r
792 Entry->DataSize = DataSize;\r
793 } else if (DataSize == Entry->DataSize) {\r
794 CopyMem (Entry->Data, Data, DataSize);\r
795 } else {\r
796 Entry->Data = AllocatePool (DataSize);\r
892b7f90 797 ASSERT (Entry->Data != NULL);\r
798\r
33a5a666
A
799 Entry->DataSize = DataSize;\r
800 CopyMem (Entry->Data, Data, DataSize);\r
801 }\r
802 }\r
803 }\r
804 }\r
805}\r
806\r
807\r
052ad7e1 808/**\r
7c80e839 809 Search the cache to check if the variable is in it.\r
052ad7e1 810\r
7c80e839 811 This function searches the variable cache. If the variable to find exists, return its data\r
812 and attributes.\r
052ad7e1 813\r
7c80e839 814 @param VariableName A Null-terminated Unicode string that is the name of the vendor's\r
815 variable. Each VariableName is unique for each \r
816 VendorGuid.\r
817 @param VendorGuid A unique identifier for the vendor\r
818 @param Attributes Pointer to the attributes bitmask of the variable for output.\r
819 @param DataSize On input, size of the buffer of Data.\r
820 On output, size of the variable's data.\r
821 @param Data Pointer to the data buffer for output.\r
822\r
823 @retval EFI_SUCCESS VariableGuid & VariableName data was returned.\r
824 @retval EFI_NOT_FOUND No matching variable found in cache.\r
825 @retval EFI_BUFFER_TOO_SMALL *DataSize is smaller than size of the variable's data to return.\r
052ad7e1
A
826\r
827**/\r
33a5a666
A
828EFI_STATUS\r
829FindVariableInCache (\r
830 IN CHAR16 *VariableName,\r
831 IN EFI_GUID *VendorGuid,\r
832 OUT UINT32 *Attributes OPTIONAL,\r
833 IN OUT UINTN *DataSize,\r
834 OUT VOID *Data\r
835 )\r
836{\r
837 VARIABLE_CACHE_ENTRY *Entry;\r
838 UINTN Index;\r
839\r
840 if (EfiAtRuntime ()) {\r
841 // Don't use the cache at runtime\r
842 return EFI_NOT_FOUND;\r
843 }\r
844\r
845 for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {\r
846 if (CompareGuid (VendorGuid, Entry->Guid)) {\r
847 if (StrCmp (VariableName, Entry->Name) == 0) {\r
848 if (Entry->DataSize == 0) {\r
052ad7e1 849 // Variable was deleted so return not found\r
33a5a666 850 return EFI_NOT_FOUND;\r
aa09397b 851 } else if (Entry->DataSize > *DataSize) {\r
052ad7e1 852 // If the buffer is too small return correct size\r
33a5a666
A
853 *DataSize = Entry->DataSize;\r
854 return EFI_BUFFER_TOO_SMALL;\r
855 } else {\r
aa09397b 856 *DataSize = Entry->DataSize;\r
052ad7e1 857 // Return the data\r
33a5a666
A
858 CopyMem (Data, Entry->Data, Entry->DataSize);\r
859 if (Attributes != NULL) {\r
860 *Attributes = Entry->Attributes;\r
861 }\r
862 return EFI_SUCCESS;\r
863 }\r
864 }\r
865 }\r
866 }\r
867 \r
868 return EFI_NOT_FOUND;\r
869}\r
870\r
7c80e839 871/**\r
872 Finds variable in storage blocks of volatile and non-volatile storage areas.\r
873\r
874 This code finds variable in storage blocks of volatile and non-volatile storage areas.\r
875 If VariableName is an empty string, then we just return the first\r
876 qualified variable without comparing VariableName and VendorGuid.\r
877 Otherwise, VariableName and VendorGuid are compared.\r
878\r
879 @param VariableName Name of the variable to be found\r
880 @param VendorGuid Vendor GUID to be found.\r
881 @param PtrTrack VARIABLE_POINTER_TRACK structure for output,\r
882 including the range searched and the target position.\r
883 @param Global Pointer to VARIABLE_GLOBAL structure, including\r
884 base of volatile variable storage area, base of\r
885 NV variable storage area, and a lock.\r
886\r
887 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while\r
888 VendorGuid is NULL\r
889 @retval EFI_SUCCESS Variable successfully found\r
890 @retval EFI_INVALID_PARAMETER Variable not found\r
33a5a666 891\r
7c80e839 892**/\r
8d3a5c82 893EFI_STATUS\r
8d3a5c82 894FindVariable (\r
895 IN CHAR16 *VariableName,\r
896 IN EFI_GUID *VendorGuid,\r
897 OUT VARIABLE_POINTER_TRACK *PtrTrack,\r
898 IN VARIABLE_GLOBAL *Global\r
899 )\r
8d3a5c82 900{\r
814bae52 901 VARIABLE_HEADER *Variable[2];\r
902 VARIABLE_HEADER *InDeletedVariable;\r
903 VARIABLE_STORE_HEADER *VariableStoreHeader[2];\r
904 UINTN InDeletedStorageIndex;\r
905 UINTN Index;\r
906 VOID *Point;\r
8d3a5c82 907\r
8d3a5c82 908 //\r
33a5a666 909 // 0: Volatile, 1: Non-Volatile\r
36873a61 910 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName\r
911 // make use of this mapping to implement search algorithme.\r
8d3a5c82 912 //\r
052ad7e1
A
913 VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
914 VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
8d3a5c82 915\r
916 //\r
917 // Start Pointers for the variable.\r
918 // Actual Data Pointer where data can be written.\r
919 //\r
9cad030b 920 Variable[0] = GetStartPointer (VariableStoreHeader[0]);\r
921 Variable[1] = GetStartPointer (VariableStoreHeader[1]);\r
8d3a5c82 922\r
923 if (VariableName[0] != 0 && VendorGuid == NULL) {\r
924 return EFI_INVALID_PARAMETER;\r
925 }\r
814bae52 926\r
8d3a5c82 927 //\r
33a5a666 928 // Find the variable by walk through volatile and then non-volatile variable store\r
8d3a5c82 929 //\r
814bae52 930 InDeletedVariable = NULL;\r
931 InDeletedStorageIndex = 0;\r
8d3a5c82 932 for (Index = 0; Index < 2; Index++) {\r
79749182 933 while ((Variable[Index] < GetEndPointer (VariableStoreHeader[Index])) && IsValidVariableHeader (Variable[Index])) {\r
814bae52 934 if (Variable[Index]->State == VAR_ADDED || \r
935 Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
936 ) {\r
8ed62a30 937 if (!EfiAtRuntime () || ((Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {\r
8d3a5c82 938 if (VariableName[0] == 0) {\r
814bae52 939 if (Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
940 InDeletedVariable = Variable[Index];\r
941 InDeletedStorageIndex = Index;\r
942 } else {\r
943 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]);\r
944 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]);\r
945 PtrTrack->CurrPtr = Variable[Index];\r
946 PtrTrack->Volatile = (BOOLEAN)(Index == 0);\r
947\r
948 return EFI_SUCCESS;\r
949 }\r
8d3a5c82 950 } else {\r
951 if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) {\r
130e2569 952 Point = (VOID *) GetVariableNamePtr (Variable[Index]);\r
953\r
954 ASSERT (NameSizeOfVariable (Variable[Index]) != 0);\r
c24b392c 955 if (CompareMem (VariableName, Point, NameSizeOfVariable (Variable[Index])) == 0) {\r
814bae52 956 if (Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
957 InDeletedVariable = Variable[Index];\r
958 InDeletedStorageIndex = Index;\r
959 } else {\r
960 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]);\r
961 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]);\r
962 PtrTrack->CurrPtr = Variable[Index];\r
963 PtrTrack->Volatile = (BOOLEAN)(Index == 0);\r
964\r
965 return EFI_SUCCESS;\r
966 }\r
8d3a5c82 967 }\r
968 }\r
969 }\r
970 }\r
971 }\r
972\r
973 Variable[Index] = GetNextVariablePtr (Variable[Index]);\r
974 }\r
814bae52 975 if (InDeletedVariable != NULL) {\r
976 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[InDeletedStorageIndex]);\r
977 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[InDeletedStorageIndex]);\r
978 PtrTrack->CurrPtr = InDeletedVariable;\r
979 PtrTrack->Volatile = (BOOLEAN)(InDeletedStorageIndex == 0);\r
980 return EFI_SUCCESS;\r
981 }\r
8d3a5c82 982 }\r
8d3a5c82 983 PtrTrack->CurrPtr = NULL;\r
984 return EFI_NOT_FOUND;\r
985}\r
986\r
33a5a666 987\r
7c80e839 988/**\r
052ad7e1 989\r
7c80e839 990 This code finds variable in storage blocks (Volatile or Non-Volatile).\r
c6492839 991\r
7c80e839 992 @param VariableName Name of Variable to be found.\r
993 @param VendorGuid Variable vendor GUID.\r
994 @param Attributes Attribute value of the variable found.\r
995 @param DataSize Size of Data found. If size is less than the\r
996 data, this value contains the required size.\r
997 @param Data Data pointer.\r
998 \r
999 @return EFI_INVALID_PARAMETER Invalid parameter\r
1000 @return EFI_SUCCESS Find the specified variable\r
1001 @return EFI_NOT_FOUND Not found\r
1002 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result\r
8d3a5c82 1003\r
7c80e839 1004**/\r
052ad7e1
A
1005EFI_STATUS\r
1006EFIAPI\r
1007RuntimeServiceGetVariable (\r
1008 IN CHAR16 *VariableName,\r
1009 IN EFI_GUID *VendorGuid,\r
1010 OUT UINT32 *Attributes OPTIONAL,\r
1011 IN OUT UINTN *DataSize,\r
1012 OUT VOID *Data\r
1013 )\r
8d3a5c82 1014{\r
052ad7e1 1015 EFI_STATUS Status;\r
8d3a5c82 1016 VARIABLE_POINTER_TRACK Variable;\r
1017 UINTN VarDataSize;\r
8d3a5c82 1018\r
1019 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
1020 return EFI_INVALID_PARAMETER;\r
1021 }\r
33a5a666 1022\r
fdb7765f 1023 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
1024\r
8d3a5c82 1025 //\r
1026 // Find existing variable\r
1027 //\r
33a5a666
A
1028 Status = FindVariableInCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
1029 if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_SUCCESS)){\r
1030 // Hit in the Cache\r
1031 UpdateVariableInfo (VariableName, VendorGuid, FALSE, TRUE, FALSE, FALSE, TRUE);\r
fdb7765f 1032 goto Done;\r
33a5a666
A
1033 }\r
1034 \r
052ad7e1 1035 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
8d3a5c82 1036 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
1037 goto Done;\r
1038 }\r
33a5a666 1039\r
8d3a5c82 1040 //\r
1041 // Get data size\r
1042 //\r
130e2569 1043 VarDataSize = DataSizeOfVariable (Variable.CurrPtr);\r
fdb7765f 1044 ASSERT (VarDataSize != 0);\r
1045\r
8d3a5c82 1046 if (*DataSize >= VarDataSize) {\r
1047 if (Data == NULL) {\r
1048 Status = EFI_INVALID_PARAMETER;\r
1049 goto Done;\r
1050 }\r
1051\r
1052 CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);\r
1053 if (Attributes != NULL) {\r
1054 *Attributes = Variable.CurrPtr->Attributes;\r
1055 }\r
1056\r
1057 *DataSize = VarDataSize;\r
33a5a666
A
1058 UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);\r
1059 UpdateVariableCache (VariableName, VendorGuid, Variable.CurrPtr->Attributes, VarDataSize, Data);\r
1060 \r
8d3a5c82 1061 Status = EFI_SUCCESS;\r
1062 goto Done;\r
1063 } else {\r
1064 *DataSize = VarDataSize;\r
1065 Status = EFI_BUFFER_TOO_SMALL;\r
1066 goto Done;\r
1067 }\r
1068\r
1069Done:\r
052ad7e1 1070 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
8d3a5c82 1071 return Status;\r
1072}\r
1073\r
052ad7e1
A
1074\r
1075\r
7c80e839 1076/**\r
8d3a5c82 1077\r
7c80e839 1078 This code Finds the Next available variable.\r
8d3a5c82 1079\r
7c80e839 1080 @param VariableNameSize Size of the variable name\r
1081 @param VariableName Pointer to variable name\r
1082 @param VendorGuid Variable Vendor Guid\r
8d3a5c82 1083\r
7c80e839 1084 @return EFI_INVALID_PARAMETER Invalid parameter\r
1085 @return EFI_SUCCESS Find the specified variable\r
1086 @return EFI_NOT_FOUND Not found\r
1087 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result\r
8d3a5c82 1088\r
7c80e839 1089**/\r
052ad7e1
A
1090EFI_STATUS\r
1091EFIAPI\r
1092RuntimeServiceGetNextVariableName (\r
1093 IN OUT UINTN *VariableNameSize,\r
1094 IN OUT CHAR16 *VariableName,\r
1095 IN OUT EFI_GUID *VendorGuid\r
1096 )\r
8d3a5c82 1097{\r
1098 VARIABLE_POINTER_TRACK Variable;\r
1099 UINTN VarNameSize;\r
1100 EFI_STATUS Status;\r
1101\r
1102 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
1103 return EFI_INVALID_PARAMETER;\r
1104 }\r
1105\r
fdb7765f 1106 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
1107\r
052ad7e1 1108 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
8d3a5c82 1109 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
1110 goto Done;\r
1111 }\r
1112\r
1113 if (VariableName[0] != 0) {\r
1114 //\r
1115 // If variable name is not NULL, get next variable\r
1116 //\r
1117 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
1118 }\r
1119\r
1120 while (TRUE) {\r
1121 //\r
1122 // If both volatile and non-volatile variable store are parsed,\r
1123 // return not found\r
1124 //\r
1125 if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) {\r
1126 Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));\r
36873a61 1127 if (!Variable.Volatile) {\r
9cad030b 1128 Variable.StartPtr = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
1129 Variable.EndPtr = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase));\r
8d3a5c82 1130 } else {\r
1131 Status = EFI_NOT_FOUND;\r
1132 goto Done;\r
1133 }\r
1134\r
1135 Variable.CurrPtr = Variable.StartPtr;\r
1136 if (!IsValidVariableHeader (Variable.CurrPtr)) {\r
1137 continue;\r
1138 }\r
1139 }\r
1140 //\r
1141 // Variable is found\r
1142 //\r
1143 if (IsValidVariableHeader (Variable.CurrPtr) && Variable.CurrPtr->State == VAR_ADDED) {\r
c24b392c 1144 if ((EfiAtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) == 0) {\r
130e2569 1145 VarNameSize = NameSizeOfVariable (Variable.CurrPtr);\r
fdb7765f 1146 ASSERT (VarNameSize != 0);\r
1147\r
8d3a5c82 1148 if (VarNameSize <= *VariableNameSize) {\r
1149 CopyMem (\r
1150 VariableName,\r
130e2569 1151 GetVariableNamePtr (Variable.CurrPtr),\r
8d3a5c82 1152 VarNameSize\r
1153 );\r
1154 CopyMem (\r
1155 VendorGuid,\r
1156 &Variable.CurrPtr->VendorGuid,\r
1157 sizeof (EFI_GUID)\r
1158 );\r
1159 Status = EFI_SUCCESS;\r
1160 } else {\r
1161 Status = EFI_BUFFER_TOO_SMALL;\r
1162 }\r
1163\r
1164 *VariableNameSize = VarNameSize;\r
1165 goto Done;\r
1166 }\r
1167 }\r
1168\r
1169 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
1170 }\r
1171\r
1172Done:\r
052ad7e1 1173 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
8d3a5c82 1174 return Status;\r
1175}\r
1176\r
7c80e839 1177/**\r
052ad7e1 1178\r
7c80e839 1179 This code sets variable in storage blocks (Volatile or Non-Volatile).\r
8d3a5c82 1180\r
7c80e839 1181 @param VariableName Name of Variable to be found\r
1182 @param VendorGuid Variable vendor GUID\r
1183 @param Attributes Attribute value of the variable found\r
1184 @param DataSize Size of Data found. If size is less than the\r
1185 data, this value contains the required size.\r
1186 @param Data Data pointer\r
8d3a5c82 1187\r
7c80e839 1188 @return EFI_INVALID_PARAMETER Invalid parameter\r
1189 @return EFI_SUCCESS Set successfully\r
1190 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable\r
1191 @return EFI_NOT_FOUND Not found\r
1192 @return EFI_WRITE_PROTECTED Variable is read-only\r
8d3a5c82 1193\r
7c80e839 1194**/\r
052ad7e1
A
1195EFI_STATUS\r
1196EFIAPI\r
1197RuntimeServiceSetVariable (\r
1198 IN CHAR16 *VariableName,\r
1199 IN EFI_GUID *VendorGuid,\r
1200 IN UINT32 Attributes,\r
1201 IN UINTN DataSize,\r
1202 IN VOID *Data\r
1203 )\r
8d3a5c82 1204{\r
8a9e0b72 1205 VARIABLE_POINTER_TRACK Variable;\r
1206 EFI_STATUS Status;\r
1207 VARIABLE_HEADER *NextVariable;\r
1208 UINTN VarNameSize;\r
1209 UINTN VarNameOffset;\r
1210 UINTN VarDataOffset;\r
1211 UINTN VarSize;\r
1212 UINT8 State;\r
1213 BOOLEAN Reclaimed;\r
1214 UINTN *VolatileOffset;\r
1215 UINTN *NonVolatileOffset;\r
1216 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
1217 BOOLEAN Volatile;\r
1218 EFI_PHYSICAL_ADDRESS Point;\r
8d3a5c82 1219\r
c6492839 1220 //\r
1221 // Check input parameters\r
1222 //\r
8d3a5c82 1223 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
1224 return EFI_INVALID_PARAMETER;\r
c6492839 1225 } \r
1226 //\r
1227 // Make sure if runtime bit is set, boot service bit is set also\r
1228 //\r
1229 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
1230 return EFI_INVALID_PARAMETER;\r
8d3a5c82 1231 }\r
fdb7765f 1232\r
c6492839 1233 //\r
1234 // The size of the VariableName, including the Unicode Null in bytes plus\r
e5618791
LG
1235 // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxHardwareErrorVariableSize)\r
1236 // bytes for HwErrRec, and FixedPcdGet32(PcdMaxVariableSize) bytes for the others.\r
c6492839 1237 //\r
1238 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
e5618791
LG
1239 if ((DataSize > FixedPcdGet32(PcdMaxHardwareErrorVariableSize)) || \r
1240 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > FixedPcdGet32(PcdMaxHardwareErrorVariableSize))) {\r
c6492839 1241 return EFI_INVALID_PARAMETER;\r
1242 } \r
1243 } else {\r
1244 //\r
1245 // The size of the VariableName, including the Unicode Null in bytes plus\r
e5618791 1246 // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxVariableSize) bytes.\r
c6492839 1247 //\r
e5618791
LG
1248 if ((DataSize > FixedPcdGet32(PcdMaxVariableSize)) ||\r
1249 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > FixedPcdGet32(PcdMaxVariableSize))) {\r
c6492839 1250 return EFI_INVALID_PARAMETER;\r
1251 } \r
1252 } \r
fdb7765f 1253\r
1254 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
1255\r
1256 Reclaimed = FALSE;\r
8a9e0b72 1257 Fvb = mVariableModuleGlobal->FvbInstance;\r
fdb7765f 1258 VolatileOffset = &mVariableModuleGlobal->VolatileLastVariableOffset;\r
1259\r
1260 //\r
1261 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated;\r
1262 //\r
1263 if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {\r
fdb7765f 1264 Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;;\r
1265 //\r
1266 // Parse non-volatile variable data and get last variable offset\r
1267 //\r
9cad030b 1268 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point);\r
fdb7765f 1269 while (IsValidVariableHeader (NextVariable)) {\r
1270 NextVariable = GetNextVariablePtr (NextVariable);\r
1271 }\r
1272 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;\r
1273 }\r
1274\r
1275 NonVolatileOffset = &mVariableModuleGlobal->NonVolatileLastVariableOffset;\r
1276 \r
1277\r
c6492839 1278 //\r
1279 // Check whether the input variable is already existed\r
1280 //\r
1281 \r
052ad7e1 1282 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
c6492839 1283 if (Status == EFI_SUCCESS && Variable.CurrPtr != NULL) {\r
8d3a5c82 1284 //\r
c6492839 1285 // Update/Delete existing variable\r
8d3a5c82 1286 //\r
fd51bf70 1287 Volatile = Variable.Volatile;\r
c6492839 1288 \r
1289 if (EfiAtRuntime ()) { \r
1290 //\r
1291 // If EfiAtRuntime and the variable is Volatile and Runtime Access, \r
1292 // the volatile is ReadOnly, and SetVariable should be aborted and \r
1293 // return EFI_WRITE_PROTECTED.\r
1294 //\r
1295 if (Variable.Volatile) {\r
1296 Status = EFI_WRITE_PROTECTED;\r
1297 goto Done;\r
1298 }\r
1299 //\r
1300 // Only variable have NV attribute can be updated/deleted in Runtime\r
1301 //\r
c24b392c 1302 if ((Variable.CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
c6492839 1303 Status = EFI_INVALID_PARAMETER;\r
1304 goto Done; \r
1305 }\r
1306 }\r
8d3a5c82 1307 //\r
c6492839 1308 // Setting a data variable with no access, or zero DataSize attributes\r
1309 // specified causes it to be deleted.\r
8d3a5c82 1310 //\r
c6492839 1311 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) { \r
1312 State = Variable.CurrPtr->State;\r
1313 State &= VAR_DELETED;\r
1314\r
1315 Status = UpdateVariableStore (\r
052ad7e1 1316 &mVariableModuleGlobal->VariableGlobal,\r
c6492839 1317 Variable.Volatile,\r
1318 FALSE,\r
8a9e0b72 1319 Fvb,\r
c6492839 1320 (UINTN) &Variable.CurrPtr->State,\r
1321 sizeof (UINT8),\r
1322 &State\r
1323 ); \r
33a5a666 1324 if (!EFI_ERROR (Status)) {\r
fd51bf70 1325 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, FALSE, TRUE, FALSE);\r
33a5a666
A
1326 UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
1327 }\r
c6492839 1328 goto Done; \r
1329 }\r
8d3a5c82 1330 //\r
c6492839 1331 // If the variable is marked valid and the same data has been passed in\r
1332 // then return to the caller immediately.\r
8d3a5c82 1333 //\r
130e2569 1334 if (DataSizeOfVariable (Variable.CurrPtr) == DataSize &&\r
c6492839 1335 (CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize) == 0)) {\r
33a5a666 1336 \r
fd51bf70 1337 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
c6492839 1338 Status = EFI_SUCCESS;\r
1339 goto Done;\r
1340 } else if ((Variable.CurrPtr->State == VAR_ADDED) ||\r
1341 (Variable.CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {\r
814bae52 1342\r
c6492839 1343 //\r
1344 // Mark the old variable as in delete transition\r
1345 //\r
1346 State = Variable.CurrPtr->State;\r
1347 State &= VAR_IN_DELETED_TRANSITION;\r
1348\r
1349 Status = UpdateVariableStore (\r
052ad7e1 1350 &mVariableModuleGlobal->VariableGlobal,\r
c6492839 1351 Variable.Volatile,\r
1352 FALSE,\r
8a9e0b72 1353 Fvb,\r
c6492839 1354 (UINTN) &Variable.CurrPtr->State,\r
1355 sizeof (UINT8),\r
1356 &State\r
1357 ); \r
1358 if (EFI_ERROR (Status)) {\r
1359 goto Done; \r
33a5a666 1360 } \r
c6492839 1361 } \r
1362 } else if (Status == EFI_NOT_FOUND) {\r
8d3a5c82 1363 //\r
c6492839 1364 // Create a new variable\r
1365 // \r
1366 \r
8d3a5c82 1367 //\r
c6492839 1368 // Make sure we are trying to create a new variable.\r
1369 // Setting a data variable with no access, or zero DataSize attributes means to delete it. \r
8d3a5c82 1370 //\r
c6492839 1371 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {\r
1372 Status = EFI_NOT_FOUND;\r
1373 goto Done;\r
1374 }\r
1375 \r
8d3a5c82 1376 //\r
c6492839 1377 // Only variable have NV|RT attribute can be created in Runtime\r
1378 //\r
1379 if (EfiAtRuntime () &&\r
45f6c85b 1380 (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {\r
c6492839 1381 Status = EFI_INVALID_PARAMETER;\r
1382 goto Done;\r
1383 } \r
1384 } else {\r
8d3a5c82 1385 //\r
c6492839 1386 // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable().\r
8d3a5c82 1387 //\r
c6492839 1388 ASSERT (Status == EFI_INVALID_PARAMETER);\r
8d3a5c82 1389 goto Done;\r
c6492839 1390 }\r
1391\r
1392 //\r
1393 // Function part - create a new variable and copy the data.\r
1394 // Both update a variable and create a variable will come here.\r
1395 //\r
1396 // Tricky part: Use scratch data area at the end of volatile variable store\r
1397 // as a temporary storage.\r
1398 //\r
052ad7e1 1399 NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));\r
c6492839 1400\r
e5618791 1401 SetMem (NextVariable, FixedPcdGet32(PcdMaxVariableSize), 0xff);\r
c6492839 1402\r
1403 NextVariable->StartId = VARIABLE_DATA;\r
1404 NextVariable->Attributes = Attributes;\r
1405 //\r
1406 // NextVariable->State = VAR_ADDED;\r
1407 //\r
1408 NextVariable->Reserved = 0;\r
1409 VarNameOffset = sizeof (VARIABLE_HEADER);\r
1410 VarNameSize = StrSize (VariableName);\r
1411 CopyMem (\r
1412 (UINT8 *) ((UINTN) NextVariable + VarNameOffset),\r
1413 VariableName,\r
1414 VarNameSize\r
1415 );\r
1416 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);\r
1417 CopyMem (\r
1418 (UINT8 *) ((UINTN) NextVariable + VarDataOffset),\r
1419 Data,\r
1420 DataSize\r
1421 );\r
1422 CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));\r
1423 //\r
1424 // There will be pad bytes after Data, the NextVariable->NameSize and\r
1425 // NextVariable->DataSize should not include pad size so that variable\r
1426 // service can get actual size in GetVariable\r
1427 //\r
1428 NextVariable->NameSize = (UINT32)VarNameSize;\r
1429 NextVariable->DataSize = (UINT32)DataSize;\r
1430\r
1431 //\r
1432 // The actual size of the variable that stores in storage should\r
1433 // include pad size.\r
1434 //\r
1435 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);\r
45f6c85b 1436 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
8d3a5c82 1437 //\r
c6492839 1438 // Create a nonvolatile variable\r
8d3a5c82 1439 //\r
fd51bf70 1440 Volatile = FALSE;\r
c6492839 1441 \r
1442 if ((UINT32) (VarSize +*NonVolatileOffset) >\r
052ad7e1 1443 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size\r
c6492839 1444 ) {\r
1445 if (EfiAtRuntime ()) {\r
1446 Status = EFI_OUT_OF_RESOURCES;\r
1447 goto Done;\r
1448 }\r
1449 //\r
1450 // Perform garbage collection & reclaim operation\r
1451 //\r
814bae52 1452 Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, NonVolatileOffset, FALSE, Variable.CurrPtr);\r
8d3a5c82 1453 if (EFI_ERROR (Status)) {\r
1454 goto Done;\r
1455 }\r
8d3a5c82 1456 //\r
c6492839 1457 // If still no enough space, return out of resources\r
8d3a5c82 1458 //\r
c6492839 1459 if ((UINT32) (VarSize +*NonVolatileOffset) >\r
052ad7e1 1460 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size\r
8d3a5c82 1461 ) {\r
c6492839 1462 Status = EFI_OUT_OF_RESOURCES;\r
8d3a5c82 1463 goto Done;\r
8d3a5c82 1464 }\r
c6492839 1465 \r
1466 Reclaimed = TRUE;\r
8d3a5c82 1467 }\r
1468 //\r
c6492839 1469 // Three steps\r
1470 // 1. Write variable header\r
130e2569 1471 // 2. Set variable state to header valid \r
1472 // 3. Write variable data\r
1473 // 4. Set variable state to valid\r
8d3a5c82 1474 //\r
8d3a5c82 1475 //\r
c6492839 1476 // Step 1:\r
8d3a5c82 1477 //\r
c6492839 1478 Status = UpdateVariableStore (\r
052ad7e1 1479 &mVariableModuleGlobal->VariableGlobal,\r
c6492839 1480 FALSE,\r
1481 TRUE,\r
8a9e0b72 1482 Fvb,\r
c6492839 1483 *NonVolatileOffset,\r
1484 sizeof (VARIABLE_HEADER),\r
1485 (UINT8 *) NextVariable\r
1486 );\r
1487\r
1488 if (EFI_ERROR (Status)) {\r
1489 goto Done;\r
1490 }\r
130e2569 1491\r
8d3a5c82 1492 //\r
c6492839 1493 // Step 2:\r
8d3a5c82 1494 //\r
130e2569 1495 NextVariable->State = VAR_HEADER_VALID_ONLY;\r
1496 Status = UpdateVariableStore (\r
1497 &mVariableModuleGlobal->VariableGlobal,\r
1498 FALSE,\r
1499 TRUE,\r
8a9e0b72 1500 Fvb,\r
130e2569 1501 *NonVolatileOffset,\r
1502 sizeof (VARIABLE_HEADER),\r
1503 (UINT8 *) NextVariable\r
1504 );\r
1505\r
1506 if (EFI_ERROR (Status)) {\r
1507 goto Done;\r
1508 }\r
1509 //\r
1510 // Step 3:\r
1511 //\r
c6492839 1512 Status = UpdateVariableStore (\r
052ad7e1 1513 &mVariableModuleGlobal->VariableGlobal,\r
c6492839 1514 FALSE,\r
1515 TRUE,\r
8a9e0b72 1516 Fvb,\r
c6492839 1517 *NonVolatileOffset + sizeof (VARIABLE_HEADER),\r
1518 (UINT32) VarSize - sizeof (VARIABLE_HEADER),\r
1519 (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)\r
1520 );\r
1521\r
1522 if (EFI_ERROR (Status)) {\r
1523 goto Done;\r
1524 }\r
8d3a5c82 1525 //\r
130e2569 1526 // Step 4:\r
8d3a5c82 1527 //\r
c6492839 1528 NextVariable->State = VAR_ADDED;\r
1529 Status = UpdateVariableStore (\r
052ad7e1 1530 &mVariableModuleGlobal->VariableGlobal,\r
c6492839 1531 FALSE,\r
1532 TRUE,\r
8a9e0b72 1533 Fvb,\r
c6492839 1534 *NonVolatileOffset,\r
1535 sizeof (VARIABLE_HEADER),\r
1536 (UINT8 *) NextVariable\r
1537 );\r
1538\r
1539 if (EFI_ERROR (Status)) {\r
1540 goto Done;\r
1541 }\r
8d3a5c82 1542\r
9cad030b 1543 *NonVolatileOffset = HEADER_ALIGN (*NonVolatileOffset + VarSize);\r
8d3a5c82 1544\r
c6492839 1545 } else {\r
1546 //\r
1547 // Create a volatile variable\r
1548 // \r
fd51bf70 1549 Volatile = TRUE;\r
c6492839 1550\r
1551 if ((UINT32) (VarSize +*VolatileOffset) >\r
052ad7e1 1552 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) {\r
8d3a5c82 1553 //\r
c6492839 1554 // Perform garbage collection & reclaim operation\r
8d3a5c82 1555 //\r
814bae52 1556 Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase, VolatileOffset, TRUE, Variable.CurrPtr);\r
8d3a5c82 1557 if (EFI_ERROR (Status)) {\r
1558 goto Done;\r
1559 }\r
1560 //\r
c6492839 1561 // If still no enough space, return out of resources\r
8d3a5c82 1562 //\r
8d3a5c82 1563 if ((UINT32) (VarSize +*VolatileOffset) >\r
052ad7e1 1564 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size\r
8d3a5c82 1565 ) {\r
c6492839 1566 Status = EFI_OUT_OF_RESOURCES;\r
8d3a5c82 1567 goto Done;\r
1568 }\r
c6492839 1569 \r
1570 Reclaimed = TRUE;\r
8d3a5c82 1571 }\r
8d3a5c82 1572\r
c6492839 1573 NextVariable->State = VAR_ADDED;\r
1574 Status = UpdateVariableStore (\r
052ad7e1 1575 &mVariableModuleGlobal->VariableGlobal,\r
c6492839 1576 TRUE,\r
1577 TRUE,\r
8a9e0b72 1578 Fvb,\r
c6492839 1579 *VolatileOffset,\r
1580 (UINT32) VarSize,\r
1581 (UINT8 *) NextVariable\r
1582 );\r
1583\r
1584 if (EFI_ERROR (Status)) {\r
1585 goto Done;\r
8d3a5c82 1586 }\r
c6492839 1587\r
9cad030b 1588 *VolatileOffset = HEADER_ALIGN (*VolatileOffset + VarSize);\r
c6492839 1589 }\r
1590 //\r
1591 // Mark the old variable as deleted\r
1592 //\r
1593 if (!Reclaimed && !EFI_ERROR (Status) && Variable.CurrPtr != NULL) {\r
1594 State = Variable.CurrPtr->State;\r
1595 State &= VAR_DELETED;\r
1596\r
1597 Status = UpdateVariableStore (\r
052ad7e1 1598 &mVariableModuleGlobal->VariableGlobal,\r
c6492839 1599 Variable.Volatile,\r
1600 FALSE,\r
8a9e0b72 1601 Fvb,\r
c6492839 1602 (UINTN) &Variable.CurrPtr->State,\r
1603 sizeof (UINT8),\r
1604 &State\r
1605 );\r
33a5a666
A
1606 \r
1607 if (!EFI_ERROR (Status)) {\r
fd51bf70 1608 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
33a5a666
A
1609 UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
1610 }\r
c6492839 1611 goto Done; \r
8d3a5c82 1612 }\r
1613\r
1614 Status = EFI_SUCCESS;\r
fd51bf70 1615 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
33a5a666
A
1616 UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
1617\r
8d3a5c82 1618Done:\r
fdb7765f 1619 InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);\r
052ad7e1 1620 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
fdb7765f 1621\r
8d3a5c82 1622 return Status;\r
1623}\r
1624\r
7c80e839 1625/**\r
8d3a5c82 1626\r
1627 This code returns information about the EFI variables.\r
1628\r
7c80e839 1629 @param Attributes Attributes bitmask to specify the type of variables\r
1630 on which to return information.\r
1631 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
1632 for the EFI variables associated with the attributes specified.\r
1633 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
1634 for EFI variables associated with the attributes specified.\r
1635 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables\r
1636 associated with the attributes specified.\r
8d3a5c82 1637\r
7c80e839 1638 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.\r
1639 @return EFI_SUCCESS Query successfully.\r
1640 @return EFI_UNSUPPORTED The attribute is not supported on this platform.\r
8d3a5c82 1641\r
7c80e839 1642**/\r
052ad7e1
A
1643EFI_STATUS\r
1644EFIAPI\r
1645RuntimeServiceQueryVariableInfo (\r
1646 IN UINT32 Attributes,\r
1647 OUT UINT64 *MaximumVariableStorageSize,\r
1648 OUT UINT64 *RemainingVariableStorageSize,\r
1649 OUT UINT64 *MaximumVariableSize\r
1650 )\r
8d3a5c82 1651{\r
1652 VARIABLE_HEADER *Variable;\r
1653 VARIABLE_HEADER *NextVariable;\r
1654 UINT64 VariableSize;\r
1655 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
1656\r
c6492839 1657 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
8d3a5c82 1658 return EFI_INVALID_PARAMETER;\r
1659 }\r
c6492839 1660 \r
1661 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {\r
8d3a5c82 1662 //\r
1663 // Make sure the Attributes combination is supported by the platform.\r
1664 //\r
c6492839 1665 return EFI_UNSUPPORTED; \r
8d3a5c82 1666 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
1667 //\r
1668 // Make sure if runtime bit is set, boot service bit is set also.\r
1669 //\r
1670 return EFI_INVALID_PARAMETER;\r
45f6c85b 1671 } else if (EfiAtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {\r
8d3a5c82 1672 //\r
1673 // Make sure RT Attribute is set if we are in Runtime phase.\r
1674 //\r
1675 return EFI_INVALID_PARAMETER;\r
1676 }\r
1677\r
052ad7e1 1678 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
8d3a5c82 1679\r
1680 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
1681 //\r
1682 // Query is Volatile related.\r
1683 //\r
052ad7e1 1684 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
8d3a5c82 1685 } else {\r
1686 //\r
1687 // Query is Non-Volatile related.\r
1688 //\r
052ad7e1 1689 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
8d3a5c82 1690 }\r
1691\r
1692 //\r
1693 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize\r
1694 // with the storage size (excluding the storage header size).\r
1695 //\r
1696 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
1697 *RemainingVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
1698\r
1699 //\r
e5618791 1700 // Let *MaximumVariableSize be FixedPcdGet32(PcdMaxVariableSize) with the exception of the variable header size.\r
8d3a5c82 1701 //\r
e5618791 1702 *MaximumVariableSize = FixedPcdGet32(PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);\r
c6492839 1703\r
1704 //\r
1705 // Harware error record variable needs larger size.\r
1706 //\r
1707 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
e5618791 1708 *MaximumVariableSize = FixedPcdGet32(PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);\r
c6492839 1709 }\r
8d3a5c82 1710\r
1711 //\r
1712 // Point to the starting address of the variables.\r
1713 //\r
9cad030b 1714 Variable = GetStartPointer (VariableStoreHeader);\r
8d3a5c82 1715\r
1716 //\r
1717 // Now walk through the related variable store.\r
1718 //\r
1719 while (IsValidVariableHeader (Variable) && (Variable < GetEndPointer (VariableStoreHeader))) {\r
1720 NextVariable = GetNextVariablePtr (Variable);\r
1721 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;\r
1722\r
1723 if (EfiAtRuntime ()) {\r
1724 //\r
1725 // we don't take the state of the variables in mind\r
1726 // when calculating RemainingVariableStorageSize,\r
1727 // since the space occupied by variables not marked with\r
1728 // VAR_ADDED is not allowed to be reclaimed in Runtime.\r
1729 //\r
1730 *RemainingVariableStorageSize -= VariableSize;\r
1731 } else {\r
1732 //\r
1733 // Only care about Variables with State VAR_ADDED,because\r
1734 // the space not marked as VAR_ADDED is reclaimable now.\r
1735 //\r
1736 if (Variable->State == VAR_ADDED) {\r
1737 *RemainingVariableStorageSize -= VariableSize;\r
1738 }\r
1739 }\r
1740\r
1741 //\r
1742 // Go to the next one\r
1743 //\r
1744 Variable = NextVariable;\r
1745 }\r
1746\r
c6492839 1747 if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {\r
1748 *MaximumVariableSize = 0;\r
1749 } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {\r
1750 *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);\r
1751 }\r
1752\r
052ad7e1 1753 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
8d3a5c82 1754 return EFI_SUCCESS;\r
1755}\r
1756\r
7c80e839 1757\r
1758/**\r
1759 Notification function of EVT_GROUP_READY_TO_BOOT event group.\r
1760\r
1761 This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.\r
1762 When the Boot Manager is about to load and execute a boot option, it reclaims variable\r
1763 storage if free size is below the threshold.\r
1764\r
1765 @param Event Event whose notification function is being invoked\r
1766 @param Context Pointer to the notification function's context\r
1767\r
1768**/\r
7800593d
LG
1769VOID\r
1770EFIAPI\r
1771ReclaimForOS(\r
1772 EFI_EVENT Event,\r
1773 VOID *Context\r
1774 )\r
1775{\r
1776 UINT32 VarSize;\r
1777 EFI_STATUS Status;\r
1778\r
1779 VarSize = ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase))->Size;\r
1780 Status = EFI_SUCCESS; \r
1781\r
1782 //\r
1783 // Check if the free area is blow a threshold\r
1784 //\r
1785 if ((VarSize - mVariableModuleGlobal->NonVolatileLastVariableOffset) < VARIABLE_RECLAIM_THRESHOLD) {\r
1786 Status = Reclaim (\r
1787 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
1788 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
814bae52 1789 FALSE,\r
1790 NULL\r
7800593d
LG
1791 );\r
1792 ASSERT_EFI_ERROR (Status);\r
1793 }\r
1794}\r
1795\r
7c80e839 1796/**\r
1797 Initializes variable store area for non-volatile and volatile variable.\r
1798\r
7c80e839 1799 @param SystemTable The pointer of EFI_SYSTEM_TABLE.\r
1800\r
1801 @retval EFI_SUCCESS Function successfully executed.\r
1802 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r
1803\r
1804**/\r
8d3a5c82 1805EFI_STATUS\r
8d3a5c82 1806VariableCommonInitialize (\r
8a9e0b72 1807 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol\r
8d3a5c82 1808 )\r
8d3a5c82 1809{\r
1810 EFI_STATUS Status;\r
8d3a5c82 1811 VARIABLE_STORE_HEADER *VolatileVariableStore;\r
1812 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
1813 VARIABLE_HEADER *NextVariable;\r
8a9e0b72 1814 EFI_PHYSICAL_ADDRESS TempVariableStoreHeader;\r
8d3a5c82 1815 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
8a9e0b72 1816 EFI_PHYSICAL_ADDRESS BaseAddress;\r
8d3a5c82 1817 UINT64 Length;\r
1818 UINTN Index;\r
1819 UINT8 Data;\r
8a9e0b72 1820 EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
052ad7e1 1821 UINT64 VariableStoreLength;\r
7800593d 1822 EFI_EVENT ReadyToBootEvent;\r
8d3a5c82 1823\r
7800593d
LG
1824 Status = EFI_SUCCESS;\r
1825 //\r
1826 // Allocate runtime memory for variable driver global structure.\r
1827 //\r
1828 mVariableModuleGlobal = AllocateRuntimePool (sizeof (VARIABLE_MODULE_GLOBAL));\r
1829 if (mVariableModuleGlobal == NULL) {\r
1830 return EFI_OUT_OF_RESOURCES;\r
1831 }\r
8d3a5c82 1832\r
052ad7e1 1833 EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);\r
fdb7765f 1834 mVariableModuleGlobal->VariableGlobal.ReentrantState = 0;\r
8d3a5c82 1835\r
1836 //\r
1837 // Allocate memory for volatile variable store\r
1838 //\r
e5618791 1839 VolatileVariableStore = AllocateRuntimePool (FixedPcdGet32(PcdVariableStoreSize) + FixedPcdGet32(PcdMaxVariableSize));\r
8d3a5c82 1840 if (VolatileVariableStore == NULL) {\r
1841 FreePool (mVariableModuleGlobal);\r
1842 return EFI_OUT_OF_RESOURCES;\r
1843 }\r
1844\r
e5618791 1845 SetMem (VolatileVariableStore, FixedPcdGet32(PcdVariableStoreSize) + FixedPcdGet32(PcdMaxVariableSize), 0xff);\r
8d3a5c82 1846\r
1847 //\r
1848 // Variable Specific Data\r
1849 //\r
052ad7e1 1850 mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
9cad030b 1851 mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;\r
8a9e0b72 1852 mVariableModuleGlobal->FvbInstance = FvbProtocol;\r
8d3a5c82 1853\r
3709c4cd 1854 CopyGuid (&VolatileVariableStore->Signature, &gEfiVariableGuid);\r
e5618791 1855 VolatileVariableStore->Size = FixedPcdGet32(PcdVariableStoreSize);\r
8d3a5c82 1856 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;\r
1857 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;\r
1858 VolatileVariableStore->Reserved = 0;\r
1859 VolatileVariableStore->Reserved1 = 0;\r
1860\r
1861 //\r
1862 // Get non volatile varaible store\r
1863 //\r
1864\r
8a9e0b72 1865 TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
052ad7e1 1866 VariableStoreBase = TempVariableStoreHeader + \\r
8a9e0b72 1867 (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
052ad7e1 1868 VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \\r
8a9e0b72 1869 (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
8d3a5c82 1870 //\r
1871 // Mark the variable storage region of the FLASH as RUNTIME\r
1872 //\r
052ad7e1
A
1873 BaseAddress = VariableStoreBase & (~EFI_PAGE_MASK);\r
1874 Length = VariableStoreLength + (VariableStoreBase - BaseAddress);\r
8d3a5c82 1875 Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);\r
1876\r
1877 Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);\r
1878 if (EFI_ERROR (Status)) {\r
7800593d 1879 goto Done;\r
8d3a5c82 1880 }\r
1881\r
1882 Status = gDS->SetMemorySpaceAttributes (\r
1883 BaseAddress,\r
1884 Length,\r
1885 GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME\r
1886 );\r
1887 if (EFI_ERROR (Status)) {\r
7800593d 1888 goto Done;\r
8d3a5c82 1889 }\r
1890 //\r
1891 // Get address of non volatile variable store base\r
1892 //\r
052ad7e1 1893 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
8a9e0b72 1894 VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
8d3a5c82 1895 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
1896 if (~VariableStoreHeader->Size == 0) {\r
1897 Status = UpdateVariableStore (\r
052ad7e1 1898 &mVariableModuleGlobal->VariableGlobal,\r
8d3a5c82 1899 FALSE,\r
1900 FALSE,\r
1901 mVariableModuleGlobal->FvbInstance,\r
1902 (UINTN) &VariableStoreHeader->Size,\r
1903 sizeof (UINT32),\r
052ad7e1 1904 (UINT8 *) &VariableStoreLength\r
8d3a5c82 1905 );\r
1906 //\r
1907 // As Variables are stored in NV storage, which are slow devices,such as flash.\r
1908 // Variable operation may skip checking variable program result to improve performance,\r
1909 // We can assume Variable program is OK through some check point.\r
1910 // Variable Store Size Setting should be the first Variable write operation,\r
1911 // We can assume all Read/Write is OK if we can set Variable store size successfully.\r
1912 // If write fail, we will assert here\r
1913 //\r
052ad7e1 1914 ASSERT(VariableStoreHeader->Size == VariableStoreLength);\r
8d3a5c82 1915\r
1916 if (EFI_ERROR (Status)) {\r
7800593d 1917 goto Done;\r
8d3a5c82 1918 }\r
1919 }\r
1920\r
8d3a5c82 1921 //\r
1922 // Parse non-volatile variable data and get last variable offset\r
1923 //\r
8a9e0b72 1924 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);\r
8d3a5c82 1925 Status = EFI_SUCCESS;\r
1926\r
1927 while (IsValidVariableHeader (NextVariable)) {\r
1928 NextVariable = GetNextVariablePtr (NextVariable);\r
1929 }\r
1930\r
8a9e0b72 1931 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;\r
8d3a5c82 1932\r
8d3a5c82 1933 //\r
1934 // Check if the free area is really free.\r
1935 //\r
1936 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {\r
052ad7e1 1937 Data = ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)[Index];\r
8d3a5c82 1938 if (Data != 0xff) {\r
1939 //\r
1940 // There must be something wrong in variable store, do reclaim operation.\r
1941 //\r
1942 Status = Reclaim (\r
052ad7e1 1943 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
8d3a5c82 1944 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
814bae52 1945 FALSE,\r
1946 NULL\r
8d3a5c82 1947 );\r
7800593d
LG
1948\r
1949 if (EFI_ERROR (Status)) {\r
1950 goto Done;\r
1951 }\r
1952\r
8d3a5c82 1953 break;\r
1954 }\r
1955 }\r
7800593d
LG
1956\r
1957 //\r
1958 // Register the event handling function to reclaim variable for OS usage.\r
1959 //\r
1960 Status = EfiCreateEventReadyToBootEx (\r
1961 TPL_NOTIFY, \r
1962 ReclaimForOS, \r
1963 NULL, \r
1964 &ReadyToBootEvent\r
1965 );\r
5bb820af 1966 } else {\r
1967 Status = EFI_VOLUME_CORRUPTED;\r
1968 DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));\r
8d3a5c82 1969 }\r
1970\r
7800593d 1971Done:\r
8d3a5c82 1972 if (EFI_ERROR (Status)) {\r
1973 FreePool (mVariableModuleGlobal);\r
1974 FreePool (VolatileVariableStore);\r
1975 }\r
1976\r
1977 return Status;\r
1978}\r
052ad7e1 1979\r
7c80e839 1980/**\r
1981 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE\r
1982\r
1983 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
1984 It convers pointer to new virtual address.\r
1985\r
1986 @param Event Event whose notification function is being invoked\r
1987 @param Context Pointer to the notification function's context\r
1988\r
1989**/\r
052ad7e1
A
1990VOID\r
1991EFIAPI\r
1992VariableClassAddressChangeEvent (\r
1993 IN EFI_EVENT Event,\r
1994 IN VOID *Context\r
1995 )\r
1996{\r
8a9e0b72 1997 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);\r
1998 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);\r
1999 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);\r
2000 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes);\r
2001 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read);\r
2002 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write);\r
2003 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks);\r
2004 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance);\r
052ad7e1
A
2005 EfiConvertPointer (\r
2006 0x0,\r
2007 (VOID **) &mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase\r
2008 );\r
2009 EfiConvertPointer (\r
2010 0x0,\r
2011 (VOID **) &mVariableModuleGlobal->VariableGlobal.VolatileVariableBase\r
2012 );\r
2013 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal);\r
2014}\r
2015\r
8a9e0b72 2016VOID\r
2017EFIAPI\r
2018FvbNotificationEvent (\r
2019 IN EFI_EVENT Event,\r
2020 IN VOID *Context\r
2021 )\r
2022{\r
2023 EFI_STATUS Status;\r
2024 EFI_HANDLE *HandleBuffer;\r
8a9e0b72 2025 UINTN HandleCount;\r
2026 UINTN Index;\r
2027 EFI_PHYSICAL_ADDRESS FvbBaseAddress;\r
2028 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
2029 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
2030 EFI_FVB_ATTRIBUTES_2 Attributes;\r
2031 EFI_SYSTEM_TABLE *SystemTable;\r
2032 EFI_PHYSICAL_ADDRESS NvStorageVariableBase;\r
2033\r
2034 SystemTable = (EFI_SYSTEM_TABLE *)Context;\r
2035 Fvb = NULL;\r
8a9e0b72 2036 \r
2037 //\r
2038 // Locate all handles of Fvb protocol\r
2039 //\r
2040 Status = gBS->LocateHandleBuffer (\r
2041 ByProtocol,\r
2042 &gEfiFirmwareVolumeBlockProtocolGuid,\r
2043 NULL,\r
2044 &HandleCount,\r
2045 &HandleBuffer\r
2046 );\r
2047 if (EFI_ERROR (Status)) {\r
2048 return ;\r
2049 }\r
2050 \r
2051 //\r
2052 // Get the FVB to access variable store\r
2053 //\r
f0480ecf 2054 for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {\r
8a9e0b72 2055 Status = gBS->HandleProtocol (\r
2056 HandleBuffer[Index],\r
2057 &gEfiFirmwareVolumeBlockProtocolGuid,\r
2058 (VOID **) &Fvb\r
2059 );\r
2060 if (EFI_ERROR (Status)) {\r
2061 Status = EFI_NOT_FOUND;\r
2062 break;\r
2063 }\r
2064\r
2065 //\r
2066 // Ensure this FVB protocol supported Write operation.\r
2067 //\r
2068 Status = Fvb->GetAttributes (Fvb, &Attributes);\r
2069 if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {\r
2070 continue; \r
2071 }\r
2072 //\r
2073 // Compare the address and select the right one\r
2074 //\r
2075 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
2076 if (EFI_ERROR (Status)) {\r
2077 continue;\r
2078 }\r
2079\r
2080 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
2081 NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
2082 if ((NvStorageVariableBase >= FvbBaseAddress) && (NvStorageVariableBase < (FvbBaseAddress + FwVolHeader->FvLength))) {\r
8a9e0b72 2083 Status = EFI_SUCCESS;\r
2084 break;\r
2085 }\r
2086 }\r
2087\r
2088 FreePool (HandleBuffer);\r
f0480ecf 2089 if (!EFI_ERROR (Status) && Fvb != NULL) {\r
533020ef 2090 //\r
2091 // Close the notify event to avoid install gEfiVariableArchProtocolGuid & gEfiVariableWriteArchProtocolGuid again.\r
2092 //\r
2093 Status = gBS->CloseEvent (Event); \r
2094 ASSERT_EFI_ERROR (Status);\r
2095\r
8a9e0b72 2096 Status = VariableCommonInitialize (Fvb);\r
2097 ASSERT_EFI_ERROR (Status);\r
2098 \r
79749182 2099 SystemTable->RuntimeServices->GetVariable = RuntimeServiceGetVariable;\r
8a9e0b72 2100 SystemTable->RuntimeServices->GetNextVariableName = RuntimeServiceGetNextVariableName;\r
79749182 2101 SystemTable->RuntimeServices->SetVariable = RuntimeServiceSetVariable;\r
2102 SystemTable->RuntimeServices->QueryVariableInfo = RuntimeServiceQueryVariableInfo;\r
8a9e0b72 2103 \r
2104 //\r
2105 // Now install the Variable Runtime Architectural Protocol on a new handle\r
2106 //\r
2107 Status = gBS->InstallMultipleProtocolInterfaces (\r
2108 &mHandle,\r
2109 &gEfiVariableArchProtocolGuid, NULL,\r
2110 &gEfiVariableWriteArchProtocolGuid, NULL,\r
2111 NULL\r
2112 );\r
2113 ASSERT_EFI_ERROR (Status);\r
2114 \r
2115 Status = gBS->CreateEventEx (\r
2116 EVT_NOTIFY_SIGNAL,\r
2117 TPL_NOTIFY,\r
2118 VariableClassAddressChangeEvent,\r
2119 NULL,\r
2120 &gEfiEventVirtualAddressChangeGuid,\r
2121 &mVirtualAddressChangeEvent\r
2122 );\r
2123 ASSERT_EFI_ERROR (Status);\r
2124 }\r
2125\r
2126}\r
052ad7e1
A
2127\r
2128/**\r
2129 Variable Driver main entry point. The Variable driver places the 4 EFI\r
2130 runtime services in the EFI System Table and installs arch protocols \r
7c80e839 2131 for variable read and write services being availible. It also registers\r
2132 notification function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
052ad7e1
A
2133\r
2134 @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
2135 @param[in] SystemTable A pointer to the EFI System Table.\r
2136 \r
7c80e839 2137 @retval EFI_SUCCESS Variable service successfully initialized.\r
052ad7e1
A
2138\r
2139**/\r
2140EFI_STATUS\r
2141EFIAPI\r
2142VariableServiceInitialize (\r
2143 IN EFI_HANDLE ImageHandle,\r
2144 IN EFI_SYSTEM_TABLE *SystemTable\r
2145 )\r
2146{\r
052ad7e1 2147 //\r
8a9e0b72 2148 // Register FvbNotificationEvent () notify function.\r
2149 // \r
2150 EfiCreateProtocolNotifyEvent (\r
2151 &gEfiFirmwareVolumeBlockProtocolGuid,\r
2152 TPL_CALLBACK,\r
2153 FvbNotificationEvent,\r
2154 (VOID *)SystemTable,\r
2155 &mFvbRegistration\r
2156 );\r
052ad7e1
A
2157\r
2158 return EFI_SUCCESS;\r
2159}\r
2160\r