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