]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Variable/EmuRuntimeDxe/EmuVariable.c
1. Uefi2.1 feature - Add Hardware Error Record Persistence Support
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / EmuRuntimeDxe / EmuVariable.c
CommitLineData
8d3a5c82 1/*++\r
2\r
3Copyright (c) 2006 - 2007, Intel Corporation\r
4All rights reserved. This program and the accompanying materials\r
5are licensed and made available under the terms and conditions of the BSD License\r
6which accompanies this distribution. The full text of the license may be found at\r
7http://opensource.org/licenses/bsd-license.php\r
8\r
9THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
10WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
11\r
12Module Name:\r
13\r
14 EmuVariable.c\r
15\r
16Abstract:\r
17\r
18Revision 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
27ESAL_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
34STATIC\r
35VOID\r
36AcquireLockOnlyAtBootTime (\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
50STATIC\r
51VOID\r
52ReleaseLockOnlyAtBootTime (\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
61STATIC\r
62UINT8 *\r
8d3a5c82 63GetVariableDataPtr (\r
64 IN VARIABLE_HEADER *Variable\r
65 )\r
66/*++\r
67\r
68Routine Description:\r
69\r
70 This code gets the pointer to the variable data.\r
71\r
72Arguments:\r
73\r
74 Variable Pointer to the Variable Header.\r
75\r
76Returns:\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
91STATIC\r
92VARIABLE_HEADER *\r
8d3a5c82 93GetNextVariablePtr (\r
94 IN VARIABLE_HEADER *Variable\r
95 )\r
96/*++\r
97\r
98Routine Description:\r
99\r
100 This code gets the pointer to the next variable header.\r
101\r
102Arguments:\r
103\r
104 Variable Pointer to the Variable Header.\r
105\r
106Returns:\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
131STATIC\r
132VARIABLE_HEADER *\r
8d3a5c82 133GetEndPointer (\r
134 IN VARIABLE_STORE_HEADER *VolHeader\r
135 )\r
136/*++\r
137\r
138Routine Description:\r
139\r
140 This code gets the pointer to the last variable memory pointer byte\r
141\r
142Arguments:\r
143\r
144 Variable Pointer to the Variable Header.\r
145\r
146Returns:\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
158STATIC\r
159EFI_STATUS\r
8d3a5c82 160FindVariable (\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
168Routine Description:\r
169\r
170 This code finds variable in storage blocks (Volatile or Non-Volatile)\r
171\r
172Arguments:\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
181Returns:\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
247EFI_STATUS\r
248EFIAPI\r
249GetVariable (\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
260Routine Description:\r
261\r
262 This code finds variable in storage blocks (Volatile or Non-Volatile)\r
263\r
264Arguments:\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
275Returns:\r
276\r
c6492839 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
8d3a5c82 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
324Done:\r
325 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
326 return Status;\r
327}\r
328\r
329EFI_STATUS\r
330EFIAPI\r
331GetNextVariableName (\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
340Routine Description:\r
341\r
342 This code Finds the Next available variable\r
343\r
344Arguments:\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
352Returns:\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
426Done:\r
427 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
428 return Status;\r
429\r
430}\r
431\r
432EFI_STATUS\r
433EFIAPI\r
434SetVariable (\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
447Routine Description:\r
448\r
449 This code sets variable in storage blocks (Volatile or Non-Volatile)\r
450\r
451Arguments:\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
464Returns:\r
465\r
c6492839 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
8d3a5c82 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
c6492839 483 //\r
484 // Check input parameters\r
485 //\r
8d3a5c82 486 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
487 return EFI_INVALID_PARAMETER;\r
c6492839 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
8d3a5c82 494 }\r
c6492839 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
8d3a5c82 519 Status = FindVariable (VariableName, VendorGuid, &Variable, Global);\r
520\r
c6492839 521 if (Status == EFI_SUCCESS && Variable.CurrPtr != NULL) {\r
8d3a5c82 522 //\r
c6492839 523 // Update/Delete existing variable\r
8d3a5c82 524 //\r
c6492839 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
8d3a5c82 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
c6492839 549 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {\r
8d3a5c82 550 Variable.CurrPtr->State &= VAR_DELETED;\r
551 Status = EFI_SUCCESS;\r
552 goto Done;\r
553 }\r
554\r
c6492839 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
8d3a5c82 565 //\r
c6492839 566 // Mark the old variable as in delete transition\r
8d3a5c82 567 //\r
c6492839 568 Variable.CurrPtr->State &= VAR_IN_DELETED_TRANSITION;\r
8d3a5c82 569 }\r
c6492839 570 \r
571 } else if (Status == EFI_NOT_FOUND) {\r
8d3a5c82 572 //\r
c6492839 573 // Create a new variable\r
574 // \r
575 \r
8d3a5c82 576 //\r
c6492839 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
8d3a5c82 583 }\r
c6492839 584 \r
8d3a5c82 585 //\r
c6492839 586 // Only variable have NV|RT attribute can be created in Runtime\r
8d3a5c82 587 //\r
c6492839 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
8d3a5c82 594 //\r
c6492839 595 // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable().\r
8d3a5c82 596 //\r
c6492839 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
8d3a5c82 617 }\r
c6492839 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
8d3a5c82 631 }\r
632\r
c6492839 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
8d3a5c82 665 Status = EFI_SUCCESS;\r
666Done:\r
667 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
668 return Status;\r
669}\r
670\r
671EFI_STATUS\r
672EFIAPI\r
673QueryVariableInfo (\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
683Routine Description:\r
684\r
685 This code returns information about the EFI variables.\r
686\r
687Arguments:\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
c6492839 694 for EFI variables associated with the attributes specified.\r
695 MaximumVariableSize Pointer to the maximum size of an individual EFI variables\r
8d3a5c82 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
700Returns:\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
c6492839 714 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
8d3a5c82 715 return EFI_INVALID_PARAMETER;\r
716 }\r
c6492839 717 \r
718 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {\r
8d3a5c82 719 //\r
720 // Make sure the Attributes combination is supported by the platform.\r
721 //\r
c6492839 722 return EFI_UNSUPPORTED; \r
8d3a5c82 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
c6492839 762 // Let *MaximumVariableSize be MAX_VARIABLE_SIZE with the exception of the variable header size.\r
8d3a5c82 763 //\r
c6492839 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
8d3a5c82 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
c6492839 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
8d3a5c82 805 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
806 return EFI_SUCCESS;\r
807}\r
808\r
809STATIC\r
810EFI_STATUS\r
8d3a5c82 811InitializeVariableStore (\r
812 OUT EFI_PHYSICAL_ADDRESS *VariableBase,\r
813 OUT UINTN *LastVariableOffset\r
814 )\r
815/*++\r
816\r
817Routine Description:\r
818 This function initializes variable store\r
819\r
820Arguments:\r
821\r
822Returns:\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
856EFI_STATUS\r
857EFIAPI\r
858VariableCommonInitialize (\r
859 IN EFI_HANDLE ImageHandle,\r
860 IN EFI_SYSTEM_TABLE *SystemTable\r
861 )\r
862/*++\r
863\r
864Routine Description:\r
865 This function does common initialization for variable services\r
866\r
867Arguments:\r
868\r
869Returns:\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