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