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