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