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