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