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