]> git.proxmox.com Git - mirror_edk2.git/blame - EdkModulePkg/Universal/Variable/RuntimeDxe/Variable.c
Variable driver: add checking to make sure flash is properly initialized
[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
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
ce8bd86e 263 EfiInvalid Variable store status is invalid\r
878ddf1f 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
c8dd259d 427 ValidBuffer = AllocatePool (ValidBufferSize);\r
428 if (ValidBuffer == NULL) {\r
429 return EFI_OUT_OF_RESOURCES;\r
878ddf1f 430 }\r
431\r
432 SetMem (ValidBuffer, ValidBufferSize, 0xff);\r
433\r
434 CurrPtr = ValidBuffer;\r
435\r
436 //\r
437 // Copy variable store header\r
438 //\r
439 CopyMem (CurrPtr, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));\r
440 CurrPtr += sizeof (VARIABLE_STORE_HEADER);\r
441\r
442 //\r
443 // Start Pointers for the variable.\r
444 //\r
445 Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);\r
446\r
447 while (IsValidVariableHeader (Variable)) {\r
448 NextVariable = GetNextVariablePtr (Variable);\r
449 if (Variable->State == VAR_ADDED) {\r
450 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
451 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
452 CurrPtr += VariableSize;\r
453 }\r
454\r
455 Variable = NextVariable;\r
456 }\r
457\r
458 if (IsVolatile) {\r
459 //\r
460 // If volatile variable store, just copy valid buffer\r
461 //\r
462 SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);\r
463 CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, ValidBufferSize);\r
464 *LastVariableOffset = ValidBufferSize;\r
465 Status = EFI_SUCCESS;\r
466 } else {\r
467 //\r
468 // If non-volatile variable store, perform FTW here.\r
469 //\r
470 Status = FtwVariableSpace (\r
471 VariableBase,\r
472 ValidBuffer,\r
473 ValidBufferSize\r
474 );\r
475 if (!EFI_ERROR (Status)) {\r
476 *LastVariableOffset = ValidBufferSize;\r
477 }\r
478 }\r
479\r
c8dd259d 480 FreePool (ValidBuffer);\r
878ddf1f 481\r
482 if (EFI_ERROR (Status)) {\r
483 *LastVariableOffset = 0;\r
484 }\r
485\r
486 return Status;\r
487}\r
488\r
1cc8ee78 489STATIC\r
878ddf1f 490EFI_STATUS\r
491EFIAPI\r
492FindVariable (\r
493 IN CHAR16 *VariableName,\r
494 IN EFI_GUID *VendorGuid,\r
495 OUT VARIABLE_POINTER_TRACK *PtrTrack,\r
496 IN VARIABLE_GLOBAL *Global\r
497 )\r
498/*++\r
499\r
500Routine Description:\r
501\r
502 This code finds variable in storage blocks (Volatile or Non-Volatile)\r
503\r
504Arguments:\r
505\r
506 VariableName Name of the variable to be found\r
507 VendorGuid Vendor GUID to be found.\r
508 PtrTrack Variable Track Pointer structure that contains\r
509 Variable Information.\r
510 Contains the pointer of Variable header.\r
511 Global VARIABLE_GLOBAL pointer\r
512\r
513Returns:\r
514\r
515 EFI STATUS\r
516\r
517--*/\r
518{\r
519 VARIABLE_HEADER *Variable[2];\r
520 VARIABLE_STORE_HEADER *VariableStoreHeader[2];\r
521 UINTN Index;\r
522\r
6ed71dcc 523 //\r
524 // We aquire the lock at the entry of FindVariable as GetVariable, GetNextVariableName\r
525 // SetVariable all call FindVariable at entry point. Please move "Aquire Lock" to\r
526 // the correct places if this assumption does not hold TRUE anymore.\r
527 //\r
528 AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);\r
529\r
878ddf1f 530 //\r
531 // 0: Non-Volatile, 1: Volatile\r
532 //\r
533 VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase);\r
534 VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);\r
535\r
536 //\r
537 // Start Pointers for the variable.\r
538 // Actual Data Pointer where data can be written.\r
539 //\r
540 Variable[0] = (VARIABLE_HEADER *) (VariableStoreHeader[0] + 1);\r
541 Variable[1] = (VARIABLE_HEADER *) (VariableStoreHeader[1] + 1);\r
542\r
543 if (VariableName[0] != 0 && VendorGuid == NULL) {\r
544 return EFI_INVALID_PARAMETER;\r
545 }\r
546 //\r
547 // Find the variable by walk through non-volatile and volatile variable store\r
548 //\r
549 for (Index = 0; Index < 2; Index++) {\r
550 PtrTrack->StartPtr = (VARIABLE_HEADER *) (VariableStoreHeader[Index] + 1);\r
551 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]);\r
552\r
553 while (IsValidVariableHeader (Variable[Index]) && (Variable[Index] <= GetEndPointer (VariableStoreHeader[Index]))) {\r
554 if (Variable[Index]->State == VAR_ADDED) {\r
555 if (!(EfiAtRuntime () && !(Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS))) {\r
556 if (VariableName[0] == 0) {\r
557 PtrTrack->CurrPtr = Variable[Index];\r
558 PtrTrack->Volatile = (BOOLEAN) Index;\r
559 return EFI_SUCCESS;\r
560 } else {\r
561 if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) {\r
bb60dd97 562 if (!CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable[Index]), Variable[Index]->NameSize)) {\r
878ddf1f 563 PtrTrack->CurrPtr = Variable[Index];\r
564 PtrTrack->Volatile = (BOOLEAN) Index;\r
565 return EFI_SUCCESS;\r
566 }\r
567 }\r
568 }\r
569 }\r
570 }\r
571\r
572 Variable[Index] = GetNextVariablePtr (Variable[Index]);\r
573 }\r
574 //\r
575 // While (...)\r
576 //\r
577 }\r
578 //\r
579 // for (...)\r
580 //\r
581 PtrTrack->CurrPtr = NULL;\r
582 return EFI_NOT_FOUND;\r
583}\r
584\r
585EFI_STATUS\r
586EFIAPI\r
587GetVariable (\r
588 IN CHAR16 *VariableName,\r
589 IN EFI_GUID * VendorGuid,\r
590 OUT UINT32 *Attributes OPTIONAL,\r
591 IN OUT UINTN *DataSize,\r
592 OUT VOID *Data,\r
593 IN VARIABLE_GLOBAL * Global,\r
594 IN UINT32 Instance\r
595 )\r
596/*++\r
597\r
598Routine Description:\r
599\r
600 This code finds variable in storage blocks (Volatile or Non-Volatile)\r
601\r
602Arguments:\r
603\r
604 VariableName Name of Variable to be found\r
605 VendorGuid Variable vendor GUID\r
606 Attributes OPTIONAL Attribute value of the variable found\r
607 DataSize Size of Data found. If size is less than the\r
608 data, this value contains the required size.\r
609 Data Data pointer\r
610 Global Pointer to VARIABLE_GLOBAL structure\r
611 Instance Instance of the Firmware Volume.\r
612\r
613Returns:\r
614\r
615 EFI STATUS\r
616\r
617--*/\r
618{\r
619 VARIABLE_POINTER_TRACK Variable;\r
620 UINTN VarDataSize;\r
621 EFI_STATUS Status;\r
622\r
623 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
624 return EFI_INVALID_PARAMETER;\r
625 }\r
626 //\r
627 // Find existing variable\r
628 //\r
629 Status = FindVariable (VariableName, VendorGuid, &Variable, Global);\r
630\r
631 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
6ed71dcc 632 goto Done;\r
878ddf1f 633 }\r
634 //\r
635 // Get data size\r
636 //\r
637 VarDataSize = Variable.CurrPtr->DataSize;\r
638 if (*DataSize >= VarDataSize) {\r
639 if (Data == NULL) {\r
6ed71dcc 640 Status = EFI_INVALID_PARAMETER;\r
641 goto Done;\r
878ddf1f 642 }\r
643\r
644 CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);\r
645 if (Attributes != NULL) {\r
646 *Attributes = Variable.CurrPtr->Attributes;\r
647 }\r
648\r
649 *DataSize = VarDataSize;\r
6ed71dcc 650 Status = EFI_SUCCESS;\r
651 goto Done;\r
878ddf1f 652 } else {\r
653 *DataSize = VarDataSize;\r
6ed71dcc 654 Status = EFI_BUFFER_TOO_SMALL;\r
655 goto Done;\r
878ddf1f 656 }\r
6ed71dcc 657\r
658Done:\r
659 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
660 return Status;\r
878ddf1f 661}\r
662\r
663EFI_STATUS\r
664EFIAPI\r
665GetNextVariableName (\r
666 IN OUT UINTN *VariableNameSize,\r
667 IN OUT CHAR16 *VariableName,\r
668 IN OUT EFI_GUID *VendorGuid,\r
669 IN VARIABLE_GLOBAL *Global,\r
670 IN UINT32 Instance\r
671 )\r
672/*++\r
673\r
674Routine Description:\r
675\r
676 This code Finds the Next available variable\r
677\r
678Arguments:\r
679\r
680 VariableNameSize Size of the variable\r
681 VariableName Pointer to variable name\r
682 VendorGuid Variable Vendor Guid\r
683 Global VARIABLE_GLOBAL structure pointer.\r
684 Instance FV instance\r
685\r
686Returns:\r
687\r
688 EFI STATUS\r
689\r
690--*/\r
691{\r
692 VARIABLE_POINTER_TRACK Variable;\r
693 UINTN VarNameSize;\r
694 EFI_STATUS Status;\r
695\r
696 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
697 return EFI_INVALID_PARAMETER;\r
698 }\r
699\r
700 Status = FindVariable (VariableName, VendorGuid, &Variable, Global);\r
701\r
702 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
6ed71dcc 703 goto Done;\r
878ddf1f 704 }\r
705\r
706 if (VariableName[0] != 0) {\r
707 //\r
708 // If variable name is not NULL, get next variable\r
709 //\r
710 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
711 }\r
712\r
713 while (TRUE) {\r
714 //\r
715 // If both volatile and non-volatile variable store are parsed,\r
716 // return not found\r
717 //\r
718 if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) {\r
719 Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));\r
720 if (Variable.Volatile) {\r
721 Variable.StartPtr = (VARIABLE_HEADER *) ((UINTN) (Global->VolatileVariableBase + sizeof (VARIABLE_STORE_HEADER)));\r
722 Variable.EndPtr = (VARIABLE_HEADER *) GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase));\r
723 } else {\r
6ed71dcc 724 Status = EFI_NOT_FOUND;\r
725 goto Done;\r
878ddf1f 726 }\r
727\r
728 Variable.CurrPtr = Variable.StartPtr;\r
729 if (!IsValidVariableHeader (Variable.CurrPtr)) {\r
730 continue;\r
731 }\r
732 }\r
733 //\r
734 // Variable is found\r
735 //\r
736 if (IsValidVariableHeader (Variable.CurrPtr) && Variable.CurrPtr->State == VAR_ADDED) {\r
737 if (!(EfiAtRuntime () && !(Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS))) {\r
738 VarNameSize = Variable.CurrPtr->NameSize;\r
739 if (VarNameSize <= *VariableNameSize) {\r
740 CopyMem (\r
741 VariableName,\r
742 GET_VARIABLE_NAME_PTR (Variable.CurrPtr),\r
743 VarNameSize\r
744 );\r
745 CopyMem (\r
746 VendorGuid,\r
747 &Variable.CurrPtr->VendorGuid,\r
748 sizeof (EFI_GUID)\r
749 );\r
750 Status = EFI_SUCCESS;\r
751 } else {\r
752 Status = EFI_BUFFER_TOO_SMALL;\r
753 }\r
754\r
755 *VariableNameSize = VarNameSize;\r
6ed71dcc 756 goto Done;\r
878ddf1f 757 }\r
758 }\r
759\r
760 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
761 }\r
762\r
6ed71dcc 763Done:\r
764 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
765 return Status;\r
878ddf1f 766}\r
767\r
768EFI_STATUS\r
769EFIAPI\r
770SetVariable (\r
771 IN CHAR16 *VariableName,\r
772 IN EFI_GUID *VendorGuid,\r
773 IN UINT32 Attributes,\r
774 IN UINTN DataSize,\r
775 IN VOID *Data,\r
776 IN VARIABLE_GLOBAL *Global,\r
777 IN UINTN *VolatileOffset,\r
778 IN UINTN *NonVolatileOffset,\r
779 IN UINT32 Instance\r
780 )\r
781/*++\r
782\r
783Routine Description:\r
784\r
785 This code sets variable in storage blocks (Volatile or Non-Volatile)\r
786\r
787Arguments:\r
788\r
789 VariableName Name of Variable to be found\r
790 VendorGuid Variable vendor GUID\r
791 Attributes Attribute value of the variable found\r
792 DataSize Size of Data found. If size is less than the\r
793 data, this value contains the required size.\r
794 Data Data pointer\r
795 Global Pointer to VARIABLE_GLOBAL structure\r
796 VolatileOffset The offset of last volatile variable\r
797 NonVolatileOffset The offset of last non-volatile variable\r
798 Instance Instance of the Firmware Volume.\r
799\r
800Returns:\r
801\r
802 EFI STATUS\r
803 EFI_INVALID_PARAMETER - Invalid parameter\r
804 EFI_SUCCESS - Set successfully\r
805 EFI_OUT_OF_RESOURCES - Resource not enough to set variable\r
806 EFI_NOT_FOUND - Not found\r
807\r
808--*/\r
809{\r
810 VARIABLE_POINTER_TRACK Variable;\r
811 EFI_STATUS Status;\r
812 VARIABLE_HEADER *NextVariable;\r
813 UINTN VarNameSize;\r
814 UINTN VarNameOffset;\r
815 UINTN VarDataOffset;\r
816 UINTN VarSize;\r
817 UINT8 State;\r
818 BOOLEAN Reclaimed;\r
819\r
820 Reclaimed = FALSE;\r
821\r
822 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
823 return EFI_INVALID_PARAMETER;\r
824 }\r
825\r
826 Status = FindVariable (VariableName, VendorGuid, &Variable, Global);\r
827\r
828 if (Status == EFI_INVALID_PARAMETER) {\r
6ed71dcc 829 goto Done;\r
f53a0732 830 } else if (!EFI_ERROR (Status) && Variable.Volatile && EfiAtRuntime()) {\r
831 //\r
ce8bd86e 832 // If EfiAtRuntime and the variable is Volatile and Runtime Access,\r
833 // the volatile is ReadOnly, and SetVariable should be aborted and\r
f53a0732 834 // return EFI_WRITE_PROTECTED.\r
835 //\r
6ed71dcc 836 Status = EFI_WRITE_PROTECTED;\r
837 goto Done;\r
bb60dd97 838 } else if (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > MAX_VARIABLE_SIZE) {\r
f53a0732 839 //\r
840 // The size of the VariableName, including the Unicode Null in bytes plus\r
841 // the DataSize is limited to maximum size of MAX_VARIABLE_SIZE (1024) bytes.\r
842 //\r
6ed71dcc 843 Status = EFI_INVALID_PARAMETER;\r
844 goto Done;\r
f53a0732 845 } else if (Attributes == EFI_VARIABLE_NON_VOLATILE) {\r
846 //\r
ce8bd86e 847 // Make sure not only EFI_VARIABLE_NON_VOLATILE is set\r
f53a0732 848 //\r
6ed71dcc 849 Status = EFI_INVALID_PARAMETER;\r
850 goto Done;\r
ce8bd86e 851 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) ==\r
f53a0732 852 EFI_VARIABLE_RUNTIME_ACCESS) {\r
853 //\r
854 // Make sure if runtime bit is set, boot service bit is set also\r
855 //\r
6ed71dcc 856 Status = EFI_INVALID_PARAMETER;\r
857 goto Done;\r
f53a0732 858 } else if (EfiAtRuntime () && Attributes && !(Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {\r
859 //\r
860 // Runtime but Attribute is not Runtime\r
861 //\r
6ed71dcc 862 Status = EFI_INVALID_PARAMETER;\r
863 goto Done;\r
f53a0732 864 } else if (EfiAtRuntime () && Attributes && !(Attributes & EFI_VARIABLE_NON_VOLATILE)) {\r
865 //\r
866 // Cannot set volatile variable in Runtime\r
867 //\r
6ed71dcc 868 Status = EFI_INVALID_PARAMETER;\r
869 goto Done;\r
f53a0732 870 } else if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {\r
871 //\r
872 // Setting a data variable with no access, or zero DataSize attributes\r
873 // specified causes it to be deleted.\r
874 //\r
878ddf1f 875 if (!EFI_ERROR (Status)) {\r
876 State = Variable.CurrPtr->State;\r
877 State &= VAR_DELETED;\r
878\r
879 Status = UpdateVariableStore (\r
880 Global,\r
881 Variable.Volatile,\r
882 FALSE,\r
883 Instance,\r
884 (UINTN) &Variable.CurrPtr->State,\r
885 sizeof (UINT8),\r
886 &State\r
887 );\r
888 if (EFI_ERROR (Status)) {\r
6ed71dcc 889 goto Done;\r
878ddf1f 890 }\r
891\r
6ed71dcc 892 Status = EFI_SUCCESS;\r
893 goto Done;\r
878ddf1f 894 }\r
895\r
6ed71dcc 896 Status = EFI_NOT_FOUND;\r
897 goto Done;\r
878ddf1f 898 } else {\r
899 if (!EFI_ERROR (Status)) {\r
900 //\r
901 // If the variable is marked valid and the same data has been passed in\r
902 // then return to the caller immediately.\r
903 //\r
904 if (Variable.CurrPtr->DataSize == DataSize &&\r
905 !CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize)\r
906 ) {\r
6ed71dcc 907 Status = EFI_SUCCESS;\r
908 goto Done;\r
878ddf1f 909 } else if (Variable.CurrPtr->State == VAR_ADDED) {\r
910 //\r
911 // Mark the old variable as in delete transition\r
912 //\r
913 State = Variable.CurrPtr->State;\r
914 State &= VAR_IN_DELETED_TRANSITION;\r
915\r
916 Status = UpdateVariableStore (\r
917 Global,\r
918 Variable.Volatile,\r
919 FALSE,\r
920 Instance,\r
921 (UINTN) &Variable.CurrPtr->State,\r
922 sizeof (UINT8),\r
923 &State\r
924 );\r
925 if (EFI_ERROR (Status)) {\r
6ed71dcc 926 goto Done;\r
878ddf1f 927 }\r
928 }\r
929 }\r
930 //\r
931 // Create a new variable and copy the data.\r
932 //\r
933 // Tricky part: Use scratch data area at the end of volatile variable store\r
934 // as a temporary storage.\r
935 //\r
936 NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase));\r
937\r
938 SetMem (NextVariable, SCRATCH_SIZE, 0xff);\r
939\r
940 NextVariable->StartId = VARIABLE_DATA;\r
941 NextVariable->Attributes = Attributes;\r
942 //\r
943 // NextVariable->State = VAR_ADDED;\r
944 //\r
945 NextVariable->Reserved = 0;\r
946 VarNameOffset = sizeof (VARIABLE_HEADER);\r
bb60dd97 947 VarNameSize = StrSize (VariableName);\r
878ddf1f 948 CopyMem (\r
949 (UINT8 *) ((UINTN) NextVariable + VarNameOffset),\r
950 VariableName,\r
951 VarNameSize\r
952 );\r
953 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);\r
954 CopyMem (\r
955 (UINT8 *) ((UINTN) NextVariable + VarDataOffset),\r
956 Data,\r
957 DataSize\r
958 );\r
959 CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));\r
960 //\r
961 // There will be pad bytes after Data, the NextVariable->NameSize and\r
962 // NextVariable->DataSize should not include pad size so that variable\r
963 // service can get actual size in GetVariable\r
964 //\r
965 NextVariable->NameSize = (UINT32)VarNameSize;\r
966 NextVariable->DataSize = (UINT32)DataSize;\r
967\r
968 //\r
969 // The actual size of the variable that stores in storage should\r
970 // include pad size.\r
971 //\r
972 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);\r
973 if (Attributes & EFI_VARIABLE_NON_VOLATILE) {\r
974 if ((UINT32) (VarSize +*NonVolatileOffset) >\r
975 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->NonVolatileVariableBase)))->Size\r
976 ) {\r
977 if (EfiAtRuntime ()) {\r
6ed71dcc 978 Status = EFI_OUT_OF_RESOURCES;\r
979 goto Done;\r
878ddf1f 980 }\r
981 //\r
982 // Perform garbage collection & reclaim operation\r
983 //\r
984 Status = Reclaim (Global->NonVolatileVariableBase, NonVolatileOffset, FALSE);\r
985 if (EFI_ERROR (Status)) {\r
6ed71dcc 986 goto Done;\r
878ddf1f 987 }\r
988 //\r
989 // If still no enough space, return out of resources\r
990 //\r
991 if ((UINT32) (VarSize +*NonVolatileOffset) >\r
992 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->NonVolatileVariableBase)))->Size\r
993 ) {\r
6ed71dcc 994 Status = EFI_OUT_OF_RESOURCES;\r
995 goto Done;\r
878ddf1f 996 }\r
ce8bd86e 997\r
878ddf1f 998 Reclaimed = TRUE;\r
999 }\r
1000 //\r
1001 // Three steps\r
1002 // 1. Write variable header\r
1003 // 2. Write variable data\r
1004 // 3. Set variable state to valid\r
1005 //\r
1006 //\r
1007 // Step 1:\r
1008 //\r
1009 Status = UpdateVariableStore (\r
1010 Global,\r
1011 FALSE,\r
1012 TRUE,\r
1013 Instance,\r
1014 *NonVolatileOffset,\r
1015 sizeof (VARIABLE_HEADER),\r
1016 (UINT8 *) NextVariable\r
1017 );\r
1018\r
1019 if (EFI_ERROR (Status)) {\r
6ed71dcc 1020 goto Done;\r
878ddf1f 1021 }\r
1022 //\r
1023 // Step 2:\r
1024 //\r
1025 Status = UpdateVariableStore (\r
1026 Global,\r
1027 FALSE,\r
1028 TRUE,\r
1029 Instance,\r
1030 *NonVolatileOffset + sizeof (VARIABLE_HEADER),\r
1031 (UINT32) VarSize - sizeof (VARIABLE_HEADER),\r
1032 (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)\r
1033 );\r
1034\r
1035 if (EFI_ERROR (Status)) {\r
6ed71dcc 1036 goto Done;\r
878ddf1f 1037 }\r
1038 //\r
1039 // Step 3:\r
1040 //\r
1041 NextVariable->State = VAR_ADDED;\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 *NonVolatileOffset = *NonVolatileOffset + VarSize;\r
1057\r
1058 } else {\r
1059 if (EfiAtRuntime ()) {\r
6ed71dcc 1060 Status = EFI_INVALID_PARAMETER;\r
1061 goto Done;\r
878ddf1f 1062 }\r
1063\r
1064 if ((UINT32) (VarSize +*VolatileOffset) >\r
1065 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size\r
1066 ) {\r
1067 //\r
1068 // Perform garbage collection & reclaim operation\r
1069 //\r
1070 Status = Reclaim (Global->VolatileVariableBase, VolatileOffset, TRUE);\r
1071 if (EFI_ERROR (Status)) {\r
6ed71dcc 1072 goto Done;\r
878ddf1f 1073 }\r
1074 //\r
1075 // If still no enough space, return out of resources\r
1076 //\r
1077 if ((UINT32) (VarSize +*VolatileOffset) >\r
1078 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size\r
1079 ) {\r
6ed71dcc 1080 Status = EFI_OUT_OF_RESOURCES;\r
1081 goto Done;\r
878ddf1f 1082 }\r
ce8bd86e 1083\r
878ddf1f 1084 Reclaimed = TRUE;\r
1085 }\r
1086\r
1087 NextVariable->State = VAR_ADDED;\r
1088 Status = UpdateVariableStore (\r
1089 Global,\r
1090 TRUE,\r
1091 TRUE,\r
1092 Instance,\r
1093 *VolatileOffset,\r
1094 (UINT32) VarSize,\r
1095 (UINT8 *) NextVariable\r
1096 );\r
1097\r
1098 if (EFI_ERROR (Status)) {\r
6ed71dcc 1099 goto Done;\r
878ddf1f 1100 }\r
1101\r
1102 *VolatileOffset = *VolatileOffset + VarSize;\r
1103 }\r
1104 //\r
1105 // Mark the old variable as deleted\r
1106 //\r
1107 if (!Reclaimed && !EFI_ERROR (Status) && Variable.CurrPtr != NULL) {\r
1108 State = Variable.CurrPtr->State;\r
1109 State &= VAR_DELETED;\r
1110\r
1111 Status = UpdateVariableStore (\r
1112 Global,\r
1113 Variable.Volatile,\r
1114 FALSE,\r
1115 Instance,\r
1116 (UINTN) &Variable.CurrPtr->State,\r
1117 sizeof (UINT8),\r
1118 &State\r
1119 );\r
1120\r
1121 if (EFI_ERROR (Status)) {\r
6ed71dcc 1122 goto Done;\r
878ddf1f 1123 }\r
1124 }\r
1125 }\r
1126\r
6ed71dcc 1127 Status = EFI_SUCCESS;\r
1128Done:\r
1129 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
1130 return Status;\r
878ddf1f 1131}\r
1132\r
045f4521 1133EFI_STATUS\r
1134EFIAPI\r
1135QueryVariableInfo (\r
1136 IN UINT32 Attributes,\r
1137 OUT UINT64 *MaximumVariableStorageSize,\r
1138 OUT UINT64 *RemainingVariableStorageSize,\r
1139 OUT UINT64 *MaximumVariableSize,\r
1140 IN VARIABLE_GLOBAL *Global,\r
1141 IN UINT32 Instance\r
1142 )\r
1143/*++\r
1144\r
1145Routine Description:\r
1146\r
1147 This code returns information about the EFI variables.\r
1148\r
1149Arguments:\r
1150\r
ce8bd86e 1151 Attributes Attributes bitmask to specify the type of variables\r
045f4521 1152 on which to return information.\r
1153 MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
1154 for the EFI variables associated with the attributes specified.\r
ce8bd86e 1155 RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
045f4521 1156 for the EFI variables associated with the attributes specified.\r
1157 MaximumVariableSize Pointer to the maximum size of the individual EFI variables\r
1158 associated with the attributes specified.\r
1159 Global Pointer to VARIABLE_GLOBAL structure.\r
1160 Instance Instance of the Firmware Volume.\r
1161\r
1162Returns:\r
1163\r
1164 EFI STATUS\r
1165 EFI_INVALID_PARAMETER - An invalid combination of attribute bits was supplied.\r
1166 EFI_SUCCESS - Query successfully.\r
1167 EFI_UNSUPPORTED - The attribute is not supported on this platform.\r
1168\r
1169--*/\r
1170{\r
1171 VARIABLE_HEADER *Variable;\r
1172 VARIABLE_HEADER *NextVariable;\r
1173 UINT64 VariableSize;\r
1174 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
6ed71dcc 1175\r
045f4521 1176 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL) {\r
1177 return EFI_INVALID_PARAMETER;\r
1178 }\r
1179\r
1180 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS)) == 0) {\r
1181 //\r
1182 // Make sure the Attributes combination is supported by the platform.\r
1183 //\r
1184 return EFI_UNSUPPORTED;\r
1185 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
1186 //\r
1187 // Make sure if runtime bit is set, boot service bit is set also.\r
1188 //\r
1189 return EFI_INVALID_PARAMETER;\r
1190 } else if (EfiAtRuntime () && !(Attributes & EFI_VARIABLE_RUNTIME_ACCESS)) {\r
1191 //\r
1192 // Make sure RT Attribute is set if we are in Runtime phase.\r
1193 //\r
1194 return EFI_INVALID_PARAMETER;\r
1195 }\r
1196\r
6ed71dcc 1197 AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);\r
ce8bd86e 1198\r
045f4521 1199 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
1200 //\r
1201 // Query is Volatile related.\r
1202 //\r
ce8bd86e 1203 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);\r
045f4521 1204 } else {\r
1205 //\r
1206 // Query is Non-Volatile related.\r
1207 //\r
1208 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase);\r
1209 }\r
1210\r
1211 //\r
ce8bd86e 1212 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize\r
045f4521 1213 // with the storage size (excluding the storage header size).\r
1214 //\r
1215 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
1216 *RemainingVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
1217\r
1218 //\r
1219 // Let *MaximumVariableSize be MAX_VARIABLE_SIZE.\r
1220 //\r
1221 *MaximumVariableSize = MAX_VARIABLE_SIZE;\r
1222\r
1223 //\r
1224 // Point to the starting address of the variables.\r
1225 //\r
1226 Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);\r
1227\r
1228 //\r
1229 // Now walk through the related variable store.\r
1230 //\r
1231 while (IsValidVariableHeader (Variable) && (Variable < GetEndPointer (VariableStoreHeader))) {\r
1232 NextVariable = GetNextVariablePtr (Variable);\r
1233 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;\r
1234\r
1235 if (EfiAtRuntime ()) {\r
1236 //\r
ce8bd86e 1237 // we don't take the state of the variables in mind\r
045f4521 1238 // when calculating RemainingVariableStorageSize,\r
ce8bd86e 1239 // since the space occupied by variables not marked with\r
045f4521 1240 // VAR_ADDED is not allowed to be reclaimed in Runtime.\r
1241 //\r
1242 *RemainingVariableStorageSize -= VariableSize;\r
1243 } else {\r
1244 //\r
ce8bd86e 1245 // Only care about Variables with State VAR_ADDED,because\r
045f4521 1246 // the space not marked as VAR_ADDED is reclaimable now.\r
1247 //\r
1248 if (Variable->State == VAR_ADDED) {\r
1249 *RemainingVariableStorageSize -= VariableSize;\r
1250 }\r
1251 }\r
c8dd259d 1252\r
045f4521 1253 //\r
1254 // Go to the next one\r
1255 //\r
1256 Variable = NextVariable;\r
1257 }\r
c8dd259d 1258\r
6ed71dcc 1259 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);\r
045f4521 1260 return EFI_SUCCESS;\r
1261}\r
045f4521 1262\r
878ddf1f 1263EFI_STATUS\r
1264EFIAPI\r
1265VariableCommonInitialize (\r
1266 IN EFI_HANDLE ImageHandle,\r
1267 IN EFI_SYSTEM_TABLE *SystemTable\r
1268 )\r
1269/*++\r
1270\r
1271Routine Description:\r
1272 This function does common initialization for variable services\r
1273\r
1274Arguments:\r
1275\r
1276 ImageHandle - The firmware allocated handle for the EFI image.\r
1277 SystemTable - A pointer to the EFI System Table.\r
1278\r
1279Returns:\r
ce8bd86e 1280\r
878ddf1f 1281 Status code.\r
ce8bd86e 1282\r
878ddf1f 1283 EFI_NOT_FOUND - Variable store area not found.\r
1284 EFI_UNSUPPORTED - Currently only one non-volatile variable store is supported.\r
1285 EFI_SUCCESS - Variable services successfully initialized.\r
1286\r
1287--*/\r
1288{\r
1289 EFI_STATUS Status;\r
1290 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
1291 CHAR8 *CurrPtr;\r
1292 VARIABLE_STORE_HEADER *VolatileVariableStore;\r
1293 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
1294 VARIABLE_HEADER *NextVariable;\r
1295 UINT32 Instance;\r
1296 EFI_PHYSICAL_ADDRESS FvVolHdr;\r
1297\r
202c5d55 1298 UINT64 TempVariableStoreHeader;\r
1299\r
878ddf1f 1300 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
1301 EFI_FLASH_SUBAREA_ENTRY VariableStoreEntry;\r
1302 UINT64 BaseAddress;\r
1303 UINT64 Length;\r
1304 UINTN Index;\r
1305 UINT8 Data;\r
878ddf1f 1306\r
c8dd259d 1307 mVariableModuleGlobal = AllocateRuntimePool (sizeof (ESAL_VARIABLE_GLOBAL));\r
1308 if (mVariableModuleGlobal == NULL) {\r
1309 return EFI_OUT_OF_RESOURCES;\r
878ddf1f 1310 }\r
6ed71dcc 1311\r
6dcb94c7 1312 EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal[Physical].VariableServicesLock, EFI_TPL_NOTIFY);\r
ce8bd86e 1313\r
878ddf1f 1314 //\r
1315 // Allocate memory for volatile variable store\r
1316 //\r
c8dd259d 1317 VolatileVariableStore = AllocateRuntimePool (VARIABLE_STORE_SIZE + SCRATCH_SIZE);\r
1318 if (VolatileVariableStore == NULL) {\r
1319 FreePool (mVariableModuleGlobal);\r
1320 return EFI_OUT_OF_RESOURCES;\r
878ddf1f 1321 }\r
1322\r
1323 SetMem (VolatileVariableStore, VARIABLE_STORE_SIZE + SCRATCH_SIZE, 0xff);\r
1324\r
1325 //\r
1326 // Variable Specific Data\r
1327 //\r
6ed71dcc 1328 mVariableModuleGlobal->VariableGlobal[Physical].VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
878ddf1f 1329 mVariableModuleGlobal->VolatileLastVariableOffset = sizeof (VARIABLE_STORE_HEADER);\r
1330\r
1331 VolatileVariableStore->Signature = VARIABLE_STORE_SIGNATURE;\r
1332 VolatileVariableStore->Size = VARIABLE_STORE_SIZE;\r
1333 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;\r
1334 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;\r
1335 VolatileVariableStore->Reserved = 0;\r
1336 VolatileVariableStore->Reserved1 = 0;\r
1337\r
1338 //\r
1339 // Get non volatile varaible store\r
1340 //\r
1341\r
202c5d55 1342 TempVariableStoreHeader = (UINT64) PcdGet32 (PcdFlashNvStorageVariableBase);\r
1343 VariableStoreEntry.Base = TempVariableStoreHeader + \\r
1344 (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);\r
1345 VariableStoreEntry.Length = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \\r
1346 (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);\r
878ddf1f 1347 //\r
1348 // Mark the variable storage region of the FLASH as RUNTIME\r
1349 //\r
1350 BaseAddress = VariableStoreEntry.Base & (~EFI_PAGE_MASK);\r
1351 Length = VariableStoreEntry.Length + (VariableStoreEntry.Base - BaseAddress);\r
1352 Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);\r
1353\r
1354 Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);\r
1355 if (EFI_ERROR (Status)) {\r
c8dd259d 1356 FreePool (mVariableModuleGlobal);\r
1357 FreePool (VolatileVariableStore);\r
878ddf1f 1358 return EFI_UNSUPPORTED;\r
1359 }\r
1360\r
1361 Status = gDS->SetMemorySpaceAttributes (\r
1362 BaseAddress,\r
1363 Length,\r
1364 GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME\r
1365 );\r
1366 if (EFI_ERROR (Status)) {\r
c8dd259d 1367 FreePool (mVariableModuleGlobal);\r
1368 FreePool (VolatileVariableStore);\r
878ddf1f 1369 return EFI_UNSUPPORTED;\r
1370 }\r
1371 //\r
1372 // Get address of non volatile variable store base\r
1373 //\r
6ed71dcc 1374 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = VariableStoreEntry.Base;\r
878ddf1f 1375\r
1376 //\r
1377 // Check Integrity\r
1378 //\r
1379 //\r
1380 // Find the Correct Instance of the FV Block Service.\r
1381 //\r
1382 Instance = 0;\r
6ed71dcc 1383 CurrPtr = (CHAR8 *) ((UINTN) mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase);\r
878ddf1f 1384 while (EfiFvbGetPhysicalAddress (Instance, &FvVolHdr) == EFI_SUCCESS) {\r
1385 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);\r
1386 if (CurrPtr >= (CHAR8 *) FwVolHeader && CurrPtr < (((CHAR8 *) FwVolHeader) + FwVolHeader->FvLength)) {\r
1387 mVariableModuleGlobal->FvbInstance = Instance;\r
1388 break;\r
1389 }\r
1390\r
1391 Instance++;\r
1392 }\r
1393\r
1394 VariableStoreHeader = (VARIABLE_STORE_HEADER *) CurrPtr;\r
1395 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
1396 if (~VariableStoreHeader->Size == 0) {\r
1397 Status = UpdateVariableStore (\r
6ed71dcc 1398 &mVariableModuleGlobal->VariableGlobal[Physical],\r
878ddf1f 1399 FALSE,\r
1400 FALSE,\r
1401 mVariableModuleGlobal->FvbInstance,\r
1402 (UINTN) &VariableStoreHeader->Size,\r
1403 sizeof (UINT32),\r
1404 (UINT8 *) &VariableStoreEntry.Length\r
1405 );\r
02dab428 1406 // \r
1407 // As Variables are stored in NV storage, which are slow devices,such as flash.\r
1408 // Variable operation may skip checking variable program result to improve performance,\r
1409 // We can assume Variable program is OK through some check point.\r
1410 // Variable Store Size Setting should be the first Variable write operation,\r
1411 // We can assume all Read/Write is OK if we can set Variable store size successfully.\r
1412 // If write fail, we will assert here\r
1413 //\r
1414 ASSERT(VariableStoreHeader->Size == VariableStoreEntry.Length);\r
878ddf1f 1415\r
1416 if (EFI_ERROR (Status)) {\r
1417 return Status;\r
1418 }\r
1419 }\r
1420\r
6ed71dcc 1421 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) CurrPtr);\r
878ddf1f 1422 //\r
1423 // Parse non-volatile variable data and get last variable offset\r
1424 //\r
1425 NextVariable = (VARIABLE_HEADER *) (CurrPtr + sizeof (VARIABLE_STORE_HEADER));\r
1426 Status = EFI_SUCCESS;\r
1427\r
1428 while (IsValidVariableHeader (NextVariable)) {\r
1429 NextVariable = GetNextVariablePtr (NextVariable);\r
1430 }\r
1431\r
1432 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) CurrPtr;\r
1433\r
c65c1e1e 1434 //\r
1435 // Check if the free area is blow a threshold\r
1436 //\r
1437 if ((((VARIABLE_STORE_HEADER *)((UINTN) CurrPtr))->Size - mVariableModuleGlobal->NonVolatileLastVariableOffset) < VARIABLE_RECLAIM_THRESHOLD) {\r
1438 Status = Reclaim (\r
6ed71dcc 1439 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,\r
c65c1e1e 1440 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
1441 FALSE\r
1442 );\r
1443 }\r
1444\r
1445 if (EFI_ERROR (Status)) {\r
c8dd259d 1446 FreePool (mVariableModuleGlobal);\r
1447 FreePool (VolatileVariableStore);\r
c65c1e1e 1448 return Status;\r
1449 }\r
1450\r
878ddf1f 1451 //\r
1452 // Check if the free area is really free.\r
1453 //\r
1454 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {\r
6ed71dcc 1455 Data = ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase)[Index];\r
878ddf1f 1456 if (Data != 0xff) {\r
1457 //\r
1458 // There must be something wrong in variable store, do reclaim operation.\r
1459 //\r
1460 Status = Reclaim (\r
6ed71dcc 1461 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,\r
878ddf1f 1462 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
1463 FALSE\r
1464 );\r
1465 break;\r
1466 }\r
1467 }\r
1468 }\r
1469\r
1470 if (EFI_ERROR (Status)) {\r
c8dd259d 1471 FreePool (mVariableModuleGlobal);\r
1472 FreePool (VolatileVariableStore);\r
878ddf1f 1473 }\r
1474\r
1475 return Status;\r
1476}\r