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