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