1. Uefi2.1 feature - Add Hardware Error Record Persistence Support
[people/mcb30/edk2.git] / edk2 / MdeModulePkg / Universal / Variable / EmuRuntimeDxe / EmuVariable.c
1 /*++\r
2 \r
3 Copyright (c) 2006 - 2007, Intel Corporation\r
4 All rights reserved. This program and the accompanying materials\r
5 are licensed and made available under the terms and conditions of the BSD License\r
6 which accompanies this distribution.  The full text of the license may be found at\r
7 http://opensource.org/licenses/bsd-license.php\r
8 \r
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11 \r
12 Module Name:\r
13 \r
14     EmuVariable.c\r
15 \r
16 Abstract:\r
17 \r
18 Revision History\r
19 \r
20 --*/\r
21 \r
22 #include "Variable.h"\r
23 \r
24 //\r
25 // Don't use module globals after the SetVirtualAddress map is signaled\r
26 //\r
27 ESAL_VARIABLE_GLOBAL  *mVariableModuleGlobal;\r
28 \r
29 //\r
30 // This is a temperary function which will be removed\r
31 // when EfiAcquireLock in UefiLib can handle the\r
32 // the call in UEFI Runtimer driver in RT phase.\r
33 //\r
34 STATIC\r
35 VOID\r
36 AcquireLockOnlyAtBootTime (\r
37   IN EFI_LOCK  *Lock\r
38   )\r
39 {\r
40   if (!EfiAtRuntime ()) {\r
41     EfiAcquireLock (Lock);\r
42   }\r
43 }\r
44 \r
45 //\r
46 // This is a temperary function which will be removed\r
47 // when EfiAcquireLock in UefiLib can handle the\r
48 // the call in UEFI Runtimer driver in RT phase.\r
49 //\r
50 STATIC\r
51 VOID\r
52 ReleaseLockOnlyAtBootTime (\r
53   IN EFI_LOCK  *Lock\r
54   )\r
55 {\r
56   if (!EfiAtRuntime ()) {\r
57     EfiReleaseLock (Lock);\r
58   }\r
59 }\r
60 \r
61 STATIC\r
62 UINT8 *\r
63 GetVariableDataPtr (\r
64   IN  VARIABLE_HEADER   *Variable\r
65   )\r
66 /*++\r
67 \r
68 Routine Description:\r
69 \r
70   This code gets the pointer to the variable data.\r
71 \r
72 Arguments:\r
73 \r
74   Variable            Pointer to the Variable Header.\r
75 \r
76 Returns:\r
77 \r
78   UINT8*              Pointer to Variable Data\r
79 \r
80 --*/\r
81 {\r
82   if (Variable->StartId != VARIABLE_DATA) {\r
83     return NULL;\r
84   }\r
85   //\r
86   // Be careful about pad size for alignment\r
87   //\r
88   return (UINT8 *) ((UINTN) GET_VARIABLE_NAME_PTR (Variable) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize));\r
89 }\r
90 \r
91 STATIC\r
92 VARIABLE_HEADER *\r
93 GetNextVariablePtr (\r
94   IN  VARIABLE_HEADER   *Variable\r
95   )\r
96 /*++\r
97 \r
98 Routine Description:\r
99 \r
100   This code gets the pointer to the next variable header.\r
101 \r
102 Arguments:\r
103 \r
104   Variable                  Pointer to the Variable Header.\r
105 \r
106 Returns:\r
107 \r
108   VARIABLE_HEADER*      Pointer to next variable header.\r
109 \r
110 --*/\r
111 {\r
112   VARIABLE_HEADER *VarHeader;\r
113 \r
114   if (Variable->StartId != VARIABLE_DATA) {\r
115     return NULL;\r
116   }\r
117   //\r
118   // Be careful about pad size for alignment\r
119   //\r
120   VarHeader = (VARIABLE_HEADER *) (GetVariableDataPtr (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize));\r
121 \r
122   if (VarHeader->StartId != VARIABLE_DATA ||\r
123       (sizeof (VARIABLE_HEADER) + VarHeader->DataSize + VarHeader->NameSize) > MAX_VARIABLE_SIZE\r
124       ) {\r
125     return NULL;\r
126   }\r
127 \r
128   return VarHeader;\r
129 }\r
130 \r
131 STATIC\r
132 VARIABLE_HEADER *\r
133 GetEndPointer (\r
134   IN VARIABLE_STORE_HEADER       *VolHeader\r
135   )\r
136 /*++\r
137 \r
138 Routine Description:\r
139 \r
140   This code gets the pointer to the last variable memory pointer byte\r
141 \r
142 Arguments:\r
143 \r
144   Variable                  Pointer to the Variable Header.\r
145 \r
146 Returns:\r
147 \r
148   VARIABLE_HEADER*      Pointer to last unavailable Variable Header\r
149 \r
150 --*/\r
151 {\r
152   //\r
153   // The end of variable store\r
154   //\r
155   return (VARIABLE_HEADER *) ((UINTN) VolHeader + VolHeader->Size);\r
156 }\r
157 \r
158 STATIC\r
159 EFI_STATUS\r
160 FindVariable (\r
161   IN  CHAR16                  *VariableName,\r
162   IN  EFI_GUID                *VendorGuid,\r
163   OUT VARIABLE_POINTER_TRACK  *PtrTrack,\r
164   IN  VARIABLE_GLOBAL         *Global\r
165   )\r
166 /*++\r
167 \r
168 Routine Description:\r
169 \r
170   This code finds variable in storage blocks (Volatile or Non-Volatile)\r
171 \r
172 Arguments:\r
173 \r
174   VariableName                Name of the variable to be found\r
175   VendorGuid                  Vendor GUID to be found.\r
176   PtrTrack                    Variable Track Pointer structure that contains\r
177                               Variable Information.\r
178                               Contains the pointer of Variable header.\r
179   Global                      VARIABLE_GLOBAL pointer\r
180 \r
181 Returns:\r
182 \r
183   EFI STATUS\r
184 \r
185 --*/\r
186 {\r
187   VARIABLE_HEADER       *Variable[2];\r
188   VARIABLE_STORE_HEADER *VariableStoreHeader[2];\r
189   UINTN                 Index;\r
190 \r
191   //\r
192   // We aquire the lock at the entry of FindVariable as GetVariable, GetNextVariableName\r
193   // SetVariable all call FindVariable at entry point. Please move "Aquire Lock" to\r
194   // the correct places if this assumption does not hold TRUE anymore.\r
195   //\r
196   AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);\r
197 \r
198   //\r
199   // 0: Non-Volatile, 1: Volatile\r
200   //\r
201   VariableStoreHeader[0]  = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase);\r
202   VariableStoreHeader[1]  = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);\r
203 \r
204   //\r
205   // Start Pointers for the variable.\r
206   // Actual Data Pointer where data can be written.\r
207   //\r
208   Variable[0] = (VARIABLE_HEADER *) (VariableStoreHeader[0] + 1);\r
209   Variable[1] = (VARIABLE_HEADER *) (VariableStoreHeader[1] + 1);\r
210 \r
211   if (VariableName[0] != 0 && VendorGuid == NULL) {\r
212     return EFI_INVALID_PARAMETER;\r
213   }\r
214   //\r
215   // Find the variable by walk through non-volatile and volatile variable store\r
216   //\r
217   for (Index = 0; Index < 2; Index++) {\r
218     PtrTrack->StartPtr  = (VARIABLE_HEADER *) (VariableStoreHeader[Index] + 1);\r
219     PtrTrack->EndPtr    = GetEndPointer (VariableStoreHeader[Index]);\r
220 \r
221     while ((Variable[Index] != NULL) && (Variable[Index] <= GetEndPointer (VariableStoreHeader[Index]))) {\r
222       if (Variable[Index]->StartId == VARIABLE_DATA && Variable[Index]->State == VAR_ADDED) {\r
223         if (!(EfiAtRuntime () && !(Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS))) {\r
224           if (VariableName[0] == 0) {\r
225             PtrTrack->CurrPtr   = Variable[Index];\r
226             PtrTrack->Volatile  = (BOOLEAN) Index;\r
227             return EFI_SUCCESS;\r
228           } else {\r
229             if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) {\r
230               if (!CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable[Index]), Variable[Index]->NameSize)) {\r
231                 PtrTrack->CurrPtr   = Variable[Index];\r
232                 PtrTrack->Volatile  = (BOOLEAN) Index;\r
233                 return EFI_SUCCESS;\r
234               }\r
235             }\r
236           }\r
237         }\r
238       }\r
239 \r
240       Variable[Index] = GetNextVariablePtr (Variable[Index]);\r
241     }\r
242   }\r
243   PtrTrack->CurrPtr = NULL;\r
244   return EFI_NOT_FOUND;\r
245 }\r
246 \r
247 EFI_STATUS\r
248 EFIAPI\r
249 GetVariable (\r
250   IN      CHAR16            *VariableName,\r
251   IN      EFI_GUID          * VendorGuid,\r
252   OUT     UINT32            *Attributes OPTIONAL,\r
253   IN OUT  UINTN             *DataSize,\r
254   OUT     VOID              *Data,\r
255   IN      VARIABLE_GLOBAL   * Global,\r
256   IN      UINT32            Instance\r
257   )\r
258 /*++\r
259 \r
260 Routine Description:\r
261 \r
262   This code finds variable in storage blocks (Volatile or Non-Volatile)\r
263 \r
264 Arguments:\r
265 \r
266   VariableName                    Name of Variable to be found\r
267   VendorGuid                      Variable vendor GUID\r
268   Attributes OPTIONAL             Attribute value of the variable found\r
269   DataSize                        Size of Data found. If size is less than the\r
270                                   data, this value contains the required size.\r
271   Data                            Data pointer\r
272   Global                          Pointer to VARIABLE_GLOBAL structure\r
273   Instance                        Instance of the Firmware Volume.\r
274 \r
275 Returns:\r
276 \r
277   EFI_INVALID_PARAMETER       - Invalid parameter\r
278   EFI_SUCCESS                 - Find the specified variable\r
279   EFI_NOT_FOUND               - Not found\r
280   EFI_BUFFER_TO_SMALL         - DataSize is too small for the result\r
281 \r
282 \r
283 --*/\r
284 {\r
285   VARIABLE_POINTER_TRACK  Variable;\r
286   UINTN                   VarDataSize;\r
287   EFI_STATUS              Status;\r
288 \r
289   if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
290     return EFI_INVALID_PARAMETER;\r
291   }\r
292   //\r
293   // Find existing variable\r
294   //\r
295   Status = FindVariable (VariableName, VendorGuid, &Variable, Global);\r
296 \r
297   if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
298     goto Done;\r
299   }\r
300   //\r
301   // Get data size\r
302   //\r
303   VarDataSize = Variable.CurrPtr->DataSize;\r
304   if (*DataSize >= VarDataSize) {\r
305     if (Data == NULL) {\r
306       Status = EFI_INVALID_PARAMETER;\r
307       goto Done;\r
308     }\r
309 \r
310     CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);\r
311     if (Attributes != NULL) {\r
312       *Attributes = Variable.CurrPtr->Attributes;\r
313     }\r
314 \r
315     *DataSize = VarDataSize;\r
316     Status = EFI_SUCCESS;\r
317     goto Done;\r
318   } else {\r
319     *DataSize = VarDataSize;\r
320     Status = EFI_BUFFER_TOO_SMALL;\r
321     goto Done;\r
322   }\r
323 \r
324 Done:\r
325   ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
326   return Status;\r
327 }\r
328 \r
329 EFI_STATUS\r
330 EFIAPI\r
331 GetNextVariableName (\r
332   IN OUT  UINTN             *VariableNameSize,\r
333   IN OUT  CHAR16            *VariableName,\r
334   IN OUT  EFI_GUID          *VendorGuid,\r
335   IN      VARIABLE_GLOBAL   *Global,\r
336   IN      UINT32            Instance\r
337   )\r
338 /*++\r
339 \r
340 Routine Description:\r
341 \r
342   This code Finds the Next available variable\r
343 \r
344 Arguments:\r
345 \r
346   VariableNameSize            Size of the variable\r
347   VariableName                Pointer to variable name\r
348   VendorGuid                  Variable Vendor Guid\r
349   Global                      VARIABLE_GLOBAL structure pointer.\r
350   Instance                    FV instance\r
351 \r
352 Returns:\r
353 \r
354   EFI STATUS\r
355 \r
356 --*/\r
357 {\r
358   VARIABLE_POINTER_TRACK  Variable;\r
359   UINTN                   VarNameSize;\r
360   EFI_STATUS              Status;\r
361 \r
362   if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
363     return EFI_INVALID_PARAMETER;\r
364   }\r
365 \r
366   Status = FindVariable (VariableName, VendorGuid, &Variable, Global);\r
367 \r
368   if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
369     goto Done;\r
370   }\r
371 \r
372   while (TRUE) {\r
373     if (VariableName[0] != 0) {\r
374       //\r
375       // If variable name is not NULL, get next variable\r
376       //\r
377       Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
378     }\r
379     //\r
380     // If both volatile and non-volatile variable store are parsed,\r
381     // return not found\r
382     //\r
383     if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) {\r
384       Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));\r
385       if (Variable.Volatile) {\r
386         Variable.StartPtr = (VARIABLE_HEADER *) ((UINTN) (Global->VolatileVariableBase + sizeof (VARIABLE_STORE_HEADER)));\r
387         Variable.EndPtr = (VARIABLE_HEADER *) GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase));\r
388       } else {\r
389         Status = EFI_NOT_FOUND;\r
390         goto Done;\r
391       }\r
392 \r
393       Variable.CurrPtr = Variable.StartPtr;\r
394       if (Variable.CurrPtr->StartId != VARIABLE_DATA) {\r
395         continue;\r
396       }\r
397     }\r
398     //\r
399     // Variable is found\r
400     //\r
401     if (Variable.CurrPtr->StartId == VARIABLE_DATA && Variable.CurrPtr->State == VAR_ADDED) {\r
402       if (!(EfiAtRuntime () && !(Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS))) {\r
403         VarNameSize = Variable.CurrPtr->NameSize;\r
404         if (VarNameSize <= *VariableNameSize) {\r
405           CopyMem (\r
406             VariableName,\r
407             GET_VARIABLE_NAME_PTR (Variable.CurrPtr),\r
408             VarNameSize\r
409             );\r
410           CopyMem (\r
411             VendorGuid,\r
412             &Variable.CurrPtr->VendorGuid,\r
413             sizeof (EFI_GUID)\r
414             );\r
415           Status = EFI_SUCCESS;\r
416         } else {\r
417           Status = EFI_BUFFER_TOO_SMALL;\r
418         }\r
419 \r
420         *VariableNameSize = VarNameSize;\r
421         goto Done;\r
422       }\r
423     }\r
424   }\r
425 \r
426 Done:\r
427   ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
428   return Status;\r
429 \r
430 }\r
431 \r
432 EFI_STATUS\r
433 EFIAPI\r
434 SetVariable (\r
435   IN CHAR16                  *VariableName,\r
436   IN EFI_GUID                *VendorGuid,\r
437   IN UINT32                  Attributes,\r
438   IN UINTN                   DataSize,\r
439   IN VOID                    *Data,\r
440   IN VARIABLE_GLOBAL         *Global,\r
441   IN UINTN                   *VolatileOffset,\r
442   IN UINTN                   *NonVolatileOffset,\r
443   IN UINT32                  Instance\r
444   )\r
445 /*++\r
446 \r
447 Routine Description:\r
448 \r
449   This code sets variable in storage blocks (Volatile or Non-Volatile)\r
450 \r
451 Arguments:\r
452 \r
453   VariableName                    Name of Variable to be found\r
454   VendorGuid                      Variable vendor GUID\r
455   Attributes                      Attribute value of the variable found\r
456   DataSize                        Size of Data found. If size is less than the\r
457                                   data, this value contains the required size.\r
458   Data                            Data pointer\r
459   Global                          Pointer to VARIABLE_GLOBAL structure\r
460   VolatileOffset                  The offset of last volatile variable\r
461   NonVolatileOffset               The offset of last non-volatile variable\r
462   Instance                        Instance of the Firmware Volume.\r
463 \r
464 Returns:\r
465 \r
466   EFI_INVALID_PARAMETER           - Invalid parameter\r
467   EFI_SUCCESS                     - Set successfully\r
468   EFI_OUT_OF_RESOURCES            - Resource not enough to set variable\r
469   EFI_NOT_FOUND                   - Not found\r
470   EFI_DEVICE_ERROR                - Variable can not be saved due to hardware failure\r
471   EFI_WRITE_PROTECTED             - Variable is read-only\r
472 \r
473 --*/\r
474 {\r
475   VARIABLE_POINTER_TRACK  Variable;\r
476   EFI_STATUS              Status;\r
477   VARIABLE_HEADER         *NextVariable;\r
478   UINTN                   VarNameSize;\r
479   UINTN                   VarNameOffset;\r
480   UINTN                   VarDataOffset;\r
481   UINTN                   VarSize;\r
482 \r
483   //\r
484   // Check input parameters\r
485   //\r
486   if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
487     return EFI_INVALID_PARAMETER;\r
488   }  \r
489   //\r
490   //  Make sure if runtime bit is set, boot service bit is set also\r
491   //\r
492   if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
493     return EFI_INVALID_PARAMETER;\r
494   }\r
495   //\r
496   //  The size of the VariableName, including the Unicode Null in bytes plus\r
497   //  the DataSize is limited to maximum size of MAX_HARDWARE_ERROR_VARIABLE_SIZE (32K)\r
498   //  bytes for HwErrRec, and MAX_VARIABLE_SIZE (1024) bytes for the others.\r
499   //\r
500   if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
501     if ((DataSize > MAX_HARDWARE_ERROR_VARIABLE_SIZE) ||                                                       \r
502         (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_HARDWARE_ERROR_VARIABLE_SIZE)) {\r
503       return EFI_INVALID_PARAMETER;\r
504     }    \r
505   } else {\r
506   //\r
507   //  The size of the VariableName, including the Unicode Null in bytes plus\r
508   //  the DataSize is limited to maximum size of MAX_VARIABLE_SIZE (1024) bytes.\r
509   //\r
510     if ((DataSize > MAX_VARIABLE_SIZE) ||\r
511         (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_VARIABLE_SIZE)) {\r
512       return EFI_INVALID_PARAMETER;\r
513     }  \r
514   }  \r
515   //\r
516   // Check whether the input variable is already existed\r
517   //\r
518   \r
519   Status = FindVariable (VariableName, VendorGuid, &Variable, Global);\r
520 \r
521   if (Status == EFI_SUCCESS && Variable.CurrPtr != NULL) {\r
522     //\r
523     // Update/Delete existing variable\r
524     //\r
525 \r
526     if (EfiAtRuntime ()) {        \r
527       //\r
528       // If EfiAtRuntime and the variable is Volatile and Runtime Access,  \r
529       // the volatile is ReadOnly, and SetVariable should be aborted and \r
530       // return EFI_WRITE_PROTECTED.\r
531       //\r
532       if (Variable.Volatile) {\r
533         Status = EFI_WRITE_PROTECTED;\r
534         goto Done;\r
535       }\r
536       //\r
537       // Only variable have NV attribute can be updated/deleted in Runtime\r
538       //\r
539       if (!(Variable.CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE)) {\r
540         Status = EFI_INVALID_PARAMETER;\r
541         goto Done;\r
542       }\r
543     }\r
544 \r
545     //\r
546     // Setting a data variable with no access, or zero DataSize attributes\r
547     // specified causes it to be deleted.\r
548     //\r
549     if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {\r
550       Variable.CurrPtr->State &= VAR_DELETED;\r
551       Status = EFI_SUCCESS;\r
552       goto Done;\r
553     }\r
554 \r
555     //\r
556     // If the variable is marked valid and the same data has been passed in\r
557     // then return to the caller immediately.\r
558     //\r
559     if (Variable.CurrPtr->DataSize == DataSize &&\r
560         !CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize)\r
561           ) {\r
562       Status = EFI_SUCCESS;\r
563       goto Done;\r
564     } else if (Variable.CurrPtr->State == VAR_ADDED) {\r
565       //\r
566       // Mark the old variable as in delete transition\r
567       //\r
568       Variable.CurrPtr->State &= VAR_IN_DELETED_TRANSITION;\r
569     }\r
570     \r
571   } else if (Status == EFI_NOT_FOUND) {\r
572     //\r
573     // Create a new variable\r
574     //  \r
575     \r
576     //\r
577     // Make sure we are trying to create a new variable.\r
578     // Setting a data variable with no access, or zero DataSize attributes means to delete it.    \r
579     //\r
580     if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {\r
581       Status = EFI_NOT_FOUND;\r
582       goto Done;\r
583     }\r
584         \r
585     //\r
586     // Only variable have NV|RT attribute can be created in Runtime\r
587     //\r
588     if (EfiAtRuntime () &&\r
589         (!(Attributes & EFI_VARIABLE_RUNTIME_ACCESS) || !(Attributes & EFI_VARIABLE_NON_VOLATILE))) {\r
590       Status = EFI_INVALID_PARAMETER;\r
591       goto Done;\r
592     }         \r
593   } else {\r
594     //\r
595     // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable().\r
596     //\r
597     ASSERT (Status == EFI_INVALID_PARAMETER);\r
598     goto Done;\r
599   } \r
600   \r
601   //\r
602   // Function part - create a new variable and copy the data.\r
603   // Both update a variable and create a variable will come here.\r
604   //\r
605   \r
606   VarNameOffset = sizeof (VARIABLE_HEADER);\r
607   VarNameSize   = StrSize (VariableName);\r
608   VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);\r
609   VarSize       = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);\r
610 \r
611   if (Attributes & EFI_VARIABLE_NON_VOLATILE) {\r
612     if ((UINT32) (VarSize +*NonVolatileOffset) >\r
613           ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->NonVolatileVariableBase)))->Size\r
614           ) {\r
615       Status = EFI_OUT_OF_RESOURCES;\r
616       goto Done;\r
617     }\r
618 \r
619     NextVariable        = (VARIABLE_HEADER *) (UINT8 *) (*NonVolatileOffset + (UINTN) Global->NonVolatileVariableBase);\r
620     *NonVolatileOffset  = *NonVolatileOffset + VarSize;\r
621   } else {\r
622     if ((UINT32) (VarSize +*VolatileOffset) >\r
623           ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size\r
624           ) {\r
625       Status = EFI_OUT_OF_RESOURCES;\r
626       goto Done;\r
627     }\r
628 \r
629     NextVariable    = (VARIABLE_HEADER *) (UINT8 *) (*VolatileOffset + (UINTN) Global->VolatileVariableBase);\r
630     *VolatileOffset = *VolatileOffset + VarSize;\r
631   }\r
632 \r
633   NextVariable->StartId     = VARIABLE_DATA;\r
634   NextVariable->Attributes  = Attributes;\r
635   NextVariable->State       = VAR_ADDED;\r
636   NextVariable->Reserved    = 0;\r
637 \r
638   //\r
639   // There will be pad bytes after Data, the NextVariable->NameSize and\r
640   // NextVariable->NameSize should not include pad size so that variable\r
641   // service can get actual size in GetVariable\r
642   //\r
643   NextVariable->NameSize  = (UINT32)VarNameSize;\r
644   NextVariable->DataSize  = (UINT32)DataSize;\r
645 \r
646   CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));\r
647   CopyMem (\r
648     (UINT8 *) ((UINTN) NextVariable + VarNameOffset),\r
649     VariableName,\r
650     VarNameSize\r
651     );\r
652   CopyMem (\r
653     (UINT8 *) ((UINTN) NextVariable + VarDataOffset),\r
654     Data,\r
655     DataSize\r
656     );\r
657 \r
658   //\r
659   // Mark the old variable as deleted\r
660   //\r
661   if (!EFI_ERROR (Status)) {\r
662     Variable.CurrPtr->State &= VAR_DELETED;\r
663   }\r
664   \r
665   Status = EFI_SUCCESS;\r
666 Done:\r
667   ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
668   return Status;\r
669 }\r
670 \r
671 EFI_STATUS\r
672 EFIAPI\r
673 QueryVariableInfo (\r
674   IN  UINT32                 Attributes,\r
675   OUT UINT64                 *MaximumVariableStorageSize,\r
676   OUT UINT64                 *RemainingVariableStorageSize,\r
677   OUT UINT64                 *MaximumVariableSize,\r
678   IN  VARIABLE_GLOBAL        *Global,\r
679   IN  UINT32                 Instance\r
680   )\r
681 /*++\r
682 \r
683 Routine Description:\r
684 \r
685   This code returns information about the EFI variables.\r
686 \r
687 Arguments:\r
688 \r
689   Attributes                      Attributes bitmask to specify the type of variables\r
690                                   on which to return information.\r
691   MaximumVariableStorageSize      Pointer to the maximum size of the storage space available\r
692                                   for the EFI variables associated with the attributes specified.\r
693   RemainingVariableStorageSize    Pointer to the remaining size of the storage space available\r
694                                   for EFI variables associated with the attributes specified.\r
695   MaximumVariableSize             Pointer to the maximum size of an individual EFI variables\r
696                                   associated with the attributes specified.\r
697   Global                          Pointer to VARIABLE_GLOBAL structure.\r
698   Instance                        Instance of the Firmware Volume.\r
699 \r
700 Returns:\r
701 \r
702   EFI STATUS\r
703   EFI_INVALID_PARAMETER           - An invalid combination of attribute bits was supplied.\r
704   EFI_SUCCESS                     - Query successfully.\r
705   EFI_UNSUPPORTED                 - The attribute is not supported on this platform.\r
706 \r
707 --*/\r
708 {\r
709   VARIABLE_HEADER        *Variable;\r
710   VARIABLE_HEADER        *NextVariable;\r
711   UINT64                 VariableSize;\r
712   VARIABLE_STORE_HEADER  *VariableStoreHeader;\r
713 \r
714   if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
715     return EFI_INVALID_PARAMETER;\r
716   }\r
717   \r
718   if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {\r
719     //\r
720     // Make sure the Attributes combination is supported by the platform.\r
721     //\r
722     return EFI_UNSUPPORTED;  \r
723   } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
724     //\r
725     // Make sure if runtime bit is set, boot service bit is set also.\r
726     //\r
727     return EFI_INVALID_PARAMETER;\r
728   } else if (EfiAtRuntime () && !(Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {\r
729     //\r
730     //   Make sure RT Attribute is set if we are in Runtime phase.\r
731     //\r
732     return EFI_INVALID_PARAMETER;\r
733   } else if (EfiAtRuntime () && Attributes && !(Attributes & EFI_VARIABLE_NON_VOLATILE)) {\r
734     //\r
735     // Cannot Query volatile variable in Runtime\r
736     //\r
737     return EFI_INVALID_PARAMETER;\r
738   }\r
739 \r
740   AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);\r
741 \r
742   if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
743     //\r
744     // Query is Volatile related.\r
745     //\r
746     VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);\r
747   } else {\r
748     //\r
749     // Query is Non-Volatile related.\r
750     //\r
751     VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase);\r
752   }\r
753 \r
754   //\r
755   // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize\r
756   // with the storage size (excluding the storage header size)\r
757   //\r
758   *MaximumVariableStorageSize   = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
759   *RemainingVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
760 \r
761   //\r
762   // Let *MaximumVariableSize be MAX_VARIABLE_SIZE with the exception of the variable header size.\r
763   //\r
764   *MaximumVariableSize = MAX_VARIABLE_SIZE - sizeof (VARIABLE_HEADER);\r
765 \r
766   //\r
767   // Harware error record variable needs larger size.\r
768   //\r
769   if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
770     *MaximumVariableSize = MAX_HARDWARE_ERROR_VARIABLE_SIZE - sizeof (VARIABLE_HEADER);\r
771   }\r
772 \r
773   //\r
774   // Point to the starting address of the variables.\r
775   //\r
776   Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);\r
777 \r
778   //\r
779   // Now walk through the related variable store.\r
780   //\r
781   while (Variable < GetEndPointer (VariableStoreHeader)) {\r
782     if (Variable->StartId != VARIABLE_DATA) {\r
783       break;\r
784     }\r
785 \r
786     NextVariable = (VARIABLE_HEADER *) (GetVariableDataPtr (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize));\r
787     VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;\r
788 \r
789     if (Variable->State == VAR_ADDED) {\r
790       *RemainingVariableStorageSize -= VariableSize;\r
791     }\r
792 \r
793     //\r
794     // Go to the next one.\r
795     //\r
796     Variable = NextVariable;\r
797   }\r
798 \r
799   if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {\r
800     *MaximumVariableSize = 0;\r
801   } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {\r
802     *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);\r
803   }\r
804   \r
805   ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
806   return EFI_SUCCESS;\r
807 }\r
808 \r
809 STATIC\r
810 EFI_STATUS\r
811 InitializeVariableStore (\r
812   OUT EFI_PHYSICAL_ADDRESS  *VariableBase,\r
813   OUT UINTN                 *LastVariableOffset\r
814   )\r
815 /*++\r
816 \r
817 Routine Description:\r
818   This function initializes variable store\r
819 \r
820 Arguments:\r
821 \r
822 Returns:\r
823 \r
824 --*/\r
825 {\r
826   VARIABLE_STORE_HEADER *VariableStore;\r
827 \r
828   //\r
829   // Allocate memory for volatile variable store\r
830   //\r
831   VariableStore = (VARIABLE_STORE_HEADER *) AllocateRuntimePool (\r
832                                               VARIABLE_STORE_SIZE\r
833                                               );\r
834   if (NULL == VariableStore) {\r
835     return EFI_OUT_OF_RESOURCES;\r
836   }\r
837 \r
838   SetMem (VariableStore, VARIABLE_STORE_SIZE, 0xff);\r
839 \r
840   //\r
841   // Variable Specific Data\r
842   //\r
843   *VariableBase             = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore;\r
844   *LastVariableOffset       = sizeof (VARIABLE_STORE_HEADER);\r
845 \r
846   VariableStore->Signature  = VARIABLE_STORE_SIGNATURE;\r
847   VariableStore->Size       = VARIABLE_STORE_SIZE;\r
848   VariableStore->Format     = VARIABLE_STORE_FORMATTED;\r
849   VariableStore->State      = VARIABLE_STORE_HEALTHY;\r
850   VariableStore->Reserved   = 0;\r
851   VariableStore->Reserved1  = 0;\r
852 \r
853   return EFI_SUCCESS;\r
854 }\r
855 \r
856 EFI_STATUS\r
857 EFIAPI\r
858 VariableCommonInitialize (\r
859   IN EFI_HANDLE         ImageHandle,\r
860   IN EFI_SYSTEM_TABLE   *SystemTable\r
861   )\r
862 /*++\r
863 \r
864 Routine Description:\r
865   This function does common initialization for variable services\r
866 \r
867 Arguments:\r
868 \r
869 Returns:\r
870 \r
871 --*/\r
872 {\r
873   EFI_STATUS  Status;\r
874 \r
875   //\r
876   // Allocate memory for mVariableModuleGlobal\r
877   //\r
878   mVariableModuleGlobal = (ESAL_VARIABLE_GLOBAL *) AllocateRuntimePool (\r
879                                                     sizeof (ESAL_VARIABLE_GLOBAL)\r
880                                                    );\r
881   if (NULL == mVariableModuleGlobal) {\r
882     return EFI_OUT_OF_RESOURCES;\r
883   }\r
884 \r
885   EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal[Physical].VariableServicesLock, TPL_NOTIFY);\r
886 \r
887   //\r
888   // Intialize volatile variable store\r
889   //\r
890   Status = InitializeVariableStore (\r
891             &mVariableModuleGlobal->VariableGlobal[Physical].VolatileVariableBase,\r
892             &mVariableModuleGlobal->VolatileLastVariableOffset\r
893             );\r
894 \r
895   if (EFI_ERROR (Status)) {\r
896     return Status;\r
897   }\r
898   //\r
899   // Intialize non volatile variable store\r
900   //\r
901   Status = InitializeVariableStore (\r
902             &mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,\r
903             &mVariableModuleGlobal->NonVolatileLastVariableOffset\r
904             );\r
905 \r
906   return Status;\r
907 }\r