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