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