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