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