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