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