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