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