Back the wrong check in for MdeModulePkg.dsc.
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Universal / Variable / RuntimeDxe / Variable.c
1 /** @file\r
2   EFI Runtime Variable services.\r
3   \r
4   Copyright (c) 2006 - 2007, Intel Corporation                                                         \r
5   All rights reserved. This program and the accompanying materials                          \r
6   are licensed and made available under the terms and conditions of the BSD License         \r
7   which accompanies this distribution.  The full text of the license may be found at        \r
8   http://opensource.org/licenses/bsd-license.php                                            \r
9 \r
10   THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,                     \r
11   WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.             \r
12 \r
13 **/\r
14 \r
15 \r
16 #include "Variable.h"\r
17 \r
18 \r
19 VARIABLE_MODULE_GLOBAL  mRuntimeData;\r
20 VARIABLE_MODULE_GLOBAL  *mVariableModuleGlobal = &mRuntimeData;\r
21 EFI_EVENT   mVirtualAddressChangeEvent = NULL;\r
22 EFI_HANDLE  mHandle = NULL;\r
23 \r
24 \r
25 //\r
26 // This is a temperary function which will be removed\r
27 // when EfiAcquireLock in UefiLib can handle the\r
28 // the call in UEFI Runtimer driver in RT phase.\r
29 //\r
30 VOID\r
31 AcquireLockOnlyAtBootTime (\r
32   IN EFI_LOCK  *Lock\r
33   )\r
34 {\r
35   if (!EfiAtRuntime ()) {\r
36     EfiAcquireLock (Lock);\r
37   }\r
38 }\r
39 \r
40 //\r
41 // This is a temperary function which will be removed\r
42 // when EfiAcquireLock in UefiLib can handle the\r
43 // the call in UEFI Runtimer driver in RT phase.\r
44 //\r
45 VOID\r
46 ReleaseLockOnlyAtBootTime (\r
47   IN EFI_LOCK  *Lock\r
48   )\r
49 {\r
50   if (!EfiAtRuntime ()) {\r
51     EfiReleaseLock (Lock);\r
52   }\r
53 }\r
54 \r
55 \r
56 GLOBAL_REMOVE_IF_UNREFERENCED VARIABLE_INFO_ENTRY *gVariableInfo = NULL;\r
57 \r
58 \r
59 /**\r
60   Routine used to track statistical information about variable usage. \r
61   The data is stored in the EFI system table so it can be accessed later.\r
62   VariableInfo.efi can dump out the table. Only Boot Services variable \r
63   accesses are tracked by this code. The PcdVariableCollectStatistics\r
64   build flag controls if this feature is enabled. \r
65 \r
66   A read that hits in the cache will have Read and Cache true for \r
67   the transaction. Data is allocated by this routine, but never\r
68   freed.\r
69 \r
70   @param[in] VariableName   Name of the Variable to track\r
71   @param[in] VendorGuid     Guid of the Variable to track\r
72   @param[in] Volatile       TRUE if volatile FALSE if non-volatile\r
73   @param[in] Read           TRUE if GetVariable() was called\r
74   @param[in] Write          TRUE if SetVariable() was called\r
75   @param[in] Delete         TRUE if deleted via SetVariable()\r
76   @param[in] Cache          TRUE for a cache hit.\r
77 \r
78 **/\r
79 VOID\r
80 UpdateVariableInfo (\r
81   IN  CHAR16                  *VariableName,\r
82   IN  EFI_GUID                *VendorGuid,\r
83   IN  BOOLEAN                 Volatile,\r
84   IN  BOOLEAN                 Read,\r
85   IN  BOOLEAN                 Write,\r
86   IN  BOOLEAN                 Delete,\r
87   IN  BOOLEAN                 Cache\r
88   )\r
89 {\r
90   VARIABLE_INFO_ENTRY   *Entry;\r
91 \r
92   if (FeaturePcdGet (PcdVariableCollectStatistics)) {\r
93 \r
94     if (EfiAtRuntime ()) {\r
95       // Don't collect statistics at runtime\r
96       return;\r
97     }\r
98 \r
99     if (gVariableInfo == NULL) {\r
100       //\r
101       // on the first call allocate a entry and place a pointer to it in\r
102       // the EFI System Table\r
103       //\r
104       gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
105       ASSERT (gVariableInfo != NULL);\r
106 \r
107       CopyGuid (&gVariableInfo->VendorGuid, VendorGuid);\r
108       gVariableInfo->Name = AllocatePool (StrLen (VariableName));\r
109       StrCpy (gVariableInfo->Name, VariableName);\r
110       gVariableInfo->Volatile = Volatile;\r
111 \r
112       gBS->InstallConfigurationTable (&gEfiVariableInfoGuid, gVariableInfo);\r
113     }\r
114 \r
115     \r
116     for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) {\r
117       if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {\r
118         if (StrCmp (VariableName, Entry->Name) == 0) {\r
119           if (Read) {\r
120             Entry->ReadCount++;\r
121           }\r
122           if (Write) {\r
123             Entry->WriteCount++;\r
124           }\r
125           if (Delete) {\r
126             Entry->DeleteCount++;\r
127           }\r
128           if (Cache) {\r
129             Entry->CacheCount++;\r
130           }\r
131 \r
132           return;\r
133         }\r
134       }\r
135 \r
136       if (Entry->Next == NULL) {\r
137         //\r
138         // If the entry is not in the table add it.\r
139         // Next iteration of the loop will fill in the data\r
140         //\r
141         Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
142         ASSERT (Entry->Next != NULL);\r
143 \r
144         CopyGuid (&Entry->Next->VendorGuid, VendorGuid);\r
145         Entry->Next->Name = AllocatePool (StrLen (VariableName));\r
146         StrCpy (Entry->Next->Name, VariableName);\r
147         Entry->Next->Volatile = Volatile;\r
148       }\r
149 \r
150     }\r
151   }\r
152 }\r
153 \r
154 \r
155 BOOLEAN\r
156 IsValidVariableHeader (\r
157   IN  VARIABLE_HEADER   *Variable\r
158   )\r
159 /*++\r
160 \r
161 Routine Description:\r
162 \r
163   This code checks if variable header is valid or not.\r
164 \r
165 Arguments:\r
166   Variable              Pointer to the Variable Header.\r
167 \r
168 Returns:\r
169   TRUE            Variable header is valid.\r
170   FALSE           Variable header is not valid.\r
171 \r
172 --*/\r
173 {\r
174   if (Variable == NULL || Variable->StartId != VARIABLE_DATA) {\r
175     return FALSE;\r
176   }\r
177 \r
178   return TRUE;\r
179 }\r
180 \r
181 \r
182 EFI_STATUS\r
183 UpdateVariableStore (\r
184   IN  VARIABLE_GLOBAL         *Global,\r
185   IN  BOOLEAN                 Volatile,\r
186   IN  BOOLEAN                 SetByIndex,\r
187   IN  UINTN                   Instance,\r
188   IN  UINTN                   DataPtrIndex,\r
189   IN  UINT32                  DataSize,\r
190   IN  UINT8                   *Buffer\r
191   )\r
192 /*++\r
193 \r
194 Routine Description:\r
195 \r
196   This function writes data to the FWH at the correct LBA even if the LBAs\r
197   are fragmented.\r
198 \r
199 Arguments:\r
200 \r
201   Global            - Pointer to VARAIBLE_GLOBAL structure\r
202   Volatile          - If the Variable is Volatile or Non-Volatile\r
203   SetByIndex        - TRUE: Target pointer is given as index\r
204                       FALSE: Target pointer is absolute\r
205   Instance          - Instance of FV Block services\r
206   DataPtrIndex      - Pointer to the Data from the end of VARIABLE_STORE_HEADER\r
207                       structure\r
208   DataSize          - Size of data to be written.\r
209   Buffer            - Pointer to the buffer from which data is written\r
210 \r
211 Returns:\r
212 \r
213   EFI_INVALID_PARAMETER   - Parameters not valid\r
214   EFI_SUCCESS             - Variable store successfully updated\r
215 \r
216 --*/\r
217 {\r
218   EFI_FV_BLOCK_MAP_ENTRY      *PtrBlockMapEntry;\r
219   UINTN                       BlockIndex2;\r
220   UINTN                       LinearOffset;\r
221   UINTN                       CurrWriteSize;\r
222   UINTN                       CurrWritePtr;\r
223   UINT8                       *CurrBuffer;\r
224   EFI_LBA                     LbaNumber;\r
225   UINTN                       Size;\r
226   EFI_FIRMWARE_VOLUME_HEADER  *FwVolHeader;\r
227   VARIABLE_STORE_HEADER       *VolatileBase;\r
228   EFI_PHYSICAL_ADDRESS        FvVolHdr;\r
229   EFI_PHYSICAL_ADDRESS        DataPtr;\r
230   EFI_STATUS                  Status;\r
231 \r
232   FwVolHeader = NULL;\r
233   DataPtr     = DataPtrIndex;\r
234 \r
235   //\r
236   // Check if the Data is Volatile\r
237   //\r
238   if (!Volatile) {\r
239     EfiFvbGetPhysicalAddress (Instance, &FvVolHdr);\r
240     FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);\r
241     //\r
242     // Data Pointer should point to the actual Address where data is to be\r
243     // written\r
244     //\r
245     if (SetByIndex) {\r
246       DataPtr += mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
247     }\r
248 \r
249     if ((DataPtr + DataSize) >= ((EFI_PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) FwVolHeader + FwVolHeader->FvLength))) {\r
250       return EFI_INVALID_PARAMETER;\r
251     }\r
252   } else {\r
253     //\r
254     // Data Pointer should point to the actual Address where data is to be\r
255     // written\r
256     //\r
257     VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
258     if (SetByIndex) {\r
259       DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
260     }\r
261 \r
262     if ((DataPtr + DataSize) >= ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) {\r
263       return EFI_INVALID_PARAMETER;\r
264     }\r
265     \r
266     //\r
267     // If Volatile Variable just do a simple mem copy.\r
268     //    \r
269     CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize);\r
270     return EFI_SUCCESS;\r
271   }\r
272   \r
273   //\r
274   // If we are here we are dealing with Non-Volatile Variables\r
275   //\r
276   LinearOffset  = (UINTN) FwVolHeader;\r
277   CurrWritePtr  = (UINTN) DataPtr;\r
278   CurrWriteSize = DataSize;\r
279   CurrBuffer    = Buffer;\r
280   LbaNumber     = 0;\r
281 \r
282   if (CurrWritePtr < LinearOffset) {\r
283     return EFI_INVALID_PARAMETER;\r
284   }\r
285 \r
286   for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
287     for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {\r
288       //\r
289       // Check to see if the Variable Writes are spanning through multiple\r
290       // blocks.\r
291       //\r
292       if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) {\r
293         if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {\r
294           Status = EfiFvbWriteBlock (\r
295                     Instance,\r
296                     LbaNumber,\r
297                     (UINTN) (CurrWritePtr - LinearOffset),\r
298                     &CurrWriteSize,\r
299                     CurrBuffer\r
300                     );\r
301             return Status;\r
302         } else {\r
303           Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);\r
304           Status = EfiFvbWriteBlock (\r
305                     Instance,\r
306                     LbaNumber,\r
307                     (UINTN) (CurrWritePtr - LinearOffset),\r
308                     &Size,\r
309                     CurrBuffer\r
310                     );\r
311           if (EFI_ERROR (Status)) {\r
312             return Status;\r
313           }\r
314 \r
315           CurrWritePtr  = LinearOffset + PtrBlockMapEntry->Length;\r
316           CurrBuffer    = CurrBuffer + Size;\r
317           CurrWriteSize = CurrWriteSize - Size;\r
318         }\r
319       }\r
320 \r
321       LinearOffset += PtrBlockMapEntry->Length;\r
322       LbaNumber++;\r
323     }\r
324   }\r
325 \r
326   return EFI_SUCCESS;\r
327 }\r
328 \r
329 \r
330 VARIABLE_STORE_STATUS\r
331 GetVariableStoreStatus (\r
332   IN VARIABLE_STORE_HEADER *VarStoreHeader\r
333   )\r
334 /*++\r
335 \r
336 Routine Description:\r
337 \r
338   This code gets the current status of Variable Store.\r
339 \r
340 Arguments:\r
341 \r
342   VarStoreHeader  Pointer to the Variable Store Header.\r
343 \r
344 Returns:\r
345 \r
346   EfiRaw        Variable store status is raw\r
347   EfiValid      Variable store status is valid\r
348   EfiInvalid    Variable store status is invalid\r
349 \r
350 --*/\r
351 {\r
352   if (VarStoreHeader->Signature == VARIABLE_STORE_SIGNATURE &&\r
353       VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&\r
354       VarStoreHeader->State == VARIABLE_STORE_HEALTHY\r
355       ) {\r
356 \r
357     return EfiValid;\r
358   } else if (VarStoreHeader->Signature == 0xffffffff &&\r
359            VarStoreHeader->Size == 0xffffffff &&\r
360            VarStoreHeader->Format == 0xff &&\r
361            VarStoreHeader->State == 0xff\r
362           ) {\r
363 \r
364     return EfiRaw;\r
365   } else {\r
366     return EfiInvalid;\r
367   }\r
368 }\r
369 \r
370 \r
371 UINTN\r
372 NameSizeOfVariable (\r
373   IN  VARIABLE_HEADER   *Variable\r
374   )\r
375 /*++\r
376 \r
377 Routine Description:\r
378 \r
379   This code gets the size of name of variable.\r
380 \r
381 Arguments:\r
382 \r
383   Variable            Pointer to the Variable Header.\r
384 \r
385 Returns:\r
386 \r
387   UINTN               Size of variable in bytes\r
388 \r
389 --*/\r
390 {\r
391   if (Variable->State    == (UINT8) (-1) ||\r
392       Variable->DataSize == (UINT32) -1 ||\r
393       Variable->NameSize == (UINT32) -1 ||\r
394       Variable->Attributes == (UINT32) -1) {\r
395     return 0;\r
396   }\r
397   return (UINTN) Variable->NameSize;\r
398 }\r
399 \r
400 UINTN\r
401 DataSizeOfVariable (\r
402   IN  VARIABLE_HEADER   *Variable\r
403   )\r
404 /*++\r
405 \r
406 Routine Description:\r
407 \r
408   This code gets the size of name of variable.\r
409 \r
410 Arguments:\r
411 \r
412   Variable            Pointer to the Variable Header.\r
413 \r
414 Returns:\r
415 \r
416   UINTN               Size of variable in bytes\r
417 \r
418 --*/\r
419 {\r
420   if (Variable->State    == (UINT8)  -1 ||\r
421       Variable->DataSize == (UINT32) -1 ||\r
422       Variable->NameSize == (UINT32) -1 ||\r
423       Variable->Attributes == (UINT32) -1) {\r
424     return 0;\r
425   }\r
426   return (UINTN) Variable->DataSize;\r
427 }\r
428 \r
429 CHAR16 *\r
430 GetVariableNamePtr (\r
431   IN  VARIABLE_HEADER   *Variable\r
432   )\r
433 /*++\r
434 \r
435 Routine Description:\r
436 \r
437   This code gets the pointer to the variable name.\r
438 \r
439 Arguments:\r
440 \r
441   Variable            Pointer to the Variable Header.\r
442 \r
443 Returns:\r
444 \r
445   CHAR16*              Pointer to Variable Name\r
446 \r
447 --*/\r
448 {\r
449 \r
450   return (CHAR16 *) (Variable + 1);\r
451 }\r
452 \r
453 UINT8 *\r
454 GetVariableDataPtr (\r
455   IN  VARIABLE_HEADER   *Variable\r
456   )\r
457 /*++\r
458 \r
459 Routine Description:\r
460 \r
461   This code gets the pointer to the variable data.\r
462 \r
463 Arguments:\r
464 \r
465   Variable            Pointer to the Variable Header.\r
466 \r
467 Returns:\r
468 \r
469   UINT8*              Pointer to Variable Data\r
470 \r
471 --*/\r
472 {\r
473   UINTN Value;\r
474   \r
475   //\r
476   // Be careful about pad size for alignment\r
477   //\r
478   Value =  (UINTN) GetVariableNamePtr (Variable);\r
479   Value += NameSizeOfVariable (Variable);\r
480   Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));\r
481 \r
482   return (UINT8 *) Value;\r
483 }\r
484 \r
485 \r
486 VARIABLE_HEADER *\r
487 GetNextVariablePtr (\r
488   IN  VARIABLE_HEADER   *Variable\r
489   )\r
490 /*++\r
491 \r
492 Routine Description:\r
493 \r
494   This code gets the pointer to the next variable header.\r
495 \r
496 Arguments:\r
497 \r
498   Variable              Pointer to the Variable Header.\r
499 \r
500 Returns:\r
501 \r
502   VARIABLE_HEADER*      Pointer to next variable header.\r
503 \r
504 --*/\r
505 {\r
506   UINTN Value;\r
507 \r
508   if (!IsValidVariableHeader (Variable)) {\r
509     return NULL;\r
510   }\r
511 \r
512   Value =  (UINTN) GetVariableDataPtr (Variable);\r
513   Value += DataSizeOfVariable (Variable);\r
514   Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));\r
515 \r
516   //\r
517   // Be careful about pad size for alignment\r
518   //\r
519   return (VARIABLE_HEADER *) HEADER_ALIGN (Value);\r
520 }\r
521 \r
522 VARIABLE_HEADER *\r
523 GetStartPointer (\r
524   IN VARIABLE_STORE_HEADER       *VarStoreHeader\r
525   )\r
526 /*++\r
527 \r
528 Routine Description:\r
529 \r
530   This code gets the pointer to the first variable memory pointer byte\r
531 \r
532 Arguments:\r
533 \r
534   VarStoreHeader        Pointer to the Variable Store Header.\r
535 \r
536 Returns:\r
537 \r
538   VARIABLE_HEADER*      Pointer to last unavailable Variable Header\r
539 \r
540 --*/\r
541 {\r
542   //\r
543   // The end of variable store\r
544   //\r
545   return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);\r
546 }\r
547 \r
548 VARIABLE_HEADER *\r
549 GetEndPointer (\r
550   IN VARIABLE_STORE_HEADER       *VarStoreHeader\r
551   )\r
552 /*++\r
553 \r
554 Routine Description:\r
555 \r
556   This code gets the pointer to the last variable memory pointer byte\r
557 \r
558 Arguments:\r
559 \r
560   VarStoreHeader        Pointer to the Variable Store Header.\r
561 \r
562 Returns:\r
563 \r
564   VARIABLE_HEADER*      Pointer to last unavailable Variable Header\r
565 \r
566 --*/\r
567 {\r
568   //\r
569   // The end of variable store\r
570   //\r
571   return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);\r
572 }\r
573 \r
574 \r
575 EFI_STATUS\r
576 Reclaim (\r
577   IN  EFI_PHYSICAL_ADDRESS  VariableBase,\r
578   OUT UINTN                 *LastVariableOffset,\r
579   IN  BOOLEAN               IsVolatile\r
580   )\r
581 /*++\r
582 \r
583 Routine Description:\r
584 \r
585   Variable store garbage collection and reclaim operation\r
586 \r
587 Arguments:\r
588 \r
589   VariableBase                Base address of variable store\r
590   LastVariableOffset          Offset of last variable\r
591   IsVolatile                  The variable store is volatile or not,\r
592                               if it is non-volatile, need FTW\r
593 \r
594 Returns:\r
595 \r
596   EFI STATUS\r
597 \r
598 --*/\r
599 {\r
600   VARIABLE_HEADER       *Variable;\r
601   VARIABLE_HEADER       *NextVariable;\r
602   VARIABLE_STORE_HEADER *VariableStoreHeader;\r
603   UINT8                 *ValidBuffer;\r
604   UINTN                 ValidBufferSize;\r
605   UINTN                 VariableSize;\r
606   UINT8                 *CurrPtr;\r
607   EFI_STATUS            Status;\r
608 \r
609   VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);\r
610 \r
611   //\r
612   // Start Pointers for the variable.\r
613   //\r
614   Variable        = GetStartPointer (VariableStoreHeader);\r
615   ValidBufferSize = sizeof (VARIABLE_STORE_HEADER);\r
616 \r
617   while (IsValidVariableHeader (Variable)) {\r
618     NextVariable = GetNextVariablePtr (Variable);\r
619     if (Variable->State == VAR_ADDED) {\r
620       VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
621       ValidBufferSize += VariableSize;\r
622     }\r
623 \r
624     Variable = NextVariable;\r
625   }\r
626 \r
627   ValidBuffer = AllocatePool (ValidBufferSize);\r
628   if (ValidBuffer == NULL) {\r
629     return EFI_OUT_OF_RESOURCES;\r
630   }\r
631 \r
632   SetMem (ValidBuffer, ValidBufferSize, 0xff);\r
633 \r
634   CurrPtr = ValidBuffer;\r
635 \r
636   //\r
637   // Copy variable store header\r
638   //\r
639   CopyMem (CurrPtr, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));\r
640   CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) CurrPtr);\r
641 \r
642   //\r
643   // Start Pointers for the variable.\r
644   //\r
645   Variable = GetStartPointer (VariableStoreHeader);\r
646 \r
647   while (IsValidVariableHeader (Variable)) {\r
648     NextVariable = GetNextVariablePtr (Variable);\r
649     if (Variable->State == VAR_ADDED) {\r
650       VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
651       CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
652       CurrPtr += VariableSize;\r
653     }\r
654 \r
655     Variable = NextVariable;\r
656   }\r
657 \r
658   if (IsVolatile) {\r
659     //\r
660     // If volatile variable store, just copy valid buffer\r
661     //\r
662     SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);\r
663     CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, ValidBufferSize);\r
664     *LastVariableOffset = ValidBufferSize;\r
665     Status              = EFI_SUCCESS;\r
666   } else {\r
667     //\r
668     // If non-volatile variable store, perform FTW here.\r
669     //\r
670     Status = FtwVariableSpace (\r
671               VariableBase,\r
672               ValidBuffer,\r
673               ValidBufferSize\r
674               );\r
675     if (!EFI_ERROR (Status)) {\r
676       *LastVariableOffset = ValidBufferSize;\r
677     }\r
678   }\r
679 \r
680   FreePool (ValidBuffer);\r
681 \r
682   if (EFI_ERROR (Status)) {\r
683     *LastVariableOffset = 0;\r
684   }\r
685 \r
686   return Status;\r
687 }\r
688 \r
689 \r
690 //\r
691 // The current Hii implementation accesses this variable a larg # of times on every boot.\r
692 // Other common variables are only accessed a single time. This is why this cache algorithm\r
693 // only targets a single variable. Probably to get an performance improvement out of\r
694 // a Cache you would need a cache that improves the search performance for a variable.\r
695 //\r
696 VARIABLE_CACHE_ENTRY mVariableCache[] = {\r
697   {\r
698     &gEfiGlobalVariableGuid,\r
699     L"Lang",\r
700     0x00000000,\r
701     0x00,\r
702     NULL\r
703   }\r
704 };\r
705 \r
706 \r
707 /**\r
708   Update the Cache with Variable information. These are the same \r
709   arguments as the EFI Variable services.\r
710 \r
711   @param[in] VariableName  Name of variable\r
712   @param[in] VendorGuid    Guid of variable\r
713   @param[in] Attribute     Attribue of the variable\r
714   @param[in] DataSize      Size of data. 0 means delete\r
715   @param[in] Data          Variable data\r
716 \r
717 **/\r
718 VOID\r
719 UpdateVariableCache (\r
720   IN      CHAR16            *VariableName,\r
721   IN      EFI_GUID          *VendorGuid,\r
722   IN      UINT32            Attributes,\r
723   IN      UINTN             DataSize,\r
724   IN      VOID              *Data\r
725   )\r
726 {\r
727   VARIABLE_CACHE_ENTRY      *Entry;\r
728   UINTN                     Index;\r
729 \r
730   if (EfiAtRuntime ()) {\r
731     // Don't use the cache at runtime\r
732     return;\r
733   }\r
734 \r
735   for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {\r
736     if (CompareGuid (VendorGuid, Entry->Guid)) {\r
737       if (StrCmp (VariableName, Entry->Name) == 0) { \r
738         Entry->Attributes = Attributes;\r
739         if (DataSize == 0) {\r
740           // Delete Case\r
741           if (Entry->DataSize != 0) {\r
742             FreePool (Entry->Data);\r
743           }\r
744           Entry->DataSize = DataSize;\r
745         } else if (DataSize == Entry->DataSize) {\r
746           CopyMem (Entry->Data, Data, DataSize);\r
747         } else {\r
748           Entry->Data = AllocatePool (DataSize);\r
749           Entry->DataSize = DataSize;\r
750           CopyMem (Entry->Data, Data, DataSize);\r
751         }\r
752       }\r
753     }\r
754   }\r
755 }\r
756 \r
757 \r
758 /**\r
759   Search the cache to see if the variable is in the cache.\r
760 \r
761   @param[in] VariableName  Name of variable\r
762   @param[in] VendorGuid    Guid of variable\r
763   @param[in] Attribute     Attribue returned \r
764   @param[in] DataSize      Size of data returned\r
765   @param[in] Data          Variable data returned\r
766 \r
767   @retval EFI_SUCCESS      VariableGuid & VariableName data was returned.\r
768   @retval other            Not found.\r
769 \r
770 **/\r
771 EFI_STATUS\r
772 FindVariableInCache (\r
773   IN      CHAR16            *VariableName,\r
774   IN      EFI_GUID          *VendorGuid,\r
775   OUT     UINT32            *Attributes OPTIONAL,\r
776   IN OUT  UINTN             *DataSize,\r
777   OUT     VOID              *Data\r
778   )\r
779 {\r
780   VARIABLE_CACHE_ENTRY      *Entry;\r
781   UINTN                     Index;\r
782 \r
783   if (EfiAtRuntime ()) {\r
784     // Don't use the cache at runtime\r
785     return EFI_NOT_FOUND;\r
786   }\r
787 \r
788   for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {\r
789     if (CompareGuid (VendorGuid, Entry->Guid)) {\r
790       if (StrCmp (VariableName, Entry->Name) == 0) {\r
791         if (Entry->DataSize == 0) {\r
792           // Variable was deleted so return not found\r
793           return EFI_NOT_FOUND;\r
794         } else if (Entry->DataSize > *DataSize) {\r
795           // If the buffer is too small return correct size\r
796           *DataSize = Entry->DataSize;\r
797           return EFI_BUFFER_TOO_SMALL;\r
798         } else {\r
799           *DataSize = Entry->DataSize;\r
800           // Return the data\r
801           CopyMem (Data, Entry->Data, Entry->DataSize);\r
802           if (Attributes != NULL) {\r
803             *Attributes = Entry->Attributes;\r
804           }\r
805           return EFI_SUCCESS;\r
806         }\r
807       }\r
808     }\r
809   }\r
810   \r
811   return EFI_NOT_FOUND;\r
812 }\r
813 \r
814 \r
815 EFI_STATUS\r
816 FindVariable (\r
817   IN  CHAR16                  *VariableName,\r
818   IN  EFI_GUID                *VendorGuid,\r
819   OUT VARIABLE_POINTER_TRACK  *PtrTrack,\r
820   IN  VARIABLE_GLOBAL         *Global\r
821   )\r
822 /*++\r
823 \r
824 Routine Description:\r
825 \r
826   This code finds variable in storage blocks (Volatile or Non-Volatile)\r
827 \r
828 Arguments:\r
829 \r
830   VariableName                Name of the variable to be found\r
831   VendorGuid                  Vendor GUID to be found.\r
832   PtrTrack                    Variable Track Pointer structure that contains\r
833                               Variable Information.\r
834                               Contains the pointer of Variable header.\r
835   Global                      VARIABLE_GLOBAL pointer\r
836 \r
837 Returns:\r
838 \r
839   EFI STATUS\r
840 \r
841 --*/\r
842 {\r
843   VARIABLE_HEADER       *Variable[2];\r
844   VARIABLE_STORE_HEADER *VariableStoreHeader[2];\r
845   UINTN                 Index;\r
846   VOID                  *Point;\r
847 \r
848   //\r
849   // 0: Volatile, 1: Non-Volatile\r
850   // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName\r
851   // make use of this mapping to implement search algorithme.\r
852   //\r
853   VariableStoreHeader[0]  = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
854   VariableStoreHeader[1]  = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
855 \r
856   //\r
857   // Start Pointers for the variable.\r
858   // Actual Data Pointer where data can be written.\r
859   //\r
860   Variable[0] = GetStartPointer (VariableStoreHeader[0]);\r
861   Variable[1] = GetStartPointer (VariableStoreHeader[1]);\r
862 \r
863   if (VariableName[0] != 0 && VendorGuid == NULL) {\r
864     return EFI_INVALID_PARAMETER;\r
865   }\r
866   //\r
867   // Find the variable by walk through volatile and then non-volatile variable store\r
868   //\r
869   for (Index = 0; Index < 2; Index++) {\r
870     PtrTrack->StartPtr  = GetStartPointer (VariableStoreHeader[Index]);\r
871     PtrTrack->EndPtr    = GetEndPointer (VariableStoreHeader[Index]);\r
872 \r
873     while (IsValidVariableHeader (Variable[Index]) && (Variable[Index] <= GetEndPointer (VariableStoreHeader[Index]))) {\r
874       if (Variable[Index]->State == VAR_ADDED) {\r
875         if (!EfiAtRuntime () || (Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {\r
876           if (VariableName[0] == 0) {\r
877             PtrTrack->CurrPtr   = Variable[Index];\r
878             PtrTrack->Volatile  = (BOOLEAN)(Index == 0);\r
879             return EFI_SUCCESS;\r
880           } else {\r
881             if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) {\r
882               Point = (VOID *) GetVariableNamePtr (Variable[Index]);\r
883 \r
884               ASSERT (NameSizeOfVariable (Variable[Index]) != 0);\r
885               if (!CompareMem (VariableName, Point, NameSizeOfVariable (Variable[Index]))) {\r
886                 PtrTrack->CurrPtr   = Variable[Index];\r
887                 PtrTrack->Volatile  = (BOOLEAN)(Index == 0);\r
888                 return EFI_SUCCESS;\r
889               }\r
890             }\r
891           }\r
892         }\r
893       }\r
894 \r
895       Variable[Index] = GetNextVariablePtr (Variable[Index]);\r
896     }\r
897   }\r
898   PtrTrack->CurrPtr = NULL;\r
899   return EFI_NOT_FOUND;\r
900 }\r
901 \r
902 \r
903 \r
904 /*++\r
905 \r
906 Routine Description:\r
907 \r
908   This code finds variable in storage blocks (Volatile or Non-Volatile)\r
909 \r
910 Arguments:\r
911 \r
912   VariableName                Name of Variable to be found\r
913   VendorGuid                  Variable vendor GUID\r
914   Attributes OPTIONAL         Attribute value of the variable found\r
915   DataSize                    Size of Data found. If size is less than the\r
916                               data, this value contains the required size.\r
917   Data                        Data pointer\r
918   Global                      Pointer to VARIABLE_GLOBAL structure\r
919   Instance                    Instance of the Firmware Volume.\r
920 \r
921 Returns:\r
922 \r
923   EFI_INVALID_PARAMETER       - Invalid parameter\r
924   EFI_SUCCESS                 - Find the specified variable\r
925   EFI_NOT_FOUND               - Not found\r
926   EFI_BUFFER_TO_SMALL         - DataSize is too small for the result\r
927 \r
928 \r
929 --*/\r
930 EFI_STATUS\r
931 EFIAPI\r
932 RuntimeServiceGetVariable (\r
933   IN      CHAR16            *VariableName,\r
934   IN      EFI_GUID          *VendorGuid,\r
935   OUT     UINT32            *Attributes OPTIONAL,\r
936   IN OUT  UINTN             *DataSize,\r
937   OUT     VOID              *Data\r
938   )\r
939 {\r
940   EFI_STATUS              Status;\r
941   VARIABLE_POINTER_TRACK  Variable;\r
942   UINTN                   VarDataSize;\r
943 \r
944   if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
945     return EFI_INVALID_PARAMETER;\r
946   }\r
947 \r
948   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
949 \r
950   //\r
951   // Find existing variable\r
952   //\r
953   Status = FindVariableInCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
954   if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_SUCCESS)){\r
955     // Hit in the Cache\r
956     UpdateVariableInfo (VariableName, VendorGuid, FALSE, TRUE, FALSE, FALSE, TRUE);\r
957     goto Done;\r
958   }\r
959   \r
960   Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
961   if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
962     goto Done;\r
963   }\r
964 \r
965   //\r
966   // Get data size\r
967   //\r
968   VarDataSize = DataSizeOfVariable (Variable.CurrPtr);\r
969   ASSERT (VarDataSize != 0);\r
970 \r
971   if (*DataSize >= VarDataSize) {\r
972     if (Data == NULL) {\r
973       Status = EFI_INVALID_PARAMETER;\r
974       goto Done;\r
975     }\r
976 \r
977     CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);\r
978     if (Attributes != NULL) {\r
979       *Attributes = Variable.CurrPtr->Attributes;\r
980     }\r
981 \r
982     *DataSize = VarDataSize;\r
983     UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);\r
984     UpdateVariableCache (VariableName, VendorGuid, Variable.CurrPtr->Attributes, VarDataSize, Data);\r
985  \r
986     Status = EFI_SUCCESS;\r
987     goto Done;\r
988   } else {\r
989     *DataSize = VarDataSize;\r
990     Status = EFI_BUFFER_TOO_SMALL;\r
991     goto Done;\r
992   }\r
993 \r
994 Done:\r
995   ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
996   return Status;\r
997 }\r
998 \r
999 \r
1000 \r
1001 /*++\r
1002 \r
1003 Routine Description:\r
1004 \r
1005   This code Finds the Next available variable\r
1006 \r
1007 Arguments:\r
1008 \r
1009   VariableNameSize            Size of the variable\r
1010   VariableName                Pointer to variable name\r
1011   VendorGuid                  Variable Vendor Guid\r
1012   Global                      VARIABLE_GLOBAL structure pointer.\r
1013   Instance                    FV instance\r
1014 \r
1015 Returns:\r
1016 \r
1017   EFI STATUS\r
1018 \r
1019 --*/\r
1020 EFI_STATUS\r
1021 EFIAPI\r
1022 RuntimeServiceGetNextVariableName (\r
1023   IN OUT  UINTN             *VariableNameSize,\r
1024   IN OUT  CHAR16            *VariableName,\r
1025   IN OUT  EFI_GUID          *VendorGuid\r
1026   )\r
1027 {\r
1028   VARIABLE_POINTER_TRACK  Variable;\r
1029   UINTN                   VarNameSize;\r
1030   EFI_STATUS              Status;\r
1031 \r
1032   if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
1033     return EFI_INVALID_PARAMETER;\r
1034   }\r
1035 \r
1036   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
1037 \r
1038   Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
1039   if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
1040     goto Done;\r
1041   }\r
1042 \r
1043   if (VariableName[0] != 0) {\r
1044     //\r
1045     // If variable name is not NULL, get next variable\r
1046     //\r
1047     Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
1048   }\r
1049 \r
1050   while (TRUE) {\r
1051     //\r
1052     // If both volatile and non-volatile variable store are parsed,\r
1053     // return not found\r
1054     //\r
1055     if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) {\r
1056       Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));\r
1057       if (!Variable.Volatile) {\r
1058         Variable.StartPtr = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
1059         Variable.EndPtr   = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase));\r
1060       } else {\r
1061         Status = EFI_NOT_FOUND;\r
1062         goto Done;\r
1063       }\r
1064 \r
1065       Variable.CurrPtr = Variable.StartPtr;\r
1066       if (!IsValidVariableHeader (Variable.CurrPtr)) {\r
1067         continue;\r
1068       }\r
1069     }\r
1070     //\r
1071     // Variable is found\r
1072     //\r
1073     if (IsValidVariableHeader (Variable.CurrPtr) && Variable.CurrPtr->State == VAR_ADDED) {\r
1074       if (!(EfiAtRuntime () && !(Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS))) {\r
1075         VarNameSize = NameSizeOfVariable (Variable.CurrPtr);\r
1076         ASSERT (VarNameSize != 0);\r
1077 \r
1078         if (VarNameSize <= *VariableNameSize) {\r
1079           CopyMem (\r
1080             VariableName,\r
1081             GetVariableNamePtr (Variable.CurrPtr),\r
1082             VarNameSize\r
1083             );\r
1084           CopyMem (\r
1085             VendorGuid,\r
1086             &Variable.CurrPtr->VendorGuid,\r
1087             sizeof (EFI_GUID)\r
1088             );\r
1089           Status = EFI_SUCCESS;\r
1090         } else {\r
1091           Status = EFI_BUFFER_TOO_SMALL;\r
1092         }\r
1093 \r
1094         *VariableNameSize = VarNameSize;\r
1095         goto Done;\r
1096       }\r
1097     }\r
1098 \r
1099     Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
1100   }\r
1101 \r
1102 Done:\r
1103   ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
1104   return Status;\r
1105 }\r
1106 \r
1107 \r
1108 /*++\r
1109 \r
1110 Routine Description:\r
1111 \r
1112   This code sets variable in storage blocks (Volatile or Non-Volatile)\r
1113 \r
1114 Arguments:\r
1115 \r
1116   VariableName                    Name of Variable to be found\r
1117   VendorGuid                      Variable vendor GUID\r
1118   Attributes                      Attribute value of the variable found\r
1119   DataSize                        Size of Data found. If size is less than the\r
1120                                   data, this value contains the required size.\r
1121   Data                            Data pointer\r
1122   Global                          Pointer to VARIABLE_GLOBAL structure\r
1123   VolatileOffset                  The offset of last volatile variable\r
1124   NonVolatileOffset               The offset of last non-volatile variable\r
1125   Instance                        Instance of the Firmware Volume.\r
1126 \r
1127 Returns:\r
1128 \r
1129   EFI_INVALID_PARAMETER           - Invalid parameter\r
1130   EFI_SUCCESS                     - Set successfully\r
1131   EFI_OUT_OF_RESOURCES            - Resource not enough to set variable\r
1132   EFI_NOT_FOUND                   - Not found\r
1133   EFI_DEVICE_ERROR                - Variable can not be saved due to hardware failure\r
1134   EFI_WRITE_PROTECTED             - Variable is read-only\r
1135 \r
1136 --*/\r
1137 EFI_STATUS\r
1138 EFIAPI\r
1139 RuntimeServiceSetVariable (\r
1140   IN CHAR16                  *VariableName,\r
1141   IN EFI_GUID                *VendorGuid,\r
1142   IN UINT32                  Attributes,\r
1143   IN UINTN                   DataSize,\r
1144   IN VOID                    *Data\r
1145   )\r
1146 {\r
1147   VARIABLE_POINTER_TRACK  Variable;\r
1148   EFI_STATUS              Status;\r
1149   VARIABLE_HEADER         *NextVariable;\r
1150   UINTN                   VarNameSize;\r
1151   UINTN                   VarNameOffset;\r
1152   UINTN                   VarDataOffset;\r
1153   UINTN                   VarSize;\r
1154   UINT8                   State;\r
1155   BOOLEAN                 Reclaimed;\r
1156   UINTN                   *VolatileOffset;\r
1157   UINTN                   *NonVolatileOffset;\r
1158   UINT32                  Instance;\r
1159   BOOLEAN                 Volatile;\r
1160   EFI_PHYSICAL_ADDRESS    Point;\r
1161 \r
1162   //\r
1163   // Check input parameters\r
1164   //\r
1165   if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
1166     return EFI_INVALID_PARAMETER;\r
1167   }  \r
1168   //\r
1169   //  Make sure if runtime bit is set, boot service bit is set also\r
1170   //\r
1171   if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
1172     return EFI_INVALID_PARAMETER;\r
1173   }\r
1174 \r
1175   //\r
1176   //  The size of the VariableName, including the Unicode Null in bytes plus\r
1177   //  the DataSize is limited to maximum size of MAX_HARDWARE_ERROR_VARIABLE_SIZE (32K)\r
1178   //  bytes for HwErrRec, and MAX_VARIABLE_SIZE (1024) bytes for the others.\r
1179   //\r
1180   if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
1181     if ((DataSize > MAX_HARDWARE_ERROR_VARIABLE_SIZE) ||                                                       \r
1182         (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_HARDWARE_ERROR_VARIABLE_SIZE)) {\r
1183       return EFI_INVALID_PARAMETER;\r
1184     }    \r
1185   } else {\r
1186   //\r
1187   //  The size of the VariableName, including the Unicode Null in bytes plus\r
1188   //  the DataSize is limited to maximum size of MAX_VARIABLE_SIZE (1024) bytes.\r
1189   //\r
1190     if ((DataSize > MAX_VARIABLE_SIZE) ||\r
1191         (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_VARIABLE_SIZE)) {\r
1192       return EFI_INVALID_PARAMETER;\r
1193     }  \r
1194   }  \r
1195 \r
1196   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
1197 \r
1198   Reclaimed         = FALSE;\r
1199   Instance          = mVariableModuleGlobal->FvbInstance;\r
1200   VolatileOffset    = &mVariableModuleGlobal->VolatileLastVariableOffset;\r
1201 \r
1202   //\r
1203   // Consider reentrant in MCA/INIT/NMI. It needs be reupdated;\r
1204   //\r
1205   if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {\r
1206     Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;;\r
1207     //\r
1208     // Parse non-volatile variable data and get last variable offset\r
1209     //\r
1210     NextVariable  = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point);\r
1211     while (IsValidVariableHeader (NextVariable)) {\r
1212       NextVariable = GetNextVariablePtr (NextVariable);\r
1213     }\r
1214     mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;\r
1215   }\r
1216 \r
1217   NonVolatileOffset = &mVariableModuleGlobal->NonVolatileLastVariableOffset;\r
1218   \r
1219 \r
1220   //\r
1221   // Check whether the input variable is already existed\r
1222   //\r
1223   \r
1224   Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
1225   if (Status == EFI_SUCCESS && Variable.CurrPtr != NULL) {\r
1226     //\r
1227     // Update/Delete existing variable\r
1228     //\r
1229     Volatile = Variable.Volatile;\r
1230     \r
1231     if (EfiAtRuntime ()) {        \r
1232       //\r
1233       // If EfiAtRuntime and the variable is Volatile and Runtime Access,  \r
1234       // the volatile is ReadOnly, and SetVariable should be aborted and \r
1235       // return EFI_WRITE_PROTECTED.\r
1236       //\r
1237       if (Variable.Volatile) {\r
1238         Status = EFI_WRITE_PROTECTED;\r
1239         goto Done;\r
1240       }\r
1241       //\r
1242       // Only variable have NV attribute can be updated/deleted in Runtime\r
1243       //\r
1244       if (!(Variable.CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE)) {\r
1245         Status = EFI_INVALID_PARAMETER;\r
1246         goto Done;      \r
1247       }\r
1248     }\r
1249     //\r
1250     // Setting a data variable with no access, or zero DataSize attributes\r
1251     // specified causes it to be deleted.\r
1252     //\r
1253     if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {    \r
1254       State = Variable.CurrPtr->State;\r
1255       State &= VAR_DELETED;\r
1256 \r
1257       Status = UpdateVariableStore (\r
1258                  &mVariableModuleGlobal->VariableGlobal,\r
1259                  Variable.Volatile,\r
1260                  FALSE,\r
1261                  Instance,\r
1262                  (UINTN) &Variable.CurrPtr->State,\r
1263                  sizeof (UINT8),\r
1264                  &State\r
1265                  ); \r
1266       if (!EFI_ERROR (Status)) {\r
1267         UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, FALSE, TRUE, FALSE);\r
1268         UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
1269       }\r
1270       goto Done;     \r
1271     }\r
1272     //\r
1273     // If the variable is marked valid and the same data has been passed in\r
1274     // then return to the caller immediately.\r
1275     //\r
1276     if (DataSizeOfVariable (Variable.CurrPtr) == DataSize &&\r
1277         (CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize) == 0)) {\r
1278       \r
1279       UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
1280       Status = EFI_SUCCESS;\r
1281       goto Done;\r
1282     } else if ((Variable.CurrPtr->State == VAR_ADDED) ||\r
1283                (Variable.CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {\r
1284       //\r
1285       // Mark the old variable as in delete transition\r
1286       //\r
1287       State = Variable.CurrPtr->State;\r
1288       State &= VAR_IN_DELETED_TRANSITION;\r
1289 \r
1290       Status = UpdateVariableStore (\r
1291                  &mVariableModuleGlobal->VariableGlobal,\r
1292                  Variable.Volatile,\r
1293                  FALSE,\r
1294                  Instance,\r
1295                  (UINTN) &Variable.CurrPtr->State,\r
1296                  sizeof (UINT8),\r
1297                  &State\r
1298                  );      \r
1299       if (EFI_ERROR (Status)) {\r
1300         goto Done;  \r
1301       } \r
1302     }    \r
1303   } else if (Status == EFI_NOT_FOUND) {\r
1304     //\r
1305     // Create a new variable\r
1306     //  \r
1307     \r
1308     //\r
1309     // Make sure we are trying to create a new variable.\r
1310     // Setting a data variable with no access, or zero DataSize attributes means to delete it.    \r
1311     //\r
1312     if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {\r
1313       Status = EFI_NOT_FOUND;\r
1314       goto Done;\r
1315     }\r
1316         \r
1317     //\r
1318     // Only variable have NV|RT attribute can be created in Runtime\r
1319     //\r
1320     if (EfiAtRuntime () &&\r
1321         (!(Attributes & EFI_VARIABLE_RUNTIME_ACCESS) || !(Attributes & EFI_VARIABLE_NON_VOLATILE))) {\r
1322       Status = EFI_INVALID_PARAMETER;\r
1323       goto Done;\r
1324     }         \r
1325   } else {\r
1326     //\r
1327     // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable().\r
1328     //\r
1329     ASSERT (Status == EFI_INVALID_PARAMETER);\r
1330     goto Done;\r
1331   }\r
1332 \r
1333   //\r
1334   // Function part - create a new variable and copy the data.\r
1335   // Both update a variable and create a variable will come here.\r
1336   //\r
1337   // Tricky part: Use scratch data area at the end of volatile variable store\r
1338   // as a temporary storage.\r
1339   //\r
1340   NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));\r
1341 \r
1342   SetMem (NextVariable, SCRATCH_SIZE, 0xff);\r
1343 \r
1344   NextVariable->StartId     = VARIABLE_DATA;\r
1345   NextVariable->Attributes  = Attributes;\r
1346   //\r
1347   // NextVariable->State = VAR_ADDED;\r
1348   //\r
1349   NextVariable->Reserved  = 0;\r
1350   VarNameOffset           = sizeof (VARIABLE_HEADER);\r
1351   VarNameSize             = StrSize (VariableName);\r
1352   CopyMem (\r
1353     (UINT8 *) ((UINTN) NextVariable + VarNameOffset),\r
1354     VariableName,\r
1355     VarNameSize\r
1356     );\r
1357   VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);\r
1358   CopyMem (\r
1359     (UINT8 *) ((UINTN) NextVariable + VarDataOffset),\r
1360     Data,\r
1361     DataSize\r
1362     );\r
1363   CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));\r
1364   //\r
1365   // There will be pad bytes after Data, the NextVariable->NameSize and\r
1366   // NextVariable->DataSize should not include pad size so that variable\r
1367   // service can get actual size in GetVariable\r
1368   //\r
1369   NextVariable->NameSize  = (UINT32)VarNameSize;\r
1370   NextVariable->DataSize  = (UINT32)DataSize;\r
1371 \r
1372   //\r
1373   // The actual size of the variable that stores in storage should\r
1374   // include pad size.\r
1375   //\r
1376   VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);\r
1377   if (Attributes & EFI_VARIABLE_NON_VOLATILE) {\r
1378     //\r
1379     // Create a nonvolatile variable\r
1380     //\r
1381     Volatile = FALSE;\r
1382     \r
1383     if ((UINT32) (VarSize +*NonVolatileOffset) >\r
1384           ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size\r
1385           ) {\r
1386       if (EfiAtRuntime ()) {\r
1387         Status = EFI_OUT_OF_RESOURCES;\r
1388         goto Done;\r
1389       }\r
1390       //\r
1391       // Perform garbage collection & reclaim operation\r
1392       //\r
1393       Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, NonVolatileOffset, FALSE);\r
1394       if (EFI_ERROR (Status)) {\r
1395         goto Done;\r
1396       }\r
1397       //\r
1398       // If still no enough space, return out of resources\r
1399       //\r
1400       if ((UINT32) (VarSize +*NonVolatileOffset) >\r
1401             ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size\r
1402             ) {\r
1403         Status = EFI_OUT_OF_RESOURCES;\r
1404         goto Done;\r
1405       }\r
1406       \r
1407       Reclaimed = TRUE;\r
1408     }\r
1409     //\r
1410     // Three steps\r
1411     // 1. Write variable header\r
1412     // 2. Set variable state to header valid  \r
1413     // 3. Write variable data\r
1414     // 4. Set variable state to valid\r
1415     //\r
1416     //\r
1417     // Step 1:\r
1418     //\r
1419     Status = UpdateVariableStore (\r
1420                &mVariableModuleGlobal->VariableGlobal,\r
1421                FALSE,\r
1422                TRUE,\r
1423                Instance,\r
1424                *NonVolatileOffset,\r
1425                sizeof (VARIABLE_HEADER),\r
1426                (UINT8 *) NextVariable\r
1427                );\r
1428 \r
1429     if (EFI_ERROR (Status)) {\r
1430       goto Done;\r
1431     }\r
1432 \r
1433     //\r
1434     // Step 2:\r
1435     //\r
1436     NextVariable->State = VAR_HEADER_VALID_ONLY;\r
1437     Status = UpdateVariableStore (\r
1438                &mVariableModuleGlobal->VariableGlobal,\r
1439                FALSE,\r
1440                TRUE,\r
1441                Instance,\r
1442                *NonVolatileOffset,\r
1443                sizeof (VARIABLE_HEADER),\r
1444                (UINT8 *) NextVariable\r
1445                );\r
1446 \r
1447     if (EFI_ERROR (Status)) {\r
1448       goto Done;\r
1449     }\r
1450     //\r
1451     // Step 3:\r
1452     //\r
1453     Status = UpdateVariableStore (\r
1454                &mVariableModuleGlobal->VariableGlobal,\r
1455                FALSE,\r
1456                TRUE,\r
1457                Instance,\r
1458                *NonVolatileOffset + sizeof (VARIABLE_HEADER),\r
1459                (UINT32) VarSize - sizeof (VARIABLE_HEADER),\r
1460                (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)\r
1461                );\r
1462 \r
1463     if (EFI_ERROR (Status)) {\r
1464       goto Done;\r
1465     }\r
1466     //\r
1467     // Step 4:\r
1468     //\r
1469     NextVariable->State = VAR_ADDED;\r
1470     Status = UpdateVariableStore (\r
1471                &mVariableModuleGlobal->VariableGlobal,\r
1472                FALSE,\r
1473                TRUE,\r
1474                Instance,\r
1475                *NonVolatileOffset,\r
1476                sizeof (VARIABLE_HEADER),\r
1477                (UINT8 *) NextVariable\r
1478                );\r
1479 \r
1480     if (EFI_ERROR (Status)) {\r
1481       goto Done;\r
1482     }\r
1483 \r
1484     *NonVolatileOffset = HEADER_ALIGN (*NonVolatileOffset + VarSize);\r
1485 \r
1486   } else {\r
1487     //\r
1488     // Create a volatile variable\r
1489     //      \r
1490     Volatile = TRUE;\r
1491 \r
1492     if ((UINT32) (VarSize +*VolatileOffset) >\r
1493         ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) {\r
1494       //\r
1495       // Perform garbage collection & reclaim operation\r
1496       //\r
1497       Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase, VolatileOffset, TRUE);\r
1498       if (EFI_ERROR (Status)) {\r
1499         goto Done;\r
1500       }\r
1501       //\r
1502       // If still no enough space, return out of resources\r
1503       //\r
1504       if ((UINT32) (VarSize +*VolatileOffset) >\r
1505             ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size\r
1506             ) {\r
1507         Status = EFI_OUT_OF_RESOURCES;\r
1508         goto Done;\r
1509       }\r
1510       \r
1511       Reclaimed = TRUE;\r
1512     }\r
1513 \r
1514     NextVariable->State = VAR_ADDED;\r
1515     Status = UpdateVariableStore (\r
1516                &mVariableModuleGlobal->VariableGlobal,\r
1517                TRUE,\r
1518                TRUE,\r
1519                Instance,\r
1520                *VolatileOffset,\r
1521                (UINT32) VarSize,\r
1522                (UINT8 *) NextVariable\r
1523                );\r
1524 \r
1525     if (EFI_ERROR (Status)) {\r
1526       goto Done;\r
1527     }\r
1528 \r
1529     *VolatileOffset = HEADER_ALIGN (*VolatileOffset + VarSize);\r
1530   }\r
1531   //\r
1532   // Mark the old variable as deleted\r
1533   //\r
1534   if (!Reclaimed && !EFI_ERROR (Status) && Variable.CurrPtr != NULL) {\r
1535     State = Variable.CurrPtr->State;\r
1536     State &= VAR_DELETED;\r
1537 \r
1538     Status = UpdateVariableStore (\r
1539                &mVariableModuleGlobal->VariableGlobal,\r
1540                Variable.Volatile,\r
1541                FALSE,\r
1542                Instance,\r
1543                (UINTN) &Variable.CurrPtr->State,\r
1544                sizeof (UINT8),\r
1545                &State\r
1546                );\r
1547     \r
1548     if (!EFI_ERROR (Status)) {\r
1549       UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
1550       UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
1551     }\r
1552     goto Done;      \r
1553   }\r
1554 \r
1555   Status = EFI_SUCCESS;\r
1556   UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
1557   UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
1558 \r
1559 Done:\r
1560   InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);\r
1561   ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
1562 \r
1563   return Status;\r
1564 }\r
1565 \r
1566 \r
1567 /*++\r
1568 \r
1569 Routine Description:\r
1570 \r
1571   This code returns information about the EFI variables.\r
1572 \r
1573 Arguments:\r
1574 \r
1575   Attributes                      Attributes bitmask to specify the type of variables\r
1576                                   on which to return information.\r
1577   MaximumVariableStorageSize      Pointer to the maximum size of the storage space available\r
1578                                   for the EFI variables associated with the attributes specified.\r
1579   RemainingVariableStorageSize    Pointer to the remaining size of the storage space available\r
1580                                   for EFI variables associated with the attributes specified.\r
1581   MaximumVariableSize             Pointer to the maximum size of an individual EFI variables\r
1582                                   associated with the attributes specified.\r
1583   Global                          Pointer to VARIABLE_GLOBAL structure.\r
1584   Instance                        Instance of the Firmware Volume.\r
1585 \r
1586 Returns:\r
1587 \r
1588   EFI STATUS\r
1589   EFI_INVALID_PARAMETER           - An invalid combination of attribute bits was supplied.\r
1590   EFI_SUCCESS                     - Query successfully.\r
1591   EFI_UNSUPPORTED                 - The attribute is not supported on this platform.\r
1592 \r
1593 --*/\r
1594 EFI_STATUS\r
1595 EFIAPI\r
1596 RuntimeServiceQueryVariableInfo (\r
1597   IN  UINT32                 Attributes,\r
1598   OUT UINT64                 *MaximumVariableStorageSize,\r
1599   OUT UINT64                 *RemainingVariableStorageSize,\r
1600   OUT UINT64                 *MaximumVariableSize\r
1601   )\r
1602 {\r
1603   VARIABLE_HEADER        *Variable;\r
1604   VARIABLE_HEADER        *NextVariable;\r
1605   UINT64                 VariableSize;\r
1606   VARIABLE_STORE_HEADER  *VariableStoreHeader;\r
1607 \r
1608   if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
1609     return EFI_INVALID_PARAMETER;\r
1610   }\r
1611   \r
1612   if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {\r
1613     //\r
1614     // Make sure the Attributes combination is supported by the platform.\r
1615     //\r
1616     return EFI_UNSUPPORTED;  \r
1617   } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
1618     //\r
1619     // Make sure if runtime bit is set, boot service bit is set also.\r
1620     //\r
1621     return EFI_INVALID_PARAMETER;\r
1622   } else if (EfiAtRuntime () && !(Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {\r
1623     //\r
1624     // Make sure RT Attribute is set if we are in Runtime phase.\r
1625     //\r
1626     return EFI_INVALID_PARAMETER;\r
1627   }\r
1628 \r
1629   AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
1630 \r
1631   if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
1632     //\r
1633     // Query is Volatile related.\r
1634     //\r
1635     VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
1636   } else {\r
1637     //\r
1638     // Query is Non-Volatile related.\r
1639     //\r
1640     VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
1641   }\r
1642 \r
1643   //\r
1644   // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize\r
1645   // with the storage size (excluding the storage header size).\r
1646   //\r
1647   *MaximumVariableStorageSize   = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
1648   *RemainingVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
1649 \r
1650   //\r
1651   // Let *MaximumVariableSize be MAX_VARIABLE_SIZE with the exception of the variable header size.\r
1652   //\r
1653   *MaximumVariableSize = MAX_VARIABLE_SIZE - sizeof (VARIABLE_HEADER);\r
1654 \r
1655   //\r
1656   // Harware error record variable needs larger size.\r
1657   //\r
1658   if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
1659     *MaximumVariableSize = MAX_HARDWARE_ERROR_VARIABLE_SIZE - sizeof (VARIABLE_HEADER);\r
1660   }\r
1661 \r
1662   //\r
1663   // Point to the starting address of the variables.\r
1664   //\r
1665   Variable = GetStartPointer (VariableStoreHeader);\r
1666 \r
1667   //\r
1668   // Now walk through the related variable store.\r
1669   //\r
1670   while (IsValidVariableHeader (Variable) && (Variable < GetEndPointer (VariableStoreHeader))) {\r
1671     NextVariable = GetNextVariablePtr (Variable);\r
1672     VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;\r
1673 \r
1674     if (EfiAtRuntime ()) {\r
1675       //\r
1676       // we don't take the state of the variables in mind\r
1677       // when calculating RemainingVariableStorageSize,\r
1678       // since the space occupied by variables not marked with\r
1679       // VAR_ADDED is not allowed to be reclaimed in Runtime.\r
1680       //\r
1681       *RemainingVariableStorageSize -= VariableSize;\r
1682     } else {\r
1683       //\r
1684       // Only care about Variables with State VAR_ADDED,because\r
1685       // the space not marked as VAR_ADDED is reclaimable now.\r
1686       //\r
1687       if (Variable->State == VAR_ADDED) {\r
1688         *RemainingVariableStorageSize -= VariableSize;\r
1689       }\r
1690     }\r
1691 \r
1692     //\r
1693     // Go to the next one\r
1694     //\r
1695     Variable = NextVariable;\r
1696   }\r
1697 \r
1698   if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {\r
1699     *MaximumVariableSize = 0;\r
1700   } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {\r
1701     *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);\r
1702   }\r
1703 \r
1704   ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
1705   return EFI_SUCCESS;\r
1706 }\r
1707 \r
1708 EFI_STATUS\r
1709 VariableCommonInitialize (\r
1710   IN EFI_HANDLE         ImageHandle,\r
1711   IN EFI_SYSTEM_TABLE   *SystemTable\r
1712   )\r
1713 /*++\r
1714 \r
1715 Routine Description:\r
1716   This function does common initialization for variable services\r
1717 \r
1718 Arguments:\r
1719 \r
1720   ImageHandle   - The firmware allocated handle for the EFI image.\r
1721   SystemTable   - A pointer to the EFI System Table.\r
1722 \r
1723 Returns:\r
1724 \r
1725   Status code.\r
1726 \r
1727   EFI_NOT_FOUND     - Variable store area not found.\r
1728   EFI_UNSUPPORTED   - Currently only one non-volatile variable store is supported.\r
1729   EFI_SUCCESS       - Variable services successfully initialized.\r
1730 \r
1731 --*/\r
1732 {\r
1733   EFI_STATUS                      Status;\r
1734   EFI_FIRMWARE_VOLUME_HEADER      *FwVolHeader;\r
1735   CHAR8                           *CurrPtr;\r
1736   VARIABLE_STORE_HEADER           *VolatileVariableStore;\r
1737   VARIABLE_STORE_HEADER           *VariableStoreHeader;\r
1738   VARIABLE_HEADER                 *NextVariable;\r
1739   UINT32                          Instance;\r
1740   EFI_PHYSICAL_ADDRESS            FvVolHdr;\r
1741   UINT64                          TempVariableStoreHeader;\r
1742   EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
1743   UINT64                          BaseAddress;\r
1744   UINT64                          Length;\r
1745   UINTN                           Index;\r
1746   UINT8                           Data;\r
1747   UINT64                          VariableStoreBase;\r
1748   UINT64                          VariableStoreLength;\r
1749 \r
1750 \r
1751   EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);\r
1752   mVariableModuleGlobal->VariableGlobal.ReentrantState = 0;\r
1753 \r
1754   //\r
1755   // Allocate memory for volatile variable store\r
1756   //\r
1757   VolatileVariableStore = AllocateRuntimePool (VARIABLE_STORE_SIZE + SCRATCH_SIZE);\r
1758   if (VolatileVariableStore == NULL) {\r
1759     FreePool (mVariableModuleGlobal);\r
1760     return EFI_OUT_OF_RESOURCES;\r
1761   }\r
1762 \r
1763   SetMem (VolatileVariableStore, VARIABLE_STORE_SIZE + SCRATCH_SIZE, 0xff);\r
1764 \r
1765   //\r
1766   //  Variable Specific Data\r
1767   //\r
1768   mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
1769   mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;\r
1770 \r
1771   VolatileVariableStore->Signature                  = VARIABLE_STORE_SIGNATURE;\r
1772   VolatileVariableStore->Size                       = VARIABLE_STORE_SIZE;\r
1773   VolatileVariableStore->Format                     = VARIABLE_STORE_FORMATTED;\r
1774   VolatileVariableStore->State                      = VARIABLE_STORE_HEALTHY;\r
1775   VolatileVariableStore->Reserved                   = 0;\r
1776   VolatileVariableStore->Reserved1                  = 0;\r
1777 \r
1778   //\r
1779   // Get non volatile varaible store\r
1780   //\r
1781 \r
1782   TempVariableStoreHeader = (UINT64) PcdGet32 (PcdFlashNvStorageVariableBase);\r
1783   VariableStoreBase = TempVariableStoreHeader + \\r
1784                               (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);\r
1785   VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \\r
1786                                 (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);\r
1787   //\r
1788   // Mark the variable storage region of the FLASH as RUNTIME\r
1789   //\r
1790   BaseAddress = VariableStoreBase & (~EFI_PAGE_MASK);\r
1791   Length      = VariableStoreLength + (VariableStoreBase - BaseAddress);\r
1792   Length      = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);\r
1793 \r
1794   Status      = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);\r
1795   if (EFI_ERROR (Status)) {\r
1796     FreePool (mVariableModuleGlobal);\r
1797     FreePool (VolatileVariableStore);\r
1798     return EFI_UNSUPPORTED;\r
1799   }\r
1800 \r
1801   Status = gDS->SetMemorySpaceAttributes (\r
1802                   BaseAddress,\r
1803                   Length,\r
1804                   GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME\r
1805                   );\r
1806   if (EFI_ERROR (Status)) {\r
1807     FreePool (mVariableModuleGlobal);\r
1808     FreePool (VolatileVariableStore);\r
1809     return EFI_UNSUPPORTED;\r
1810   }\r
1811   //\r
1812   // Get address of non volatile variable store base\r
1813   //\r
1814   mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
1815 \r
1816   //\r
1817   // Check Integrity\r
1818   //\r
1819   //\r
1820   // Find the Correct Instance of the FV Block Service.\r
1821   //\r
1822   Instance  = 0;\r
1823   CurrPtr   = (CHAR8 *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
1824   while (EfiFvbGetPhysicalAddress (Instance, &FvVolHdr) == EFI_SUCCESS) {\r
1825     FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);\r
1826     if (CurrPtr >= (CHAR8 *) FwVolHeader && CurrPtr < (((CHAR8 *) FwVolHeader) + FwVolHeader->FvLength)) {\r
1827       mVariableModuleGlobal->FvbInstance = Instance;\r
1828       break;\r
1829     }\r
1830 \r
1831     Instance++;\r
1832   }\r
1833 \r
1834   VariableStoreHeader = (VARIABLE_STORE_HEADER *) CurrPtr;\r
1835   if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
1836     if (~VariableStoreHeader->Size == 0) {\r
1837       Status = UpdateVariableStore (\r
1838                 &mVariableModuleGlobal->VariableGlobal,\r
1839                 FALSE,\r
1840                 FALSE,\r
1841                 mVariableModuleGlobal->FvbInstance,\r
1842                 (UINTN) &VariableStoreHeader->Size,\r
1843                 sizeof (UINT32),\r
1844                 (UINT8 *) &VariableStoreLength\r
1845                 );\r
1846       //\r
1847       // As Variables are stored in NV storage, which are slow devices,such as flash.\r
1848       // Variable operation may skip checking variable program result to improve performance,\r
1849       // We can assume Variable program is OK through some check point.\r
1850       // Variable Store Size Setting should be the first Variable write operation,\r
1851       // We can assume all Read/Write is OK if we can set Variable store size successfully.\r
1852       // If write fail, we will assert here\r
1853       //\r
1854       ASSERT(VariableStoreHeader->Size == VariableStoreLength);\r
1855 \r
1856       if (EFI_ERROR (Status)) {\r
1857         return Status;\r
1858       }\r
1859     }\r
1860 \r
1861     mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) CurrPtr);\r
1862     //\r
1863     // Parse non-volatile variable data and get last variable offset\r
1864     //\r
1865     NextVariable  = GetStartPointer ((VARIABLE_STORE_HEADER *) CurrPtr);\r
1866     Status        = EFI_SUCCESS;\r
1867 \r
1868     while (IsValidVariableHeader (NextVariable)) {\r
1869       NextVariable = GetNextVariablePtr (NextVariable);\r
1870     }\r
1871 \r
1872     mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) CurrPtr;\r
1873 \r
1874     //\r
1875     // Check if the free area is blow a threshold\r
1876     //\r
1877     if ((((VARIABLE_STORE_HEADER *)((UINTN) CurrPtr))->Size - mVariableModuleGlobal->NonVolatileLastVariableOffset) < VARIABLE_RECLAIM_THRESHOLD) {\r
1878       Status = Reclaim (\r
1879                 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
1880                 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
1881                 FALSE\r
1882                 );\r
1883     }\r
1884 \r
1885     if (EFI_ERROR (Status)) {\r
1886       FreePool (mVariableModuleGlobal);\r
1887       FreePool (VolatileVariableStore);\r
1888       return Status;\r
1889     }\r
1890 \r
1891     //\r
1892     // Check if the free area is really free.\r
1893     //\r
1894     for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {\r
1895       Data = ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)[Index];\r
1896       if (Data != 0xff) {\r
1897         //\r
1898         // There must be something wrong in variable store, do reclaim operation.\r
1899         //\r
1900         Status = Reclaim (\r
1901                   mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
1902                   &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
1903                   FALSE\r
1904                   );\r
1905         break;\r
1906       }\r
1907     }\r
1908   }\r
1909 \r
1910   if (EFI_ERROR (Status)) {\r
1911     FreePool (mVariableModuleGlobal);\r
1912     FreePool (VolatileVariableStore);\r
1913   }\r
1914 \r
1915   return Status;\r
1916 }\r
1917 \r
1918 \r
1919 \r
1920 \r
1921 VOID\r
1922 EFIAPI\r
1923 VariableClassAddressChangeEvent (\r
1924   IN EFI_EVENT        Event,\r
1925   IN VOID             *Context\r
1926   )\r
1927 {\r
1928   EfiConvertPointer (\r
1929     0x0,\r
1930     (VOID **) &mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase\r
1931     );\r
1932   EfiConvertPointer (\r
1933     0x0,\r
1934     (VOID **) &mVariableModuleGlobal->VariableGlobal.VolatileVariableBase\r
1935     );\r
1936   EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal);\r
1937 }\r
1938 \r
1939 \r
1940 /**\r
1941   Variable Driver main entry point. The Variable driver places the 4 EFI\r
1942   runtime services in the EFI System Table and installs arch protocols \r
1943   for variable read and write services being availible. \r
1944 \r
1945   @param[in] ImageHandle    The firmware allocated handle for the EFI image.  \r
1946   @param[in] SystemTable    A pointer to the EFI System Table.\r
1947   \r
1948   @retval EFI_SUCCESS       The entry point is executed successfully.\r
1949   @retval other             Some error occurs when executing this entry point.\r
1950 \r
1951 **/\r
1952 EFI_STATUS\r
1953 EFIAPI\r
1954 VariableServiceInitialize (\r
1955   IN EFI_HANDLE         ImageHandle,\r
1956   IN EFI_SYSTEM_TABLE   *SystemTable\r
1957   )\r
1958 {\r
1959   EFI_STATUS  Status;\r
1960 \r
1961   Status = VariableCommonInitialize (ImageHandle, SystemTable);\r
1962   ASSERT_EFI_ERROR (Status);\r
1963 \r
1964   SystemTable->RuntimeServices->GetVariable         = RuntimeServiceGetVariable;\r
1965   SystemTable->RuntimeServices->GetNextVariableName = RuntimeServiceGetNextVariableName;\r
1966   SystemTable->RuntimeServices->SetVariable         = RuntimeServiceSetVariable;\r
1967   SystemTable->RuntimeServices->QueryVariableInfo   = RuntimeServiceQueryVariableInfo;\r
1968 \r
1969   //\r
1970   // Now install the Variable Runtime Architectural Protocol on a new handle\r
1971   //\r
1972   Status = gBS->InstallMultipleProtocolInterfaces (\r
1973                   &mHandle,\r
1974                   &gEfiVariableArchProtocolGuid,        NULL,\r
1975                   &gEfiVariableWriteArchProtocolGuid,   NULL,\r
1976                   NULL\r
1977                   );\r
1978   ASSERT_EFI_ERROR (Status);\r
1979 \r
1980   Status = gBS->CreateEvent (\r
1981                   EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,\r
1982                   TPL_NOTIFY,\r
1983                   VariableClassAddressChangeEvent,\r
1984                   NULL,\r
1985                   &mVirtualAddressChangeEvent\r
1986                   );\r
1987   ASSERT_EFI_ERROR (Status);\r
1988 \r
1989   return EFI_SUCCESS;\r
1990 }\r
1991 \r