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