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