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