]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
1. Don't assume that flush the HOB variable to flash must be successful.
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / Variable.c
... / ...
CommitLineData
1/** @file\r
2\r
3 The common variable operation routines shared by DXE_RUNTIME variable \r
4 module and DXE_SMM variable module.\r
5 \r
6Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>\r
7This program and the accompanying materials \r
8are licensed and made available under the terms and conditions of the BSD License \r
9which accompanies this distribution. The full text of the license may be found at \r
10http://opensource.org/licenses/bsd-license.php \r
11\r
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
14\r
15**/\r
16\r
17#include "Variable.h"\r
18\r
19VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;\r
20\r
21///\r
22/// Define a memory cache that improves the search performance for a variable.\r
23///\r
24VARIABLE_STORE_HEADER *mNvVariableCache = NULL;\r
25\r
26///\r
27/// The memory entry used for variable statistics data.\r
28///\r
29VARIABLE_INFO_ENTRY *gVariableInfo = NULL;\r
30\r
31\r
32/**\r
33 Routine used to track statistical information about variable usage. \r
34 The data is stored in the EFI system table so it can be accessed later.\r
35 VariableInfo.efi can dump out the table. Only Boot Services variable \r
36 accesses are tracked by this code. The PcdVariableCollectStatistics\r
37 build flag controls if this feature is enabled. \r
38\r
39 A read that hits in the cache will have Read and Cache true for \r
40 the transaction. Data is allocated by this routine, but never\r
41 freed.\r
42\r
43 @param[in] VariableName Name of the Variable to track.\r
44 @param[in] VendorGuid Guid of the Variable to track.\r
45 @param[in] Volatile TRUE if volatile FALSE if non-volatile.\r
46 @param[in] Read TRUE if GetVariable() was called.\r
47 @param[in] Write TRUE if SetVariable() was called.\r
48 @param[in] Delete TRUE if deleted via SetVariable().\r
49 @param[in] Cache TRUE for a cache hit.\r
50\r
51**/\r
52VOID\r
53UpdateVariableInfo (\r
54 IN CHAR16 *VariableName,\r
55 IN EFI_GUID *VendorGuid,\r
56 IN BOOLEAN Volatile,\r
57 IN BOOLEAN Read,\r
58 IN BOOLEAN Write,\r
59 IN BOOLEAN Delete,\r
60 IN BOOLEAN Cache\r
61 )\r
62{\r
63 VARIABLE_INFO_ENTRY *Entry;\r
64\r
65 if (FeaturePcdGet (PcdVariableCollectStatistics)) {\r
66\r
67 if (AtRuntime ()) {\r
68 // Don't collect statistics at runtime.\r
69 return;\r
70 }\r
71\r
72 if (gVariableInfo == NULL) {\r
73 //\r
74 // On the first call allocate a entry and place a pointer to it in\r
75 // the EFI System Table.\r
76 //\r
77 gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
78 ASSERT (gVariableInfo != NULL);\r
79\r
80 CopyGuid (&gVariableInfo->VendorGuid, VendorGuid);\r
81 gVariableInfo->Name = AllocatePool (StrSize (VariableName));\r
82 ASSERT (gVariableInfo->Name != NULL);\r
83 StrCpy (gVariableInfo->Name, VariableName);\r
84 gVariableInfo->Volatile = Volatile;\r
85 }\r
86\r
87 \r
88 for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) {\r
89 if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {\r
90 if (StrCmp (VariableName, Entry->Name) == 0) {\r
91 if (Read) {\r
92 Entry->ReadCount++;\r
93 }\r
94 if (Write) {\r
95 Entry->WriteCount++;\r
96 }\r
97 if (Delete) {\r
98 Entry->DeleteCount++;\r
99 }\r
100 if (Cache) {\r
101 Entry->CacheCount++;\r
102 }\r
103\r
104 return;\r
105 }\r
106 }\r
107\r
108 if (Entry->Next == NULL) {\r
109 //\r
110 // If the entry is not in the table add it.\r
111 // Next iteration of the loop will fill in the data.\r
112 //\r
113 Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
114 ASSERT (Entry->Next != NULL);\r
115\r
116 CopyGuid (&Entry->Next->VendorGuid, VendorGuid);\r
117 Entry->Next->Name = AllocatePool (StrSize (VariableName));\r
118 ASSERT (Entry->Next->Name != NULL);\r
119 StrCpy (Entry->Next->Name, VariableName);\r
120 Entry->Next->Volatile = Volatile;\r
121 }\r
122\r
123 }\r
124 }\r
125}\r
126\r
127\r
128/**\r
129\r
130 This code checks if variable header is valid or not.\r
131\r
132 @param Variable Pointer to the Variable Header.\r
133\r
134 @retval TRUE Variable header is valid.\r
135 @retval FALSE Variable header is not valid.\r
136\r
137**/\r
138BOOLEAN\r
139IsValidVariableHeader (\r
140 IN VARIABLE_HEADER *Variable\r
141 )\r
142{\r
143 if (Variable == NULL || Variable->StartId != VARIABLE_DATA) {\r
144 return FALSE;\r
145 }\r
146\r
147 return TRUE;\r
148}\r
149\r
150\r
151/**\r
152\r
153 This function writes data to the FWH at the correct LBA even if the LBAs\r
154 are fragmented.\r
155\r
156 @param Global Pointer to VARAIBLE_GLOBAL structure.\r
157 @param Volatile Point out the Variable is Volatile or Non-Volatile.\r
158 @param SetByIndex TRUE if target pointer is given as index.\r
159 FALSE if target pointer is absolute.\r
160 @param Fvb Pointer to the writable FVB protocol.\r
161 @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER\r
162 structure.\r
163 @param DataSize Size of data to be written.\r
164 @param Buffer Pointer to the buffer from which data is written.\r
165\r
166 @retval EFI_INVALID_PARAMETER Parameters not valid.\r
167 @retval EFI_SUCCESS Variable store successfully updated.\r
168\r
169**/\r
170EFI_STATUS\r
171UpdateVariableStore (\r
172 IN VARIABLE_GLOBAL *Global,\r
173 IN BOOLEAN Volatile,\r
174 IN BOOLEAN SetByIndex,\r
175 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,\r
176 IN UINTN DataPtrIndex,\r
177 IN UINT32 DataSize,\r
178 IN UINT8 *Buffer\r
179 )\r
180{\r
181 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
182 UINTN BlockIndex2;\r
183 UINTN LinearOffset;\r
184 UINTN CurrWriteSize;\r
185 UINTN CurrWritePtr;\r
186 UINT8 *CurrBuffer;\r
187 EFI_LBA LbaNumber;\r
188 UINTN Size;\r
189 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
190 VARIABLE_STORE_HEADER *VolatileBase;\r
191 EFI_PHYSICAL_ADDRESS FvVolHdr;\r
192 EFI_PHYSICAL_ADDRESS DataPtr;\r
193 EFI_STATUS Status;\r
194\r
195 FwVolHeader = NULL;\r
196 DataPtr = DataPtrIndex;\r
197\r
198 //\r
199 // Check if the Data is Volatile.\r
200 //\r
201 if (!Volatile) {\r
202 ASSERT (Fvb != NULL);\r
203 Status = Fvb->GetPhysicalAddress(Fvb, &FvVolHdr);\r
204 ASSERT_EFI_ERROR (Status);\r
205\r
206 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);\r
207 //\r
208 // Data Pointer should point to the actual Address where data is to be\r
209 // written.\r
210 //\r
211 if (SetByIndex) {\r
212 DataPtr += mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
213 }\r
214\r
215 if ((DataPtr + DataSize) >= ((EFI_PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) FwVolHeader + FwVolHeader->FvLength))) {\r
216 return EFI_INVALID_PARAMETER;\r
217 }\r
218 } else {\r
219 //\r
220 // Data Pointer should point to the actual Address where data is to be\r
221 // written.\r
222 //\r
223 VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
224 if (SetByIndex) {\r
225 DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
226 }\r
227\r
228 if ((DataPtr + DataSize) >= ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) {\r
229 return EFI_INVALID_PARAMETER;\r
230 }\r
231 \r
232 //\r
233 // If Volatile Variable just do a simple mem copy.\r
234 // \r
235 CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize);\r
236 return EFI_SUCCESS;\r
237 }\r
238 \r
239 //\r
240 // If we are here we are dealing with Non-Volatile Variables.\r
241 //\r
242 LinearOffset = (UINTN) FwVolHeader;\r
243 CurrWritePtr = (UINTN) DataPtr;\r
244 CurrWriteSize = DataSize;\r
245 CurrBuffer = Buffer;\r
246 LbaNumber = 0;\r
247\r
248 if (CurrWritePtr < LinearOffset) {\r
249 return EFI_INVALID_PARAMETER;\r
250 }\r
251\r
252 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
253 for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {\r
254 //\r
255 // Check to see if the Variable Writes are spanning through multiple\r
256 // blocks.\r
257 //\r
258 if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) {\r
259 if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {\r
260 Status = Fvb->Write (\r
261 Fvb,\r
262 LbaNumber,\r
263 (UINTN) (CurrWritePtr - LinearOffset),\r
264 &CurrWriteSize,\r
265 CurrBuffer\r
266 );\r
267 return Status;\r
268 } else {\r
269 Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);\r
270 Status = Fvb->Write (\r
271 Fvb,\r
272 LbaNumber,\r
273 (UINTN) (CurrWritePtr - LinearOffset),\r
274 &Size,\r
275 CurrBuffer\r
276 );\r
277 if (EFI_ERROR (Status)) {\r
278 return Status;\r
279 }\r
280\r
281 CurrWritePtr = LinearOffset + PtrBlockMapEntry->Length;\r
282 CurrBuffer = CurrBuffer + Size;\r
283 CurrWriteSize = CurrWriteSize - Size;\r
284 }\r
285 }\r
286\r
287 LinearOffset += PtrBlockMapEntry->Length;\r
288 LbaNumber++;\r
289 }\r
290 }\r
291\r
292 return EFI_SUCCESS;\r
293}\r
294\r
295\r
296/**\r
297\r
298 This code gets the current status of Variable Store.\r
299\r
300 @param VarStoreHeader Pointer to the Variable Store Header.\r
301\r
302 @retval EfiRaw Variable store status is raw.\r
303 @retval EfiValid Variable store status is valid.\r
304 @retval EfiInvalid Variable store status is invalid.\r
305\r
306**/\r
307VARIABLE_STORE_STATUS\r
308GetVariableStoreStatus (\r
309 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
310 )\r
311{\r
312 if (CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid) &&\r
313 VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&\r
314 VarStoreHeader->State == VARIABLE_STORE_HEALTHY\r
315 ) {\r
316\r
317 return EfiValid;\r
318 } else if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff &&\r
319 ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff &&\r
320 ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff &&\r
321 ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff &&\r
322 VarStoreHeader->Size == 0xffffffff &&\r
323 VarStoreHeader->Format == 0xff &&\r
324 VarStoreHeader->State == 0xff\r
325 ) {\r
326\r
327 return EfiRaw;\r
328 } else {\r
329 return EfiInvalid;\r
330 }\r
331}\r
332\r
333\r
334/**\r
335\r
336 This code gets the size of name of variable.\r
337\r
338 @param Variable Pointer to the Variable Header.\r
339\r
340 @return UINTN Size of variable in bytes.\r
341\r
342**/\r
343UINTN\r
344NameSizeOfVariable (\r
345 IN VARIABLE_HEADER *Variable\r
346 )\r
347{\r
348 if (Variable->State == (UINT8) (-1) ||\r
349 Variable->DataSize == (UINT32) (-1) ||\r
350 Variable->NameSize == (UINT32) (-1) ||\r
351 Variable->Attributes == (UINT32) (-1)) {\r
352 return 0;\r
353 }\r
354 return (UINTN) Variable->NameSize;\r
355}\r
356\r
357/**\r
358\r
359 This code gets the size of variable data.\r
360\r
361 @param Variable Pointer to the Variable Header.\r
362\r
363 @return Size of variable in bytes.\r
364\r
365**/\r
366UINTN\r
367DataSizeOfVariable (\r
368 IN VARIABLE_HEADER *Variable\r
369 )\r
370{\r
371 if (Variable->State == (UINT8) (-1) ||\r
372 Variable->DataSize == (UINT32) (-1) ||\r
373 Variable->NameSize == (UINT32) (-1) ||\r
374 Variable->Attributes == (UINT32) (-1)) {\r
375 return 0;\r
376 }\r
377 return (UINTN) Variable->DataSize;\r
378}\r
379\r
380/**\r
381\r
382 This code gets the pointer to the variable name.\r
383\r
384 @param Variable Pointer to the Variable Header.\r
385\r
386 @return Pointer to Variable Name which is Unicode encoding.\r
387\r
388**/\r
389CHAR16 *\r
390GetVariableNamePtr (\r
391 IN VARIABLE_HEADER *Variable\r
392 )\r
393{\r
394\r
395 return (CHAR16 *) (Variable + 1);\r
396}\r
397\r
398/**\r
399\r
400 This code gets the pointer to the variable data.\r
401\r
402 @param Variable Pointer to the Variable Header.\r
403\r
404 @return Pointer to Variable Data.\r
405\r
406**/\r
407UINT8 *\r
408GetVariableDataPtr (\r
409 IN VARIABLE_HEADER *Variable\r
410 )\r
411{\r
412 UINTN Value;\r
413 \r
414 //\r
415 // Be careful about pad size for alignment.\r
416 //\r
417 Value = (UINTN) GetVariableNamePtr (Variable);\r
418 Value += NameSizeOfVariable (Variable);\r
419 Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));\r
420\r
421 return (UINT8 *) Value;\r
422}\r
423\r
424\r
425/**\r
426\r
427 This code gets the pointer to the next variable header.\r
428\r
429 @param Variable Pointer to the Variable Header.\r
430\r
431 @return Pointer to next variable header.\r
432\r
433**/\r
434VARIABLE_HEADER *\r
435GetNextVariablePtr (\r
436 IN VARIABLE_HEADER *Variable\r
437 )\r
438{\r
439 UINTN Value;\r
440\r
441 if (!IsValidVariableHeader (Variable)) {\r
442 return NULL;\r
443 }\r
444\r
445 Value = (UINTN) GetVariableDataPtr (Variable);\r
446 Value += DataSizeOfVariable (Variable);\r
447 Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));\r
448\r
449 //\r
450 // Be careful about pad size for alignment.\r
451 //\r
452 return (VARIABLE_HEADER *) HEADER_ALIGN (Value);\r
453}\r
454\r
455/**\r
456\r
457 Gets the pointer to the first variable header in given variable store area.\r
458\r
459 @param VarStoreHeader Pointer to the Variable Store Header.\r
460\r
461 @return Pointer to the first variable header.\r
462\r
463**/\r
464VARIABLE_HEADER *\r
465GetStartPointer (\r
466 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
467 )\r
468{\r
469 //\r
470 // The end of variable store.\r
471 //\r
472 return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);\r
473}\r
474\r
475/**\r
476\r
477 Gets the pointer to the end of the variable storage area.\r
478\r
479 This function gets pointer to the end of the variable storage\r
480 area, according to the input variable store header.\r
481\r
482 @param VarStoreHeader Pointer to the Variable Store Header.\r
483\r
484 @return Pointer to the end of the variable storage area. \r
485\r
486**/\r
487VARIABLE_HEADER *\r
488GetEndPointer (\r
489 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
490 )\r
491{\r
492 //\r
493 // The end of variable store\r
494 //\r
495 return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);\r
496}\r
497\r
498\r
499/**\r
500\r
501 Variable store garbage collection and reclaim operation.\r
502\r
503 @param VariableBase Base address of variable store.\r
504 @param LastVariableOffset Offset of last variable.\r
505 @param IsVolatile The variable store is volatile or not;\r
506 if it is non-volatile, need FTW.\r
507 @param UpdatingVariable Pointer to updating variable.\r
508 @param ReclaimAnyway If TRUE, do reclaim anyway.\r
509\r
510 @return EFI_OUT_OF_RESOURCES\r
511 @return EFI_SUCCESS\r
512 @return Others\r
513\r
514**/\r
515EFI_STATUS\r
516Reclaim (\r
517 IN EFI_PHYSICAL_ADDRESS VariableBase,\r
518 OUT UINTN *LastVariableOffset,\r
519 IN BOOLEAN IsVolatile,\r
520 IN VARIABLE_HEADER *UpdatingVariable,\r
521 IN BOOLEAN ReclaimAnyway\r
522 )\r
523{\r
524 VARIABLE_HEADER *Variable;\r
525 VARIABLE_HEADER *AddedVariable;\r
526 VARIABLE_HEADER *NextVariable;\r
527 VARIABLE_HEADER *NextAddedVariable;\r
528 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
529 UINT8 *ValidBuffer;\r
530 UINTN MaximumBufferSize;\r
531 UINTN VariableSize;\r
532 UINTN VariableNameSize;\r
533 UINTN UpdatingVariableNameSize;\r
534 UINTN NameSize;\r
535 UINT8 *CurrPtr;\r
536 VOID *Point0;\r
537 VOID *Point1;\r
538 BOOLEAN FoundAdded;\r
539 EFI_STATUS Status;\r
540 CHAR16 *VariableNamePtr;\r
541 CHAR16 *UpdatingVariableNamePtr;\r
542 UINTN CommonVariableTotalSize;\r
543 UINTN HwErrVariableTotalSize;\r
544 BOOLEAN NeedDoReclaim;\r
545\r
546 NeedDoReclaim = FALSE;\r
547 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);\r
548\r
549 CommonVariableTotalSize = 0;\r
550 HwErrVariableTotalSize = 0;\r
551\r
552 //\r
553 // Start Pointers for the variable.\r
554 //\r
555 Variable = GetStartPointer (VariableStoreHeader);\r
556 MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);\r
557\r
558 while (IsValidVariableHeader (Variable)) {\r
559 NextVariable = GetNextVariablePtr (Variable);\r
560 if (Variable->State == VAR_ADDED || \r
561 Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
562 ) {\r
563 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
564 MaximumBufferSize += VariableSize;\r
565 } else {\r
566 NeedDoReclaim = TRUE;\r
567 }\r
568\r
569 Variable = NextVariable;\r
570 }\r
571\r
572 if (!ReclaimAnyway && !NeedDoReclaim) {\r
573 DEBUG ((EFI_D_INFO, "Variable driver: no DELETED variable found, so no variable space could be reclaimed.\n"));\r
574 return EFI_SUCCESS;\r
575 }\r
576\r
577 //\r
578 // Reserve the 1 Bytes with Oxff to identify the \r
579 // end of the variable buffer. \r
580 // \r
581 MaximumBufferSize += 1;\r
582 ValidBuffer = AllocatePool (MaximumBufferSize);\r
583 if (ValidBuffer == NULL) {\r
584 return EFI_OUT_OF_RESOURCES;\r
585 }\r
586\r
587 SetMem (ValidBuffer, MaximumBufferSize, 0xff);\r
588\r
589 //\r
590 // Copy variable store header.\r
591 //\r
592 CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));\r
593 CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
594\r
595 //\r
596 // Reinstall all ADDED variables as long as they are not identical to Updating Variable.\r
597 // \r
598 Variable = GetStartPointer (VariableStoreHeader);\r
599 while (IsValidVariableHeader (Variable)) {\r
600 NextVariable = GetNextVariablePtr (Variable);\r
601 if (Variable->State == VAR_ADDED) {\r
602 if (UpdatingVariable != NULL) {\r
603 if (UpdatingVariable == Variable) {\r
604 Variable = NextVariable;\r
605 continue;\r
606 }\r
607\r
608 VariableNameSize = NameSizeOfVariable(Variable);\r
609 UpdatingVariableNameSize = NameSizeOfVariable(UpdatingVariable);\r
610\r
611 VariableNamePtr = GetVariableNamePtr (Variable);\r
612 UpdatingVariableNamePtr = GetVariableNamePtr (UpdatingVariable);\r
613 if (CompareGuid (&Variable->VendorGuid, &UpdatingVariable->VendorGuid) &&\r
614 VariableNameSize == UpdatingVariableNameSize &&\r
615 CompareMem (VariableNamePtr, UpdatingVariableNamePtr, VariableNameSize) == 0 ) {\r
616 Variable = NextVariable;\r
617 continue;\r
618 }\r
619 }\r
620 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
621 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
622 CurrPtr += VariableSize;\r
623 if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
624 HwErrVariableTotalSize += VariableSize;\r
625 } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
626 CommonVariableTotalSize += VariableSize;\r
627 }\r
628 }\r
629 Variable = NextVariable;\r
630 }\r
631\r
632 //\r
633 // Reinstall the variable being updated if it is not NULL.\r
634 //\r
635 if (UpdatingVariable != NULL) {\r
636 VariableSize = (UINTN)(GetNextVariablePtr (UpdatingVariable)) - (UINTN)UpdatingVariable;\r
637 CopyMem (CurrPtr, (UINT8 *) UpdatingVariable, VariableSize);\r
638 CurrPtr += VariableSize;\r
639 if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
640 HwErrVariableTotalSize += VariableSize;\r
641 } else if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
642 CommonVariableTotalSize += VariableSize;\r
643 }\r
644 }\r
645\r
646 //\r
647 // Reinstall all in delete transition variables.\r
648 // \r
649 Variable = GetStartPointer (VariableStoreHeader);\r
650 while (IsValidVariableHeader (Variable)) {\r
651 NextVariable = GetNextVariablePtr (Variable);\r
652 if (Variable != UpdatingVariable && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
653\r
654 //\r
655 // Buffer has cached all ADDED variable. \r
656 // Per IN_DELETED variable, we have to guarantee that\r
657 // no ADDED one in previous buffer. \r
658 // \r
659 \r
660 FoundAdded = FALSE;\r
661 AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
662 while (IsValidVariableHeader (AddedVariable)) {\r
663 NextAddedVariable = GetNextVariablePtr (AddedVariable);\r
664 NameSize = NameSizeOfVariable (AddedVariable);\r
665 if (CompareGuid (&AddedVariable->VendorGuid, &Variable->VendorGuid) &&\r
666 NameSize == NameSizeOfVariable (Variable)\r
667 ) {\r
668 Point0 = (VOID *) GetVariableNamePtr (AddedVariable);\r
669 Point1 = (VOID *) GetVariableNamePtr (Variable);\r
670 if (CompareMem (Point0, Point1, NameSizeOfVariable (AddedVariable)) == 0) {\r
671 FoundAdded = TRUE;\r
672 break;\r
673 }\r
674 }\r
675 AddedVariable = NextAddedVariable;\r
676 }\r
677 if (!FoundAdded) {\r
678 //\r
679 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.\r
680 //\r
681 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
682 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
683 ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;\r
684 CurrPtr += VariableSize;\r
685 if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
686 HwErrVariableTotalSize += VariableSize;\r
687 } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
688 CommonVariableTotalSize += VariableSize;\r
689 }\r
690 }\r
691 }\r
692\r
693 Variable = NextVariable;\r
694 }\r
695\r
696 if (IsVolatile) {\r
697 //\r
698 // If volatile variable store, just copy valid buffer.\r
699 //\r
700 SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);\r
701 CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - (UINT8 *) ValidBuffer));\r
702 Status = EFI_SUCCESS;\r
703 } else {\r
704 //\r
705 // If non-volatile variable store, perform FTW here.\r
706 //\r
707 Status = FtwVariableSpace (\r
708 VariableBase,\r
709 ValidBuffer,\r
710 (UINTN) (CurrPtr - (UINT8 *) ValidBuffer)\r
711 );\r
712 CopyMem (mNvVariableCache, (CHAR8 *)(UINTN)VariableBase, VariableStoreHeader->Size);\r
713 }\r
714 if (!EFI_ERROR (Status)) {\r
715 *LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer);\r
716 if (!IsVolatile) {\r
717 mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;\r
718 mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;\r
719 }\r
720 } else {\r
721 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);\r
722 while (IsValidVariableHeader (NextVariable)) {\r
723 VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);\r
724 if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
725 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);\r
726 } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
727 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);\r
728 }\r
729\r
730 NextVariable = GetNextVariablePtr (NextVariable);\r
731 }\r
732 *LastVariableOffset = (UINTN) NextVariable - (UINTN) VariableBase;\r
733 }\r
734\r
735 FreePool (ValidBuffer);\r
736\r
737 return Status;\r
738}\r
739\r
740/**\r
741 Find the variable in the specified variable store.\r
742\r
743 @param VariableName Name of the variable to be found\r
744 @param VendorGuid Vendor GUID to be found.\r
745 @param IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute\r
746 check at runtime when searching variable.\r
747 @param PtrTrack Variable Track Pointer structure that contains Variable Information.\r
748\r
749 @retval EFI_SUCCESS Variable found successfully\r
750 @retval EFI_NOT_FOUND Variable not found\r
751**/\r
752EFI_STATUS\r
753FindVariableEx (\r
754 IN CHAR16 *VariableName,\r
755 IN EFI_GUID *VendorGuid,\r
756 IN BOOLEAN IgnoreRtCheck,\r
757 IN OUT VARIABLE_POINTER_TRACK *PtrTrack\r
758 )\r
759{\r
760 VARIABLE_HEADER *InDeletedVariable;\r
761 VOID *Point;\r
762\r
763 //\r
764 // Find the variable by walk through HOB, volatile and non-volatile variable store.\r
765 //\r
766 InDeletedVariable = NULL;\r
767\r
768 for ( PtrTrack->CurrPtr = PtrTrack->StartPtr\r
769 ; (PtrTrack->CurrPtr < PtrTrack->EndPtr) && IsValidVariableHeader (PtrTrack->CurrPtr)\r
770 ; PtrTrack->CurrPtr = GetNextVariablePtr (PtrTrack->CurrPtr)\r
771 ) {\r
772 if (PtrTrack->CurrPtr->State == VAR_ADDED || \r
773 PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
774 ) {\r
775 if (IgnoreRtCheck || !AtRuntime () || ((PtrTrack->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {\r
776 if (VariableName[0] == 0) {\r
777 if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
778 InDeletedVariable = PtrTrack->CurrPtr;\r
779 } else {\r
780 return EFI_SUCCESS;\r
781 }\r
782 } else {\r
783 if (CompareGuid (VendorGuid, &PtrTrack->CurrPtr->VendorGuid)) {\r
784 Point = (VOID *) GetVariableNamePtr (PtrTrack->CurrPtr);\r
785\r
786 ASSERT (NameSizeOfVariable (PtrTrack->CurrPtr) != 0);\r
787 if (CompareMem (VariableName, Point, NameSizeOfVariable (PtrTrack->CurrPtr)) == 0) {\r
788 if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
789 InDeletedVariable = PtrTrack->CurrPtr;\r
790 } else {\r
791 return EFI_SUCCESS;\r
792 }\r
793 }\r
794 }\r
795 }\r
796 }\r
797 }\r
798 }\r
799\r
800 PtrTrack->CurrPtr = InDeletedVariable;\r
801 return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;\r
802}\r
803\r
804\r
805/**\r
806 Finds variable in storage blocks of volatile and non-volatile storage areas.\r
807\r
808 This code finds variable in storage blocks of volatile and non-volatile storage areas.\r
809 If VariableName is an empty string, then we just return the first\r
810 qualified variable without comparing VariableName and VendorGuid.\r
811 If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check\r
812 at runtime when searching existing variable, only VariableName and VendorGuid are compared.\r
813 Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime.\r
814\r
815 @param VariableName Name of the variable to be found.\r
816 @param VendorGuid Vendor GUID to be found.\r
817 @param PtrTrack VARIABLE_POINTER_TRACK structure for output,\r
818 including the range searched and the target position.\r
819 @param Global Pointer to VARIABLE_GLOBAL structure, including\r
820 base of volatile variable storage area, base of\r
821 NV variable storage area, and a lock.\r
822 @param IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute\r
823 check at runtime when searching variable.\r
824\r
825 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while\r
826 VendorGuid is NULL.\r
827 @retval EFI_SUCCESS Variable successfully found.\r
828 @retval EFI_NOT_FOUND Variable not found\r
829\r
830**/\r
831EFI_STATUS\r
832FindVariable (\r
833 IN CHAR16 *VariableName,\r
834 IN EFI_GUID *VendorGuid,\r
835 OUT VARIABLE_POINTER_TRACK *PtrTrack,\r
836 IN VARIABLE_GLOBAL *Global,\r
837 IN BOOLEAN IgnoreRtCheck\r
838 )\r
839{\r
840 EFI_STATUS Status;\r
841 VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];\r
842 VARIABLE_STORE_TYPE Type;\r
843\r
844 if (VariableName[0] != 0 && VendorGuid == NULL) {\r
845 return EFI_INVALID_PARAMETER;\r
846 }\r
847\r
848 //\r
849 // 0: Volatile, 1: HOB, 2: Non-Volatile.\r
850 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName\r
851 // make use of this mapping to implement search algorithm.\r
852 //\r
853 VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) Global->VolatileVariableBase;\r
854 VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *) (UINTN) Global->HobVariableBase;\r
855 VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache;\r
856\r
857 //\r
858 // Find the variable by walk through HOB, volatile and non-volatile variable store.\r
859 //\r
860 for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {\r
861 if (VariableStoreHeader[Type] == NULL) {\r
862 continue;\r
863 }\r
864\r
865 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Type]);\r
866 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Type]);\r
867 PtrTrack->Volatile = (BOOLEAN) (Type == VariableStoreTypeVolatile);\r
868\r
869 Status = FindVariableEx (VariableName, VendorGuid, IgnoreRtCheck, PtrTrack);\r
870 if (!EFI_ERROR (Status)) {\r
871 return Status;\r
872 }\r
873 }\r
874 return EFI_NOT_FOUND;\r
875}\r
876\r
877/**\r
878 Get index from supported language codes according to language string.\r
879\r
880 This code is used to get corresponding index in supported language codes. It can handle\r
881 RFC4646 and ISO639 language tags.\r
882 In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.\r
883 In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.\r
884\r
885 For example:\r
886 SupportedLang = "engfraengfra"\r
887 Lang = "eng"\r
888 Iso639Language = TRUE\r
889 The return value is "0".\r
890 Another example:\r
891 SupportedLang = "en;fr;en-US;fr-FR"\r
892 Lang = "fr-FR"\r
893 Iso639Language = FALSE\r
894 The return value is "3".\r
895\r
896 @param SupportedLang Platform supported language codes.\r
897 @param Lang Configured language.\r
898 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
899\r
900 @retval The index of language in the language codes.\r
901\r
902**/\r
903UINTN\r
904GetIndexFromSupportedLangCodes(\r
905 IN CHAR8 *SupportedLang,\r
906 IN CHAR8 *Lang,\r
907 IN BOOLEAN Iso639Language\r
908 ) \r
909{\r
910 UINTN Index;\r
911 UINTN CompareLength;\r
912 UINTN LanguageLength;\r
913\r
914 if (Iso639Language) {\r
915 CompareLength = ISO_639_2_ENTRY_SIZE;\r
916 for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {\r
917 if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {\r
918 //\r
919 // Successfully find the index of Lang string in SupportedLang string.\r
920 //\r
921 Index = Index / CompareLength;\r
922 return Index;\r
923 }\r
924 }\r
925 ASSERT (FALSE);\r
926 return 0;\r
927 } else {\r
928 //\r
929 // Compare RFC4646 language code\r
930 //\r
931 Index = 0;\r
932 for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++);\r
933\r
934 for (Index = 0; *SupportedLang != '\0'; Index++, SupportedLang += CompareLength) {\r
935 //\r
936 // Skip ';' characters in SupportedLang\r
937 //\r
938 for (; *SupportedLang != '\0' && *SupportedLang == ';'; SupportedLang++);\r
939 //\r
940 // Determine the length of the next language code in SupportedLang\r
941 //\r
942 for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++);\r
943 \r
944 if ((CompareLength == LanguageLength) && \r
945 (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0)) {\r
946 //\r
947 // Successfully find the index of Lang string in SupportedLang string.\r
948 //\r
949 return Index;\r
950 }\r
951 }\r
952 ASSERT (FALSE);\r
953 return 0;\r
954 }\r
955}\r
956\r
957/**\r
958 Get language string from supported language codes according to index.\r
959\r
960 This code is used to get corresponding language strings in supported language codes. It can handle\r
961 RFC4646 and ISO639 language tags.\r
962 In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.\r
963 In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.\r
964\r
965 For example:\r
966 SupportedLang = "engfraengfra"\r
967 Index = "1"\r
968 Iso639Language = TRUE\r
969 The return value is "fra".\r
970 Another example:\r
971 SupportedLang = "en;fr;en-US;fr-FR"\r
972 Index = "1"\r
973 Iso639Language = FALSE\r
974 The return value is "fr".\r
975\r
976 @param SupportedLang Platform supported language codes.\r
977 @param Index The index in supported language codes.\r
978 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
979\r
980 @retval The language string in the language codes.\r
981\r
982**/\r
983CHAR8 *\r
984GetLangFromSupportedLangCodes (\r
985 IN CHAR8 *SupportedLang,\r
986 IN UINTN Index,\r
987 IN BOOLEAN Iso639Language\r
988)\r
989{\r
990 UINTN SubIndex;\r
991 UINTN CompareLength;\r
992 CHAR8 *Supported;\r
993\r
994 SubIndex = 0;\r
995 Supported = SupportedLang;\r
996 if (Iso639Language) {\r
997 //\r
998 // According to the index of Lang string in SupportedLang string to get the language.\r
999 // This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation.\r
1000 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
1001 //\r
1002 CompareLength = ISO_639_2_ENTRY_SIZE;\r
1003 mVariableModuleGlobal->Lang[CompareLength] = '\0';\r
1004 return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength);\r
1005\r
1006 } else {\r
1007 while (TRUE) {\r
1008 //\r
1009 // Take semicolon as delimitation, sequentially traverse supported language codes.\r
1010 //\r
1011 for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {\r
1012 Supported++;\r
1013 }\r
1014 if ((*Supported == '\0') && (SubIndex != Index)) {\r
1015 //\r
1016 // Have completed the traverse, but not find corrsponding string.\r
1017 // This case is not allowed to happen.\r
1018 //\r
1019 ASSERT(FALSE);\r
1020 return NULL;\r
1021 }\r
1022 if (SubIndex == Index) {\r
1023 //\r
1024 // According to the index of Lang string in SupportedLang string to get the language.\r
1025 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.\r
1026 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
1027 //\r
1028 mVariableModuleGlobal->PlatformLang[CompareLength] = '\0';\r
1029 return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - CompareLength, CompareLength);\r
1030 }\r
1031 SubIndex++;\r
1032\r
1033 //\r
1034 // Skip ';' characters in Supported\r
1035 //\r
1036 for (; *Supported != '\0' && *Supported == ';'; Supported++);\r
1037 }\r
1038 }\r
1039}\r
1040\r
1041/**\r
1042 Returns a pointer to an allocated buffer that contains the best matching language \r
1043 from a set of supported languages. \r
1044 \r
1045 This function supports both ISO 639-2 and RFC 4646 language codes, but language \r
1046 code types may not be mixed in a single call to this function. This function\r
1047 supports a variable argument list that allows the caller to pass in a prioritized\r
1048 list of language codes to test against all the language codes in SupportedLanguages.\r
1049\r
1050 If SupportedLanguages is NULL, then ASSERT().\r
1051\r
1052 @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that\r
1053 contains a set of language codes in the format \r
1054 specified by Iso639Language.\r
1055 @param[in] Iso639Language If TRUE, then all language codes are assumed to be\r
1056 in ISO 639-2 format. If FALSE, then all language\r
1057 codes are assumed to be in RFC 4646 language format\r
1058 @param[in] ... A variable argument list that contains pointers to \r
1059 Null-terminated ASCII strings that contain one or more\r
1060 language codes in the format specified by Iso639Language.\r
1061 The first language code from each of these language\r
1062 code lists is used to determine if it is an exact or\r
1063 close match to any of the language codes in \r
1064 SupportedLanguages. Close matches only apply to RFC 4646\r
1065 language codes, and the matching algorithm from RFC 4647\r
1066 is used to determine if a close match is present. If \r
1067 an exact or close match is found, then the matching\r
1068 language code from SupportedLanguages is returned. If\r
1069 no matches are found, then the next variable argument\r
1070 parameter is evaluated. The variable argument list \r
1071 is terminated by a NULL.\r
1072\r
1073 @retval NULL The best matching language could not be found in SupportedLanguages.\r
1074 @retval NULL There are not enough resources available to return the best matching \r
1075 language.\r
1076 @retval Other A pointer to a Null-terminated ASCII string that is the best matching \r
1077 language in SupportedLanguages.\r
1078\r
1079**/\r
1080CHAR8 *\r
1081EFIAPI\r
1082VariableGetBestLanguage (\r
1083 IN CONST CHAR8 *SupportedLanguages, \r
1084 IN BOOLEAN Iso639Language,\r
1085 ...\r
1086 )\r
1087{\r
1088 VA_LIST Args;\r
1089 CHAR8 *Language;\r
1090 UINTN CompareLength;\r
1091 UINTN LanguageLength;\r
1092 CONST CHAR8 *Supported;\r
1093 CHAR8 *Buffer;\r
1094\r
1095 ASSERT (SupportedLanguages != NULL);\r
1096\r
1097 VA_START (Args, Iso639Language);\r
1098 while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {\r
1099 //\r
1100 // Default to ISO 639-2 mode\r
1101 //\r
1102 CompareLength = 3;\r
1103 LanguageLength = MIN (3, AsciiStrLen (Language));\r
1104\r
1105 //\r
1106 // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language\r
1107 //\r
1108 if (!Iso639Language) {\r
1109 for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++);\r
1110 }\r
1111\r
1112 //\r
1113 // Trim back the length of Language used until it is empty\r
1114 //\r
1115 while (LanguageLength > 0) {\r
1116 //\r
1117 // Loop through all language codes in SupportedLanguages\r
1118 //\r
1119 for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {\r
1120 //\r
1121 // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages\r
1122 //\r
1123 if (!Iso639Language) {\r
1124 //\r
1125 // Skip ';' characters in Supported\r
1126 //\r
1127 for (; *Supported != '\0' && *Supported == ';'; Supported++);\r
1128 //\r
1129 // Determine the length of the next language code in Supported\r
1130 //\r
1131 for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++);\r
1132 //\r
1133 // If Language is longer than the Supported, then skip to the next language\r
1134 //\r
1135 if (LanguageLength > CompareLength) {\r
1136 continue;\r
1137 }\r
1138 }\r
1139 //\r
1140 // See if the first LanguageLength characters in Supported match Language\r
1141 //\r
1142 if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {\r
1143 VA_END (Args);\r
1144\r
1145 Buffer = Iso639Language ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang;\r
1146 Buffer[CompareLength] = '\0';\r
1147 return CopyMem (Buffer, Supported, CompareLength);\r
1148 }\r
1149 }\r
1150\r
1151 if (Iso639Language) {\r
1152 //\r
1153 // If ISO 639 mode, then each language can only be tested once\r
1154 //\r
1155 LanguageLength = 0;\r
1156 } else {\r
1157 //\r
1158 // If RFC 4646 mode, then trim Language from the right to the next '-' character \r
1159 //\r
1160 for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--);\r
1161 }\r
1162 }\r
1163 }\r
1164 VA_END (Args);\r
1165\r
1166 //\r
1167 // No matches were found \r
1168 //\r
1169 return NULL;\r
1170}\r
1171\r
1172/**\r
1173 Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.\r
1174\r
1175 When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.\r
1176\r
1177 According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,\r
1178 and are read-only. Therefore, in variable driver, only store the original value for other use.\r
1179\r
1180 @param[in] VariableName Name of variable.\r
1181\r
1182 @param[in] Data Variable data.\r
1183\r
1184 @param[in] DataSize Size of data. 0 means delete.\r
1185\r
1186**/\r
1187VOID\r
1188AutoUpdateLangVariable (\r
1189 IN CHAR16 *VariableName,\r
1190 IN VOID *Data,\r
1191 IN UINTN DataSize\r
1192 )\r
1193{\r
1194 EFI_STATUS Status;\r
1195 CHAR8 *BestPlatformLang;\r
1196 CHAR8 *BestLang;\r
1197 UINTN Index;\r
1198 UINT32 Attributes;\r
1199 VARIABLE_POINTER_TRACK Variable;\r
1200 BOOLEAN SetLanguageCodes;\r
1201\r
1202 //\r
1203 // Don't do updates for delete operation\r
1204 //\r
1205 if (DataSize == 0) {\r
1206 return;\r
1207 }\r
1208\r
1209 SetLanguageCodes = FALSE;\r
1210\r
1211 if (StrCmp (VariableName, L"PlatformLangCodes") == 0) {\r
1212 //\r
1213 // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.\r
1214 //\r
1215 if (AtRuntime ()) {\r
1216 return;\r
1217 }\r
1218\r
1219 SetLanguageCodes = TRUE;\r
1220\r
1221 //\r
1222 // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only\r
1223 // Therefore, in variable driver, only store the original value for other use.\r
1224 //\r
1225 if (mVariableModuleGlobal->PlatformLangCodes != NULL) {\r
1226 FreePool (mVariableModuleGlobal->PlatformLangCodes);\r
1227 }\r
1228 mVariableModuleGlobal->PlatformLangCodes = AllocateRuntimeCopyPool (DataSize, Data);\r
1229 ASSERT (mVariableModuleGlobal->PlatformLangCodes != NULL);\r
1230\r
1231 //\r
1232 // PlatformLang holds a single language from PlatformLangCodes, \r
1233 // so the size of PlatformLangCodes is enough for the PlatformLang.\r
1234 //\r
1235 if (mVariableModuleGlobal->PlatformLang != NULL) {\r
1236 FreePool (mVariableModuleGlobal->PlatformLang);\r
1237 }\r
1238 mVariableModuleGlobal->PlatformLang = AllocateRuntimePool (DataSize);\r
1239 ASSERT (mVariableModuleGlobal->PlatformLang != NULL);\r
1240\r
1241 } else if (StrCmp (VariableName, L"LangCodes") == 0) {\r
1242 //\r
1243 // LangCodes is a volatile variable, so it can not be updated at runtime.\r
1244 //\r
1245 if (AtRuntime ()) {\r
1246 return;\r
1247 }\r
1248\r
1249 SetLanguageCodes = TRUE;\r
1250\r
1251 //\r
1252 // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only\r
1253 // Therefore, in variable driver, only store the original value for other use.\r
1254 //\r
1255 if (mVariableModuleGlobal->LangCodes != NULL) {\r
1256 FreePool (mVariableModuleGlobal->LangCodes);\r
1257 }\r
1258 mVariableModuleGlobal->LangCodes = AllocateRuntimeCopyPool (DataSize, Data);\r
1259 ASSERT (mVariableModuleGlobal->LangCodes != NULL);\r
1260 }\r
1261\r
1262 if (SetLanguageCodes \r
1263 && (mVariableModuleGlobal->PlatformLangCodes != NULL)\r
1264 && (mVariableModuleGlobal->LangCodes != NULL)) {\r
1265 //\r
1266 // Update Lang if PlatformLang is already set\r
1267 // Update PlatformLang if Lang is already set\r
1268 //\r
1269 Status = FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
1270 if (!EFI_ERROR (Status)) {\r
1271 //\r
1272 // Update Lang\r
1273 //\r
1274 VariableName = L"PlatformLang";\r
1275 Data = GetVariableDataPtr (Variable.CurrPtr);\r
1276 DataSize = Variable.CurrPtr->DataSize;\r
1277 } else {\r
1278 Status = FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
1279 if (!EFI_ERROR (Status)) {\r
1280 //\r
1281 // Update PlatformLang\r
1282 //\r
1283 VariableName = L"Lang";\r
1284 Data = GetVariableDataPtr (Variable.CurrPtr);\r
1285 DataSize = Variable.CurrPtr->DataSize;\r
1286 } else {\r
1287 //\r
1288 // Neither PlatformLang nor Lang is set, directly return\r
1289 //\r
1290 return;\r
1291 }\r
1292 }\r
1293 }\r
1294 \r
1295 //\r
1296 // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.\r
1297 //\r
1298 Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;\r
1299\r
1300 if (StrCmp (VariableName, L"PlatformLang") == 0) {\r
1301 //\r
1302 // Update Lang when PlatformLangCodes/LangCodes were set.\r
1303 //\r
1304 if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {\r
1305 //\r
1306 // When setting PlatformLang, firstly get most matched language string from supported language codes.\r
1307 //\r
1308 BestPlatformLang = VariableGetBestLanguage (mVariableModuleGlobal->PlatformLangCodes, FALSE, Data, NULL);\r
1309 if (BestPlatformLang != NULL) {\r
1310 //\r
1311 // Get the corresponding index in language codes.\r
1312 //\r
1313 Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, BestPlatformLang, FALSE);\r
1314\r
1315 //\r
1316 // Get the corresponding ISO639 language tag according to RFC4646 language tag.\r
1317 //\r
1318 BestLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, Index, TRUE);\r
1319\r
1320 //\r
1321 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.\r
1322 //\r
1323 FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal, FALSE);\r
1324\r
1325 Status = UpdateVariable (L"Lang", &gEfiGlobalVariableGuid, BestLang,\r
1326 ISO_639_2_ENTRY_SIZE + 1, Attributes, &Variable);\r
1327\r
1328 DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang));\r
1329\r
1330 ASSERT_EFI_ERROR(Status);\r
1331 }\r
1332 }\r
1333\r
1334 } else if (StrCmp (VariableName, L"Lang") == 0) {\r
1335 //\r
1336 // Update PlatformLang when PlatformLangCodes/LangCodes were set.\r
1337 //\r
1338 if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {\r
1339 //\r
1340 // When setting Lang, firstly get most matched language string from supported language codes.\r
1341 //\r
1342 BestLang = VariableGetBestLanguage (mVariableModuleGlobal->LangCodes, TRUE, Data, NULL);\r
1343 if (BestLang != NULL) {\r
1344 //\r
1345 // Get the corresponding index in language codes.\r
1346 //\r
1347 Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, BestLang, TRUE);\r
1348\r
1349 //\r
1350 // Get the corresponding RFC4646 language tag according to ISO639 language tag.\r
1351 //\r
1352 BestPlatformLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, Index, FALSE);\r
1353\r
1354 //\r
1355 // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.\r
1356 //\r
1357 FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
1358\r
1359 Status = UpdateVariable (L"PlatformLang", &gEfiGlobalVariableGuid, BestPlatformLang, \r
1360 AsciiStrSize (BestPlatformLang), Attributes, &Variable);\r
1361\r
1362 DEBUG ((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a\n", BestLang, BestPlatformLang));\r
1363 ASSERT_EFI_ERROR (Status);\r
1364 }\r
1365 }\r
1366 }\r
1367}\r
1368\r
1369/**\r
1370 Update the variable region with Variable information. These are the same \r
1371 arguments as the EFI Variable services.\r
1372\r
1373 @param[in] VariableName Name of variable.\r
1374 @param[in] VendorGuid Guid of variable.\r
1375 @param[in] Data Variable data.\r
1376 @param[in] DataSize Size of data. 0 means delete.\r
1377 @param[in] Attributes Attribues of the variable.\r
1378 @param[in] CacheVariable The variable information which is used to keep track of variable usage.\r
1379 \r
1380 @retval EFI_SUCCESS The update operation is success.\r
1381 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.\r
1382\r
1383**/\r
1384EFI_STATUS\r
1385UpdateVariable (\r
1386 IN CHAR16 *VariableName,\r
1387 IN EFI_GUID *VendorGuid,\r
1388 IN VOID *Data,\r
1389 IN UINTN DataSize,\r
1390 IN UINT32 Attributes OPTIONAL,\r
1391 IN VARIABLE_POINTER_TRACK *CacheVariable\r
1392 )\r
1393{\r
1394 EFI_STATUS Status;\r
1395 VARIABLE_HEADER *NextVariable;\r
1396 UINTN ScratchSize;\r
1397 UINTN NonVolatileVarableStoreSize;\r
1398 UINTN VarNameOffset;\r
1399 UINTN VarDataOffset;\r
1400 UINTN VarNameSize;\r
1401 UINTN VarSize;\r
1402 BOOLEAN Volatile;\r
1403 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
1404 UINT8 State;\r
1405 BOOLEAN Reclaimed;\r
1406 VARIABLE_POINTER_TRACK *Variable;\r
1407 VARIABLE_POINTER_TRACK NvVariable;\r
1408 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
1409 UINTN CacheOffset;\r
1410\r
1411 if ((mVariableModuleGlobal->FvbInstance == NULL) && ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0)) {\r
1412 //\r
1413 // The FVB protocol is not ready. Trying to update NV variable prior to the installation\r
1414 // of EFI_VARIABLE_WRITE_ARCH_PROTOCOL.\r
1415 //\r
1416 return EFI_NOT_AVAILABLE_YET; \r
1417 }\r
1418\r
1419 if ((CacheVariable->CurrPtr == NULL) || CacheVariable->Volatile) {\r
1420 Variable = CacheVariable;\r
1421 } else {\r
1422 //\r
1423 // Update/Delete existing NV variable.\r
1424 // CacheVariable points to the variable in the memory copy of Flash area\r
1425 // Now let Variable points to the same variable in Flash area.\r
1426 //\r
1427 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
1428 Variable = &NvVariable; \r
1429 Variable->StartPtr = GetStartPointer (VariableStoreHeader);\r
1430 Variable->EndPtr = GetEndPointer (VariableStoreHeader);\r
1431 Variable->CurrPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->CurrPtr - (UINTN)CacheVariable->StartPtr));\r
1432 Variable->Volatile = FALSE;\r
1433 } \r
1434\r
1435 Fvb = mVariableModuleGlobal->FvbInstance;\r
1436 Reclaimed = FALSE;\r
1437\r
1438 if (Variable->CurrPtr != NULL) {\r
1439 //\r
1440 // Update/Delete existing variable.\r
1441 //\r
1442 if (AtRuntime ()) { \r
1443 //\r
1444 // If AtRuntime and the variable is Volatile and Runtime Access, \r
1445 // the volatile is ReadOnly, and SetVariable should be aborted and \r
1446 // return EFI_WRITE_PROTECTED.\r
1447 //\r
1448 if (Variable->Volatile) {\r
1449 Status = EFI_WRITE_PROTECTED;\r
1450 goto Done;\r
1451 }\r
1452 //\r
1453 // Only variable that have NV|RT attributes can be updated/deleted in Runtime.\r
1454 //\r
1455 if (((Variable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0)) {\r
1456 Status = EFI_INVALID_PARAMETER;\r
1457 goto Done; \r
1458 }\r
1459 }\r
1460\r
1461 //\r
1462 // Setting a data variable with no access, or zero DataSize attributes\r
1463 // causes it to be deleted.\r
1464 //\r
1465 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) { \r
1466 State = Variable->CurrPtr->State;\r
1467 State &= VAR_DELETED;\r
1468\r
1469 Status = UpdateVariableStore (\r
1470 &mVariableModuleGlobal->VariableGlobal,\r
1471 Variable->Volatile,\r
1472 FALSE,\r
1473 Fvb,\r
1474 (UINTN) &Variable->CurrPtr->State,\r
1475 sizeof (UINT8),\r
1476 &State\r
1477 ); \r
1478 if (!EFI_ERROR (Status)) {\r
1479 UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE);\r
1480 if (!Variable->Volatile) {\r
1481 CacheVariable->CurrPtr->State = State;\r
1482 FlushHobVariableToFlash (VariableName, VendorGuid);\r
1483 }\r
1484 }\r
1485 goto Done; \r
1486 }\r
1487 //\r
1488 // If the variable is marked valid, and the same data has been passed in,\r
1489 // then return to the caller immediately.\r
1490 //\r
1491 if (DataSizeOfVariable (Variable->CurrPtr) == DataSize &&\r
1492 (CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0)) {\r
1493 \r
1494 UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE);\r
1495 Status = EFI_SUCCESS;\r
1496 goto Done;\r
1497 } else if ((Variable->CurrPtr->State == VAR_ADDED) ||\r
1498 (Variable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {\r
1499\r
1500 //\r
1501 // Mark the old variable as in delete transition.\r
1502 //\r
1503 State = Variable->CurrPtr->State;\r
1504 State &= VAR_IN_DELETED_TRANSITION;\r
1505\r
1506 Status = UpdateVariableStore (\r
1507 &mVariableModuleGlobal->VariableGlobal,\r
1508 Variable->Volatile,\r
1509 FALSE,\r
1510 Fvb,\r
1511 (UINTN) &Variable->CurrPtr->State,\r
1512 sizeof (UINT8),\r
1513 &State\r
1514 ); \r
1515 if (EFI_ERROR (Status)) {\r
1516 goto Done; \r
1517 } \r
1518 if (!Variable->Volatile) {\r
1519 CacheVariable->CurrPtr->State = State;\r
1520 }\r
1521 } \r
1522 } else {\r
1523 //\r
1524 // Not found existing variable. Create a new variable.\r
1525 // \r
1526 \r
1527 //\r
1528 // Make sure we are trying to create a new variable.\r
1529 // Setting a data variable with zero DataSize or no access attributes means to delete it. \r
1530 //\r
1531 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {\r
1532 Status = EFI_NOT_FOUND;\r
1533 goto Done;\r
1534 }\r
1535 \r
1536 //\r
1537 // Only variable have NV|RT attribute can be created in Runtime.\r
1538 //\r
1539 if (AtRuntime () &&\r
1540 (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {\r
1541 Status = EFI_INVALID_PARAMETER;\r
1542 goto Done;\r
1543 } \r
1544 }\r
1545\r
1546 //\r
1547 // Function part - create a new variable and copy the data.\r
1548 // Both update a variable and create a variable will come here.\r
1549\r
1550 //\r
1551 // Tricky part: Use scratch data area at the end of volatile variable store\r
1552 // as a temporary storage.\r
1553 //\r
1554 NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));\r
1555 ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
1556\r
1557 SetMem (NextVariable, ScratchSize, 0xff);\r
1558\r
1559 NextVariable->StartId = VARIABLE_DATA;\r
1560 NextVariable->Attributes = Attributes;\r
1561 //\r
1562 // NextVariable->State = VAR_ADDED;\r
1563 //\r
1564 NextVariable->Reserved = 0;\r
1565 VarNameOffset = sizeof (VARIABLE_HEADER);\r
1566 VarNameSize = StrSize (VariableName);\r
1567 CopyMem (\r
1568 (UINT8 *) ((UINTN) NextVariable + VarNameOffset),\r
1569 VariableName,\r
1570 VarNameSize\r
1571 );\r
1572 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);\r
1573 CopyMem (\r
1574 (UINT8 *) ((UINTN) NextVariable + VarDataOffset),\r
1575 Data,\r
1576 DataSize\r
1577 );\r
1578 CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));\r
1579 //\r
1580 // There will be pad bytes after Data, the NextVariable->NameSize and\r
1581 // NextVariable->DataSize should not include pad size so that variable\r
1582 // service can get actual size in GetVariable.\r
1583 //\r
1584 NextVariable->NameSize = (UINT32)VarNameSize;\r
1585 NextVariable->DataSize = (UINT32)DataSize;\r
1586\r
1587 //\r
1588 // The actual size of the variable that stores in storage should\r
1589 // include pad size.\r
1590 //\r
1591 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);\r
1592 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
1593 //\r
1594 // Create a nonvolatile variable.\r
1595 //\r
1596 Volatile = FALSE;\r
1597 NonVolatileVarableStoreSize = ((VARIABLE_STORE_HEADER *)(UINTN)(mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase))->Size;\r
1598 if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \r
1599 && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))\r
1600 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
1601 && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize)))) {\r
1602 if (AtRuntime ()) {\r
1603 Status = EFI_OUT_OF_RESOURCES;\r
1604 goto Done;\r
1605 }\r
1606 //\r
1607 // Perform garbage collection & reclaim operation.\r
1608 //\r
1609 Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, \r
1610 &mVariableModuleGlobal->NonVolatileLastVariableOffset, FALSE, Variable->CurrPtr, FALSE);\r
1611 if (EFI_ERROR (Status)) {\r
1612 goto Done;\r
1613 }\r
1614 //\r
1615 // If still no enough space, return out of resources.\r
1616 //\r
1617 if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \r
1618 && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))\r
1619 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
1620 && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize)))) {\r
1621 Status = EFI_OUT_OF_RESOURCES;\r
1622 goto Done;\r
1623 }\r
1624 Reclaimed = TRUE;\r
1625 }\r
1626 //\r
1627 // Four steps\r
1628 // 1. Write variable header\r
1629 // 2. Set variable state to header valid \r
1630 // 3. Write variable data\r
1631 // 4. Set variable state to valid\r
1632 //\r
1633 //\r
1634 // Step 1:\r
1635 //\r
1636 CacheOffset = mVariableModuleGlobal->NonVolatileLastVariableOffset;\r
1637 Status = UpdateVariableStore (\r
1638 &mVariableModuleGlobal->VariableGlobal,\r
1639 FALSE,\r
1640 TRUE,\r
1641 Fvb,\r
1642 mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
1643 sizeof (VARIABLE_HEADER),\r
1644 (UINT8 *) NextVariable\r
1645 );\r
1646\r
1647 if (EFI_ERROR (Status)) {\r
1648 goto Done;\r
1649 }\r
1650\r
1651 //\r
1652 // Step 2:\r
1653 //\r
1654 NextVariable->State = VAR_HEADER_VALID_ONLY;\r
1655 Status = UpdateVariableStore (\r
1656 &mVariableModuleGlobal->VariableGlobal,\r
1657 FALSE,\r
1658 TRUE,\r
1659 Fvb,\r
1660 mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
1661 sizeof (UINT8),\r
1662 &NextVariable->State\r
1663 );\r
1664\r
1665 if (EFI_ERROR (Status)) {\r
1666 goto Done;\r
1667 }\r
1668 //\r
1669 // Step 3:\r
1670 //\r
1671 Status = UpdateVariableStore (\r
1672 &mVariableModuleGlobal->VariableGlobal,\r
1673 FALSE,\r
1674 TRUE,\r
1675 Fvb,\r
1676 mVariableModuleGlobal->NonVolatileLastVariableOffset + sizeof (VARIABLE_HEADER),\r
1677 (UINT32) VarSize - sizeof (VARIABLE_HEADER),\r
1678 (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)\r
1679 );\r
1680\r
1681 if (EFI_ERROR (Status)) {\r
1682 goto Done;\r
1683 }\r
1684 //\r
1685 // Step 4:\r
1686 //\r
1687 NextVariable->State = VAR_ADDED;\r
1688 Status = UpdateVariableStore (\r
1689 &mVariableModuleGlobal->VariableGlobal,\r
1690 FALSE,\r
1691 TRUE,\r
1692 Fvb,\r
1693 mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
1694 sizeof (UINT8),\r
1695 &NextVariable->State\r
1696 );\r
1697\r
1698 if (EFI_ERROR (Status)) {\r
1699 goto Done;\r
1700 }\r
1701\r
1702 mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
1703\r
1704 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {\r
1705 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);\r
1706 } else {\r
1707 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);\r
1708 }\r
1709 //\r
1710 // update the memory copy of Flash region.\r
1711 //\r
1712 CopyMem ((UINT8 *)mNvVariableCache + CacheOffset, (UINT8 *)NextVariable, VarSize);\r
1713 } else {\r
1714 //\r
1715 // Create a volatile variable.\r
1716 // \r
1717 Volatile = TRUE;\r
1718\r
1719 if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >\r
1720 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) {\r
1721 //\r
1722 // Perform garbage collection & reclaim operation.\r
1723 //\r
1724 Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase, \r
1725 &mVariableModuleGlobal->VolatileLastVariableOffset, TRUE, Variable->CurrPtr, FALSE);\r
1726 if (EFI_ERROR (Status)) {\r
1727 goto Done;\r
1728 }\r
1729 //\r
1730 // If still no enough space, return out of resources.\r
1731 //\r
1732 if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >\r
1733 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size\r
1734 ) {\r
1735 Status = EFI_OUT_OF_RESOURCES;\r
1736 goto Done;\r
1737 }\r
1738 Reclaimed = TRUE;\r
1739 }\r
1740\r
1741 NextVariable->State = VAR_ADDED;\r
1742 Status = UpdateVariableStore (\r
1743 &mVariableModuleGlobal->VariableGlobal,\r
1744 TRUE,\r
1745 TRUE,\r
1746 Fvb,\r
1747 mVariableModuleGlobal->VolatileLastVariableOffset,\r
1748 (UINT32) VarSize,\r
1749 (UINT8 *) NextVariable\r
1750 );\r
1751\r
1752 if (EFI_ERROR (Status)) {\r
1753 goto Done;\r
1754 }\r
1755\r
1756 mVariableModuleGlobal->VolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
1757 }\r
1758\r
1759 //\r
1760 // Mark the old variable as deleted.\r
1761 //\r
1762 if (!Reclaimed && !EFI_ERROR (Status) && Variable->CurrPtr != NULL) {\r
1763 State = Variable->CurrPtr->State;\r
1764 State &= VAR_DELETED;\r
1765\r
1766 Status = UpdateVariableStore (\r
1767 &mVariableModuleGlobal->VariableGlobal,\r
1768 Variable->Volatile,\r
1769 FALSE,\r
1770 Fvb,\r
1771 (UINTN) &Variable->CurrPtr->State,\r
1772 sizeof (UINT8),\r
1773 &State\r
1774 );\r
1775 if (!EFI_ERROR (Status) && !Variable->Volatile) { \r
1776 CacheVariable->CurrPtr->State = State;\r
1777 }\r
1778 }\r
1779\r
1780 if (!EFI_ERROR (Status)) {\r
1781 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
1782 if (!Volatile) {\r
1783 FlushHobVariableToFlash (VariableName, VendorGuid);\r
1784 }\r
1785 }\r
1786\r
1787Done:\r
1788 return Status;\r
1789}\r
1790\r
1791/**\r
1792 Check if a Unicode character is a hexadecimal character.\r
1793\r
1794 This function checks if a Unicode character is a \r
1795 hexadecimal character. The valid hexadecimal character is \r
1796 L'0' to L'9', L'a' to L'f', or L'A' to L'F'.\r
1797\r
1798\r
1799 @param Char The character to check against.\r
1800\r
1801 @retval TRUE If the Char is a hexadecmial character.\r
1802 @retval FALSE If the Char is not a hexadecmial character.\r
1803\r
1804**/\r
1805BOOLEAN\r
1806EFIAPI\r
1807IsHexaDecimalDigitCharacter (\r
1808 IN CHAR16 Char\r
1809 )\r
1810{\r
1811 return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f'));\r
1812}\r
1813\r
1814/**\r
1815\r
1816 This code checks if variable is hardware error record variable or not.\r
1817\r
1818 According to UEFI spec, hardware error record variable should use the EFI_HARDWARE_ERROR_VARIABLE VendorGuid\r
1819 and have the L"HwErrRec####" name convention, #### is a printed hex value and no 0x or h is included in the hex value.\r
1820\r
1821 @param VariableName Pointer to variable name.\r
1822 @param VendorGuid Variable Vendor Guid.\r
1823\r
1824 @retval TRUE Variable is hardware error record variable.\r
1825 @retval FALSE Variable is not hardware error record variable.\r
1826\r
1827**/\r
1828BOOLEAN\r
1829EFIAPI\r
1830IsHwErrRecVariable (\r
1831 IN CHAR16 *VariableName,\r
1832 IN EFI_GUID *VendorGuid\r
1833 )\r
1834{\r
1835 if (!CompareGuid (VendorGuid, &gEfiHardwareErrorVariableGuid) ||\r
1836 (StrLen (VariableName) != StrLen (L"HwErrRec####")) ||\r
1837 (StrnCmp(VariableName, L"HwErrRec", StrLen (L"HwErrRec")) != 0) ||\r
1838 !IsHexaDecimalDigitCharacter (VariableName[0x8]) ||\r
1839 !IsHexaDecimalDigitCharacter (VariableName[0x9]) ||\r
1840 !IsHexaDecimalDigitCharacter (VariableName[0xA]) ||\r
1841 !IsHexaDecimalDigitCharacter (VariableName[0xB])) {\r
1842 return FALSE;\r
1843 }\r
1844\r
1845 return TRUE;\r
1846}\r
1847\r
1848/**\r
1849\r
1850 This code finds variable in storage blocks (Volatile or Non-Volatile).\r
1851\r
1852 @param VariableName Name of Variable to be found.\r
1853 @param VendorGuid Variable vendor GUID.\r
1854 @param Attributes Attribute value of the variable found.\r
1855 @param DataSize Size of Data found. If size is less than the\r
1856 data, this value contains the required size.\r
1857 @param Data Data pointer.\r
1858 \r
1859 @return EFI_INVALID_PARAMETER Invalid parameter.\r
1860 @return EFI_SUCCESS Find the specified variable.\r
1861 @return EFI_NOT_FOUND Not found.\r
1862 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
1863\r
1864**/\r
1865EFI_STATUS\r
1866EFIAPI\r
1867VariableServiceGetVariable (\r
1868 IN CHAR16 *VariableName,\r
1869 IN EFI_GUID *VendorGuid,\r
1870 OUT UINT32 *Attributes OPTIONAL,\r
1871 IN OUT UINTN *DataSize,\r
1872 OUT VOID *Data\r
1873 )\r
1874{\r
1875 EFI_STATUS Status;\r
1876 VARIABLE_POINTER_TRACK Variable;\r
1877 UINTN VarDataSize;\r
1878\r
1879 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
1880 return EFI_INVALID_PARAMETER;\r
1881 }\r
1882\r
1883 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
1884 \r
1885 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
1886 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
1887 goto Done;\r
1888 }\r
1889\r
1890 //\r
1891 // Get data size\r
1892 //\r
1893 VarDataSize = DataSizeOfVariable (Variable.CurrPtr);\r
1894 ASSERT (VarDataSize != 0);\r
1895\r
1896 if (*DataSize >= VarDataSize) {\r
1897 if (Data == NULL) {\r
1898 Status = EFI_INVALID_PARAMETER;\r
1899 goto Done;\r
1900 }\r
1901\r
1902 CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);\r
1903 if (Attributes != NULL) {\r
1904 *Attributes = Variable.CurrPtr->Attributes;\r
1905 }\r
1906\r
1907 *DataSize = VarDataSize;\r
1908 UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);\r
1909 \r
1910 Status = EFI_SUCCESS;\r
1911 goto Done;\r
1912 } else {\r
1913 *DataSize = VarDataSize;\r
1914 Status = EFI_BUFFER_TOO_SMALL;\r
1915 goto Done;\r
1916 }\r
1917\r
1918Done:\r
1919 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
1920 return Status;\r
1921}\r
1922\r
1923\r
1924\r
1925/**\r
1926\r
1927 This code Finds the Next available variable.\r
1928\r
1929 @param VariableNameSize Size of the variable name.\r
1930 @param VariableName Pointer to variable name.\r
1931 @param VendorGuid Variable Vendor Guid.\r
1932\r
1933 @return EFI_INVALID_PARAMETER Invalid parameter.\r
1934 @return EFI_SUCCESS Find the specified variable.\r
1935 @return EFI_NOT_FOUND Not found.\r
1936 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
1937\r
1938**/\r
1939EFI_STATUS\r
1940EFIAPI\r
1941VariableServiceGetNextVariableName (\r
1942 IN OUT UINTN *VariableNameSize,\r
1943 IN OUT CHAR16 *VariableName,\r
1944 IN OUT EFI_GUID *VendorGuid\r
1945 )\r
1946{\r
1947 VARIABLE_STORE_TYPE Type;\r
1948 VARIABLE_POINTER_TRACK Variable;\r
1949 VARIABLE_POINTER_TRACK VariableInHob;\r
1950 UINTN VarNameSize;\r
1951 EFI_STATUS Status;\r
1952 VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];\r
1953\r
1954 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
1955 return EFI_INVALID_PARAMETER;\r
1956 }\r
1957\r
1958 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
1959\r
1960 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
1961 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
1962 goto Done;\r
1963 }\r
1964\r
1965 if (VariableName[0] != 0) {\r
1966 //\r
1967 // If variable name is not NULL, get next variable.\r
1968 //\r
1969 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
1970 }\r
1971\r
1972 //\r
1973 // 0: Volatile, 1: HOB, 2: Non-Volatile.\r
1974 // The index and attributes mapping must be kept in this order as FindVariable\r
1975 // makes use of this mapping to implement search algorithm.\r
1976 //\r
1977 VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
1978 VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;\r
1979 VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache;\r
1980\r
1981 while (TRUE) {\r
1982 //\r
1983 // Switch from Volatile to HOB, to Non-Volatile.\r
1984 //\r
1985 while ((Variable.CurrPtr >= Variable.EndPtr) ||\r
1986 (Variable.CurrPtr == NULL) ||\r
1987 !IsValidVariableHeader (Variable.CurrPtr)\r
1988 ) {\r
1989 //\r
1990 // Find current storage index\r
1991 //\r
1992 for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {\r
1993 if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) {\r
1994 break;\r
1995 }\r
1996 }\r
1997 ASSERT (Type < VariableStoreTypeMax);\r
1998 //\r
1999 // Switch to next storage\r
2000 //\r
2001 for (Type++; Type < VariableStoreTypeMax; Type++) {\r
2002 if (VariableStoreHeader[Type] != NULL) {\r
2003 break;\r
2004 }\r
2005 }\r
2006 //\r
2007 // Capture the case that \r
2008 // 1. current storage is the last one, or\r
2009 // 2. no further storage\r
2010 //\r
2011 if (Type == VariableStoreTypeMax) {\r
2012 Status = EFI_NOT_FOUND;\r
2013 goto Done;\r
2014 }\r
2015 Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]);\r
2016 Variable.EndPtr = GetEndPointer (VariableStoreHeader[Type]);\r
2017 Variable.CurrPtr = Variable.StartPtr;\r
2018 }\r
2019\r
2020 //\r
2021 // Variable is found\r
2022 //\r
2023 if (Variable.CurrPtr->State == VAR_ADDED) {\r
2024 if ((AtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) == 0) {\r
2025\r
2026 //\r
2027 // Don't return NV variable when HOB overrides it\r
2028 //\r
2029 if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) && (VariableStoreHeader[VariableStoreTypeNv] != NULL) && \r
2030 (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv]))\r
2031 ) {\r
2032 VariableInHob.StartPtr = GetStartPointer (VariableStoreHeader[VariableStoreTypeHob]);\r
2033 VariableInHob.EndPtr = GetEndPointer (VariableStoreHeader[VariableStoreTypeHob]);\r
2034 Status = FindVariableEx (\r
2035 GetVariableNamePtr (Variable.CurrPtr),\r
2036 &Variable.CurrPtr->VendorGuid,\r
2037 FALSE,\r
2038 &VariableInHob\r
2039 );\r
2040 if (!EFI_ERROR (Status)) {\r
2041 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
2042 continue;\r
2043 }\r
2044 }\r
2045\r
2046 VarNameSize = NameSizeOfVariable (Variable.CurrPtr);\r
2047 ASSERT (VarNameSize != 0);\r
2048\r
2049 if (VarNameSize <= *VariableNameSize) {\r
2050 CopyMem (VariableName, GetVariableNamePtr (Variable.CurrPtr), VarNameSize);\r
2051 CopyMem (VendorGuid, &Variable.CurrPtr->VendorGuid, sizeof (EFI_GUID));\r
2052 Status = EFI_SUCCESS;\r
2053 } else {\r
2054 Status = EFI_BUFFER_TOO_SMALL;\r
2055 }\r
2056\r
2057 *VariableNameSize = VarNameSize;\r
2058 goto Done;\r
2059 }\r
2060 }\r
2061\r
2062 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
2063 }\r
2064\r
2065Done:\r
2066 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2067 return Status;\r
2068}\r
2069\r
2070/**\r
2071\r
2072 This code sets variable in storage blocks (Volatile or Non-Volatile).\r
2073\r
2074 @param VariableName Name of Variable to be found.\r
2075 @param VendorGuid Variable vendor GUID.\r
2076 @param Attributes Attribute value of the variable found\r
2077 @param DataSize Size of Data found. If size is less than the\r
2078 data, this value contains the required size.\r
2079 @param Data Data pointer.\r
2080\r
2081 @return EFI_INVALID_PARAMETER Invalid parameter.\r
2082 @return EFI_SUCCESS Set successfully.\r
2083 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.\r
2084 @return EFI_NOT_FOUND Not found.\r
2085 @return EFI_WRITE_PROTECTED Variable is read-only.\r
2086\r
2087**/\r
2088EFI_STATUS\r
2089EFIAPI\r
2090VariableServiceSetVariable (\r
2091 IN CHAR16 *VariableName,\r
2092 IN EFI_GUID *VendorGuid,\r
2093 IN UINT32 Attributes,\r
2094 IN UINTN DataSize,\r
2095 IN VOID *Data\r
2096 )\r
2097{\r
2098 VARIABLE_POINTER_TRACK Variable;\r
2099 EFI_STATUS Status;\r
2100 VARIABLE_HEADER *NextVariable;\r
2101 EFI_PHYSICAL_ADDRESS Point;\r
2102\r
2103 //\r
2104 // Check input parameters.\r
2105 //\r
2106 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
2107 return EFI_INVALID_PARAMETER;\r
2108 } \r
2109\r
2110 if (DataSize != 0 && Data == NULL) {\r
2111 return EFI_INVALID_PARAMETER;\r
2112 }\r
2113\r
2114 //\r
2115 // Not support authenticated variable write yet.\r
2116 //\r
2117 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
2118 return EFI_INVALID_PARAMETER;\r
2119 }\r
2120\r
2121 //\r
2122 // Make sure if runtime bit is set, boot service bit is set also.\r
2123 //\r
2124 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
2125 return EFI_INVALID_PARAMETER;\r
2126 }\r
2127\r
2128 //\r
2129 // The size of the VariableName, including the Unicode Null in bytes plus\r
2130 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)\r
2131 // bytes for HwErrRec, and PcdGet32 (PcdMaxVariableSize) bytes for the others.\r
2132 //\r
2133 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2134 if ((DataSize > PcdGet32 (PcdMaxHardwareErrorVariableSize)) ||\r
2135 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxHardwareErrorVariableSize))) {\r
2136 return EFI_INVALID_PARAMETER;\r
2137 }\r
2138 if (!IsHwErrRecVariable(VariableName, VendorGuid)) {\r
2139 return EFI_INVALID_PARAMETER;\r
2140 }\r
2141 } else {\r
2142 //\r
2143 // The size of the VariableName, including the Unicode Null in bytes plus\r
2144 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxVariableSize) bytes.\r
2145 //\r
2146 if ((DataSize > PcdGet32 (PcdMaxVariableSize)) ||\r
2147 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxVariableSize))) {\r
2148 return EFI_INVALID_PARAMETER;\r
2149 } \r
2150 }\r
2151\r
2152 if (AtRuntime ()) {\r
2153 //\r
2154 // HwErrRecSupport Global Variable identifies the level of hardware error record persistence\r
2155 // support implemented by the platform. This variable is only modified by firmware and is read-only to the OS.\r
2156 //\r
2157 if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, L"HwErrRecSupport") == 0)) {\r
2158 return EFI_WRITE_PROTECTED;\r
2159 }\r
2160 }\r
2161\r
2162 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2163\r
2164 //\r
2165 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.\r
2166 //\r
2167 if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {\r
2168 Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
2169 //\r
2170 // Parse non-volatile variable data and get last variable offset.\r
2171 //\r
2172 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point);\r
2173 while ((NextVariable < GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point)) \r
2174 && IsValidVariableHeader (NextVariable)) {\r
2175 NextVariable = GetNextVariablePtr (NextVariable);\r
2176 }\r
2177 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;\r
2178 }\r
2179\r
2180 //\r
2181 // Check whether the input variable is already existed.\r
2182 //\r
2183 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, TRUE);\r
2184 if (!EFI_ERROR (Status)) {\r
2185 if (((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) && AtRuntime ()) {\r
2186 return EFI_WRITE_PROTECTED;\r
2187 }\r
2188 }\r
2189\r
2190 //\r
2191 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.\r
2192 //\r
2193 AutoUpdateLangVariable (VariableName, Data, DataSize);\r
2194\r
2195 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, &Variable);\r
2196\r
2197 InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);\r
2198 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2199\r
2200 return Status;\r
2201}\r
2202\r
2203/**\r
2204\r
2205 This code returns information about the EFI variables.\r
2206\r
2207 @param Attributes Attributes bitmask to specify the type of variables\r
2208 on which to return information.\r
2209 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
2210 for the EFI variables associated with the attributes specified.\r
2211 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
2212 for EFI variables associated with the attributes specified.\r
2213 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables\r
2214 associated with the attributes specified.\r
2215\r
2216 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.\r
2217 @return EFI_SUCCESS Query successfully.\r
2218 @return EFI_UNSUPPORTED The attribute is not supported on this platform.\r
2219\r
2220**/\r
2221EFI_STATUS\r
2222EFIAPI\r
2223VariableServiceQueryVariableInfo (\r
2224 IN UINT32 Attributes,\r
2225 OUT UINT64 *MaximumVariableStorageSize,\r
2226 OUT UINT64 *RemainingVariableStorageSize,\r
2227 OUT UINT64 *MaximumVariableSize\r
2228 )\r
2229{\r
2230 VARIABLE_HEADER *Variable;\r
2231 VARIABLE_HEADER *NextVariable;\r
2232 UINT64 VariableSize;\r
2233 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
2234 UINT64 CommonVariableTotalSize;\r
2235 UINT64 HwErrVariableTotalSize;\r
2236\r
2237 CommonVariableTotalSize = 0;\r
2238 HwErrVariableTotalSize = 0;\r
2239\r
2240 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
2241 return EFI_INVALID_PARAMETER;\r
2242 }\r
2243\r
2244 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {\r
2245 //\r
2246 // Make sure the Attributes combination is supported by the platform.\r
2247 //\r
2248 return EFI_UNSUPPORTED; \r
2249 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
2250 //\r
2251 // Make sure if runtime bit is set, boot service bit is set also.\r
2252 //\r
2253 return EFI_INVALID_PARAMETER;\r
2254 } else if (AtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {\r
2255 //\r
2256 // Make sure RT Attribute is set if we are in Runtime phase.\r
2257 //\r
2258 return EFI_INVALID_PARAMETER;\r
2259 } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2260 //\r
2261 // Make sure Hw Attribute is set with NV.\r
2262 //\r
2263 return EFI_INVALID_PARAMETER;\r
2264 } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
2265 //\r
2266 // Not support authentiated variable write yet.\r
2267 //\r
2268 return EFI_UNSUPPORTED;\r
2269 }\r
2270\r
2271 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2272\r
2273 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
2274 //\r
2275 // Query is Volatile related.\r
2276 //\r
2277 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
2278 } else {\r
2279 //\r
2280 // Query is Non-Volatile related.\r
2281 //\r
2282 VariableStoreHeader = mNvVariableCache;\r
2283 }\r
2284\r
2285 //\r
2286 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize\r
2287 // with the storage size (excluding the storage header size).\r
2288 //\r
2289 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
2290\r
2291 //\r
2292 // Harware error record variable needs larger size.\r
2293 //\r
2294 if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
2295 *MaximumVariableStorageSize = PcdGet32 (PcdHwErrStorageSize);\r
2296 *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);\r
2297 } else {\r
2298 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
2299 ASSERT (PcdGet32 (PcdHwErrStorageSize) < VariableStoreHeader->Size);\r
2300 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize);\r
2301 }\r
2302\r
2303 //\r
2304 // Let *MaximumVariableSize be PcdGet32 (PcdMaxVariableSize) with the exception of the variable header size.\r
2305 //\r
2306 *MaximumVariableSize = PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);\r
2307 }\r
2308\r
2309 //\r
2310 // Point to the starting address of the variables.\r
2311 //\r
2312 Variable = GetStartPointer (VariableStoreHeader);\r
2313\r
2314 //\r
2315 // Now walk through the related variable store.\r
2316 //\r
2317 while ((Variable < GetEndPointer (VariableStoreHeader)) && IsValidVariableHeader (Variable)) {\r
2318 NextVariable = GetNextVariablePtr (Variable);\r
2319 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;\r
2320\r
2321 if (AtRuntime ()) {\r
2322 //\r
2323 // We don't take the state of the variables in mind\r
2324 // when calculating RemainingVariableStorageSize,\r
2325 // since the space occupied by variables not marked with\r
2326 // VAR_ADDED is not allowed to be reclaimed in Runtime.\r
2327 //\r
2328 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2329 HwErrVariableTotalSize += VariableSize;\r
2330 } else {\r
2331 CommonVariableTotalSize += VariableSize;\r
2332 }\r
2333 } else {\r
2334 //\r
2335 // Only care about Variables with State VAR_ADDED, because\r
2336 // the space not marked as VAR_ADDED is reclaimable now.\r
2337 //\r
2338 if (Variable->State == VAR_ADDED) {\r
2339 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2340 HwErrVariableTotalSize += VariableSize;\r
2341 } else {\r
2342 CommonVariableTotalSize += VariableSize;\r
2343 }\r
2344 }\r
2345 }\r
2346\r
2347 //\r
2348 // Go to the next one.\r
2349 //\r
2350 Variable = NextVariable;\r
2351 }\r
2352\r
2353 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){\r
2354 *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;\r
2355 }else {\r
2356 *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;\r
2357 }\r
2358\r
2359 if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {\r
2360 *MaximumVariableSize = 0;\r
2361 } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {\r
2362 *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);\r
2363 }\r
2364\r
2365 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2366 return EFI_SUCCESS;\r
2367}\r
2368\r
2369\r
2370/**\r
2371 This function reclaims variable storage if free size is below the threshold.\r
2372 \r
2373**/\r
2374VOID\r
2375ReclaimForOS(\r
2376 VOID\r
2377 )\r
2378{\r
2379 EFI_STATUS Status;\r
2380 UINTN CommonVariableSpace;\r
2381 UINTN RemainingCommonVariableSpace;\r
2382 UINTN RemainingHwErrVariableSpace;\r
2383\r
2384 Status = EFI_SUCCESS; \r
2385\r
2386 CommonVariableSpace = ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize); //Allowable max size of common variable storage space\r
2387\r
2388 RemainingCommonVariableSpace = CommonVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;\r
2389\r
2390 RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;\r
2391 //\r
2392 // Check if the free area is blow a threshold.\r
2393 //\r
2394 if ((RemainingCommonVariableSpace < PcdGet32 (PcdMaxVariableSize))\r
2395 || ((PcdGet32 (PcdHwErrStorageSize) != 0) && \r
2396 (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize)))){\r
2397 Status = Reclaim (\r
2398 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
2399 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
2400 FALSE,\r
2401 NULL,\r
2402 FALSE\r
2403 );\r
2404 ASSERT_EFI_ERROR (Status);\r
2405 }\r
2406}\r
2407\r
2408/**\r
2409 Flush the HOB variable to flash.\r
2410\r
2411 @param[in] VariableName Name of variable has been updated or deleted.\r
2412 @param[in] VendorGuid Guid of variable has been updated or deleted.\r
2413\r
2414**/\r
2415VOID\r
2416FlushHobVariableToFlash (\r
2417 IN CHAR16 *VariableName,\r
2418 IN EFI_GUID *VendorGuid\r
2419 )\r
2420{\r
2421 EFI_STATUS Status;\r
2422 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
2423 VARIABLE_HEADER *Variable;\r
2424 VOID *VariableData;\r
2425 BOOLEAN ErrorFlag;\r
2426\r
2427 ErrorFlag = FALSE;\r
2428\r
2429 //\r
2430 // Flush the HOB variable to flash.\r
2431 //\r
2432 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {\r
2433 VariableStoreHeader = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;\r
2434 //\r
2435 // Set HobVariableBase to 0, it can avoid SetVariable to call back.\r
2436 //\r
2437 mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;\r
2438 for ( Variable = GetStartPointer (VariableStoreHeader)\r
2439 ; (Variable < GetEndPointer (VariableStoreHeader) && IsValidVariableHeader (Variable))\r
2440 ; Variable = GetNextVariablePtr (Variable)\r
2441 ) {\r
2442 if (Variable->State != VAR_ADDED) {\r
2443 //\r
2444 // The HOB variable has been set to DELETED state in local.\r
2445 //\r
2446 continue;\r
2447 }\r
2448 ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0);\r
2449 if (VendorGuid == NULL || VariableName == NULL ||\r
2450 !CompareGuid (VendorGuid, &Variable->VendorGuid) ||\r
2451 StrCmp (VariableName, GetVariableNamePtr (Variable)) != 0) {\r
2452 VariableData = GetVariableDataPtr (Variable);\r
2453 Status = VariableServiceSetVariable (\r
2454 GetVariableNamePtr (Variable),\r
2455 &Variable->VendorGuid,\r
2456 Variable->Attributes,\r
2457 Variable->DataSize,\r
2458 VariableData\r
2459 );\r
2460 DEBUG ((EFI_D_INFO, "Variable driver flush the HOB variable to flash: %g %s %r\n", &Variable->VendorGuid, GetVariableNamePtr (Variable), Status));\r
2461 } else {\r
2462 //\r
2463 // The updated or deleted variable is matched with the HOB variable.\r
2464 // Don't break here because we will try to set other HOB variables\r
2465 // since this variable could be set successfully.\r
2466 //\r
2467 Status = EFI_SUCCESS;\r
2468 }\r
2469 if (!EFI_ERROR (Status)) {\r
2470 //\r
2471 // If set variable successful, or the updated or deleted variable is matched with the HOB variable,\r
2472 // set the HOB variable to DELETED state in local.\r
2473 //\r
2474 DEBUG ((EFI_D_INFO, "Variable driver set the HOB variable to DELETED state in local: %g %s\n", &Variable->VendorGuid, GetVariableNamePtr (Variable)));\r
2475 Variable->State &= VAR_DELETED;\r
2476 } else {\r
2477 ErrorFlag = TRUE;\r
2478 }\r
2479 }\r
2480 if (ErrorFlag) {\r
2481 //\r
2482 // We still have HOB variable(s) not flushed in flash.\r
2483 //\r
2484 mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStoreHeader;\r
2485 } else {\r
2486 //\r
2487 // All HOB variables have been flushed in flash.\r
2488 //\r
2489 DEBUG ((EFI_D_INFO, "Variable driver: all HOB variables have been flushed in flash.\n"));\r
2490 if (!AtRuntime ()) {\r
2491 FreePool ((VOID *) VariableStoreHeader);\r
2492 }\r
2493 }\r
2494 }\r
2495\r
2496}\r
2497\r
2498/**\r
2499 Initializes variable write service after FVB was ready.\r
2500\r
2501 @retval EFI_SUCCESS Function successfully executed.\r
2502 @retval Others Fail to initialize the variable service.\r
2503\r
2504**/\r
2505EFI_STATUS\r
2506VariableWriteServiceInitialize (\r
2507 VOID\r
2508 )\r
2509{\r
2510 EFI_STATUS Status;\r
2511 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
2512 UINTN Index;\r
2513 UINT8 Data;\r
2514 EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
2515\r
2516 VariableStoreBase = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
2517 VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
2518 \r
2519 //\r
2520 // Check if the free area is really free.\r
2521 //\r
2522 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {\r
2523 Data = ((UINT8 *) mNvVariableCache)[Index];\r
2524 if (Data != 0xff) {\r
2525 //\r
2526 // There must be something wrong in variable store, do reclaim operation.\r
2527 //\r
2528 Status = Reclaim (\r
2529 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
2530 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
2531 FALSE,\r
2532 NULL,\r
2533 TRUE\r
2534 );\r
2535 if (EFI_ERROR (Status)) {\r
2536 return Status;\r
2537 }\r
2538 break;\r
2539 }\r
2540 }\r
2541\r
2542 FlushHobVariableToFlash (NULL, NULL);\r
2543\r
2544 return EFI_SUCCESS;\r
2545}\r
2546\r
2547\r
2548/**\r
2549 Initializes variable store area for non-volatile and volatile variable.\r
2550\r
2551 @retval EFI_SUCCESS Function successfully executed.\r
2552 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r
2553\r
2554**/\r
2555EFI_STATUS\r
2556VariableCommonInitialize (\r
2557 VOID\r
2558 )\r
2559{\r
2560 EFI_STATUS Status;\r
2561 VARIABLE_STORE_HEADER *VolatileVariableStore;\r
2562 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
2563 VARIABLE_HEADER *NextVariable;\r
2564 EFI_PHYSICAL_ADDRESS TempVariableStoreHeader;\r
2565 EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
2566 UINT64 VariableStoreLength;\r
2567 UINTN ScratchSize;\r
2568 UINTN VariableSize;\r
2569 EFI_HOB_GUID_TYPE *GuidHob;\r
2570\r
2571 //\r
2572 // Allocate runtime memory for variable driver global structure.\r
2573 //\r
2574 mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL));\r
2575 if (mVariableModuleGlobal == NULL) {\r
2576 return EFI_OUT_OF_RESOURCES;\r
2577 }\r
2578\r
2579 InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);\r
2580\r
2581 //\r
2582 // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r
2583 // is stored with common variable in the same NV region. So the platform integrator should\r
2584 // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of \r
2585 // PcdFlashNvStorageVariableSize.\r
2586 //\r
2587 ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));\r
2588\r
2589 //\r
2590 // Get HOB variable store.\r
2591 //\r
2592 GuidHob = GetFirstGuidHob (&gEfiVariableGuid);\r
2593 if (GuidHob != NULL) {\r
2594 VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob);\r
2595 VariableStoreLength = (UINT64) (GuidHob->Header.HobLength - sizeof (EFI_HOB_GUID_TYPE));\r
2596 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
2597 mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateRuntimeCopyPool ((UINTN) VariableStoreLength, (VOID *) VariableStoreHeader);\r
2598 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) {\r
2599 return EFI_OUT_OF_RESOURCES;\r
2600 }\r
2601 } else {\r
2602 DEBUG ((EFI_D_ERROR, "HOB Variable Store header is corrupted!\n"));\r
2603 }\r
2604 }\r
2605\r
2606 //\r
2607 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.\r
2608 //\r
2609 ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
2610 VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);\r
2611 if (VolatileVariableStore == NULL) {\r
2612 FreePool (mVariableModuleGlobal);\r
2613 return EFI_OUT_OF_RESOURCES;\r
2614 }\r
2615\r
2616 SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);\r
2617\r
2618 //\r
2619 // Initialize Variable Specific Data.\r
2620 //\r
2621 mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
2622 mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;\r
2623 mVariableModuleGlobal->FvbInstance = NULL;\r
2624\r
2625 CopyGuid (&VolatileVariableStore->Signature, &gEfiVariableGuid);\r
2626 VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize);\r
2627 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;\r
2628 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;\r
2629 VolatileVariableStore->Reserved = 0;\r
2630 VolatileVariableStore->Reserved1 = 0;\r
2631\r
2632 //\r
2633 // Get non-volatile variable store.\r
2634 //\r
2635\r
2636 TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
2637 if (TempVariableStoreHeader == 0) {\r
2638 TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
2639 }\r
2640\r
2641 //\r
2642 // Check if the Firmware Volume is not corrupted\r
2643 //\r
2644 if ((((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader))->Signature != EFI_FVH_SIGNATURE) ||\r
2645 (!CompareGuid (&gEfiSystemNvDataFvGuid, &((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader))->FileSystemGuid))) {\r
2646 Status = EFI_VOLUME_CORRUPTED;\r
2647 DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n"));\r
2648 goto Done;\r
2649 }\r
2650\r
2651 VariableStoreBase = TempVariableStoreHeader + \\r
2652 (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
2653 VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \\r
2654 (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
2655\r
2656 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
2657 VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
2658 if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {\r
2659 Status = EFI_VOLUME_CORRUPTED;\r
2660 DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));\r
2661 goto Done;\r
2662 } \r
2663 ASSERT(VariableStoreHeader->Size == VariableStoreLength);\r
2664 \r
2665 //\r
2666 // Parse non-volatile variable data and get last variable offset.\r
2667 //\r
2668 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);\r
2669 while (IsValidVariableHeader (NextVariable)) {\r
2670 VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);\r
2671 if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
2672 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);\r
2673 } else {\r
2674 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);\r
2675 }\r
2676\r
2677 NextVariable = GetNextVariablePtr (NextVariable);\r
2678 }\r
2679\r
2680 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;\r
2681 \r
2682 //\r
2683 // Allocate runtime memory used for a memory copy of the FLASH region.\r
2684 // Keep the memory and the FLASH in sync as updates occur\r
2685 //\r
2686 mNvVariableCache = AllocateRuntimeZeroPool ((UINTN)VariableStoreLength);\r
2687 if (mNvVariableCache == NULL) {\r
2688 Status = EFI_OUT_OF_RESOURCES;\r
2689 goto Done;\r
2690 }\r
2691 CopyMem (mNvVariableCache, (CHAR8 *)(UINTN)VariableStoreBase, (UINTN)VariableStoreLength);\r
2692 Status = EFI_SUCCESS;\r
2693\r
2694Done:\r
2695 if (EFI_ERROR (Status)) {\r
2696 FreePool (mVariableModuleGlobal);\r
2697 FreePool (VolatileVariableStore);\r
2698 }\r
2699\r
2700 return Status;\r
2701}\r
2702\r
2703\r
2704/**\r
2705 Get the proper fvb handle and/or fvb protocol by the given Flash address.\r
2706\r
2707 @param[in] Address The Flash address.\r
2708 @param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle.\r
2709 @param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol.\r
2710\r
2711**/\r
2712EFI_STATUS\r
2713GetFvbInfoByAddress (\r
2714 IN EFI_PHYSICAL_ADDRESS Address,\r
2715 OUT EFI_HANDLE *FvbHandle OPTIONAL,\r
2716 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvbProtocol OPTIONAL\r
2717 )\r
2718{\r
2719 EFI_STATUS Status;\r
2720 EFI_HANDLE *HandleBuffer;\r
2721 UINTN HandleCount;\r
2722 UINTN Index;\r
2723 EFI_PHYSICAL_ADDRESS FvbBaseAddress;\r
2724 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
2725 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
2726 EFI_FVB_ATTRIBUTES_2 Attributes;\r
2727 \r
2728 //\r
2729 // Get all FVB handles.\r
2730 //\r
2731 Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);\r
2732 if (EFI_ERROR (Status)) {\r
2733 return EFI_NOT_FOUND;\r
2734 }\r
2735\r
2736 //\r
2737 // Get the FVB to access variable store.\r
2738 //\r
2739 Fvb = NULL;\r
2740 for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {\r
2741 Status = GetFvbByHandle (HandleBuffer[Index], &Fvb);\r
2742 if (EFI_ERROR (Status)) {\r
2743 Status = EFI_NOT_FOUND;\r
2744 break;\r
2745 }\r
2746\r
2747 //\r
2748 // Ensure this FVB protocol supported Write operation.\r
2749 //\r
2750 Status = Fvb->GetAttributes (Fvb, &Attributes);\r
2751 if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {\r
2752 continue; \r
2753 }\r
2754 \r
2755 //\r
2756 // Compare the address and select the right one.\r
2757 //\r
2758 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
2759 if (EFI_ERROR (Status)) {\r
2760 continue;\r
2761 }\r
2762\r
2763 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
2764 if ((Address >= FvbBaseAddress) && (Address < (FvbBaseAddress + FwVolHeader->FvLength))) {\r
2765 if (FvbHandle != NULL) {\r
2766 *FvbHandle = HandleBuffer[Index];\r
2767 }\r
2768 if (FvbProtocol != NULL) {\r
2769 *FvbProtocol = Fvb;\r
2770 }\r
2771 Status = EFI_SUCCESS;\r
2772 break;\r
2773 }\r
2774 }\r
2775 FreePool (HandleBuffer);\r
2776\r
2777 if (Fvb == NULL) {\r
2778 Status = EFI_NOT_FOUND;\r
2779 }\r
2780 \r
2781 return Status; \r
2782}\r
2783\r