]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
1. Uefi2.1 feature - Add Hardware Error Record Persistence Support
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / Variable.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 Variable.c\r
15\r
16Abstract:\r
17\r
18Revision History\r
19\r
20--*/\r
21\r
22\r
23#include "Variable.h"\r
3cfb790c 24#include <Guid/FlashMapHob.h>\r
8d3a5c82 25\r
26//\r
27// Don't use module globals after the SetVirtualAddress map is signaled\r
28//\r
29ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal;\r
30\r
31//\r
32// This is a temperary function which will be removed\r
33// when EfiAcquireLock in UefiLib can handle the\r
34// the call in UEFI Runtimer driver in RT phase.\r
35//\r
36STATIC\r
37VOID\r
38AcquireLockOnlyAtBootTime (\r
39 IN EFI_LOCK *Lock\r
40 )\r
41{\r
42 if (!EfiAtRuntime ()) {\r
43 EfiAcquireLock (Lock);\r
44 }\r
45}\r
46\r
47//\r
48// This is a temperary function which will be removed\r
49// when EfiAcquireLock in UefiLib can handle the\r
50// the call in UEFI Runtimer driver in RT phase.\r
51//\r
52STATIC\r
53VOID\r
54ReleaseLockOnlyAtBootTime (\r
55 IN EFI_LOCK *Lock\r
56 )\r
57{\r
58 if (!EfiAtRuntime ()) {\r
59 EfiReleaseLock (Lock);\r
60 }\r
61}\r
62\r
63STATIC\r
64BOOLEAN\r
65EFIAPI\r
66IsValidVariableHeader (\r
67 IN VARIABLE_HEADER *Variable\r
68 )\r
69/*++\r
70\r
71Routine Description:\r
72\r
73 This code checks if variable header is valid or not.\r
74\r
75Arguments:\r
76 Variable Pointer to the Variable Header.\r
77\r
78Returns:\r
79 TRUE Variable header is valid.\r
80 FALSE Variable header is not valid.\r
81\r
82--*/\r
83{\r
84 if (Variable == NULL ||\r
85 Variable->StartId != VARIABLE_DATA ||\r
86 (sizeof (VARIABLE_HEADER) + Variable->NameSize + Variable->DataSize) > MAX_VARIABLE_SIZE\r
87 ) {\r
88 return FALSE;\r
89 }\r
90\r
91 return TRUE;\r
92}\r
93\r
94STATIC\r
95EFI_STATUS\r
96EFIAPI\r
97UpdateVariableStore (\r
98 IN VARIABLE_GLOBAL *Global,\r
99 IN BOOLEAN Volatile,\r
100 IN BOOLEAN SetByIndex,\r
101 IN UINTN Instance,\r
102 IN UINTN DataPtrIndex,\r
103 IN UINT32 DataSize,\r
104 IN UINT8 *Buffer\r
105 )\r
106/*++\r
107\r
108Routine Description:\r
109\r
110 This function writes data to the FWH at the correct LBA even if the LBAs\r
111 are fragmented.\r
112\r
113Arguments:\r
114\r
c6492839 115 Global - Pointer to VARAIBLE_GLOBAL structure\r
116 Volatile - If the Variable is Volatile or Non-Volatile\r
117 SetByIndex - TRUE: Target pointer is given as index\r
118 FALSE: Target pointer is absolute\r
119 Instance - Instance of FV Block services\r
120 DataPtrIndex - Pointer to the Data from the end of VARIABLE_STORE_HEADER\r
121 structure\r
122 DataSize - Size of data to be written.\r
123 Buffer - Pointer to the buffer from which data is written\r
8d3a5c82 124\r
125Returns:\r
126\r
c6492839 127 EFI_INVALID_PARAMETER - Parameters not valid\r
128 EFI_SUCCESS - Variable store successfully updated\r
8d3a5c82 129\r
130--*/\r
131{\r
132 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
133 UINTN BlockIndex2;\r
134 UINTN LinearOffset;\r
135 UINTN CurrWriteSize;\r
136 UINTN CurrWritePtr;\r
137 UINT8 *CurrBuffer;\r
138 EFI_LBA LbaNumber;\r
139 UINTN Size;\r
140 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
141 VARIABLE_STORE_HEADER *VolatileBase;\r
142 EFI_PHYSICAL_ADDRESS FvVolHdr;\r
143 EFI_PHYSICAL_ADDRESS DataPtr;\r
144 EFI_STATUS Status;\r
145\r
146 FwVolHeader = NULL;\r
147 DataPtr = DataPtrIndex;\r
148\r
149 //\r
150 // Check if the Data is Volatile\r
151 //\r
152 if (!Volatile) {\r
153 EfiFvbGetPhysicalAddress (Instance, &FvVolHdr);\r
154 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);\r
155 //\r
156 // Data Pointer should point to the actual Address where data is to be\r
157 // written\r
158 //\r
159 if (SetByIndex) {\r
160 DataPtr += Global->NonVolatileVariableBase;\r
161 }\r
162\r
163 if ((DataPtr + DataSize) >= ((EFI_PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) FwVolHeader + FwVolHeader->FvLength))) {\r
164 return EFI_INVALID_PARAMETER;\r
165 }\r
166 } else {\r
167 //\r
168 // Data Pointer should point to the actual Address where data is to be\r
169 // written\r
170 //\r
171 VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);\r
172 if (SetByIndex) {\r
173 DataPtr += Global->VolatileVariableBase;\r
174 }\r
175\r
176 if ((DataPtr + DataSize) >= ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) {\r
177 return EFI_INVALID_PARAMETER;\r
178 }\r
c6492839 179 \r
180 //\r
181 // If Volatile Variable just do a simple mem copy.\r
182 // \r
183 CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize);\r
8d3a5c82 184 return EFI_SUCCESS;\r
185 }\r
c6492839 186 \r
8d3a5c82 187 //\r
188 // If we are here we are dealing with Non-Volatile Variables\r
189 //\r
190 LinearOffset = (UINTN) FwVolHeader;\r
191 CurrWritePtr = (UINTN) DataPtr;\r
192 CurrWriteSize = DataSize;\r
193 CurrBuffer = Buffer;\r
194 LbaNumber = 0;\r
195\r
196 if (CurrWritePtr < LinearOffset) {\r
197 return EFI_INVALID_PARAMETER;\r
198 }\r
199\r
200 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
201 for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {\r
202 //\r
203 // Check to see if the Variable Writes are spanning through multiple\r
204 // blocks.\r
205 //\r
206 if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) {\r
207 if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {\r
208 Status = EfiFvbWriteBlock (\r
209 Instance,\r
210 LbaNumber,\r
211 (UINTN) (CurrWritePtr - LinearOffset),\r
212 &CurrWriteSize,\r
213 CurrBuffer\r
214 );\r
8d3a5c82 215 return Status;\r
8d3a5c82 216 } else {\r
217 Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);\r
218 Status = EfiFvbWriteBlock (\r
219 Instance,\r
220 LbaNumber,\r
221 (UINTN) (CurrWritePtr - LinearOffset),\r
222 &Size,\r
223 CurrBuffer\r
224 );\r
225 if (EFI_ERROR (Status)) {\r
226 return Status;\r
227 }\r
228\r
229 CurrWritePtr = LinearOffset + PtrBlockMapEntry->Length;\r
230 CurrBuffer = CurrBuffer + Size;\r
231 CurrWriteSize = CurrWriteSize - Size;\r
232 }\r
233 }\r
234\r
235 LinearOffset += PtrBlockMapEntry->Length;\r
236 LbaNumber++;\r
237 }\r
238 }\r
239\r
240 return EFI_SUCCESS;\r
241}\r
242\r
243STATIC\r
244VARIABLE_STORE_STATUS\r
245EFIAPI\r
246GetVariableStoreStatus (\r
247 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
248 )\r
249/*++\r
250\r
251Routine Description:\r
252\r
253 This code gets the current status of Variable Store.\r
254\r
255Arguments:\r
256\r
257 VarStoreHeader Pointer to the Variable Store Header.\r
258\r
259Returns:\r
260\r
261 EfiRaw Variable store status is raw\r
262 EfiValid Variable store status is valid\r
263 EfiInvalid Variable store status is invalid\r
264\r
265--*/\r
266{\r
267 if (VarStoreHeader->Signature == VARIABLE_STORE_SIGNATURE &&\r
268 VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&\r
269 VarStoreHeader->State == VARIABLE_STORE_HEALTHY\r
270 ) {\r
271\r
272 return EfiValid;\r
273 } else if (VarStoreHeader->Signature == 0xffffffff &&\r
274 VarStoreHeader->Size == 0xffffffff &&\r
275 VarStoreHeader->Format == 0xff &&\r
276 VarStoreHeader->State == 0xff\r
277 ) {\r
278\r
279 return EfiRaw;\r
280 } else {\r
281 return EfiInvalid;\r
282 }\r
283}\r
284\r
285STATIC\r
286UINT8 *\r
287EFIAPI\r
288GetVariableDataPtr (\r
289 IN VARIABLE_HEADER *Variable\r
290 )\r
291/*++\r
292\r
293Routine Description:\r
294\r
295 This code gets the pointer to the variable data.\r
296\r
297Arguments:\r
298\r
299 Variable Pointer to the Variable Header.\r
300\r
301Returns:\r
302\r
303 UINT8* Pointer to Variable Data\r
304\r
305--*/\r
306{\r
307 //\r
308 // Be careful about pad size for alignment\r
309 //\r
310 return (UINT8 *) ((UINTN) GET_VARIABLE_NAME_PTR (Variable) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize));\r
311}\r
312\r
313STATIC\r
314VARIABLE_HEADER *\r
8d3a5c82 315GetNextVariablePtr (\r
316 IN VARIABLE_HEADER *Variable\r
317 )\r
318/*++\r
319\r
320Routine Description:\r
321\r
322 This code gets the pointer to the next variable header.\r
323\r
324Arguments:\r
325\r
326 Variable Pointer to the Variable Header.\r
327\r
328Returns:\r
329\r
330 VARIABLE_HEADER* Pointer to next variable header.\r
331\r
332--*/\r
333{\r
334 if (!IsValidVariableHeader (Variable)) {\r
335 return NULL;\r
336 }\r
337 //\r
338 // Be careful about pad size for alignment\r
339 //\r
340 return (VARIABLE_HEADER *) ((UINTN) GetVariableDataPtr (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize));\r
341}\r
342\r
343STATIC\r
344VARIABLE_HEADER *\r
345EFIAPI\r
346GetEndPointer (\r
347 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
348 )\r
349/*++\r
350\r
351Routine Description:\r
352\r
353 This code gets the pointer to the last variable memory pointer byte\r
354\r
355Arguments:\r
356\r
357 VarStoreHeader Pointer to the Variable Store Header.\r
358\r
359Returns:\r
360\r
361 VARIABLE_HEADER* Pointer to last unavailable Variable Header\r
362\r
363--*/\r
364{\r
365 //\r
366 // The end of variable store\r
367 //\r
368 return (VARIABLE_HEADER *) ((UINTN) VarStoreHeader + VarStoreHeader->Size);\r
369}\r
370\r
371STATIC\r
372EFI_STATUS\r
373EFIAPI\r
374Reclaim (\r
375 IN EFI_PHYSICAL_ADDRESS VariableBase,\r
376 OUT UINTN *LastVariableOffset,\r
377 IN BOOLEAN IsVolatile\r
378 )\r
379/*++\r
380\r
381Routine Description:\r
382\r
383 Variable store garbage collection and reclaim operation\r
384\r
385Arguments:\r
386\r
387 VariableBase Base address of variable store\r
388 LastVariableOffset Offset of last variable\r
389 IsVolatile The variable store is volatile or not,\r
390 if it is non-volatile, need FTW\r
391\r
392Returns:\r
393\r
394 EFI STATUS\r
395\r
396--*/\r
397{\r
398 VARIABLE_HEADER *Variable;\r
399 VARIABLE_HEADER *NextVariable;\r
400 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
401 UINT8 *ValidBuffer;\r
402 UINTN ValidBufferSize;\r
403 UINTN VariableSize;\r
404 UINT8 *CurrPtr;\r
405 EFI_STATUS Status;\r
406\r
407 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);\r
408\r
409 //\r
410 // Start Pointers for the variable.\r
411 //\r
412 Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);\r
413\r
414 ValidBufferSize = sizeof (VARIABLE_STORE_HEADER);\r
415\r
416 while (IsValidVariableHeader (Variable)) {\r
417 NextVariable = GetNextVariablePtr (Variable);\r
418 if (Variable->State == VAR_ADDED) {\r
419 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
420 ValidBufferSize += VariableSize;\r
421 }\r
422\r
423 Variable = NextVariable;\r
424 }\r
425\r
426 ValidBuffer = AllocatePool (ValidBufferSize);\r
427 if (ValidBuffer == NULL) {\r
428 return EFI_OUT_OF_RESOURCES;\r
429 }\r
430\r
431 SetMem (ValidBuffer, ValidBufferSize, 0xff);\r
432\r
433 CurrPtr = ValidBuffer;\r
434\r
435 //\r
436 // Copy variable store header\r
437 //\r
438 CopyMem (CurrPtr, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));\r
439 CurrPtr += sizeof (VARIABLE_STORE_HEADER);\r
440\r
441 //\r
442 // Start Pointers for the variable.\r
443 //\r
444 Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);\r
445\r
446 while (IsValidVariableHeader (Variable)) {\r
447 NextVariable = GetNextVariablePtr (Variable);\r
448 if (Variable->State == VAR_ADDED) {\r
449 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
450 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
451 CurrPtr += VariableSize;\r
452 }\r
453\r
454 Variable = NextVariable;\r
455 }\r
456\r
457 if (IsVolatile) {\r
458 //\r
459 // If volatile variable store, just copy valid buffer\r
460 //\r
461 SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);\r
462 CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, ValidBufferSize);\r
463 *LastVariableOffset = ValidBufferSize;\r
464 Status = EFI_SUCCESS;\r
465 } else {\r
466 //\r
467 // If non-volatile variable store, perform FTW here.\r
468 //\r
469 Status = FtwVariableSpace (\r
470 VariableBase,\r
471 ValidBuffer,\r
472 ValidBufferSize\r
473 );\r
474 if (!EFI_ERROR (Status)) {\r
475 *LastVariableOffset = ValidBufferSize;\r
476 }\r
477 }\r
478\r
479 FreePool (ValidBuffer);\r
480\r
481 if (EFI_ERROR (Status)) {\r
482 *LastVariableOffset = 0;\r
483 }\r
484\r
485 return Status;\r
486}\r
487\r
488STATIC\r
489EFI_STATUS\r
490EFIAPI\r
491FindVariable (\r
492 IN CHAR16 *VariableName,\r
493 IN EFI_GUID *VendorGuid,\r
494 OUT VARIABLE_POINTER_TRACK *PtrTrack,\r
495 IN VARIABLE_GLOBAL *Global\r
496 )\r
497/*++\r
498\r
499Routine Description:\r
500\r
501 This code finds variable in storage blocks (Volatile or Non-Volatile)\r
502\r
503Arguments:\r
504\r
505 VariableName Name of the variable to be found\r
506 VendorGuid Vendor GUID to be found.\r
507 PtrTrack Variable Track Pointer structure that contains\r
508 Variable Information.\r
509 Contains the pointer of Variable header.\r
510 Global VARIABLE_GLOBAL pointer\r
511\r
512Returns:\r
513\r
514 EFI STATUS\r
515\r
516--*/\r
517{\r
518 VARIABLE_HEADER *Variable[2];\r
519 VARIABLE_STORE_HEADER *VariableStoreHeader[2];\r
520 UINTN Index;\r
521\r
522 //\r
523 // We aquire the lock at the entry of FindVariable as GetVariable, GetNextVariableName\r
524 // SetVariable all call FindVariable at entry point. Please move "Aquire Lock" to\r
525 // the correct places if this assumption does not hold TRUE anymore.\r
526 //\r
527 AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);\r
528\r
529 //\r
530 // 0: Non-Volatile, 1: Volatile\r
531 //\r
532 VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase);\r
533 VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);\r
534\r
535 //\r
536 // Start Pointers for the variable.\r
537 // Actual Data Pointer where data can be written.\r
538 //\r
539 Variable[0] = (VARIABLE_HEADER *) (VariableStoreHeader[0] + 1);\r
540 Variable[1] = (VARIABLE_HEADER *) (VariableStoreHeader[1] + 1);\r
541\r
542 if (VariableName[0] != 0 && VendorGuid == NULL) {\r
543 return EFI_INVALID_PARAMETER;\r
544 }\r
545 //\r
546 // Find the variable by walk through non-volatile and volatile variable store\r
547 //\r
548 for (Index = 0; Index < 2; Index++) {\r
549 PtrTrack->StartPtr = (VARIABLE_HEADER *) (VariableStoreHeader[Index] + 1);\r
550 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]);\r
551\r
552 while (IsValidVariableHeader (Variable[Index]) && (Variable[Index] <= GetEndPointer (VariableStoreHeader[Index]))) {\r
553 if (Variable[Index]->State == VAR_ADDED) {\r
c6492839 554 if (!EfiAtRuntime () || (Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {\r
8d3a5c82 555 if (VariableName[0] == 0) {\r
556 PtrTrack->CurrPtr = Variable[Index];\r
557 PtrTrack->Volatile = (BOOLEAN) Index;\r
558 return EFI_SUCCESS;\r
559 } else {\r
560 if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) {\r
561 if (!CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable[Index]), Variable[Index]->NameSize)) {\r
562 PtrTrack->CurrPtr = Variable[Index];\r
563 PtrTrack->Volatile = (BOOLEAN) Index;\r
564 return EFI_SUCCESS;\r
565 }\r
566 }\r
567 }\r
568 }\r
569 }\r
570\r
571 Variable[Index] = GetNextVariablePtr (Variable[Index]);\r
572 }\r
573 //\r
574 // While (...)\r
575 //\r
576 }\r
577 //\r
578 // for (...)\r
579 //\r
580 PtrTrack->CurrPtr = NULL;\r
581 return EFI_NOT_FOUND;\r
582}\r
583\r
584EFI_STATUS\r
585EFIAPI\r
586GetVariable (\r
587 IN CHAR16 *VariableName,\r
c6492839 588 IN EFI_GUID *VendorGuid,\r
8d3a5c82 589 OUT UINT32 *Attributes OPTIONAL,\r
590 IN OUT UINTN *DataSize,\r
591 OUT VOID *Data,\r
c6492839 592 IN VARIABLE_GLOBAL *Global,\r
8d3a5c82 593 IN UINT32 Instance\r
594 )\r
595/*++\r
596\r
597Routine Description:\r
598\r
599 This code finds variable in storage blocks (Volatile or Non-Volatile)\r
600\r
601Arguments:\r
602\r
c6492839 603 VariableName Name of Variable to be found\r
604 VendorGuid Variable vendor GUID\r
605 Attributes OPTIONAL Attribute value of the variable found\r
606 DataSize Size of Data found. If size is less than the\r
607 data, this value contains the required size.\r
608 Data Data pointer\r
609 Global Pointer to VARIABLE_GLOBAL structure\r
610 Instance Instance of the Firmware Volume.\r
8d3a5c82 611\r
612Returns:\r
613\r
c6492839 614 EFI_INVALID_PARAMETER - Invalid parameter\r
615 EFI_SUCCESS - Find the specified variable\r
616 EFI_NOT_FOUND - Not found\r
617 EFI_BUFFER_TO_SMALL - DataSize is too small for the result\r
618\r
8d3a5c82 619\r
620--*/\r
621{\r
622 VARIABLE_POINTER_TRACK Variable;\r
623 UINTN VarDataSize;\r
624 EFI_STATUS Status;\r
625\r
626 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
627 return EFI_INVALID_PARAMETER;\r
628 }\r
629 //\r
630 // Find existing variable\r
631 //\r
632 Status = FindVariable (VariableName, VendorGuid, &Variable, Global);\r
633\r
634 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
635 goto Done;\r
636 }\r
637 //\r
638 // Get data size\r
639 //\r
640 VarDataSize = Variable.CurrPtr->DataSize;\r
641 if (*DataSize >= VarDataSize) {\r
642 if (Data == NULL) {\r
643 Status = EFI_INVALID_PARAMETER;\r
644 goto Done;\r
645 }\r
646\r
647 CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);\r
648 if (Attributes != NULL) {\r
649 *Attributes = Variable.CurrPtr->Attributes;\r
650 }\r
651\r
652 *DataSize = VarDataSize;\r
653 Status = EFI_SUCCESS;\r
654 goto Done;\r
655 } else {\r
656 *DataSize = VarDataSize;\r
657 Status = EFI_BUFFER_TOO_SMALL;\r
658 goto Done;\r
659 }\r
660\r
661Done:\r
662 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
663 return Status;\r
664}\r
665\r
666EFI_STATUS\r
667EFIAPI\r
668GetNextVariableName (\r
669 IN OUT UINTN *VariableNameSize,\r
670 IN OUT CHAR16 *VariableName,\r
671 IN OUT EFI_GUID *VendorGuid,\r
672 IN VARIABLE_GLOBAL *Global,\r
673 IN UINT32 Instance\r
674 )\r
675/*++\r
676\r
677Routine Description:\r
678\r
679 This code Finds the Next available variable\r
680\r
681Arguments:\r
682\r
683 VariableNameSize Size of the variable\r
684 VariableName Pointer to variable name\r
685 VendorGuid Variable Vendor Guid\r
686 Global VARIABLE_GLOBAL structure pointer.\r
687 Instance FV instance\r
688\r
689Returns:\r
690\r
691 EFI STATUS\r
692\r
693--*/\r
694{\r
695 VARIABLE_POINTER_TRACK Variable;\r
696 UINTN VarNameSize;\r
697 EFI_STATUS Status;\r
698\r
699 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
700 return EFI_INVALID_PARAMETER;\r
701 }\r
702\r
703 Status = FindVariable (VariableName, VendorGuid, &Variable, Global);\r
704\r
705 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
706 goto Done;\r
707 }\r
708\r
709 if (VariableName[0] != 0) {\r
710 //\r
711 // If variable name is not NULL, get next variable\r
712 //\r
713 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
714 }\r
715\r
716 while (TRUE) {\r
717 //\r
718 // If both volatile and non-volatile variable store are parsed,\r
719 // return not found\r
720 //\r
721 if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) {\r
722 Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));\r
723 if (Variable.Volatile) {\r
724 Variable.StartPtr = (VARIABLE_HEADER *) ((UINTN) (Global->VolatileVariableBase + sizeof (VARIABLE_STORE_HEADER)));\r
725 Variable.EndPtr = (VARIABLE_HEADER *) GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase));\r
726 } else {\r
727 Status = EFI_NOT_FOUND;\r
728 goto Done;\r
729 }\r
730\r
731 Variable.CurrPtr = Variable.StartPtr;\r
732 if (!IsValidVariableHeader (Variable.CurrPtr)) {\r
733 continue;\r
734 }\r
735 }\r
736 //\r
737 // Variable is found\r
738 //\r
739 if (IsValidVariableHeader (Variable.CurrPtr) && Variable.CurrPtr->State == VAR_ADDED) {\r
740 if (!(EfiAtRuntime () && !(Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS))) {\r
741 VarNameSize = Variable.CurrPtr->NameSize;\r
742 if (VarNameSize <= *VariableNameSize) {\r
743 CopyMem (\r
744 VariableName,\r
745 GET_VARIABLE_NAME_PTR (Variable.CurrPtr),\r
746 VarNameSize\r
747 );\r
748 CopyMem (\r
749 VendorGuid,\r
750 &Variable.CurrPtr->VendorGuid,\r
751 sizeof (EFI_GUID)\r
752 );\r
753 Status = EFI_SUCCESS;\r
754 } else {\r
755 Status = EFI_BUFFER_TOO_SMALL;\r
756 }\r
757\r
758 *VariableNameSize = VarNameSize;\r
759 goto Done;\r
760 }\r
761 }\r
762\r
763 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
764 }\r
765\r
766Done:\r
767 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
768 return Status;\r
769}\r
770\r
771EFI_STATUS\r
772EFIAPI\r
773SetVariable (\r
774 IN CHAR16 *VariableName,\r
775 IN EFI_GUID *VendorGuid,\r
776 IN UINT32 Attributes,\r
777 IN UINTN DataSize,\r
778 IN VOID *Data,\r
779 IN VARIABLE_GLOBAL *Global,\r
780 IN UINTN *VolatileOffset,\r
781 IN UINTN *NonVolatileOffset,\r
782 IN UINT32 Instance\r
783 )\r
784/*++\r
785\r
786Routine Description:\r
787\r
788 This code sets variable in storage blocks (Volatile or Non-Volatile)\r
789\r
790Arguments:\r
791\r
792 VariableName Name of Variable to be found\r
793 VendorGuid Variable vendor GUID\r
794 Attributes Attribute value of the variable found\r
795 DataSize Size of Data found. If size is less than the\r
796 data, this value contains the required size.\r
797 Data Data pointer\r
798 Global Pointer to VARIABLE_GLOBAL structure\r
799 VolatileOffset The offset of last volatile variable\r
800 NonVolatileOffset The offset of last non-volatile variable\r
801 Instance Instance of the Firmware Volume.\r
802\r
803Returns:\r
804\r
8d3a5c82 805 EFI_INVALID_PARAMETER - Invalid parameter\r
806 EFI_SUCCESS - Set successfully\r
807 EFI_OUT_OF_RESOURCES - Resource not enough to set variable\r
808 EFI_NOT_FOUND - Not found\r
c6492839 809 EFI_DEVICE_ERROR - Variable can not be saved due to hardware failure\r
810 EFI_WRITE_PROTECTED - Variable is read-only\r
8d3a5c82 811\r
812--*/\r
813{\r
814 VARIABLE_POINTER_TRACK Variable;\r
815 EFI_STATUS Status;\r
816 VARIABLE_HEADER *NextVariable;\r
817 UINTN VarNameSize;\r
818 UINTN VarNameOffset;\r
819 UINTN VarDataOffset;\r
820 UINTN VarSize;\r
821 UINT8 State;\r
822 BOOLEAN Reclaimed;\r
823\r
824 Reclaimed = FALSE;\r
825\r
c6492839 826 //\r
827 // Check input parameters\r
828 //\r
8d3a5c82 829 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
830 return EFI_INVALID_PARAMETER;\r
c6492839 831 } \r
832 //\r
833 // Make sure if runtime bit is set, boot service bit is set also\r
834 //\r
835 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
836 return EFI_INVALID_PARAMETER;\r
8d3a5c82 837 }\r
c6492839 838 //\r
839 // The size of the VariableName, including the Unicode Null in bytes plus\r
840 // the DataSize is limited to maximum size of MAX_HARDWARE_ERROR_VARIABLE_SIZE (32K)\r
841 // bytes for HwErrRec, and MAX_VARIABLE_SIZE (1024) bytes for the others.\r
842 //\r
843 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
844 if ((DataSize > MAX_HARDWARE_ERROR_VARIABLE_SIZE) || \r
845 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_HARDWARE_ERROR_VARIABLE_SIZE)) {\r
846 return EFI_INVALID_PARAMETER;\r
847 } \r
848 } else {\r
849 //\r
850 // The size of the VariableName, including the Unicode Null in bytes plus\r
851 // the DataSize is limited to maximum size of MAX_VARIABLE_SIZE (1024) bytes.\r
852 //\r
853 if ((DataSize > MAX_VARIABLE_SIZE) ||\r
854 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_VARIABLE_SIZE)) {\r
855 return EFI_INVALID_PARAMETER;\r
856 } \r
857 } \r
858 //\r
859 // Check whether the input variable is already existed\r
860 //\r
861 \r
8d3a5c82 862 Status = FindVariable (VariableName, VendorGuid, &Variable, Global);\r
863\r
c6492839 864 if (Status == EFI_SUCCESS && Variable.CurrPtr != NULL) {\r
8d3a5c82 865 //\r
c6492839 866 // Update/Delete existing variable\r
8d3a5c82 867 //\r
c6492839 868 \r
869 if (EfiAtRuntime ()) { \r
870 //\r
871 // If EfiAtRuntime and the variable is Volatile and Runtime Access, \r
872 // the volatile is ReadOnly, and SetVariable should be aborted and \r
873 // return EFI_WRITE_PROTECTED.\r
874 //\r
875 if (Variable.Volatile) {\r
876 Status = EFI_WRITE_PROTECTED;\r
877 goto Done;\r
878 }\r
879 //\r
880 // Only variable have NV attribute can be updated/deleted in Runtime\r
881 //\r
882 if (!(Variable.CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE)) {\r
883 Status = EFI_INVALID_PARAMETER;\r
884 goto Done; \r
885 }\r
886 }\r
8d3a5c82 887 //\r
c6492839 888 // Setting a data variable with no access, or zero DataSize attributes\r
889 // specified causes it to be deleted.\r
8d3a5c82 890 //\r
c6492839 891 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) { \r
892 State = Variable.CurrPtr->State;\r
893 State &= VAR_DELETED;\r
894\r
895 Status = UpdateVariableStore (\r
896 Global,\r
897 Variable.Volatile,\r
898 FALSE,\r
899 Instance,\r
900 (UINTN) &Variable.CurrPtr->State,\r
901 sizeof (UINT8),\r
902 &State\r
903 ); \r
904 goto Done; \r
905 }\r
8d3a5c82 906 //\r
c6492839 907 // If the variable is marked valid and the same data has been passed in\r
908 // then return to the caller immediately.\r
8d3a5c82 909 //\r
c6492839 910 if (Variable.CurrPtr->DataSize == DataSize &&\r
911 (CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize) == 0)) {\r
912 Status = EFI_SUCCESS;\r
913 goto Done;\r
914 } else if ((Variable.CurrPtr->State == VAR_ADDED) ||\r
915 (Variable.CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {\r
916 //\r
917 // Mark the old variable as in delete transition\r
918 //\r
919 State = Variable.CurrPtr->State;\r
920 State &= VAR_IN_DELETED_TRANSITION;\r
921\r
922 Status = UpdateVariableStore (\r
923 Global,\r
924 Variable.Volatile,\r
925 FALSE,\r
926 Instance,\r
927 (UINTN) &Variable.CurrPtr->State,\r
928 sizeof (UINT8),\r
929 &State\r
930 ); \r
931 if (EFI_ERROR (Status)) {\r
932 goto Done; \r
933 }\r
934 } \r
935 } else if (Status == EFI_NOT_FOUND) {\r
8d3a5c82 936 //\r
c6492839 937 // Create a new variable\r
938 // \r
939 \r
8d3a5c82 940 //\r
c6492839 941 // Make sure we are trying to create a new variable.\r
942 // Setting a data variable with no access, or zero DataSize attributes means to delete it. \r
8d3a5c82 943 //\r
c6492839 944 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {\r
945 Status = EFI_NOT_FOUND;\r
946 goto Done;\r
947 }\r
948 \r
8d3a5c82 949 //\r
c6492839 950 // Only variable have NV|RT attribute can be created in Runtime\r
951 //\r
952 if (EfiAtRuntime () &&\r
953 (!(Attributes & EFI_VARIABLE_RUNTIME_ACCESS) || !(Attributes & EFI_VARIABLE_NON_VOLATILE))) {\r
954 Status = EFI_INVALID_PARAMETER;\r
955 goto Done;\r
956 } \r
957 } else {\r
8d3a5c82 958 //\r
c6492839 959 // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable().\r
8d3a5c82 960 //\r
c6492839 961 ASSERT (Status == EFI_INVALID_PARAMETER);\r
8d3a5c82 962 goto Done;\r
c6492839 963 }\r
964\r
965 //\r
966 // Function part - create a new variable and copy the data.\r
967 // Both update a variable and create a variable will come here.\r
968 //\r
969 // Tricky part: Use scratch data area at the end of volatile variable store\r
970 // as a temporary storage.\r
971 //\r
972 NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase));\r
973\r
974 SetMem (NextVariable, SCRATCH_SIZE, 0xff);\r
975\r
976 NextVariable->StartId = VARIABLE_DATA;\r
977 NextVariable->Attributes = Attributes;\r
978 //\r
979 // NextVariable->State = VAR_ADDED;\r
980 //\r
981 NextVariable->Reserved = 0;\r
982 VarNameOffset = sizeof (VARIABLE_HEADER);\r
983 VarNameSize = StrSize (VariableName);\r
984 CopyMem (\r
985 (UINT8 *) ((UINTN) NextVariable + VarNameOffset),\r
986 VariableName,\r
987 VarNameSize\r
988 );\r
989 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);\r
990 CopyMem (\r
991 (UINT8 *) ((UINTN) NextVariable + VarDataOffset),\r
992 Data,\r
993 DataSize\r
994 );\r
995 CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));\r
996 //\r
997 // There will be pad bytes after Data, the NextVariable->NameSize and\r
998 // NextVariable->DataSize should not include pad size so that variable\r
999 // service can get actual size in GetVariable\r
1000 //\r
1001 NextVariable->NameSize = (UINT32)VarNameSize;\r
1002 NextVariable->DataSize = (UINT32)DataSize;\r
1003\r
1004 //\r
1005 // The actual size of the variable that stores in storage should\r
1006 // include pad size.\r
1007 //\r
1008 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);\r
1009 if (Attributes & EFI_VARIABLE_NON_VOLATILE) {\r
8d3a5c82 1010 //\r
c6492839 1011 // Create a nonvolatile variable\r
8d3a5c82 1012 //\r
c6492839 1013 \r
1014 if ((UINT32) (VarSize +*NonVolatileOffset) >\r
1015 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->NonVolatileVariableBase)))->Size\r
1016 ) {\r
1017 if (EfiAtRuntime ()) {\r
1018 Status = EFI_OUT_OF_RESOURCES;\r
1019 goto Done;\r
1020 }\r
1021 //\r
1022 // Perform garbage collection & reclaim operation\r
1023 //\r
1024 Status = Reclaim (Global->NonVolatileVariableBase, NonVolatileOffset, FALSE);\r
8d3a5c82 1025 if (EFI_ERROR (Status)) {\r
1026 goto Done;\r
1027 }\r
8d3a5c82 1028 //\r
c6492839 1029 // If still no enough space, return out of resources\r
8d3a5c82 1030 //\r
c6492839 1031 if ((UINT32) (VarSize +*NonVolatileOffset) >\r
1032 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->NonVolatileVariableBase)))->Size\r
8d3a5c82 1033 ) {\r
c6492839 1034 Status = EFI_OUT_OF_RESOURCES;\r
8d3a5c82 1035 goto Done;\r
8d3a5c82 1036 }\r
c6492839 1037 \r
1038 Reclaimed = TRUE;\r
8d3a5c82 1039 }\r
1040 //\r
c6492839 1041 // Three steps\r
1042 // 1. Write variable header\r
1043 // 2. Write variable data\r
1044 // 3. Set variable state to valid\r
8d3a5c82 1045 //\r
8d3a5c82 1046 //\r
c6492839 1047 // Step 1:\r
8d3a5c82 1048 //\r
c6492839 1049 Status = UpdateVariableStore (\r
1050 Global,\r
1051 FALSE,\r
1052 TRUE,\r
1053 Instance,\r
1054 *NonVolatileOffset,\r
1055 sizeof (VARIABLE_HEADER),\r
1056 (UINT8 *) NextVariable\r
1057 );\r
1058\r
1059 if (EFI_ERROR (Status)) {\r
1060 goto Done;\r
1061 }\r
8d3a5c82 1062 //\r
c6492839 1063 // Step 2:\r
8d3a5c82 1064 //\r
c6492839 1065 Status = UpdateVariableStore (\r
1066 Global,\r
1067 FALSE,\r
1068 TRUE,\r
1069 Instance,\r
1070 *NonVolatileOffset + sizeof (VARIABLE_HEADER),\r
1071 (UINT32) VarSize - sizeof (VARIABLE_HEADER),\r
1072 (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)\r
1073 );\r
1074\r
1075 if (EFI_ERROR (Status)) {\r
1076 goto Done;\r
1077 }\r
8d3a5c82 1078 //\r
c6492839 1079 // Step 3:\r
8d3a5c82 1080 //\r
c6492839 1081 NextVariable->State = VAR_ADDED;\r
1082 Status = UpdateVariableStore (\r
1083 Global,\r
1084 FALSE,\r
1085 TRUE,\r
1086 Instance,\r
1087 *NonVolatileOffset,\r
1088 sizeof (VARIABLE_HEADER),\r
1089 (UINT8 *) NextVariable\r
1090 );\r
1091\r
1092 if (EFI_ERROR (Status)) {\r
1093 goto Done;\r
1094 }\r
8d3a5c82 1095\r
c6492839 1096 *NonVolatileOffset = *NonVolatileOffset + VarSize;\r
8d3a5c82 1097\r
c6492839 1098 } else {\r
1099 //\r
1100 // Create a volatile variable\r
1101 // \r
1102\r
1103 if ((UINT32) (VarSize +*VolatileOffset) >\r
1104 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size) {\r
8d3a5c82 1105 //\r
c6492839 1106 // Perform garbage collection & reclaim operation\r
8d3a5c82 1107 //\r
c6492839 1108 Status = Reclaim (Global->VolatileVariableBase, VolatileOffset, TRUE);\r
8d3a5c82 1109 if (EFI_ERROR (Status)) {\r
1110 goto Done;\r
1111 }\r
1112 //\r
c6492839 1113 // If still no enough space, return out of resources\r
8d3a5c82 1114 //\r
8d3a5c82 1115 if ((UINT32) (VarSize +*VolatileOffset) >\r
1116 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size\r
1117 ) {\r
c6492839 1118 Status = EFI_OUT_OF_RESOURCES;\r
8d3a5c82 1119 goto Done;\r
1120 }\r
c6492839 1121 \r
1122 Reclaimed = TRUE;\r
8d3a5c82 1123 }\r
8d3a5c82 1124\r
c6492839 1125 NextVariable->State = VAR_ADDED;\r
1126 Status = UpdateVariableStore (\r
1127 Global,\r
1128 TRUE,\r
1129 TRUE,\r
1130 Instance,\r
1131 *VolatileOffset,\r
1132 (UINT32) VarSize,\r
1133 (UINT8 *) NextVariable\r
1134 );\r
1135\r
1136 if (EFI_ERROR (Status)) {\r
1137 goto Done;\r
8d3a5c82 1138 }\r
c6492839 1139\r
1140 *VolatileOffset = *VolatileOffset + VarSize;\r
1141 }\r
1142 //\r
1143 // Mark the old variable as deleted\r
1144 //\r
1145 if (!Reclaimed && !EFI_ERROR (Status) && Variable.CurrPtr != NULL) {\r
1146 State = Variable.CurrPtr->State;\r
1147 State &= VAR_DELETED;\r
1148\r
1149 Status = UpdateVariableStore (\r
1150 Global,\r
1151 Variable.Volatile,\r
1152 FALSE,\r
1153 Instance,\r
1154 (UINTN) &Variable.CurrPtr->State,\r
1155 sizeof (UINT8),\r
1156 &State\r
1157 );\r
1158 goto Done; \r
8d3a5c82 1159 }\r
1160\r
1161 Status = EFI_SUCCESS;\r
1162Done:\r
1163 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
1164 return Status;\r
1165}\r
1166\r
1167EFI_STATUS\r
1168EFIAPI\r
1169QueryVariableInfo (\r
1170 IN UINT32 Attributes,\r
1171 OUT UINT64 *MaximumVariableStorageSize,\r
1172 OUT UINT64 *RemainingVariableStorageSize,\r
1173 OUT UINT64 *MaximumVariableSize,\r
1174 IN VARIABLE_GLOBAL *Global,\r
1175 IN UINT32 Instance\r
1176 )\r
1177/*++\r
1178\r
1179Routine Description:\r
1180\r
1181 This code returns information about the EFI variables.\r
1182\r
1183Arguments:\r
1184\r
1185 Attributes Attributes bitmask to specify the type of variables\r
1186 on which to return information.\r
1187 MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
1188 for the EFI variables associated with the attributes specified.\r
1189 RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
c6492839 1190 for EFI variables associated with the attributes specified.\r
1191 MaximumVariableSize Pointer to the maximum size of an individual EFI variables\r
8d3a5c82 1192 associated with the attributes specified.\r
1193 Global Pointer to VARIABLE_GLOBAL structure.\r
1194 Instance Instance of the Firmware Volume.\r
1195\r
1196Returns:\r
1197\r
1198 EFI STATUS\r
1199 EFI_INVALID_PARAMETER - An invalid combination of attribute bits was supplied.\r
1200 EFI_SUCCESS - Query successfully.\r
1201 EFI_UNSUPPORTED - The attribute is not supported on this platform.\r
1202\r
1203--*/\r
1204{\r
1205 VARIABLE_HEADER *Variable;\r
1206 VARIABLE_HEADER *NextVariable;\r
1207 UINT64 VariableSize;\r
1208 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
1209\r
c6492839 1210 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
8d3a5c82 1211 return EFI_INVALID_PARAMETER;\r
1212 }\r
c6492839 1213 \r
1214 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {\r
8d3a5c82 1215 //\r
1216 // Make sure the Attributes combination is supported by the platform.\r
1217 //\r
c6492839 1218 return EFI_UNSUPPORTED; \r
8d3a5c82 1219 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
1220 //\r
1221 // Make sure if runtime bit is set, boot service bit is set also.\r
1222 //\r
1223 return EFI_INVALID_PARAMETER;\r
1224 } else if (EfiAtRuntime () && !(Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {\r
1225 //\r
1226 // Make sure RT Attribute is set if we are in Runtime phase.\r
1227 //\r
1228 return EFI_INVALID_PARAMETER;\r
1229 }\r
1230\r
1231 AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);\r
1232\r
1233 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
1234 //\r
1235 // Query is Volatile related.\r
1236 //\r
1237 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);\r
1238 } else {\r
1239 //\r
1240 // Query is Non-Volatile related.\r
1241 //\r
1242 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase);\r
1243 }\r
1244\r
1245 //\r
1246 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize\r
1247 // with the storage size (excluding the storage header size).\r
1248 //\r
1249 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
1250 *RemainingVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
1251\r
1252 //\r
c6492839 1253 // Let *MaximumVariableSize be MAX_VARIABLE_SIZE with the exception of the variable header size.\r
8d3a5c82 1254 //\r
c6492839 1255 *MaximumVariableSize = MAX_VARIABLE_SIZE - sizeof (VARIABLE_HEADER);\r
1256\r
1257 //\r
1258 // Harware error record variable needs larger size.\r
1259 //\r
1260 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
1261 *MaximumVariableSize = MAX_HARDWARE_ERROR_VARIABLE_SIZE - sizeof (VARIABLE_HEADER);\r
1262 }\r
8d3a5c82 1263\r
1264 //\r
1265 // Point to the starting address of the variables.\r
1266 //\r
1267 Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);\r
1268\r
1269 //\r
1270 // Now walk through the related variable store.\r
1271 //\r
1272 while (IsValidVariableHeader (Variable) && (Variable < GetEndPointer (VariableStoreHeader))) {\r
1273 NextVariable = GetNextVariablePtr (Variable);\r
1274 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;\r
1275\r
1276 if (EfiAtRuntime ()) {\r
1277 //\r
1278 // we don't take the state of the variables in mind\r
1279 // when calculating RemainingVariableStorageSize,\r
1280 // since the space occupied by variables not marked with\r
1281 // VAR_ADDED is not allowed to be reclaimed in Runtime.\r
1282 //\r
1283 *RemainingVariableStorageSize -= VariableSize;\r
1284 } else {\r
1285 //\r
1286 // Only care about Variables with State VAR_ADDED,because\r
1287 // the space not marked as VAR_ADDED is reclaimable now.\r
1288 //\r
1289 if (Variable->State == VAR_ADDED) {\r
1290 *RemainingVariableStorageSize -= VariableSize;\r
1291 }\r
1292 }\r
1293\r
1294 //\r
1295 // Go to the next one\r
1296 //\r
1297 Variable = NextVariable;\r
1298 }\r
1299\r
c6492839 1300 if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {\r
1301 *MaximumVariableSize = 0;\r
1302 } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {\r
1303 *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);\r
1304 }\r
1305\r
8d3a5c82 1306 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
1307 return EFI_SUCCESS;\r
1308}\r
1309\r
1310EFI_STATUS\r
1311EFIAPI\r
1312VariableCommonInitialize (\r
1313 IN EFI_HANDLE ImageHandle,\r
1314 IN EFI_SYSTEM_TABLE *SystemTable\r
1315 )\r
1316/*++\r
1317\r
1318Routine Description:\r
1319 This function does common initialization for variable services\r
1320\r
1321Arguments:\r
1322\r
1323 ImageHandle - The firmware allocated handle for the EFI image.\r
1324 SystemTable - A pointer to the EFI System Table.\r
1325\r
1326Returns:\r
1327\r
1328 Status code.\r
1329\r
1330 EFI_NOT_FOUND - Variable store area not found.\r
1331 EFI_UNSUPPORTED - Currently only one non-volatile variable store is supported.\r
1332 EFI_SUCCESS - Variable services successfully initialized.\r
1333\r
1334--*/\r
1335{\r
1336 EFI_STATUS Status;\r
1337 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
1338 CHAR8 *CurrPtr;\r
1339 VARIABLE_STORE_HEADER *VolatileVariableStore;\r
1340 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
1341 VARIABLE_HEADER *NextVariable;\r
1342 UINT32 Instance;\r
1343 EFI_PHYSICAL_ADDRESS FvVolHdr;\r
8d3a5c82 1344 UINT64 TempVariableStoreHeader;\r
8d3a5c82 1345 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
1346 EFI_FLASH_SUBAREA_ENTRY VariableStoreEntry;\r
1347 UINT64 BaseAddress;\r
1348 UINT64 Length;\r
1349 UINTN Index;\r
1350 UINT8 Data;\r
1351\r
1352 mVariableModuleGlobal = AllocateRuntimePool (sizeof (ESAL_VARIABLE_GLOBAL));\r
1353 if (mVariableModuleGlobal == NULL) {\r
1354 return EFI_OUT_OF_RESOURCES;\r
1355 }\r
1356\r
1357 EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal[Physical].VariableServicesLock, TPL_NOTIFY);\r
1358\r
1359 //\r
1360 // Allocate memory for volatile variable store\r
1361 //\r
1362 VolatileVariableStore = AllocateRuntimePool (VARIABLE_STORE_SIZE + SCRATCH_SIZE);\r
1363 if (VolatileVariableStore == NULL) {\r
1364 FreePool (mVariableModuleGlobal);\r
1365 return EFI_OUT_OF_RESOURCES;\r
1366 }\r
1367\r
1368 SetMem (VolatileVariableStore, VARIABLE_STORE_SIZE + SCRATCH_SIZE, 0xff);\r
1369\r
1370 //\r
1371 // Variable Specific Data\r
1372 //\r
1373 mVariableModuleGlobal->VariableGlobal[Physical].VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
1374 mVariableModuleGlobal->VolatileLastVariableOffset = sizeof (VARIABLE_STORE_HEADER);\r
1375\r
1376 VolatileVariableStore->Signature = VARIABLE_STORE_SIGNATURE;\r
1377 VolatileVariableStore->Size = VARIABLE_STORE_SIZE;\r
1378 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;\r
1379 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;\r
1380 VolatileVariableStore->Reserved = 0;\r
1381 VolatileVariableStore->Reserved1 = 0;\r
1382\r
1383 //\r
1384 // Get non volatile varaible store\r
1385 //\r
1386\r
1387 TempVariableStoreHeader = (UINT64) PcdGet32 (PcdFlashNvStorageVariableBase);\r
1388 VariableStoreEntry.Base = TempVariableStoreHeader + \\r
1389 (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);\r
1390 VariableStoreEntry.Length = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \\r
1391 (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);\r
1392 //\r
1393 // Mark the variable storage region of the FLASH as RUNTIME\r
1394 //\r
1395 BaseAddress = VariableStoreEntry.Base & (~EFI_PAGE_MASK);\r
1396 Length = VariableStoreEntry.Length + (VariableStoreEntry.Base - BaseAddress);\r
1397 Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);\r
1398\r
1399 Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);\r
1400 if (EFI_ERROR (Status)) {\r
1401 FreePool (mVariableModuleGlobal);\r
1402 FreePool (VolatileVariableStore);\r
1403 return EFI_UNSUPPORTED;\r
1404 }\r
1405\r
1406 Status = gDS->SetMemorySpaceAttributes (\r
1407 BaseAddress,\r
1408 Length,\r
1409 GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME\r
1410 );\r
1411 if (EFI_ERROR (Status)) {\r
1412 FreePool (mVariableModuleGlobal);\r
1413 FreePool (VolatileVariableStore);\r
1414 return EFI_UNSUPPORTED;\r
1415 }\r
1416 //\r
1417 // Get address of non volatile variable store base\r
1418 //\r
1419 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = VariableStoreEntry.Base;\r
1420\r
1421 //\r
1422 // Check Integrity\r
1423 //\r
1424 //\r
1425 // Find the Correct Instance of the FV Block Service.\r
1426 //\r
1427 Instance = 0;\r
1428 CurrPtr = (CHAR8 *) ((UINTN) mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase);\r
1429 while (EfiFvbGetPhysicalAddress (Instance, &FvVolHdr) == EFI_SUCCESS) {\r
1430 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);\r
1431 if (CurrPtr >= (CHAR8 *) FwVolHeader && CurrPtr < (((CHAR8 *) FwVolHeader) + FwVolHeader->FvLength)) {\r
1432 mVariableModuleGlobal->FvbInstance = Instance;\r
1433 break;\r
1434 }\r
1435\r
1436 Instance++;\r
1437 }\r
1438\r
1439 VariableStoreHeader = (VARIABLE_STORE_HEADER *) CurrPtr;\r
1440 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
1441 if (~VariableStoreHeader->Size == 0) {\r
1442 Status = UpdateVariableStore (\r
1443 &mVariableModuleGlobal->VariableGlobal[Physical],\r
1444 FALSE,\r
1445 FALSE,\r
1446 mVariableModuleGlobal->FvbInstance,\r
1447 (UINTN) &VariableStoreHeader->Size,\r
1448 sizeof (UINT32),\r
1449 (UINT8 *) &VariableStoreEntry.Length\r
1450 );\r
1451 //\r
1452 // As Variables are stored in NV storage, which are slow devices,such as flash.\r
1453 // Variable operation may skip checking variable program result to improve performance,\r
1454 // We can assume Variable program is OK through some check point.\r
1455 // Variable Store Size Setting should be the first Variable write operation,\r
1456 // We can assume all Read/Write is OK if we can set Variable store size successfully.\r
1457 // If write fail, we will assert here\r
1458 //\r
1459 ASSERT(VariableStoreHeader->Size == VariableStoreEntry.Length);\r
1460\r
1461 if (EFI_ERROR (Status)) {\r
1462 return Status;\r
1463 }\r
1464 }\r
1465\r
1466 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) CurrPtr);\r
1467 //\r
1468 // Parse non-volatile variable data and get last variable offset\r
1469 //\r
1470 NextVariable = (VARIABLE_HEADER *) (CurrPtr + sizeof (VARIABLE_STORE_HEADER));\r
1471 Status = EFI_SUCCESS;\r
1472\r
1473 while (IsValidVariableHeader (NextVariable)) {\r
1474 NextVariable = GetNextVariablePtr (NextVariable);\r
1475 }\r
1476\r
1477 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) CurrPtr;\r
1478\r
1479 //\r
1480 // Check if the free area is blow a threshold\r
1481 //\r
1482 if ((((VARIABLE_STORE_HEADER *)((UINTN) CurrPtr))->Size - mVariableModuleGlobal->NonVolatileLastVariableOffset) < VARIABLE_RECLAIM_THRESHOLD) {\r
1483 Status = Reclaim (\r
1484 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,\r
1485 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
1486 FALSE\r
1487 );\r
1488 }\r
1489\r
1490 if (EFI_ERROR (Status)) {\r
1491 FreePool (mVariableModuleGlobal);\r
1492 FreePool (VolatileVariableStore);\r
1493 return Status;\r
1494 }\r
1495\r
1496 //\r
1497 // Check if the free area is really free.\r
1498 //\r
1499 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {\r
1500 Data = ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase)[Index];\r
1501 if (Data != 0xff) {\r
1502 //\r
1503 // There must be something wrong in variable store, do reclaim operation.\r
1504 //\r
1505 Status = Reclaim (\r
1506 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,\r
1507 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
1508 FALSE\r
1509 );\r
1510 break;\r
1511 }\r
1512 }\r
1513 }\r
1514\r
1515 if (EFI_ERROR (Status)) {\r
1516 FreePool (mVariableModuleGlobal);\r
1517 FreePool (VolatileVariableStore);\r
1518 }\r
1519\r
1520 return Status;\r
1521}\r