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