]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c
EFI_STATUS_CODE_DATA_MAX_SIZE is just for the maximum size of an EFI_DEBUG_INFO struc...
[mirror_edk2.git] / SecurityPkg / VariableAuthenticated / RuntimeDxe / Variable.c
CommitLineData
0c18794e 1/** @file\r
021a1af9 2 The common variable operation routines shared by DXE_RUNTIME 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
a5f15e30
SZ
1887/**\r
1888 Check if a Unicode character is a hexadecimal character.\r
1889\r
1890 This function checks if a Unicode character is a \r
1891 hexadecimal character. The valid hexadecimal character is \r
1892 L'0' to L'9', L'a' to L'f', or L'A' to L'F'.\r
1893\r
1894\r
1895 @param Char The character to check against.\r
1896\r
1897 @retval TRUE If the Char is a hexadecmial character.\r
1898 @retval FALSE If the Char is not a hexadecmial character.\r
1899\r
1900**/\r
1901BOOLEAN\r
1902EFIAPI\r
1903IsHexaDecimalDigitCharacter (\r
1904 IN CHAR16 Char\r
1905 )\r
1906{\r
1907 return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f'));\r
1908}\r
1909\r
1910/**\r
1911\r
1912 This code checks if variable is hardware error record variable or not.\r
1913\r
1914 According to UEFI spec, hardware error record variable should use the EFI_HARDWARE_ERROR_VARIABLE VendorGuid\r
1915 and have the L"HwErrRec####" name convention, #### is a printed hex value and no 0x or h is included in the hex value.\r
1916\r
1917 @param VariableName Pointer to variable name.\r
1918 @param VendorGuid Variable Vendor Guid.\r
1919\r
1920 @retval TRUE Variable is hardware error record variable.\r
1921 @retval FALSE Variable is not hardware error record variable.\r
1922\r
1923**/\r
1924BOOLEAN\r
1925EFIAPI\r
1926IsHwErrRecVariable (\r
1927 IN CHAR16 *VariableName,\r
1928 IN EFI_GUID *VendorGuid\r
1929 )\r
1930{\r
1931 if (!CompareGuid (VendorGuid, &gEfiHardwareErrorVariableGuid) ||\r
1932 (StrLen (VariableName) != StrLen (L"HwErrRec####")) ||\r
1933 (StrnCmp(VariableName, L"HwErrRec", StrLen (L"HwErrRec")) != 0) ||\r
1934 !IsHexaDecimalDigitCharacter (VariableName[0x8]) ||\r
1935 !IsHexaDecimalDigitCharacter (VariableName[0x9]) ||\r
1936 !IsHexaDecimalDigitCharacter (VariableName[0xA]) ||\r
1937 !IsHexaDecimalDigitCharacter (VariableName[0xB])) {\r
1938 return FALSE;\r
1939 }\r
1940\r
1941 return TRUE;\r
1942}\r
1943\r
0c18794e 1944/**\r
1945\r
1946 This code finds variable in storage blocks (Volatile or Non-Volatile).\r
1947\r
1948 @param VariableName Name of Variable to be found.\r
1949 @param VendorGuid Variable vendor GUID.\r
1950 @param Attributes Attribute value of the variable found.\r
1951 @param DataSize Size of Data found. If size is less than the\r
1952 data, this value contains the required size.\r
1953 @param Data Data pointer.\r
2d3fb919 1954\r
0c18794e 1955 @return EFI_INVALID_PARAMETER Invalid parameter.\r
1956 @return EFI_SUCCESS Find the specified variable.\r
1957 @return EFI_NOT_FOUND Not found.\r
1958 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
1959\r
1960**/\r
1961EFI_STATUS\r
1962EFIAPI\r
1963VariableServiceGetVariable (\r
1964 IN CHAR16 *VariableName,\r
1965 IN EFI_GUID *VendorGuid,\r
1966 OUT UINT32 *Attributes OPTIONAL,\r
1967 IN OUT UINTN *DataSize,\r
1968 OUT VOID *Data\r
1969 )\r
1970{\r
1971 EFI_STATUS Status;\r
1972 VARIABLE_POINTER_TRACK Variable;\r
1973 UINTN VarDataSize;\r
1974\r
1975 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
1976 return EFI_INVALID_PARAMETER;\r
1977 }\r
1978\r
1979 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2d3fb919 1980\r
ecc722ad 1981 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
0c18794e 1982 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
1983 goto Done;\r
1984 }\r
1985\r
1986 //\r
1987 // Get data size\r
1988 //\r
1989 VarDataSize = DataSizeOfVariable (Variable.CurrPtr);\r
1990 ASSERT (VarDataSize != 0);\r
1991\r
1992 if (*DataSize >= VarDataSize) {\r
1993 if (Data == NULL) {\r
1994 Status = EFI_INVALID_PARAMETER;\r
1995 goto Done;\r
1996 }\r
1997\r
1998 CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);\r
1999 if (Attributes != NULL) {\r
2000 *Attributes = Variable.CurrPtr->Attributes;\r
2001 }\r
2002\r
2003 *DataSize = VarDataSize;\r
2004 UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);\r
2d3fb919 2005\r
0c18794e 2006 Status = EFI_SUCCESS;\r
2007 goto Done;\r
2008 } else {\r
2009 *DataSize = VarDataSize;\r
2010 Status = EFI_BUFFER_TOO_SMALL;\r
2011 goto Done;\r
2012 }\r
2013\r
2014Done:\r
2015 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2016 return Status;\r
2017}\r
2018\r
2019\r
2020\r
2021/**\r
2022\r
2023 This code Finds the Next available variable.\r
2024\r
2025 @param VariableNameSize Size of the variable name.\r
2026 @param VariableName Pointer to variable name.\r
2027 @param VendorGuid Variable Vendor Guid.\r
2028\r
2029 @return EFI_INVALID_PARAMETER Invalid parameter.\r
2030 @return EFI_SUCCESS Find the specified variable.\r
2031 @return EFI_NOT_FOUND Not found.\r
2032 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
2033\r
2034**/\r
2035EFI_STATUS\r
2036EFIAPI\r
2037VariableServiceGetNextVariableName (\r
2038 IN OUT UINTN *VariableNameSize,\r
2039 IN OUT CHAR16 *VariableName,\r
2040 IN OUT EFI_GUID *VendorGuid\r
2041 )\r
2042{\r
9a000b46 2043 VARIABLE_STORE_TYPE Type;\r
0c18794e 2044 VARIABLE_POINTER_TRACK Variable;\r
9a000b46 2045 VARIABLE_POINTER_TRACK VariableInHob;\r
0c18794e 2046 UINTN VarNameSize;\r
2047 EFI_STATUS Status;\r
9a000b46 2048 VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];\r
0c18794e 2049\r
2050 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
2051 return EFI_INVALID_PARAMETER;\r
2052 }\r
2053\r
2054 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2055\r
ecc722ad 2056 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
0c18794e 2057 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
2058 goto Done;\r
2059 }\r
2060\r
2061 if (VariableName[0] != 0) {\r
2062 //\r
2063 // If variable name is not NULL, get next variable.\r
2064 //\r
2065 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
2066 }\r
2067\r
9a000b46
RN
2068 //\r
2069 // 0: Volatile, 1: HOB, 2: Non-Volatile.\r
2070 // The index and attributes mapping must be kept in this order as FindVariable\r
2071 // makes use of this mapping to implement search algorithm.\r
2072 //\r
2073 VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
2074 VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;\r
2075 VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache;\r
2076\r
0c18794e 2077 while (TRUE) {\r
2078 //\r
9a000b46 2079 // Switch from Volatile to HOB, to Non-Volatile.\r
0c18794e 2080 //\r
9a000b46
RN
2081 while ((Variable.CurrPtr >= Variable.EndPtr) ||\r
2082 (Variable.CurrPtr == NULL) ||\r
2083 !IsValidVariableHeader (Variable.CurrPtr)\r
2084 ) {\r
2085 //\r
2086 // Find current storage index\r
2087 //\r
2088 for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {\r
2089 if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) {\r
2090 break;\r
2091 }\r
2092 }\r
2093 ASSERT (Type < VariableStoreTypeMax);\r
2094 //\r
2095 // Switch to next storage\r
2096 //\r
2097 for (Type++; Type < VariableStoreTypeMax; Type++) {\r
2098 if (VariableStoreHeader[Type] != NULL) {\r
2099 break;\r
2100 }\r
2101 }\r
2102 //\r
2d3fb919 2103 // Capture the case that\r
9a000b46
RN
2104 // 1. current storage is the last one, or\r
2105 // 2. no further storage\r
2106 //\r
2107 if (Type == VariableStoreTypeMax) {\r
0c18794e 2108 Status = EFI_NOT_FOUND;\r
2109 goto Done;\r
2110 }\r
9a000b46
RN
2111 Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]);\r
2112 Variable.EndPtr = GetEndPointer (VariableStoreHeader[Type]);\r
2113 Variable.CurrPtr = Variable.StartPtr;\r
0c18794e 2114 }\r
9a000b46 2115\r
0c18794e 2116 //\r
2117 // Variable is found\r
2118 //\r
9a000b46 2119 if (Variable.CurrPtr->State == VAR_ADDED) {\r
0c18794e 2120 if ((AtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) == 0) {\r
9a000b46
RN
2121\r
2122 //\r
2123 // Don't return NV variable when HOB overrides it\r
2124 //\r
2d3fb919 2125 if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) && (VariableStoreHeader[VariableStoreTypeNv] != NULL) &&\r
9a000b46
RN
2126 (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv]))\r
2127 ) {\r
2128 VariableInHob.StartPtr = GetStartPointer (VariableStoreHeader[VariableStoreTypeHob]);\r
2129 VariableInHob.EndPtr = GetEndPointer (VariableStoreHeader[VariableStoreTypeHob]);\r
2130 Status = FindVariableEx (\r
2131 GetVariableNamePtr (Variable.CurrPtr),\r
2132 &Variable.CurrPtr->VendorGuid,\r
ecc722ad 2133 FALSE,\r
9a000b46
RN
2134 &VariableInHob\r
2135 );\r
2136 if (!EFI_ERROR (Status)) {\r
2137 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
2138 continue;\r
2139 }\r
2140 }\r
2141\r
0c18794e 2142 VarNameSize = NameSizeOfVariable (Variable.CurrPtr);\r
2143 ASSERT (VarNameSize != 0);\r
2144\r
2145 if (VarNameSize <= *VariableNameSize) {\r
9a000b46
RN
2146 CopyMem (VariableName, GetVariableNamePtr (Variable.CurrPtr), VarNameSize);\r
2147 CopyMem (VendorGuid, &Variable.CurrPtr->VendorGuid, sizeof (EFI_GUID));\r
0c18794e 2148 Status = EFI_SUCCESS;\r
2149 } else {\r
2150 Status = EFI_BUFFER_TOO_SMALL;\r
2151 }\r
2152\r
2153 *VariableNameSize = VarNameSize;\r
2154 goto Done;\r
2155 }\r
2156 }\r
2157\r
2158 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
2159 }\r
2160\r
2161Done:\r
2162 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2163 return Status;\r
2164}\r
2165\r
2166/**\r
2167\r
2168 This code sets variable in storage blocks (Volatile or Non-Volatile).\r
2169\r
2170 @param VariableName Name of Variable to be found.\r
2171 @param VendorGuid Variable vendor GUID.\r
2172 @param Attributes Attribute value of the variable found\r
2173 @param DataSize Size of Data found. If size is less than the\r
2174 data, this value contains the required size.\r
2175 @param Data Data pointer.\r
2176\r
2177 @return EFI_INVALID_PARAMETER Invalid parameter.\r
2178 @return EFI_SUCCESS Set successfully.\r
2179 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.\r
2180 @return EFI_NOT_FOUND Not found.\r
2181 @return EFI_WRITE_PROTECTED Variable is read-only.\r
2182\r
2183**/\r
2184EFI_STATUS\r
2185EFIAPI\r
2186VariableServiceSetVariable (\r
2187 IN CHAR16 *VariableName,\r
2188 IN EFI_GUID *VendorGuid,\r
2189 IN UINT32 Attributes,\r
2190 IN UINTN DataSize,\r
2191 IN VOID *Data\r
2192 )\r
2193{\r
2194 VARIABLE_POINTER_TRACK Variable;\r
2195 EFI_STATUS Status;\r
2196 VARIABLE_HEADER *NextVariable;\r
2197 EFI_PHYSICAL_ADDRESS Point;\r
2198 UINTN PayloadSize;\r
2199\r
2200 //\r
2201 // Check input parameters.\r
2202 //\r
2203 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
2204 return EFI_INVALID_PARAMETER;\r
2d3fb919 2205 }\r
0c18794e 2206\r
2207 if (DataSize != 0 && Data == NULL) {\r
2208 return EFI_INVALID_PARAMETER;\r
2209 }\r
2210\r
2211 //\r
2212 // Make sure if runtime bit is set, boot service bit is set also.\r
2213 //\r
2214 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
2215 return EFI_INVALID_PARAMETER;\r
2216 }\r
2217\r
2218 //\r
2d3fb919 2219 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute\r
0c18794e 2220 // cannot be set both.\r
2221 //\r
2d3fb919 2222 if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)\r
0c18794e 2223 && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {\r
2224 return EFI_INVALID_PARAMETER;\r
2d3fb919 2225 }\r
0c18794e 2226\r
2227 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) {\r
2228 if (DataSize < AUTHINFO_SIZE) {\r
2229 //\r
2d3fb919 2230 // Try to write Authenticated Variable without AuthInfo.\r
0c18794e 2231 //\r
2232 return EFI_SECURITY_VIOLATION;\r
2d3fb919 2233 }\r
2234 PayloadSize = DataSize - AUTHINFO_SIZE;\r
2235 } else if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {\r
2236 //\r
2237 // Sanity check for EFI_VARIABLE_AUTHENTICATION_2 descriptor.\r
2238 //\r
2239 if (DataSize < OFFSET_OF_AUTHINFO2_CERT_DATA ||\r
6bc4e19f 2240 ((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->AuthInfo.Hdr.dwLength > DataSize - (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo)) ||\r
2241 ((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->AuthInfo.Hdr.dwLength < OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)) {\r
2d3fb919 2242 return EFI_SECURITY_VIOLATION;\r
2243 }\r
2244 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r
0c18794e 2245 } else {\r
2d3fb919 2246 PayloadSize = DataSize;\r
0c18794e 2247 }\r
2d3fb919 2248\r
0c18794e 2249 //\r
2250 // The size of the VariableName, including the Unicode Null in bytes plus\r
2251 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)\r
2252 // bytes for HwErrRec, and PcdGet32 (PcdMaxVariableSize) bytes for the others.\r
2253 //\r
2254 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2255 if ((PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize)) ||\r
2256 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize))) {\r
2257 return EFI_INVALID_PARAMETER;\r
2258 }\r
a5f15e30 2259 if (!IsHwErrRecVariable(VariableName, VendorGuid)) {\r
0c18794e 2260 return EFI_INVALID_PARAMETER;\r
2261 }\r
2262 } else {\r
2263 //\r
2264 // The size of the VariableName, including the Unicode Null in bytes plus\r
2265 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxVariableSize) bytes.\r
2266 //\r
2267 if ((PayloadSize > PcdGet32 (PcdMaxVariableSize)) ||\r
2268 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxVariableSize))) {\r
2269 return EFI_INVALID_PARAMETER;\r
2d3fb919 2270 }\r
2271 }\r
0c18794e 2272\r
021a1af9
SZ
2273 if (AtRuntime ()) {\r
2274 //\r
2275 // HwErrRecSupport Global Variable identifies the level of hardware error record persistence\r
2276 // support implemented by the platform. This variable is only modified by firmware and is read-only to the OS.\r
2277 //\r
2278 if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, L"HwErrRecSupport") == 0)) {\r
2279 return EFI_WRITE_PROTECTED;\r
2280 }\r
2281 }\r
2282\r
0c18794e 2283 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2284\r
2285 //\r
2286 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.\r
2287 //\r
2288 if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {\r
2289 Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
2290 //\r
2291 // Parse non-volatile variable data and get last variable offset.\r
2292 //\r
2293 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point);\r
2d3fb919 2294 while ((NextVariable < GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point))\r
0c18794e 2295 && IsValidVariableHeader (NextVariable)) {\r
2296 NextVariable = GetNextVariablePtr (NextVariable);\r
2297 }\r
2298 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;\r
2299 }\r
2300\r
2301 //\r
2302 // Check whether the input variable is already existed.\r
2303 //\r
ecc722ad 2304 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, TRUE);\r
2305 if (!EFI_ERROR (Status)) {\r
2306 if (((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) && AtRuntime ()) {\r
2307 return EFI_WRITE_PROTECTED;\r
2308 }\r
2309 }\r
2310 \r
0c18794e 2311 //\r
2312 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.\r
2313 //\r
2314 AutoUpdateLangVariable (VariableName, Data, DataSize);\r
2315 //\r
2316 // Process PK, KEK, Sigdb seperately.\r
2317 //\r
2318 if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){\r
2319 Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, TRUE);\r
2320 } else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) {\r
2321 Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, FALSE);\r
ecc722ad 2322 } else if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) && \r
2323 ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0))) {\r
0c18794e 2324 Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);\r
2325 } else {\r
2326 Status = ProcessVariable (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);\r
2327 }\r
2328\r
2329 InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);\r
2330 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2331\r
2332 return Status;\r
2333}\r
2334\r
2335/**\r
2336\r
2337 This code returns information about the EFI variables.\r
2338\r
2339 @param Attributes Attributes bitmask to specify the type of variables\r
2340 on which to return information.\r
2341 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
2342 for the EFI variables associated with the attributes specified.\r
2343 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
2344 for EFI variables associated with the attributes specified.\r
2345 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables\r
2346 associated with the attributes specified.\r
2347\r
2348 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.\r
2349 @return EFI_SUCCESS Query successfully.\r
2350 @return EFI_UNSUPPORTED The attribute is not supported on this platform.\r
2351\r
2352**/\r
2353EFI_STATUS\r
2354EFIAPI\r
2355VariableServiceQueryVariableInfo (\r
2356 IN UINT32 Attributes,\r
2357 OUT UINT64 *MaximumVariableStorageSize,\r
2358 OUT UINT64 *RemainingVariableStorageSize,\r
2359 OUT UINT64 *MaximumVariableSize\r
2360 )\r
2361{\r
2362 VARIABLE_HEADER *Variable;\r
2363 VARIABLE_HEADER *NextVariable;\r
2364 UINT64 VariableSize;\r
2365 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
2366 UINT64 CommonVariableTotalSize;\r
2367 UINT64 HwErrVariableTotalSize;\r
2368\r
2369 CommonVariableTotalSize = 0;\r
2370 HwErrVariableTotalSize = 0;\r
2371\r
2372 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
2373 return EFI_INVALID_PARAMETER;\r
2374 }\r
2375\r
2376 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {\r
2377 //\r
2378 // Make sure the Attributes combination is supported by the platform.\r
2379 //\r
2d3fb919 2380 return EFI_UNSUPPORTED;\r
0c18794e 2381 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
2382 //\r
2383 // Make sure if runtime bit is set, boot service bit is set also.\r
2384 //\r
2385 return EFI_INVALID_PARAMETER;\r
2386 } else if (AtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {\r
2387 //\r
2388 // Make sure RT Attribute is set if we are in Runtime phase.\r
2389 //\r
2390 return EFI_INVALID_PARAMETER;\r
2391 } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2392 //\r
2393 // Make sure Hw Attribute is set with NV.\r
2394 //\r
2395 return EFI_INVALID_PARAMETER;\r
2396 }\r
2397\r
2398 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2399\r
2400 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
2401 //\r
2402 // Query is Volatile related.\r
2403 //\r
2404 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
2405 } else {\r
2406 //\r
2407 // Query is Non-Volatile related.\r
2408 //\r
2409 VariableStoreHeader = mNvVariableCache;\r
2410 }\r
2411\r
2412 //\r
2413 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize\r
2414 // with the storage size (excluding the storage header size).\r
2415 //\r
2416 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
2417\r
2418 //\r
2419 // Harware error record variable needs larger size.\r
2420 //\r
2421 if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
2422 *MaximumVariableStorageSize = PcdGet32 (PcdHwErrStorageSize);\r
2423 *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);\r
2424 } else {\r
2425 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
2426 ASSERT (PcdGet32 (PcdHwErrStorageSize) < VariableStoreHeader->Size);\r
2427 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize);\r
2428 }\r
2429\r
2430 //\r
2431 // Let *MaximumVariableSize be PcdGet32 (PcdMaxVariableSize) with the exception of the variable header size.\r
2432 //\r
2433 *MaximumVariableSize = PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);\r
2434 }\r
2435\r
2436 //\r
2437 // Point to the starting address of the variables.\r
2438 //\r
2439 Variable = GetStartPointer (VariableStoreHeader);\r
2440\r
2441 //\r
2442 // Now walk through the related variable store.\r
2443 //\r
2444 while ((Variable < GetEndPointer (VariableStoreHeader)) && IsValidVariableHeader (Variable)) {\r
2445 NextVariable = GetNextVariablePtr (Variable);\r
2446 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;\r
2447\r
2448 if (AtRuntime ()) {\r
2449 //\r
2450 // We don't take the state of the variables in mind\r
2451 // when calculating RemainingVariableStorageSize,\r
2452 // since the space occupied by variables not marked with\r
2453 // VAR_ADDED is not allowed to be reclaimed in Runtime.\r
2454 //\r
2455 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2456 HwErrVariableTotalSize += VariableSize;\r
2457 } else {\r
2458 CommonVariableTotalSize += VariableSize;\r
2459 }\r
2460 } else {\r
2461 //\r
2462 // Only care about Variables with State VAR_ADDED, because\r
2463 // the space not marked as VAR_ADDED is reclaimable now.\r
2464 //\r
2465 if (Variable->State == VAR_ADDED) {\r
2466 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2467 HwErrVariableTotalSize += VariableSize;\r
2468 } else {\r
2469 CommonVariableTotalSize += VariableSize;\r
2470 }\r
2471 }\r
2472 }\r
2473\r
2474 //\r
2475 // Go to the next one.\r
2476 //\r
2477 Variable = NextVariable;\r
2478 }\r
2479\r
2480 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){\r
2481 *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;\r
2482 }else {\r
2483 *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;\r
2484 }\r
2485\r
2486 if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {\r
2487 *MaximumVariableSize = 0;\r
2488 } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {\r
2489 *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);\r
2490 }\r
2491\r
2492 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2493 return EFI_SUCCESS;\r
2494}\r
2495\r
2496\r
2497/**\r
2498 This function reclaims variable storage if free size is below the threshold.\r
2d3fb919 2499\r
0c18794e 2500**/\r
2501VOID\r
2502ReclaimForOS(\r
2503 VOID\r
2504 )\r
2505{\r
2506 EFI_STATUS Status;\r
2507 UINTN CommonVariableSpace;\r
2508 UINTN RemainingCommonVariableSpace;\r
2509 UINTN RemainingHwErrVariableSpace;\r
2510\r
2d3fb919 2511 Status = EFI_SUCCESS;\r
0c18794e 2512\r
2513 CommonVariableSpace = ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize); //Allowable max size of common variable storage space\r
2514\r
2515 RemainingCommonVariableSpace = CommonVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;\r
2516\r
2517 RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;\r
2518 //\r
2519 // Check if the free area is blow a threshold.\r
2520 //\r
2521 if ((RemainingCommonVariableSpace < PcdGet32 (PcdMaxVariableSize))\r
2d3fb919 2522 || ((PcdGet32 (PcdHwErrStorageSize) != 0) &&\r
0c18794e 2523 (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize)))){\r
2524 Status = Reclaim (\r
2525 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
2526 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
2527 FALSE,\r
2528 NULL\r
2529 );\r
2530 ASSERT_EFI_ERROR (Status);\r
2531 }\r
2532}\r
2533\r
2534\r
2535/**\r
2536 Initializes variable write service after FVB was ready.\r
2537\r
2538 @retval EFI_SUCCESS Function successfully executed.\r
2539 @retval Others Fail to initialize the variable service.\r
2540\r
2541**/\r
2542EFI_STATUS\r
2543VariableWriteServiceInitialize (\r
2544 VOID\r
2545 )\r
2546{\r
2547 EFI_STATUS Status;\r
2548 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
2549 UINTN Index;\r
2550 UINT8 Data;\r
2551 EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
9a000b46
RN
2552 VARIABLE_HEADER *Variable;\r
2553 VOID *VariableData;\r
0c18794e 2554\r
2555 VariableStoreBase = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
2556 VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
2d3fb919 2557\r
0c18794e 2558 //\r
2559 // Check if the free area is really free.\r
2560 //\r
9a000b46 2561 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {\r
0c18794e 2562 Data = ((UINT8 *) mNvVariableCache)[Index];\r
2563 if (Data != 0xff) {\r
2564 //\r
2565 // There must be something wrong in variable store, do reclaim operation.\r
2566 //\r
2567 Status = Reclaim (\r
2568 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
2569 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
2570 FALSE,\r
2571 NULL\r
2572 );\r
2573 if (EFI_ERROR (Status)) {\r
2574 return Status;\r
2575 }\r
2576 break;\r
2577 }\r
2578 }\r
2579\r
2d3fb919 2580\r
9a000b46
RN
2581 //\r
2582 // Flush the HOB variable to flash and invalidate HOB variable.\r
2583 //\r
2584 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {\r
2585 //\r
2586 // Clear the HobVariableBase to avoid SetVariable() updating the variable in HOB\r
2587 //\r
2588 VariableStoreHeader = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;\r
2589 mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;\r
2590\r
2591 for ( Variable = GetStartPointer (VariableStoreHeader)\r
2592 ; (Variable < GetEndPointer (VariableStoreHeader) && IsValidVariableHeader (Variable))\r
2593 ; Variable = GetNextVariablePtr (Variable)\r
2594 ) {\r
2595 ASSERT (Variable->State == VAR_ADDED);\r
2596 ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0);\r
2597 VariableData = GetVariableDataPtr (Variable);\r
2598 Status = VariableServiceSetVariable (\r
2599 GetVariableNamePtr (Variable),\r
2600 &Variable->VendorGuid,\r
2601 Variable->Attributes,\r
2602 Variable->DataSize,\r
2603 VariableData\r
2604 );\r
2605 ASSERT_EFI_ERROR (Status);\r
2606 }\r
2607 }\r
2608\r
0c18794e 2609 //\r
2610 // Authenticated variable initialize.\r
2611 //\r
2612 Status = AutenticatedVariableServiceInitialize ();\r
2613\r
2614 return Status;\r
2615}\r
2616\r
2617\r
2618/**\r
2619 Initializes variable store area for non-volatile and volatile variable.\r
2620\r
2621 @retval EFI_SUCCESS Function successfully executed.\r
2622 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r
2623\r
2624**/\r
2625EFI_STATUS\r
2626VariableCommonInitialize (\r
2627 VOID\r
2628 )\r
2629{\r
2630 EFI_STATUS Status;\r
2631 VARIABLE_STORE_HEADER *VolatileVariableStore;\r
2632 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
2633 VARIABLE_HEADER *NextVariable;\r
2634 EFI_PHYSICAL_ADDRESS TempVariableStoreHeader;\r
2635 EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
2636 UINT64 VariableStoreLength;\r
2637 UINTN ScratchSize;\r
2638 UINTN VariableSize;\r
9a000b46 2639 EFI_HOB_GUID_TYPE *GuidHob;\r
0c18794e 2640\r
2641 //\r
2642 // Allocate runtime memory for variable driver global structure.\r
2643 //\r
2644 mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL));\r
2645 if (mVariableModuleGlobal == NULL) {\r
2646 return EFI_OUT_OF_RESOURCES;\r
2647 }\r
2648\r
2649 InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);\r
2650\r
2651 //\r
2652 // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r
2653 // is stored with common variable in the same NV region. So the platform integrator should\r
2d3fb919 2654 // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of\r
0c18794e 2655 // PcdFlashNvStorageVariableSize.\r
2656 //\r
2657 ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));\r
2658\r
9a000b46
RN
2659 //\r
2660 // Get HOB variable store.\r
2661 //\r
2662 GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);\r
2663 if (GuidHob != NULL) {\r
2664 VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob);\r
2665 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
2666 mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStoreHeader;\r
2667 } else {\r
2668 DEBUG ((EFI_D_ERROR, "HOB Variable Store header is corrupted!\n"));\r
2669 }\r
2670 }\r
2671\r
0c18794e 2672 //\r
2673 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.\r
2674 //\r
2675 ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
2676 VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);\r
2677 if (VolatileVariableStore == NULL) {\r
2678 FreePool (mVariableModuleGlobal);\r
2679 return EFI_OUT_OF_RESOURCES;\r
2680 }\r
2681\r
2682 SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);\r
2683\r
2684 //\r
2685 // Initialize Variable Specific Data.\r
2686 //\r
2687 mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
2688 mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;\r
2689 mVariableModuleGlobal->FvbInstance = NULL;\r
2690\r
2691 CopyGuid (&VolatileVariableStore->Signature, &gEfiAuthenticatedVariableGuid);\r
2692 VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize);\r
2693 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;\r
2694 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;\r
2695 VolatileVariableStore->Reserved = 0;\r
2696 VolatileVariableStore->Reserved1 = 0;\r
2697\r
2698 //\r
9a000b46 2699 // Get non-volatile variable store.\r
0c18794e 2700 //\r
2701\r
2702 TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
2703 if (TempVariableStoreHeader == 0) {\r
2704 TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
2705 }\r
4d832aab 2706 \r
2707 //\r
2708 // Check if the Firmware Volume is not corrupted\r
2709 //\r
2710 if ((((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader))->Signature != EFI_FVH_SIGNATURE) ||\r
2711 (!CompareGuid (&gEfiSystemNvDataFvGuid, &((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader))->FileSystemGuid))) {\r
2712 Status = EFI_VOLUME_CORRUPTED;\r
2713 DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n"));\r
2714 goto Done;\r
2715 }\r
2716\r
0c18794e 2717 VariableStoreBase = TempVariableStoreHeader + \\r
2718 (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
2719 VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \\r
2720 (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
2721\r
2722 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
2723 VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
2724 if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {\r
2725 Status = EFI_VOLUME_CORRUPTED;\r
2726 DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));\r
2727 goto Done;\r
2d3fb919 2728 }\r
0c18794e 2729 ASSERT(VariableStoreHeader->Size == VariableStoreLength);\r
2d3fb919 2730\r
0c18794e 2731 //\r
2732 // Parse non-volatile variable data and get last variable offset.\r
2733 //\r
2734 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);\r
2735 while (IsValidVariableHeader (NextVariable)) {\r
2736 VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);\r
2737 if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
2738 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);\r
2739 } else {\r
2740 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);\r
2741 }\r
2742\r
2743 NextVariable = GetNextVariablePtr (NextVariable);\r
2744 }\r
2745\r
2746 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;\r
2d3fb919 2747\r
0c18794e 2748 //\r
2749 // Allocate runtime memory used for a memory copy of the FLASH region.\r
2750 // Keep the memory and the FLASH in sync as updates occur\r
2751 //\r
2752 mNvVariableCache = AllocateRuntimeZeroPool ((UINTN)VariableStoreLength);\r
2753 if (mNvVariableCache == NULL) {\r
2754 Status = EFI_OUT_OF_RESOURCES;\r
2755 goto Done;\r
2756 }\r
2757 CopyMem (mNvVariableCache, (CHAR8 *)(UINTN)VariableStoreBase, (UINTN)VariableStoreLength);\r
2758 Status = EFI_SUCCESS;\r
2759\r
2760Done:\r
2761 if (EFI_ERROR (Status)) {\r
2762 FreePool (mVariableModuleGlobal);\r
2763 FreePool (VolatileVariableStore);\r
2764 }\r
2765\r
2766 return Status;\r
2767}\r
2768\r
2769\r
2770/**\r
2771 Get the proper fvb handle and/or fvb protocol by the given Flash address.\r
2772\r
2773 @param[in] Address The Flash address.\r
2774 @param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle.\r
2775 @param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol.\r
2776\r
2777**/\r
2778EFI_STATUS\r
2779GetFvbInfoByAddress (\r
2780 IN EFI_PHYSICAL_ADDRESS Address,\r
2781 OUT EFI_HANDLE *FvbHandle OPTIONAL,\r
2782 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvbProtocol OPTIONAL\r
2783 )\r
2784{\r
2785 EFI_STATUS Status;\r
2786 EFI_HANDLE *HandleBuffer;\r
2787 UINTN HandleCount;\r
2788 UINTN Index;\r
2789 EFI_PHYSICAL_ADDRESS FvbBaseAddress;\r
2790 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
2791 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
2792 EFI_FVB_ATTRIBUTES_2 Attributes;\r
2d3fb919 2793\r
0c18794e 2794 //\r
2795 // Get all FVB handles.\r
2796 //\r
2797 Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);\r
2798 if (EFI_ERROR (Status)) {\r
2799 return EFI_NOT_FOUND;\r
2800 }\r
2801\r
2802 //\r
2803 // Get the FVB to access variable store.\r
2804 //\r
2805 Fvb = NULL;\r
2806 for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {\r
2807 Status = GetFvbByHandle (HandleBuffer[Index], &Fvb);\r
2808 if (EFI_ERROR (Status)) {\r
2809 Status = EFI_NOT_FOUND;\r
2810 break;\r
2811 }\r
2812\r
2813 //\r
2814 // Ensure this FVB protocol supported Write operation.\r
2815 //\r
2816 Status = Fvb->GetAttributes (Fvb, &Attributes);\r
2817 if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {\r
2d3fb919 2818 continue;\r
0c18794e 2819 }\r
2d3fb919 2820\r
0c18794e 2821 //\r
2822 // Compare the address and select the right one.\r
2823 //\r
2824 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
2825 if (EFI_ERROR (Status)) {\r
2826 continue;\r
2827 }\r
2828\r
2829 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
2830 if ((Address >= FvbBaseAddress) && (Address < (FvbBaseAddress + FwVolHeader->FvLength))) {\r
2831 if (FvbHandle != NULL) {\r
2832 *FvbHandle = HandleBuffer[Index];\r
2833 }\r
2834 if (FvbProtocol != NULL) {\r
2835 *FvbProtocol = Fvb;\r
2836 }\r
2837 Status = EFI_SUCCESS;\r
2838 break;\r
2839 }\r
2840 }\r
2841 FreePool (HandleBuffer);\r
2842\r
2843 if (Fvb == NULL) {\r
2844 Status = EFI_NOT_FOUND;\r
2845 }\r
2d3fb919 2846\r
2847 return Status;\r
0c18794e 2848}\r
2849\r