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