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