]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/VariableAuthenticated/RuntimeDxe/Variable.c
SecurityPkg Variable: Implement variable quota management.
[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
dc204d5a
JY
5 Caution: This module requires additional review when modified.\r
6 This driver will have external input - variable data. They may be input in SMM mode.\r
7 This external input must be validated carefully to avoid security issue like\r
8 buffer overflow, integer overflow.\r
9\r
10 VariableServiceGetNextVariableName () and VariableServiceQueryVariableInfo() are external API.\r
11 They need check input parameter.\r
12\r
13 VariableServiceGetVariable() and VariableServiceSetVariable() are external API\r
14 to receive datasize and data buffer. The size should be checked carefully.\r
15\r
16 VariableServiceSetVariable() should also check authenticate data to avoid buffer overflow,\r
17 integer overflow. It should also check attribute to avoid authentication bypass.\r
18\r
17409b7a 19Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
2d3fb919 20This program and the accompanying materials\r
21are licensed and made available under the terms and conditions of the BSD License\r
22which accompanies this distribution. The full text of the license may be found at\r
0c18794e 23http://opensource.org/licenses/bsd-license.php\r
24\r
2d3fb919 25THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
0c18794e 26WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
27\r
28**/\r
29\r
30#include "Variable.h"\r
31#include "AuthService.h"\r
32\r
33VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;\r
34\r
35///\r
36/// Define a memory cache that improves the search performance for a variable.\r
37///\r
6ab9f441 38VARIABLE_STORE_HEADER *mNvVariableCache = NULL;\r
0c18794e 39\r
40///\r
41/// The memory entry used for variable statistics data.\r
42///\r
6ab9f441
RN
43VARIABLE_INFO_ENTRY *gVariableInfo = NULL;\r
44\r
45///\r
46/// The list to store the variables which cannot be set after the EFI_END_OF_DXE_EVENT_GROUP_GUID\r
47/// or EVT_GROUP_READY_TO_BOOT event.\r
48///\r
49LIST_ENTRY mLockedVariableList = INITIALIZE_LIST_HEAD_VARIABLE (mLockedVariableList);\r
50\r
51///\r
52/// The flag to indicate whether the platform has left the DXE phase of execution.\r
53///\r
54BOOLEAN mEndOfDxe = FALSE;\r
55\r
56///\r
57/// The flag to indicate whether the variable storage locking is enabled.\r
58///\r
59BOOLEAN mEnableLocking = TRUE;\r
0c18794e 60\r
c1d93242
JY
61/**\r
62\r
63 SecureBoot Hook for auth variable update.\r
64\r
65 @param[in] VariableName Name of Variable to be found.\r
66 @param[in] VendorGuid Variable vendor GUID.\r
67**/\r
68VOID\r
69EFIAPI\r
70SecureBootHook (\r
71 IN CHAR16 *VariableName,\r
72 IN EFI_GUID *VendorGuid\r
73 );\r
74\r
0c18794e 75/**\r
2d3fb919 76 Routine used to track statistical information about variable usage.\r
0c18794e 77 The data is stored in the EFI system table so it can be accessed later.\r
2d3fb919 78 VariableInfo.efi can dump out the table. Only Boot Services variable\r
0c18794e 79 accesses are tracked by this code. The PcdVariableCollectStatistics\r
2d3fb919 80 build flag controls if this feature is enabled.\r
0c18794e 81\r
2d3fb919 82 A read that hits in the cache will have Read and Cache true for\r
0c18794e 83 the transaction. Data is allocated by this routine, but never\r
84 freed.\r
85\r
86 @param[in] VariableName Name of the Variable to track.\r
87 @param[in] VendorGuid Guid of the Variable to track.\r
88 @param[in] Volatile TRUE if volatile FALSE if non-volatile.\r
89 @param[in] Read TRUE if GetVariable() was called.\r
90 @param[in] Write TRUE if SetVariable() was called.\r
91 @param[in] Delete TRUE if deleted via SetVariable().\r
92 @param[in] Cache TRUE for a cache hit.\r
93\r
94**/\r
95VOID\r
96UpdateVariableInfo (\r
97 IN CHAR16 *VariableName,\r
98 IN EFI_GUID *VendorGuid,\r
99 IN BOOLEAN Volatile,\r
100 IN BOOLEAN Read,\r
101 IN BOOLEAN Write,\r
102 IN BOOLEAN Delete,\r
103 IN BOOLEAN Cache\r
104 )\r
105{\r
106 VARIABLE_INFO_ENTRY *Entry;\r
107\r
108 if (FeaturePcdGet (PcdVariableCollectStatistics)) {\r
109\r
110 if (AtRuntime ()) {\r
111 // Don't collect statistics at runtime.\r
112 return;\r
113 }\r
114\r
115 if (gVariableInfo == NULL) {\r
116 //\r
117 // On the first call allocate a entry and place a pointer to it in\r
118 // the EFI System Table.\r
119 //\r
120 gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
121 ASSERT (gVariableInfo != NULL);\r
122\r
123 CopyGuid (&gVariableInfo->VendorGuid, VendorGuid);\r
124 gVariableInfo->Name = AllocatePool (StrSize (VariableName));\r
125 ASSERT (gVariableInfo->Name != NULL);\r
126 StrCpy (gVariableInfo->Name, VariableName);\r
127 gVariableInfo->Volatile = Volatile;\r
128 }\r
129\r
2d3fb919 130\r
0c18794e 131 for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) {\r
132 if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {\r
133 if (StrCmp (VariableName, Entry->Name) == 0) {\r
134 if (Read) {\r
135 Entry->ReadCount++;\r
136 }\r
137 if (Write) {\r
138 Entry->WriteCount++;\r
139 }\r
140 if (Delete) {\r
141 Entry->DeleteCount++;\r
142 }\r
143 if (Cache) {\r
144 Entry->CacheCount++;\r
145 }\r
146\r
147 return;\r
148 }\r
149 }\r
150\r
151 if (Entry->Next == NULL) {\r
152 //\r
153 // If the entry is not in the table add it.\r
154 // Next iteration of the loop will fill in the data.\r
155 //\r
156 Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
157 ASSERT (Entry->Next != NULL);\r
158\r
159 CopyGuid (&Entry->Next->VendorGuid, VendorGuid);\r
160 Entry->Next->Name = AllocatePool (StrSize (VariableName));\r
161 ASSERT (Entry->Next->Name != NULL);\r
162 StrCpy (Entry->Next->Name, VariableName);\r
163 Entry->Next->Volatile = Volatile;\r
164 }\r
165\r
166 }\r
167 }\r
168}\r
169\r
170\r
171/**\r
172\r
173 This code checks if variable header is valid or not.\r
174\r
6ebffb67
SZ
175 @param Variable Pointer to the Variable Header.\r
176 @param VariableStoreEnd Pointer to the Variable Store End.\r
0c18794e 177\r
6ebffb67
SZ
178 @retval TRUE Variable header is valid.\r
179 @retval FALSE Variable header is not valid.\r
0c18794e 180\r
181**/\r
182BOOLEAN\r
183IsValidVariableHeader (\r
6ebffb67
SZ
184 IN VARIABLE_HEADER *Variable,\r
185 IN VARIABLE_HEADER *VariableStoreEnd\r
0c18794e 186 )\r
187{\r
6ebffb67
SZ
188 if ((Variable == NULL) || (Variable >= VariableStoreEnd) || (Variable->StartId != VARIABLE_DATA)) {\r
189 //\r
190 // Variable is NULL or has reached the end of variable store,\r
191 // or the StartId is not correct.\r
192 //\r
0c18794e 193 return FALSE;\r
194 }\r
195\r
196 return TRUE;\r
197}\r
198\r
199\r
200/**\r
201\r
202 This function writes data to the FWH at the correct LBA even if the LBAs\r
203 are fragmented.\r
204\r
205 @param Global Pointer to VARAIBLE_GLOBAL structure.\r
206 @param Volatile Point out the Variable is Volatile or Non-Volatile.\r
207 @param SetByIndex TRUE if target pointer is given as index.\r
208 FALSE if target pointer is absolute.\r
209 @param Fvb Pointer to the writable FVB protocol.\r
210 @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER\r
211 structure.\r
212 @param DataSize Size of data to be written.\r
213 @param Buffer Pointer to the buffer from which data is written.\r
214\r
215 @retval EFI_INVALID_PARAMETER Parameters not valid.\r
216 @retval EFI_SUCCESS Variable store successfully updated.\r
217\r
218**/\r
219EFI_STATUS\r
220UpdateVariableStore (\r
221 IN VARIABLE_GLOBAL *Global,\r
222 IN BOOLEAN Volatile,\r
223 IN BOOLEAN SetByIndex,\r
224 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,\r
225 IN UINTN DataPtrIndex,\r
226 IN UINT32 DataSize,\r
227 IN UINT8 *Buffer\r
228 )\r
229{\r
230 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
231 UINTN BlockIndex2;\r
232 UINTN LinearOffset;\r
233 UINTN CurrWriteSize;\r
234 UINTN CurrWritePtr;\r
235 UINT8 *CurrBuffer;\r
236 EFI_LBA LbaNumber;\r
237 UINTN Size;\r
238 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
239 VARIABLE_STORE_HEADER *VolatileBase;\r
240 EFI_PHYSICAL_ADDRESS FvVolHdr;\r
241 EFI_PHYSICAL_ADDRESS DataPtr;\r
242 EFI_STATUS Status;\r
243\r
244 FwVolHeader = NULL;\r
245 DataPtr = DataPtrIndex;\r
246\r
247 //\r
248 // Check if the Data is Volatile.\r
249 //\r
250 if (!Volatile) {\r
648f98d1 251 if (Fvb == NULL) {\r
252 return EFI_INVALID_PARAMETER;\r
253 }\r
0c18794e 254 Status = Fvb->GetPhysicalAddress(Fvb, &FvVolHdr);\r
255 ASSERT_EFI_ERROR (Status);\r
256\r
257 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);\r
258 //\r
259 // Data Pointer should point to the actual Address where data is to be\r
260 // written.\r
261 //\r
262 if (SetByIndex) {\r
263 DataPtr += mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
264 }\r
265\r
266 if ((DataPtr + DataSize) >= ((EFI_PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) FwVolHeader + FwVolHeader->FvLength))) {\r
267 return EFI_INVALID_PARAMETER;\r
268 }\r
269 } else {\r
270 //\r
271 // Data Pointer should point to the actual Address where data is to be\r
272 // written.\r
273 //\r
274 VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
275 if (SetByIndex) {\r
276 DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
277 }\r
278\r
279 if ((DataPtr + DataSize) >= ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) {\r
280 return EFI_INVALID_PARAMETER;\r
281 }\r
2d3fb919 282\r
0c18794e 283 //\r
284 // If Volatile Variable just do a simple mem copy.\r
2d3fb919 285 //\r
0c18794e 286 CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize);\r
287 return EFI_SUCCESS;\r
288 }\r
2d3fb919 289\r
0c18794e 290 //\r
291 // If we are here we are dealing with Non-Volatile Variables.\r
292 //\r
293 LinearOffset = (UINTN) FwVolHeader;\r
294 CurrWritePtr = (UINTN) DataPtr;\r
295 CurrWriteSize = DataSize;\r
296 CurrBuffer = Buffer;\r
297 LbaNumber = 0;\r
298\r
299 if (CurrWritePtr < LinearOffset) {\r
300 return EFI_INVALID_PARAMETER;\r
301 }\r
302\r
303 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
304 for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {\r
305 //\r
306 // Check to see if the Variable Writes are spanning through multiple\r
307 // blocks.\r
308 //\r
309 if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) {\r
310 if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {\r
311 Status = Fvb->Write (\r
312 Fvb,\r
313 LbaNumber,\r
314 (UINTN) (CurrWritePtr - LinearOffset),\r
315 &CurrWriteSize,\r
316 CurrBuffer\r
317 );\r
318 return Status;\r
319 } else {\r
320 Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);\r
321 Status = Fvb->Write (\r
322 Fvb,\r
323 LbaNumber,\r
324 (UINTN) (CurrWritePtr - LinearOffset),\r
325 &Size,\r
326 CurrBuffer\r
327 );\r
328 if (EFI_ERROR (Status)) {\r
329 return Status;\r
330 }\r
331\r
332 CurrWritePtr = LinearOffset + PtrBlockMapEntry->Length;\r
333 CurrBuffer = CurrBuffer + Size;\r
334 CurrWriteSize = CurrWriteSize - Size;\r
335 }\r
336 }\r
337\r
338 LinearOffset += PtrBlockMapEntry->Length;\r
339 LbaNumber++;\r
340 }\r
341 }\r
342\r
343 return EFI_SUCCESS;\r
344}\r
345\r
346\r
347/**\r
348\r
349 This code gets the current status of Variable Store.\r
350\r
351 @param VarStoreHeader Pointer to the Variable Store Header.\r
352\r
353 @retval EfiRaw Variable store status is raw.\r
354 @retval EfiValid Variable store status is valid.\r
355 @retval EfiInvalid Variable store status is invalid.\r
356\r
357**/\r
358VARIABLE_STORE_STATUS\r
359GetVariableStoreStatus (\r
360 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
361 )\r
362{\r
363 if (CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) &&\r
364 VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&\r
365 VarStoreHeader->State == VARIABLE_STORE_HEALTHY\r
366 ) {\r
367\r
368 return EfiValid;\r
369 } else if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff &&\r
370 ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff &&\r
371 ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff &&\r
372 ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff &&\r
373 VarStoreHeader->Size == 0xffffffff &&\r
374 VarStoreHeader->Format == 0xff &&\r
375 VarStoreHeader->State == 0xff\r
376 ) {\r
377\r
378 return EfiRaw;\r
379 } else {\r
380 return EfiInvalid;\r
381 }\r
382}\r
383\r
384\r
385/**\r
386\r
387 This code gets the size of name of variable.\r
388\r
389 @param Variable Pointer to the Variable Header.\r
390\r
391 @return UINTN Size of variable in bytes.\r
392\r
393**/\r
394UINTN\r
395NameSizeOfVariable (\r
396 IN VARIABLE_HEADER *Variable\r
397 )\r
398{\r
399 if (Variable->State == (UINT8) (-1) ||\r
400 Variable->DataSize == (UINT32) (-1) ||\r
401 Variable->NameSize == (UINT32) (-1) ||\r
402 Variable->Attributes == (UINT32) (-1)) {\r
403 return 0;\r
404 }\r
405 return (UINTN) Variable->NameSize;\r
406}\r
407\r
408/**\r
409\r
410 This code gets the size of variable data.\r
411\r
412 @param Variable Pointer to the Variable Header.\r
413\r
414 @return Size of variable in bytes.\r
415\r
416**/\r
417UINTN\r
418DataSizeOfVariable (\r
419 IN VARIABLE_HEADER *Variable\r
420 )\r
421{\r
422 if (Variable->State == (UINT8) (-1) ||\r
423 Variable->DataSize == (UINT32) (-1) ||\r
424 Variable->NameSize == (UINT32) (-1) ||\r
425 Variable->Attributes == (UINT32) (-1)) {\r
426 return 0;\r
427 }\r
428 return (UINTN) Variable->DataSize;\r
429}\r
430\r
431/**\r
432\r
433 This code gets the pointer to the variable name.\r
434\r
435 @param Variable Pointer to the Variable Header.\r
436\r
437 @return Pointer to Variable Name which is Unicode encoding.\r
438\r
439**/\r
440CHAR16 *\r
441GetVariableNamePtr (\r
442 IN VARIABLE_HEADER *Variable\r
443 )\r
444{\r
445\r
446 return (CHAR16 *) (Variable + 1);\r
447}\r
448\r
449/**\r
450\r
451 This code gets the pointer to the variable data.\r
452\r
453 @param Variable Pointer to the Variable Header.\r
454\r
455 @return Pointer to Variable Data.\r
456\r
457**/\r
458UINT8 *\r
459GetVariableDataPtr (\r
460 IN VARIABLE_HEADER *Variable\r
461 )\r
462{\r
463 UINTN Value;\r
2d3fb919 464\r
0c18794e 465 //\r
466 // Be careful about pad size for alignment.\r
467 //\r
468 Value = (UINTN) GetVariableNamePtr (Variable);\r
469 Value += NameSizeOfVariable (Variable);\r
470 Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));\r
471\r
472 return (UINT8 *) Value;\r
473}\r
474\r
475\r
476/**\r
477\r
478 This code gets the pointer to the next variable header.\r
479\r
480 @param Variable Pointer to the Variable Header.\r
481\r
482 @return Pointer to next variable header.\r
483\r
484**/\r
485VARIABLE_HEADER *\r
486GetNextVariablePtr (\r
487 IN VARIABLE_HEADER *Variable\r
488 )\r
489{\r
490 UINTN Value;\r
491\r
0c18794e 492 Value = (UINTN) GetVariableDataPtr (Variable);\r
493 Value += DataSizeOfVariable (Variable);\r
494 Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));\r
495\r
496 //\r
497 // Be careful about pad size for alignment.\r
498 //\r
499 return (VARIABLE_HEADER *) HEADER_ALIGN (Value);\r
500}\r
501\r
502/**\r
503\r
504 Gets the pointer to the first variable header in given variable store area.\r
505\r
506 @param VarStoreHeader Pointer to the Variable Store Header.\r
507\r
508 @return Pointer to the first variable header.\r
509\r
510**/\r
511VARIABLE_HEADER *\r
512GetStartPointer (\r
513 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
514 )\r
515{\r
516 //\r
517 // The end of variable store.\r
518 //\r
519 return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);\r
520}\r
521\r
522/**\r
523\r
524 Gets the pointer to the end of the variable storage area.\r
525\r
526 This function gets pointer to the end of the variable storage\r
527 area, according to the input variable store header.\r
528\r
529 @param VarStoreHeader Pointer to the Variable Store Header.\r
530\r
2d3fb919 531 @return Pointer to the end of the variable storage area.\r
0c18794e 532\r
533**/\r
534VARIABLE_HEADER *\r
535GetEndPointer (\r
536 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
537 )\r
538{\r
539 //\r
540 // The end of variable store\r
541 //\r
542 return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);\r
543}\r
544\r
952ba83c
SZ
545/**\r
546 Record variable error flag.\r
547\r
548 @param[in] Flag Variable error flag to record.\r
549 @param[in] VariableName Name of variable.\r
550 @param[in] VendorGuid Guid of variable.\r
551 @param[in] Attributes Attributes of the variable.\r
552 @param[in] VariableSize Size of the variable.\r
553\r
554**/\r
555VOID\r
556RecordVarErrorFlag (\r
557 IN VAR_ERROR_FLAG Flag,\r
558 IN CHAR16 *VariableName,\r
559 IN EFI_GUID *VendorGuid,\r
560 IN UINT32 Attributes,\r
561 IN UINTN VariableSize\r
562 )\r
563{\r
564 EFI_STATUS Status;\r
565 VARIABLE_POINTER_TRACK Variable;\r
566 VAR_ERROR_FLAG *VarErrFlag;\r
567 VAR_ERROR_FLAG TempFlag;\r
568\r
569 DEBUG_CODE (\r
570 DEBUG ((EFI_D_ERROR, "RecordVarErrorFlag (0x%02x) %s:%g - 0x%08x - 0x%x\n", Flag, VariableName, VendorGuid, Attributes, VariableSize));\r
571 if (Flag == VAR_ERROR_FLAG_SYSTEM_ERROR) {\r
572 if (AtRuntime ()) {\r
573 DEBUG ((EFI_D_ERROR, "CommonRuntimeVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonRuntimeVariableSpace, mVariableModuleGlobal->CommonVariableTotalSize));\r
574 } else {\r
575 DEBUG ((EFI_D_ERROR, "CommonVariableSpace = 0x%x - CommonVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonVariableSpace, mVariableModuleGlobal->CommonVariableTotalSize));\r
576 }\r
577 } else {\r
578 DEBUG ((EFI_D_ERROR, "CommonMaxUserVariableSpace = 0x%x - CommonUserVariableTotalSize = 0x%x\n", mVariableModuleGlobal->CommonMaxUserVariableSpace, mVariableModuleGlobal->CommonUserVariableTotalSize));\r
579 }\r
580 );\r
581\r
582 //\r
583 // Record error flag (it should have be initialized).\r
584 //\r
585 Status = FindVariable (\r
586 VAR_ERROR_FLAG_NAME,\r
587 &gEdkiiVarErrorFlagGuid,\r
588 &Variable,\r
589 &mVariableModuleGlobal->VariableGlobal,\r
590 FALSE\r
591 );\r
592 if (!EFI_ERROR (Status)) {\r
593 VarErrFlag = (VAR_ERROR_FLAG *) GetVariableDataPtr (Variable.CurrPtr);\r
594 TempFlag = *VarErrFlag;\r
595 TempFlag &= Flag;\r
596 if (TempFlag == *VarErrFlag) {\r
597 return;\r
598 }\r
599 Status = UpdateVariableStore (\r
600 &mVariableModuleGlobal->VariableGlobal,\r
601 FALSE,\r
602 FALSE,\r
603 mVariableModuleGlobal->FvbInstance,\r
604 (UINTN) VarErrFlag - (UINTN) mNvVariableCache + (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
605 sizeof (TempFlag),\r
606 &TempFlag\r
607 );\r
608 if (!EFI_ERROR (Status)) {\r
609 //\r
610 // Update the data in NV cache.\r
611 //\r
612 *VarErrFlag = Flag;\r
613 }\r
614 }\r
615}\r
616\r
617/**\r
618 Initialize variable error flag.\r
619\r
620 Before EndOfDxe, the variable indicates the last boot variable error flag,\r
621 then it means the last boot variable error flag must be got before EndOfDxe.\r
622 After EndOfDxe, the variable indicates the current boot variable error flag,\r
623 then it means the current boot variable error flag must be got after EndOfDxe.\r
624\r
625**/\r
626VOID\r
627InitializeVarErrorFlag (\r
628 VOID\r
629 )\r
630{\r
631 EFI_STATUS Status;\r
632 VARIABLE_POINTER_TRACK Variable;\r
633 VAR_ERROR_FLAG Flag;\r
634 VAR_ERROR_FLAG VarErrFlag;\r
635\r
636 if (!mEndOfDxe) {\r
637 return;\r
638 }\r
639\r
640 Flag = VAR_ERROR_FLAG_NO_ERROR;\r
641 DEBUG ((EFI_D_INFO, "Initialize variable error flag (%02x)\n", Flag));\r
642\r
643 Status = FindVariable (\r
644 VAR_ERROR_FLAG_NAME,\r
645 &gEdkiiVarErrorFlagGuid,\r
646 &Variable,\r
647 &mVariableModuleGlobal->VariableGlobal,\r
648 FALSE\r
649 );\r
650 if (!EFI_ERROR (Status)) {\r
651 VarErrFlag = *((VAR_ERROR_FLAG *) GetVariableDataPtr (Variable.CurrPtr));\r
652 if (VarErrFlag == Flag) {\r
653 return;\r
654 }\r
655 }\r
656\r
657 UpdateVariable (\r
658 VAR_ERROR_FLAG_NAME,\r
659 &gEdkiiVarErrorFlagGuid,\r
660 &Flag,\r
661 sizeof (Flag),\r
662 VARIABLE_ATTRIBUTE_NV_BS_RT,\r
663 0,\r
664 0,\r
665 &Variable,\r
666 NULL\r
667 );\r
668}\r
669\r
670/**\r
671 Is user variable?\r
672\r
673 @param[in] Variable Pointer to variable header.\r
674\r
675 @retval TRUE User variable.\r
676 @retval FALSE System variable.\r
677\r
678**/\r
679BOOLEAN\r
680IsUserVariable (\r
681 IN VARIABLE_HEADER *Variable\r
682 )\r
683{\r
684 VAR_CHECK_VARIABLE_PROPERTY Property;\r
685\r
686 //\r
687 // Only after End Of Dxe, the variables belong to system variable are fixed.\r
688 // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,\r
689 // then no need to check if the variable is user variable or not specially.\r
690 //\r
691 if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) {\r
692 if (InternalVarCheckVariablePropertyGet (GetVariableNamePtr (Variable), &Variable->VendorGuid, &Property) == EFI_NOT_FOUND) {\r
693 return TRUE;\r
694 }\r
695 }\r
696 return FALSE;\r
697}\r
698\r
699/**\r
700 Calculate common user variable total size.\r
701\r
702**/\r
703VOID\r
704CalculateCommonUserVariableTotalSize (\r
705 VOID\r
706 )\r
707{\r
708 VARIABLE_HEADER *Variable;\r
709 VARIABLE_HEADER *NextVariable;\r
710 UINTN VariableSize;\r
711 VAR_CHECK_VARIABLE_PROPERTY Property;\r
712\r
713 //\r
714 // Only after End Of Dxe, the variables belong to system variable are fixed.\r
715 // If PcdMaxUserNvStorageVariableSize is 0, it means user variable share the same NV storage with system variable,\r
716 // then no need to calculate the common user variable total size specially.\r
717 //\r
718 if (mEndOfDxe && (mVariableModuleGlobal->CommonMaxUserVariableSpace != mVariableModuleGlobal->CommonVariableSpace)) {\r
719 Variable = GetStartPointer (mNvVariableCache);\r
720 while (IsValidVariableHeader (Variable, GetEndPointer (mNvVariableCache))) {\r
721 NextVariable = GetNextVariablePtr (Variable);\r
722 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
723 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
724 if (InternalVarCheckVariablePropertyGet (GetVariableNamePtr (Variable), &Variable->VendorGuid, &Property) == EFI_NOT_FOUND) {\r
725 //\r
726 // No property, it is user variable.\r
727 //\r
728 mVariableModuleGlobal->CommonUserVariableTotalSize += VariableSize;\r
729 }\r
730 }\r
731\r
732 Variable = NextVariable;\r
733 }\r
734 }\r
735}\r
736\r
737/**\r
738 Initialize variable quota.\r
739\r
740**/\r
741VOID\r
742InitializeVariableQuota (\r
743 VOID\r
744 )\r
745{\r
746 STATIC BOOLEAN Initialized;\r
747\r
748 if (!mEndOfDxe || Initialized) {\r
749 return;\r
750 }\r
751 Initialized = TRUE;\r
752\r
753 InitializeVarErrorFlag ();\r
754 CalculateCommonUserVariableTotalSize ();\r
755}\r
756\r
83758cdc 757/**\r
758\r
759 Check the PubKeyIndex is a valid key or not.\r
760\r
20333c6d 761 This function will iterate the NV storage to see if this PubKeyIndex is still referenced\r
83758cdc 762 by any valid count-based auth variabe.\r
20333c6d 763\r
83758cdc 764 @param[in] PubKeyIndex Index of the public key in public key store.\r
765\r
766 @retval TRUE The PubKeyIndex is still in use.\r
767 @retval FALSE The PubKeyIndex is not referenced by any count-based auth variabe.\r
20333c6d 768\r
83758cdc 769**/\r
770BOOLEAN\r
771IsValidPubKeyIndex (\r
772 IN UINT32 PubKeyIndex\r
773 )\r
774{\r
775 VARIABLE_HEADER *Variable;\r
6ebffb67 776 VARIABLE_HEADER *VariableStoreEnd;\r
83758cdc 777\r
778 if (PubKeyIndex > mPubKeyNumber) {\r
779 return FALSE;\r
780 }\r
6ebffb67 781\r
9a12e582 782 Variable = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
6ebffb67
SZ
783 VariableStoreEnd = GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
784\r
785 while (IsValidVariableHeader (Variable, VariableStoreEnd)) {\r
20333c6d 786 if ((Variable->State == VAR_ADDED || Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) &&\r
83758cdc 787 Variable->PubKeyIndex == PubKeyIndex) {\r
788 return TRUE;\r
789 }\r
790 Variable = GetNextVariablePtr (Variable);\r
791 }\r
20333c6d 792\r
83758cdc 793 return FALSE;\r
794}\r
0c18794e 795\r
796/**\r
797\r
83758cdc 798 Get the number of valid public key in PubKeyStore.\r
20333c6d 799\r
83758cdc 800 @param[in] PubKeyNumber Number of the public key in public key store.\r
801\r
802 @return Number of valid public key in PubKeyStore.\r
803\r
804**/\r
805UINT32\r
806GetValidPubKeyNumber (\r
807 IN UINT32 PubKeyNumber\r
808 )\r
809{\r
810 UINT32 PubKeyIndex;\r
811 UINT32 Counter;\r
812\r
813 Counter = 0;\r
20333c6d 814\r
83758cdc 815 for (PubKeyIndex = 1; PubKeyIndex <= PubKeyNumber; PubKeyIndex++) {\r
816 if (IsValidPubKeyIndex (PubKeyIndex)) {\r
817 Counter++;\r
818 }\r
819 }\r
20333c6d 820\r
83758cdc 821 return Counter;\r
822}\r
823\r
824/**\r
825\r
826 Filter the useless key in public key store.\r
827\r
20333c6d 828 This function will find out all valid public keys in public key database, save them in new allocated\r
83758cdc 829 buffer NewPubKeyStore, and give the new PubKeyIndex. The caller is responsible for freeing buffer\r
830 NewPubKeyIndex and NewPubKeyStore with FreePool().\r
831\r
832 @param[in] PubKeyStore Point to the public key database.\r
833 @param[in] PubKeyNumber Number of the public key in PubKeyStore.\r
834 @param[out] NewPubKeyIndex Point to an array of new PubKeyIndex corresponds to NewPubKeyStore.\r
835 @param[out] NewPubKeyStore Saved all valid public keys in PubKeyStore.\r
836 @param[out] NewPubKeySize Buffer size of the NewPubKeyStore.\r
20333c6d 837\r
83758cdc 838 @retval EFI_SUCCESS Trim operation is complete successfully.\r
839 @retval EFI_OUT_OF_RESOURCES No enough memory resources, or no useless key in PubKeyStore.\r
20333c6d 840\r
83758cdc 841**/\r
842EFI_STATUS\r
843PubKeyStoreFilter (\r
844 IN UINT8 *PubKeyStore,\r
845 IN UINT32 PubKeyNumber,\r
846 OUT UINT32 **NewPubKeyIndex,\r
847 OUT UINT8 **NewPubKeyStore,\r
848 OUT UINT32 *NewPubKeySize\r
849 )\r
850{\r
851 UINT32 PubKeyIndex;\r
852 UINT32 CopiedKey;\r
853 UINT32 NewPubKeyNumber;\r
20333c6d 854\r
83758cdc 855 NewPubKeyNumber = GetValidPubKeyNumber (PubKeyNumber);\r
856 if (NewPubKeyNumber == PubKeyNumber) {\r
857 return EFI_OUT_OF_RESOURCES;\r
858 }\r
859\r
860 if (NewPubKeyNumber != 0) {\r
861 *NewPubKeySize = NewPubKeyNumber * EFI_CERT_TYPE_RSA2048_SIZE;\r
862 } else {\r
863 *NewPubKeySize = sizeof (UINT8);\r
864 }\r
865\r
866 *NewPubKeyStore = AllocatePool (*NewPubKeySize);\r
867 if (*NewPubKeyStore == NULL) {\r
868 return EFI_OUT_OF_RESOURCES;\r
869 }\r
0c18794e 870\r
83758cdc 871 *NewPubKeyIndex = AllocateZeroPool ((PubKeyNumber + 1) * sizeof (UINT32));\r
872 if (*NewPubKeyIndex == NULL) {\r
873 FreePool (*NewPubKeyStore);\r
128ef095 874 *NewPubKeyStore = NULL;\r
83758cdc 875 return EFI_OUT_OF_RESOURCES;\r
876 }\r
0c18794e 877\r
83758cdc 878 CopiedKey = 0;\r
879 for (PubKeyIndex = 1; PubKeyIndex <= PubKeyNumber; PubKeyIndex++) {\r
880 if (IsValidPubKeyIndex (PubKeyIndex)) {\r
881 CopyMem (\r
882 *NewPubKeyStore + CopiedKey * EFI_CERT_TYPE_RSA2048_SIZE,\r
883 PubKeyStore + (PubKeyIndex - 1) * EFI_CERT_TYPE_RSA2048_SIZE,\r
884 EFI_CERT_TYPE_RSA2048_SIZE\r
885 );\r
886 (*NewPubKeyIndex)[PubKeyIndex] = ++CopiedKey;\r
887 }\r
888 }\r
889 return EFI_SUCCESS;\r
890}\r
891\r
892/**\r
893\r
894 Variable store garbage collection and reclaim operation.\r
895\r
896 If ReclaimPubKeyStore is FALSE, reclaim variable space by deleting the obsoleted varaibles.\r
897 If ReclaimPubKeyStore is TRUE, reclaim invalid key in public key database and update the PubKeyIndex\r
898 for all the count-based authenticate variable in NV storage.\r
899\r
ca5a7d87 900 @param[in] VariableBase Base address of variable store.\r
901 @param[out] LastVariableOffset Offset of last variable.\r
902 @param[in] IsVolatile The variable store is volatile or not;\r
903 if it is non-volatile, need FTW.\r
904 @param[in, out] UpdatingPtrTrack Pointer to updating variable pointer track structure.\r
7baf3c69
SZ
905 @param[in] NewVariable Pointer to new variable.\r
906 @param[in] NewVariableSize New variable size.\r
ca5a7d87 907 @param[in] ReclaimPubKeyStore Reclaim for public key database or not.\r
20333c6d 908\r
83758cdc 909 @return EFI_SUCCESS Reclaim operation has finished successfully.\r
7baf3c69 910 @return EFI_OUT_OF_RESOURCES No enough memory resources or variable space.\r
ca5a7d87 911 @return EFI_DEVICE_ERROR The public key database doesn't exist.\r
83758cdc 912 @return Others Unexpect error happened during reclaim operation.\r
0c18794e 913\r
914**/\r
915EFI_STATUS\r
916Reclaim (\r
ca5a7d87 917 IN EFI_PHYSICAL_ADDRESS VariableBase,\r
918 OUT UINTN *LastVariableOffset,\r
919 IN BOOLEAN IsVolatile,\r
920 IN OUT VARIABLE_POINTER_TRACK *UpdatingPtrTrack,\r
7baf3c69
SZ
921 IN VARIABLE_HEADER *NewVariable,\r
922 IN UINTN NewVariableSize,\r
923 IN BOOLEAN ReclaimPubKeyStore\r
0c18794e 924 )\r
925{\r
926 VARIABLE_HEADER *Variable;\r
927 VARIABLE_HEADER *AddedVariable;\r
928 VARIABLE_HEADER *NextVariable;\r
929 VARIABLE_HEADER *NextAddedVariable;\r
930 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
931 UINT8 *ValidBuffer;\r
932 UINTN MaximumBufferSize;\r
933 UINTN VariableSize;\r
0c18794e 934 UINTN NameSize;\r
935 UINT8 *CurrPtr;\r
936 VOID *Point0;\r
937 VOID *Point1;\r
938 BOOLEAN FoundAdded;\r
939 EFI_STATUS Status;\r
8f3a9e58 940 UINTN CommonVariableTotalSize;\r
952ba83c 941 UINTN CommonUserVariableTotalSize;\r
8f3a9e58 942 UINTN HwErrVariableTotalSize;\r
83758cdc 943 UINT32 *NewPubKeyIndex;\r
944 UINT8 *NewPubKeyStore;\r
945 UINT32 NewPubKeySize;\r
946 VARIABLE_HEADER *PubKeyHeader;\r
23b06935 947 VARIABLE_HEADER *UpdatingVariable;\r
7baf3c69 948 VARIABLE_HEADER *UpdatingInDeletedTransition;\r
23b06935
SZ
949\r
950 UpdatingVariable = NULL;\r
7baf3c69 951 UpdatingInDeletedTransition = NULL;\r
23b06935
SZ
952 if (UpdatingPtrTrack != NULL) {\r
953 UpdatingVariable = UpdatingPtrTrack->CurrPtr;\r
7baf3c69 954 UpdatingInDeletedTransition = UpdatingPtrTrack->InDeletedTransitionPtr;\r
23b06935 955 }\r
0c18794e 956\r
957 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);\r
8f3a9e58
SZ
958\r
959 CommonVariableTotalSize = 0;\r
952ba83c 960 CommonUserVariableTotalSize = 0;\r
8f3a9e58 961 HwErrVariableTotalSize = 0;\r
83758cdc 962 NewPubKeyIndex = NULL;\r
963 NewPubKeyStore = NULL;\r
964 NewPubKeySize = 0;\r
965 PubKeyHeader = NULL;\r
0c18794e 966\r
128ef095
SZ
967 if (IsVolatile) {\r
968 //\r
969 // Start Pointers for the variable.\r
970 //\r
971 Variable = GetStartPointer (VariableStoreHeader);\r
972 MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);\r
973\r
6ebffb67 974 while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {\r
128ef095
SZ
975 NextVariable = GetNextVariablePtr (Variable);\r
976 if ((Variable->State == VAR_ADDED || Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) &&\r
977 Variable != UpdatingVariable &&\r
978 Variable != UpdatingInDeletedTransition\r
979 ) {\r
980 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
981 MaximumBufferSize += VariableSize;\r
982 }\r
983\r
984 Variable = NextVariable;\r
0c18794e 985 }\r
986\r
128ef095
SZ
987 if (NewVariable != NULL) {\r
988 //\r
989 // Add the new variable size.\r
990 //\r
991 MaximumBufferSize += NewVariableSize;\r
992 }\r
0c18794e 993\r
7baf3c69 994 //\r
128ef095
SZ
995 // Reserve the 1 Bytes with Oxff to identify the\r
996 // end of the variable buffer.\r
7baf3c69 997 //\r
128ef095
SZ
998 MaximumBufferSize += 1;\r
999 ValidBuffer = AllocatePool (MaximumBufferSize);\r
1000 if (ValidBuffer == NULL) {\r
1001 return EFI_OUT_OF_RESOURCES;\r
1002 }\r
1003 } else {\r
1004 //\r
1005 // For NV variable reclaim, don't allocate pool here and just use mNvVariableCache\r
1006 // as the buffer to reduce SMRAM consumption for SMM variable driver.\r
1007 //\r
1008 MaximumBufferSize = mNvVariableCache->Size;\r
1009 ValidBuffer = (UINT8 *) mNvVariableCache;\r
0c18794e 1010 }\r
1011\r
1012 SetMem (ValidBuffer, MaximumBufferSize, 0xff);\r
1013\r
1014 //\r
1015 // Copy variable store header.\r
1016 //\r
1017 CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));\r
1018 CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
1019\r
83758cdc 1020 if (ReclaimPubKeyStore) {\r
7baf3c69 1021 ASSERT (IsVolatile == FALSE);\r
83758cdc 1022 //\r
1023 // Trim the PubKeyStore and get new PubKeyIndex.\r
1024 //\r
1025 Status = PubKeyStoreFilter (\r
1026 mPubKeyStore,\r
1027 mPubKeyNumber,\r
1028 &NewPubKeyIndex,\r
1029 &NewPubKeyStore,\r
1030 &NewPubKeySize\r
1031 );\r
1032 if (EFI_ERROR (Status)) {\r
128ef095 1033 goto Done;\r
83758cdc 1034 }\r
3a4b498e 1035 ASSERT ((NewPubKeyIndex != NULL) && (NewPubKeyStore != NULL));\r
0c18794e 1036\r
83758cdc 1037 //\r
1038 // Refresh the PubKeyIndex for all valid variables (ADDED and IN_DELETED_TRANSITION).\r
1039 //\r
128ef095 1040 Variable = GetStartPointer (VariableStoreHeader);\r
6ebffb67 1041 while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {\r
83758cdc 1042 NextVariable = GetNextVariablePtr (Variable);\r
1043 if (Variable->State == VAR_ADDED || Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
20333c6d 1044 if ((StrCmp (GetVariableNamePtr (Variable), AUTHVAR_KEYDB_NAME) == 0) &&\r
83758cdc 1045 (CompareGuid (&Variable->VendorGuid, &gEfiAuthenticatedVariableGuid))) {\r
1046 //\r
1047 // Skip the public key database, it will be reinstalled later.\r
1048 //\r
1049 PubKeyHeader = Variable;\r
0c18794e 1050 Variable = NextVariable;\r
1051 continue;\r
1052 }\r
20333c6d 1053\r
83758cdc 1054 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
1055 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
1056 ((VARIABLE_HEADER*) CurrPtr)->PubKeyIndex = NewPubKeyIndex[Variable->PubKeyIndex];\r
1057 CurrPtr += VariableSize;\r
7baf3c69 1058 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
83758cdc 1059 HwErrVariableTotalSize += VariableSize;\r
7baf3c69 1060 } else if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
83758cdc 1061 CommonVariableTotalSize += VariableSize;\r
952ba83c
SZ
1062 if (IsUserVariable (Variable)) {\r
1063 CommonUserVariableTotalSize += VariableSize;\r
17409b7a 1064 }\r
83758cdc 1065 }\r
952ba83c 1066 }\r
83758cdc 1067 Variable = NextVariable;\r
0c18794e 1068 }\r
0c18794e 1069\r
83758cdc 1070 //\r
1071 // Reinstall the new public key database.\r
1072 //\r
12cbe232 1073 ASSERT (PubKeyHeader != NULL);\r
ca5a7d87 1074 if (PubKeyHeader == NULL) {\r
128ef095
SZ
1075 Status = EFI_DEVICE_ERROR;\r
1076 goto Done;\r
ca5a7d87 1077 }\r
83758cdc 1078 CopyMem (CurrPtr, (UINT8*) PubKeyHeader, sizeof (VARIABLE_HEADER));\r
1079 Variable = (VARIABLE_HEADER*) CurrPtr;\r
1080 Variable->DataSize = NewPubKeySize;\r
1081 StrCpy (GetVariableNamePtr (Variable), GetVariableNamePtr (PubKeyHeader));\r
1082 CopyMem (GetVariableDataPtr (Variable), NewPubKeyStore, NewPubKeySize);\r
20333c6d 1083 CurrPtr = (UINT8*) GetNextVariablePtr (Variable);\r
83758cdc 1084 CommonVariableTotalSize += (UINTN) CurrPtr - (UINTN) Variable;\r
952ba83c
SZ
1085 if (IsUserVariable (Variable)) {\r
1086 CommonUserVariableTotalSize += (UINTN) CurrPtr - (UINTN) Variable;\r
1087 }\r
83758cdc 1088 } else {\r
1089 //\r
1090 // Reinstall all ADDED variables as long as they are not identical to Updating Variable.\r
1091 //\r
1092 Variable = GetStartPointer (VariableStoreHeader);\r
6ebffb67 1093 while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {\r
83758cdc 1094 NextVariable = GetNextVariablePtr (Variable);\r
7baf3c69 1095 if (Variable != UpdatingVariable && Variable->State == VAR_ADDED) {\r
0c18794e 1096 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
1097 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
0c18794e 1098 CurrPtr += VariableSize;\r
1099 if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
8f3a9e58 1100 HwErrVariableTotalSize += VariableSize;\r
0c18794e 1101 } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
8f3a9e58 1102 CommonVariableTotalSize += VariableSize;\r
952ba83c
SZ
1103 if (IsUserVariable (Variable)) {\r
1104 CommonUserVariableTotalSize += VariableSize;\r
17409b7a 1105 }\r
0c18794e 1106 }\r
952ba83c 1107 }\r
83758cdc 1108 Variable = NextVariable;\r
0c18794e 1109 }\r
1110\r
83758cdc 1111 //\r
1112 // Reinstall all in delete transition variables.\r
1113 //\r
7baf3c69 1114 Variable = GetStartPointer (VariableStoreHeader);\r
6ebffb67 1115 while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {\r
83758cdc 1116 NextVariable = GetNextVariablePtr (Variable);\r
7baf3c69 1117 if (Variable != UpdatingVariable && Variable != UpdatingInDeletedTransition && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
83758cdc 1118\r
1119 //\r
1120 // Buffer has cached all ADDED variable.\r
1121 // Per IN_DELETED variable, we have to guarantee that\r
1122 // no ADDED one in previous buffer.\r
1123 //\r
1124\r
1125 FoundAdded = FALSE;\r
1126 AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
6ebffb67 1127 while (IsValidVariableHeader (AddedVariable, GetEndPointer ((VARIABLE_STORE_HEADER *) ValidBuffer))) {\r
83758cdc 1128 NextAddedVariable = GetNextVariablePtr (AddedVariable);\r
1129 NameSize = NameSizeOfVariable (AddedVariable);\r
1130 if (CompareGuid (&AddedVariable->VendorGuid, &Variable->VendorGuid) &&\r
1131 NameSize == NameSizeOfVariable (Variable)\r
1132 ) {\r
1133 Point0 = (VOID *) GetVariableNamePtr (AddedVariable);\r
1134 Point1 = (VOID *) GetVariableNamePtr (Variable);\r
23b06935 1135 if (CompareMem (Point0, Point1, NameSize) == 0) {\r
83758cdc 1136 FoundAdded = TRUE;\r
1137 break;\r
1138 }\r
1139 }\r
1140 AddedVariable = NextAddedVariable;\r
1141 }\r
1142 if (!FoundAdded) {\r
1143 //\r
1144 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED.\r
1145 //\r
1146 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
1147 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
1148 ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;\r
1149 CurrPtr += VariableSize;\r
1150 if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
1151 HwErrVariableTotalSize += VariableSize;\r
1152 } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
1153 CommonVariableTotalSize += VariableSize;\r
952ba83c
SZ
1154 if (IsUserVariable (Variable)) {\r
1155 CommonUserVariableTotalSize += VariableSize;\r
17409b7a 1156 }\r
83758cdc 1157 }\r
1158 }\r
952ba83c 1159 }\r
83758cdc 1160\r
1161 Variable = NextVariable;\r
1162 }\r
7baf3c69
SZ
1163\r
1164 //\r
1165 // Install the new variable if it is not NULL.\r
1166 //\r
1167 if (NewVariable != NULL) {\r
1168 if ((UINTN) (CurrPtr - ValidBuffer) + NewVariableSize > VariableStoreHeader->Size) {\r
1169 //\r
1170 // No enough space to store the new variable.\r
1171 //\r
1172 Status = EFI_OUT_OF_RESOURCES;\r
1173 goto Done;\r
1174 }\r
1175 if (!IsVolatile) {\r
1176 if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
1177 HwErrVariableTotalSize += NewVariableSize;\r
1178 } else if ((NewVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
1179 CommonVariableTotalSize += NewVariableSize;\r
952ba83c
SZ
1180 if (IsUserVariable (NewVariable)) {\r
1181 CommonUserVariableTotalSize += NewVariableSize;\r
17409b7a 1182 }\r
952ba83c 1183 }\r
7baf3c69 1184 if ((HwErrVariableTotalSize > PcdGet32 (PcdHwErrStorageSize)) ||\r
952ba83c
SZ
1185 (CommonVariableTotalSize > mVariableModuleGlobal->CommonVariableSpace) ||\r
1186 (CommonUserVariableTotalSize > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {\r
7baf3c69
SZ
1187 //\r
1188 // No enough space to store the new variable by NV or NV+HR attribute.\r
1189 //\r
1190 Status = EFI_OUT_OF_RESOURCES;\r
1191 goto Done;\r
1192 }\r
1193 }\r
1194\r
1195 CopyMem (CurrPtr, (UINT8 *) NewVariable, NewVariableSize);\r
1196 ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;\r
1197 if (UpdatingVariable != NULL) {\r
1198 UpdatingPtrTrack->CurrPtr = (VARIABLE_HEADER *)((UINTN)UpdatingPtrTrack->StartPtr + ((UINTN)CurrPtr - (UINTN)GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer)));\r
1199 UpdatingPtrTrack->InDeletedTransitionPtr = NULL;\r
1200 }\r
1201 CurrPtr += NewVariableSize;\r
1202 }\r
0c18794e 1203 }\r
1204\r
1205 if (IsVolatile) {\r
1206 //\r
1207 // If volatile variable store, just copy valid buffer.\r
1208 //\r
1209 SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);\r
7baf3c69 1210 CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - ValidBuffer));\r
128ef095 1211 *LastVariableOffset = (UINTN) (CurrPtr - ValidBuffer);\r
0c18794e 1212 Status = EFI_SUCCESS;\r
1213 } else {\r
1214 //\r
1215 // If non-volatile variable store, perform FTW here.\r
1216 //\r
1217 Status = FtwVariableSpace (\r
1218 VariableBase,\r
128ef095 1219 (VARIABLE_STORE_HEADER *) ValidBuffer\r
0c18794e 1220 );\r
128ef095
SZ
1221 if (!EFI_ERROR (Status)) {\r
1222 *LastVariableOffset = (UINTN) (CurrPtr - ValidBuffer);\r
8f3a9e58
SZ
1223 mVariableModuleGlobal->HwErrVariableTotalSize = HwErrVariableTotalSize;\r
1224 mVariableModuleGlobal->CommonVariableTotalSize = CommonVariableTotalSize;\r
952ba83c 1225 mVariableModuleGlobal->CommonUserVariableTotalSize = CommonUserVariableTotalSize;\r
128ef095 1226 } else {\r
952ba83c
SZ
1227 Variable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase);\r
1228 while (IsValidVariableHeader (Variable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableBase))) {\r
1229 NextVariable = GetNextVariablePtr (Variable);\r
1230 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
128ef095 1231 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
952ba83c 1232 mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
128ef095 1233 } else if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
952ba83c
SZ
1234 mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
1235 if (IsUserVariable (Variable)) {\r
1236 mVariableModuleGlobal->CommonUserVariableTotalSize += VariableSize;\r
17409b7a 1237 }\r
952ba83c 1238 }\r
8f3a9e58 1239\r
952ba83c 1240 Variable = NextVariable;\r
128ef095 1241 }\r
952ba83c 1242 *LastVariableOffset = (UINTN) Variable - (UINTN) VariableBase;\r
8f3a9e58 1243 }\r
0c18794e 1244 }\r
1245\r
128ef095
SZ
1246Done:\r
1247 if (IsVolatile) {\r
1248 FreePool (ValidBuffer);\r
1249 } else {\r
1250 //\r
1251 // For NV variable reclaim, we use mNvVariableCache as the buffer, so copy the data back.\r
1252 //\r
1253 CopyMem (mNvVariableCache, (UINT8 *)(UINTN)VariableBase, VariableStoreHeader->Size);\r
83758cdc 1254\r
128ef095
SZ
1255 if (NewPubKeyStore != NULL) {\r
1256 FreePool (NewPubKeyStore);\r
1257 }\r
7baf3c69 1258\r
128ef095
SZ
1259 if (NewPubKeyIndex != NULL) {\r
1260 FreePool (NewPubKeyIndex);\r
1261 }\r
1262 }\r
0c18794e 1263\r
1264 return Status;\r
1265}\r
1266\r
9a000b46
RN
1267/**\r
1268 Find the variable in the specified variable store.\r
1269\r
ecc722ad 1270 @param[in] VariableName Name of the variable to be found\r
1271 @param[in] VendorGuid Vendor GUID to be found.\r
9622df63
SZ
1272 @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute\r
1273 check at runtime when searching variable.\r
ecc722ad 1274 @param[in, out] PtrTrack Variable Track Pointer structure that contains Variable Information.\r
9a000b46 1275\r
ecc722ad 1276 @retval EFI_SUCCESS Variable found successfully\r
1277 @retval EFI_NOT_FOUND Variable not found\r
9a000b46
RN
1278**/\r
1279EFI_STATUS\r
1280FindVariableEx (\r
1281 IN CHAR16 *VariableName,\r
1282 IN EFI_GUID *VendorGuid,\r
9622df63 1283 IN BOOLEAN IgnoreRtCheck,\r
9a000b46
RN
1284 IN OUT VARIABLE_POINTER_TRACK *PtrTrack\r
1285 )\r
1286{\r
1287 VARIABLE_HEADER *InDeletedVariable;\r
1288 VOID *Point;\r
1289\r
23b06935
SZ
1290 PtrTrack->InDeletedTransitionPtr = NULL;\r
1291\r
9a000b46
RN
1292 //\r
1293 // Find the variable by walk through HOB, volatile and non-volatile variable store.\r
1294 //\r
1295 InDeletedVariable = NULL;\r
1296\r
1297 for ( PtrTrack->CurrPtr = PtrTrack->StartPtr\r
6ebffb67 1298 ; IsValidVariableHeader (PtrTrack->CurrPtr, PtrTrack->EndPtr)\r
9a000b46
RN
1299 ; PtrTrack->CurrPtr = GetNextVariablePtr (PtrTrack->CurrPtr)\r
1300 ) {\r
2d3fb919 1301 if (PtrTrack->CurrPtr->State == VAR_ADDED ||\r
9a000b46
RN
1302 PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
1303 ) {\r
9622df63 1304 if (IgnoreRtCheck || !AtRuntime () || ((PtrTrack->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {\r
9a000b46
RN
1305 if (VariableName[0] == 0) {\r
1306 if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
1307 InDeletedVariable = PtrTrack->CurrPtr;\r
1308 } else {\r
23b06935 1309 PtrTrack->InDeletedTransitionPtr = InDeletedVariable;\r
9a000b46
RN
1310 return EFI_SUCCESS;\r
1311 }\r
1312 } else {\r
1313 if (CompareGuid (VendorGuid, &PtrTrack->CurrPtr->VendorGuid)) {\r
1314 Point = (VOID *) GetVariableNamePtr (PtrTrack->CurrPtr);\r
1315\r
1316 ASSERT (NameSizeOfVariable (PtrTrack->CurrPtr) != 0);\r
1317 if (CompareMem (VariableName, Point, NameSizeOfVariable (PtrTrack->CurrPtr)) == 0) {\r
1318 if (PtrTrack->CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
1319 InDeletedVariable = PtrTrack->CurrPtr;\r
1320 } else {\r
23b06935 1321 PtrTrack->InDeletedTransitionPtr = InDeletedVariable;\r
9a000b46
RN
1322 return EFI_SUCCESS;\r
1323 }\r
1324 }\r
1325 }\r
1326 }\r
1327 }\r
1328 }\r
1329 }\r
1330\r
1331 PtrTrack->CurrPtr = InDeletedVariable;\r
1332 return (PtrTrack->CurrPtr == NULL) ? EFI_NOT_FOUND : EFI_SUCCESS;\r
1333}\r
1334\r
0c18794e 1335\r
1336/**\r
1337 Finds variable in storage blocks of volatile and non-volatile storage areas.\r
1338\r
1339 This code finds variable in storage blocks of volatile and non-volatile storage areas.\r
1340 If VariableName is an empty string, then we just return the first\r
1341 qualified variable without comparing VariableName and VendorGuid.\r
9622df63
SZ
1342 If IgnoreRtCheck is TRUE, then we ignore the EFI_VARIABLE_RUNTIME_ACCESS attribute check\r
1343 at runtime when searching existing variable, only VariableName and VendorGuid are compared.\r
1344 Otherwise, variables without EFI_VARIABLE_RUNTIME_ACCESS are not visible at runtime.\r
0c18794e 1345\r
ecc722ad 1346 @param[in] VariableName Name of the variable to be found.\r
1347 @param[in] VendorGuid Vendor GUID to be found.\r
1348 @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output,\r
0c18794e 1349 including the range searched and the target position.\r
ecc722ad 1350 @param[in] Global Pointer to VARIABLE_GLOBAL structure, including\r
0c18794e 1351 base of volatile variable storage area, base of\r
1352 NV variable storage area, and a lock.\r
9622df63
SZ
1353 @param[in] IgnoreRtCheck Ignore EFI_VARIABLE_RUNTIME_ACCESS attribute\r
1354 check at runtime when searching variable.\r
0c18794e 1355\r
1356 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while\r
1357 VendorGuid is NULL.\r
1358 @retval EFI_SUCCESS Variable successfully found.\r
1359 @retval EFI_NOT_FOUND Variable not found\r
1360\r
1361**/\r
1362EFI_STATUS\r
1363FindVariable (\r
1364 IN CHAR16 *VariableName,\r
1365 IN EFI_GUID *VendorGuid,\r
1366 OUT VARIABLE_POINTER_TRACK *PtrTrack,\r
ecc722ad 1367 IN VARIABLE_GLOBAL *Global,\r
9622df63 1368 IN BOOLEAN IgnoreRtCheck\r
0c18794e 1369 )\r
1370{\r
9a000b46
RN
1371 EFI_STATUS Status;\r
1372 VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];\r
1373 VARIABLE_STORE_TYPE Type;\r
1374\r
1375 if (VariableName[0] != 0 && VendorGuid == NULL) {\r
1376 return EFI_INVALID_PARAMETER;\r
1377 }\r
0c18794e 1378\r
1379 //\r
9a000b46 1380 // 0: Volatile, 1: HOB, 2: Non-Volatile.\r
0c18794e 1381 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName\r
1382 // make use of this mapping to implement search algorithm.\r
1383 //\r
9a000b46
RN
1384 VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) Global->VolatileVariableBase;\r
1385 VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *) (UINTN) Global->HobVariableBase;\r
1386 VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache;\r
0c18794e 1387\r
1388 //\r
9a000b46 1389 // Find the variable by walk through HOB, volatile and non-volatile variable store.\r
0c18794e 1390 //\r
9a000b46
RN
1391 for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {\r
1392 if (VariableStoreHeader[Type] == NULL) {\r
1393 continue;\r
1394 }\r
0c18794e 1395\r
9a000b46
RN
1396 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Type]);\r
1397 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Type]);\r
1398 PtrTrack->Volatile = (BOOLEAN) (Type == VariableStoreTypeVolatile);\r
0c18794e 1399\r
9622df63 1400 Status = FindVariableEx (VariableName, VendorGuid, IgnoreRtCheck, PtrTrack);\r
9a000b46
RN
1401 if (!EFI_ERROR (Status)) {\r
1402 return Status;\r
0c18794e 1403 }\r
1404 }\r
0c18794e 1405 return EFI_NOT_FOUND;\r
1406}\r
1407\r
1408/**\r
1409 Get index from supported language codes according to language string.\r
1410\r
1411 This code is used to get corresponding index in supported language codes. It can handle\r
1412 RFC4646 and ISO639 language tags.\r
1413 In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.\r
1414 In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.\r
1415\r
1416 For example:\r
1417 SupportedLang = "engfraengfra"\r
1418 Lang = "eng"\r
1419 Iso639Language = TRUE\r
1420 The return value is "0".\r
1421 Another example:\r
1422 SupportedLang = "en;fr;en-US;fr-FR"\r
1423 Lang = "fr-FR"\r
1424 Iso639Language = FALSE\r
1425 The return value is "3".\r
1426\r
1427 @param SupportedLang Platform supported language codes.\r
1428 @param Lang Configured language.\r
1429 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
1430\r
1431 @retval The index of language in the language codes.\r
1432\r
1433**/\r
1434UINTN\r
1435GetIndexFromSupportedLangCodes(\r
1436 IN CHAR8 *SupportedLang,\r
1437 IN CHAR8 *Lang,\r
1438 IN BOOLEAN Iso639Language\r
2d3fb919 1439 )\r
0c18794e 1440{\r
1441 UINTN Index;\r
1442 UINTN CompareLength;\r
1443 UINTN LanguageLength;\r
1444\r
1445 if (Iso639Language) {\r
1446 CompareLength = ISO_639_2_ENTRY_SIZE;\r
1447 for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {\r
1448 if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {\r
1449 //\r
1450 // Successfully find the index of Lang string in SupportedLang string.\r
1451 //\r
1452 Index = Index / CompareLength;\r
1453 return Index;\r
1454 }\r
1455 }\r
1456 ASSERT (FALSE);\r
1457 return 0;\r
1458 } else {\r
1459 //\r
1460 // Compare RFC4646 language code\r
1461 //\r
1462 Index = 0;\r
1463 for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++);\r
1464\r
1465 for (Index = 0; *SupportedLang != '\0'; Index++, SupportedLang += CompareLength) {\r
1466 //\r
1467 // Skip ';' characters in SupportedLang\r
1468 //\r
1469 for (; *SupportedLang != '\0' && *SupportedLang == ';'; SupportedLang++);\r
1470 //\r
1471 // Determine the length of the next language code in SupportedLang\r
1472 //\r
1473 for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++);\r
2d3fb919 1474\r
1475 if ((CompareLength == LanguageLength) &&\r
0c18794e 1476 (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0)) {\r
1477 //\r
1478 // Successfully find the index of Lang string in SupportedLang string.\r
1479 //\r
1480 return Index;\r
1481 }\r
1482 }\r
1483 ASSERT (FALSE);\r
1484 return 0;\r
1485 }\r
1486}\r
1487\r
1488/**\r
1489 Get language string from supported language codes according to index.\r
1490\r
1491 This code is used to get corresponding language strings in supported language codes. It can handle\r
1492 RFC4646 and ISO639 language tags.\r
1493 In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.\r
1494 In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.\r
1495\r
1496 For example:\r
1497 SupportedLang = "engfraengfra"\r
1498 Index = "1"\r
1499 Iso639Language = TRUE\r
1500 The return value is "fra".\r
1501 Another example:\r
1502 SupportedLang = "en;fr;en-US;fr-FR"\r
1503 Index = "1"\r
1504 Iso639Language = FALSE\r
1505 The return value is "fr".\r
1506\r
1507 @param SupportedLang Platform supported language codes.\r
1508 @param Index The index in supported language codes.\r
1509 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
1510\r
1511 @retval The language string in the language codes.\r
1512\r
1513**/\r
1514CHAR8 *\r
1515GetLangFromSupportedLangCodes (\r
1516 IN CHAR8 *SupportedLang,\r
1517 IN UINTN Index,\r
1518 IN BOOLEAN Iso639Language\r
1519)\r
1520{\r
1521 UINTN SubIndex;\r
1522 UINTN CompareLength;\r
1523 CHAR8 *Supported;\r
1524\r
1525 SubIndex = 0;\r
1526 Supported = SupportedLang;\r
1527 if (Iso639Language) {\r
1528 //\r
1529 // According to the index of Lang string in SupportedLang string to get the language.\r
1530 // This code will be invoked in RUNTIME, therefore there is not a memory allocate/free operation.\r
1531 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
1532 //\r
1533 CompareLength = ISO_639_2_ENTRY_SIZE;\r
1534 mVariableModuleGlobal->Lang[CompareLength] = '\0';\r
1535 return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength);\r
2d3fb919 1536\r
0c18794e 1537 } else {\r
1538 while (TRUE) {\r
1539 //\r
1540 // Take semicolon as delimitation, sequentially traverse supported language codes.\r
1541 //\r
1542 for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {\r
1543 Supported++;\r
1544 }\r
1545 if ((*Supported == '\0') && (SubIndex != Index)) {\r
1546 //\r
1547 // Have completed the traverse, but not find corrsponding string.\r
1548 // This case is not allowed to happen.\r
1549 //\r
1550 ASSERT(FALSE);\r
1551 return NULL;\r
1552 }\r
1553 if (SubIndex == Index) {\r
1554 //\r
1555 // According to the index of Lang string in SupportedLang string to get the language.\r
1556 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.\r
1557 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
1558 //\r
1559 mVariableModuleGlobal->PlatformLang[CompareLength] = '\0';\r
1560 return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - CompareLength, CompareLength);\r
1561 }\r
1562 SubIndex++;\r
1563\r
1564 //\r
1565 // Skip ';' characters in Supported\r
1566 //\r
1567 for (; *Supported != '\0' && *Supported == ';'; Supported++);\r
1568 }\r
1569 }\r
1570}\r
1571\r
1572/**\r
2d3fb919 1573 Returns a pointer to an allocated buffer that contains the best matching language\r
1574 from a set of supported languages.\r
1575\r
1576 This function supports both ISO 639-2 and RFC 4646 language codes, but language\r
0c18794e 1577 code types may not be mixed in a single call to this function. This function\r
1578 supports a variable argument list that allows the caller to pass in a prioritized\r
1579 list of language codes to test against all the language codes in SupportedLanguages.\r
1580\r
1581 If SupportedLanguages is NULL, then ASSERT().\r
1582\r
1583 @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that\r
2d3fb919 1584 contains a set of language codes in the format\r
0c18794e 1585 specified by Iso639Language.\r
1586 @param[in] Iso639Language If TRUE, then all language codes are assumed to be\r
1587 in ISO 639-2 format. If FALSE, then all language\r
1588 codes are assumed to be in RFC 4646 language format\r
2d3fb919 1589 @param[in] ... A variable argument list that contains pointers to\r
0c18794e 1590 Null-terminated ASCII strings that contain one or more\r
1591 language codes in the format specified by Iso639Language.\r
1592 The first language code from each of these language\r
1593 code lists is used to determine if it is an exact or\r
2d3fb919 1594 close match to any of the language codes in\r
0c18794e 1595 SupportedLanguages. Close matches only apply to RFC 4646\r
1596 language codes, and the matching algorithm from RFC 4647\r
2d3fb919 1597 is used to determine if a close match is present. If\r
0c18794e 1598 an exact or close match is found, then the matching\r
1599 language code from SupportedLanguages is returned. If\r
1600 no matches are found, then the next variable argument\r
2d3fb919 1601 parameter is evaluated. The variable argument list\r
0c18794e 1602 is terminated by a NULL.\r
1603\r
1604 @retval NULL The best matching language could not be found in SupportedLanguages.\r
2d3fb919 1605 @retval NULL There are not enough resources available to return the best matching\r
0c18794e 1606 language.\r
2d3fb919 1607 @retval Other A pointer to a Null-terminated ASCII string that is the best matching\r
0c18794e 1608 language in SupportedLanguages.\r
1609\r
1610**/\r
1611CHAR8 *\r
1612EFIAPI\r
1613VariableGetBestLanguage (\r
2d3fb919 1614 IN CONST CHAR8 *SupportedLanguages,\r
0c18794e 1615 IN BOOLEAN Iso639Language,\r
1616 ...\r
1617 )\r
1618{\r
1619 VA_LIST Args;\r
1620 CHAR8 *Language;\r
1621 UINTN CompareLength;\r
1622 UINTN LanguageLength;\r
1623 CONST CHAR8 *Supported;\r
1624 CHAR8 *Buffer;\r
1625\r
648f98d1 1626 if (SupportedLanguages == NULL) {\r
1627 return NULL;\r
1628 }\r
0c18794e 1629\r
1630 VA_START (Args, Iso639Language);\r
1631 while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {\r
1632 //\r
1633 // Default to ISO 639-2 mode\r
1634 //\r
1635 CompareLength = 3;\r
1636 LanguageLength = MIN (3, AsciiStrLen (Language));\r
1637\r
1638 //\r
1639 // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language\r
1640 //\r
1641 if (!Iso639Language) {\r
1642 for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++);\r
1643 }\r
1644\r
1645 //\r
1646 // Trim back the length of Language used until it is empty\r
1647 //\r
1648 while (LanguageLength > 0) {\r
1649 //\r
1650 // Loop through all language codes in SupportedLanguages\r
1651 //\r
1652 for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {\r
1653 //\r
1654 // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages\r
1655 //\r
1656 if (!Iso639Language) {\r
1657 //\r
1658 // Skip ';' characters in Supported\r
1659 //\r
1660 for (; *Supported != '\0' && *Supported == ';'; Supported++);\r
1661 //\r
1662 // Determine the length of the next language code in Supported\r
1663 //\r
1664 for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++);\r
1665 //\r
1666 // If Language is longer than the Supported, then skip to the next language\r
1667 //\r
1668 if (LanguageLength > CompareLength) {\r
1669 continue;\r
1670 }\r
1671 }\r
1672 //\r
1673 // See if the first LanguageLength characters in Supported match Language\r
1674 //\r
1675 if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {\r
1676 VA_END (Args);\r
1677\r
1678 Buffer = Iso639Language ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang;\r
1679 Buffer[CompareLength] = '\0';\r
1680 return CopyMem (Buffer, Supported, CompareLength);\r
1681 }\r
1682 }\r
1683\r
1684 if (Iso639Language) {\r
1685 //\r
1686 // If ISO 639 mode, then each language can only be tested once\r
1687 //\r
1688 LanguageLength = 0;\r
1689 } else {\r
1690 //\r
2d3fb919 1691 // If RFC 4646 mode, then trim Language from the right to the next '-' character\r
0c18794e 1692 //\r
1693 for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--);\r
1694 }\r
1695 }\r
1696 }\r
1697 VA_END (Args);\r
1698\r
1699 //\r
2d3fb919 1700 // No matches were found\r
0c18794e 1701 //\r
1702 return NULL;\r
1703}\r
1704\r
b2bd493e
SZ
1705/**\r
1706 This function is to check if the remaining variable space is enough to set\r
1707 all Variables from argument list successfully. The purpose of the check\r
1708 is to keep the consistency of the Variables to be in variable storage.\r
1709\r
1710 Note: Variables are assumed to be in same storage.\r
1711 The set sequence of Variables will be same with the sequence of VariableEntry from argument list,\r
1712 so follow the argument sequence to check the Variables.\r
1713\r
1714 @param[in] Attributes Variable attributes for Variable entries.\r
9a12e582 1715 @param ... The variable argument list with type VARIABLE_ENTRY_CONSISTENCY *.\r
20333c6d 1716 A NULL terminates the list. The VariableSize of\r
9a12e582
DG
1717 VARIABLE_ENTRY_CONSISTENCY is the variable data size as input.\r
1718 It will be changed to variable total size as output.\r
b2bd493e
SZ
1719\r
1720 @retval TRUE Have enough variable space to set the Variables successfully.\r
1721 @retval FALSE No enough variable space to set the Variables successfully.\r
1722\r
1723**/\r
1724BOOLEAN\r
1725EFIAPI\r
1726CheckRemainingSpaceForConsistency (\r
1727 IN UINT32 Attributes,\r
1728 ...\r
1729 )\r
1730{\r
1731 EFI_STATUS Status;\r
1732 VA_LIST Args;\r
1733 VARIABLE_ENTRY_CONSISTENCY *VariableEntry;\r
1734 UINT64 MaximumVariableStorageSize;\r
1735 UINT64 RemainingVariableStorageSize;\r
1736 UINT64 MaximumVariableSize;\r
1737 UINTN TotalNeededSize;\r
1738 UINTN OriginalVarSize;\r
1739 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
1740 VARIABLE_POINTER_TRACK VariablePtrTrack;\r
1741 VARIABLE_HEADER *NextVariable;\r
9a12e582
DG
1742 UINTN VarNameSize;\r
1743 UINTN VarDataSize;\r
b2bd493e
SZ
1744\r
1745 //\r
1746 // Non-Volatile related.\r
1747 //\r
1748 VariableStoreHeader = mNvVariableCache;\r
1749\r
1750 Status = VariableServiceQueryVariableInfoInternal (\r
1751 Attributes,\r
1752 &MaximumVariableStorageSize,\r
1753 &RemainingVariableStorageSize,\r
1754 &MaximumVariableSize\r
1755 );\r
1756 ASSERT_EFI_ERROR (Status);\r
1757\r
1758 TotalNeededSize = 0;\r
1759 VA_START (Args, Attributes);\r
1760 VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
1761 while (VariableEntry != NULL) {\r
9a12e582
DG
1762 //\r
1763 // Calculate variable total size.\r
1764 //\r
1765 VarNameSize = StrSize (VariableEntry->Name);\r
1766 VarNameSize += GET_PAD_SIZE (VarNameSize);\r
1767 VarDataSize = VariableEntry->VariableSize;\r
1768 VarDataSize += GET_PAD_SIZE (VarDataSize);\r
1769 VariableEntry->VariableSize = HEADER_ALIGN (sizeof (VARIABLE_HEADER) + VarNameSize + VarDataSize);\r
1770\r
b2bd493e
SZ
1771 TotalNeededSize += VariableEntry->VariableSize;\r
1772 VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
1773 }\r
1774 VA_END (Args);\r
1775\r
1776 if (RemainingVariableStorageSize >= TotalNeededSize) {\r
1777 //\r
1778 // Already have enough space.\r
1779 //\r
1780 return TRUE;\r
1781 } else if (AtRuntime ()) {\r
1782 //\r
1783 // At runtime, no reclaim.\r
1784 // The original variable space of Variables can't be reused.\r
1785 //\r
1786 return FALSE;\r
1787 }\r
1788\r
1789 VA_START (Args, Attributes);\r
1790 VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
1791 while (VariableEntry != NULL) {\r
1792 //\r
1793 // Check if Variable[Index] has been present and get its size.\r
1794 //\r
1795 OriginalVarSize = 0;\r
1796 VariablePtrTrack.StartPtr = GetStartPointer (VariableStoreHeader);\r
1797 VariablePtrTrack.EndPtr = GetEndPointer (VariableStoreHeader);\r
1798 Status = FindVariableEx (\r
1799 VariableEntry->Name,\r
1800 VariableEntry->Guid,\r
1801 FALSE,\r
1802 &VariablePtrTrack\r
1803 );\r
1804 if (!EFI_ERROR (Status)) {\r
1805 //\r
1806 // Get size of Variable[Index].\r
1807 //\r
1808 NextVariable = GetNextVariablePtr (VariablePtrTrack.CurrPtr);\r
1809 OriginalVarSize = (UINTN) NextVariable - (UINTN) VariablePtrTrack.CurrPtr;\r
1810 //\r
1811 // Add the original size of Variable[Index] to remaining variable storage size.\r
1812 //\r
1813 RemainingVariableStorageSize += OriginalVarSize;\r
1814 }\r
1815 if (VariableEntry->VariableSize > RemainingVariableStorageSize) {\r
1816 //\r
1817 // No enough space for Variable[Index].\r
1818 //\r
1819 VA_END (Args);\r
1820 return FALSE;\r
1821 }\r
1822 //\r
1823 // Sub the (new) size of Variable[Index] from remaining variable storage size.\r
1824 //\r
1825 RemainingVariableStorageSize -= VariableEntry->VariableSize;\r
1826 VariableEntry = VA_ARG (Args, VARIABLE_ENTRY_CONSISTENCY *);\r
1827 }\r
1828 VA_END (Args);\r
1829\r
1830 return TRUE;\r
1831}\r
1832\r
0c18794e 1833/**\r
1834 Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.\r
1835\r
1836 When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.\r
1837\r
1838 According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,\r
1839 and are read-only. Therefore, in variable driver, only store the original value for other use.\r
1840\r
1841 @param[in] VariableName Name of variable.\r
1842\r
1843 @param[in] Data Variable data.\r
1844\r
1845 @param[in] DataSize Size of data. 0 means delete.\r
1846\r
9bc5dabb
SZ
1847 @retval EFI_SUCCESS The update operation is successful or ignored.\r
1848 @retval EFI_WRITE_PROTECTED Update PlatformLangCodes/LangCodes at runtime.\r
1849 @retval EFI_OUT_OF_RESOURCES No enough variable space to do the update operation.\r
1850 @retval Others Other errors happened during the update operation.\r
1851\r
0c18794e 1852**/\r
9bc5dabb 1853EFI_STATUS\r
4d832aab 1854AutoUpdateLangVariable (\r
0c18794e 1855 IN CHAR16 *VariableName,\r
1856 IN VOID *Data,\r
1857 IN UINTN DataSize\r
1858 )\r
1859{\r
1860 EFI_STATUS Status;\r
1861 CHAR8 *BestPlatformLang;\r
1862 CHAR8 *BestLang;\r
1863 UINTN Index;\r
1864 UINT32 Attributes;\r
1865 VARIABLE_POINTER_TRACK Variable;\r
1866 BOOLEAN SetLanguageCodes;\r
b2bd493e 1867 VARIABLE_ENTRY_CONSISTENCY VariableEntry[2];\r
0c18794e 1868\r
1869 //\r
1870 // Don't do updates for delete operation\r
1871 //\r
1872 if (DataSize == 0) {\r
9bc5dabb 1873 return EFI_SUCCESS;\r
0c18794e 1874 }\r
1875\r
1876 SetLanguageCodes = FALSE;\r
1877\r
6675a21f 1878 if (StrCmp (VariableName, EFI_PLATFORM_LANG_CODES_VARIABLE_NAME) == 0) {\r
0c18794e 1879 //\r
1880 // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.\r
1881 //\r
1882 if (AtRuntime ()) {\r
9bc5dabb 1883 return EFI_WRITE_PROTECTED;\r
0c18794e 1884 }\r
1885\r
1886 SetLanguageCodes = TRUE;\r
1887\r
1888 //\r
1889 // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only\r
1890 // Therefore, in variable driver, only store the original value for other use.\r
1891 //\r
1892 if (mVariableModuleGlobal->PlatformLangCodes != NULL) {\r
1893 FreePool (mVariableModuleGlobal->PlatformLangCodes);\r
1894 }\r
1895 mVariableModuleGlobal->PlatformLangCodes = AllocateRuntimeCopyPool (DataSize, Data);\r
1896 ASSERT (mVariableModuleGlobal->PlatformLangCodes != NULL);\r
1897\r
1898 //\r
2d3fb919 1899 // PlatformLang holds a single language from PlatformLangCodes,\r
0c18794e 1900 // so the size of PlatformLangCodes is enough for the PlatformLang.\r
1901 //\r
1902 if (mVariableModuleGlobal->PlatformLang != NULL) {\r
1903 FreePool (mVariableModuleGlobal->PlatformLang);\r
1904 }\r
1905 mVariableModuleGlobal->PlatformLang = AllocateRuntimePool (DataSize);\r
1906 ASSERT (mVariableModuleGlobal->PlatformLang != NULL);\r
1907\r
6675a21f 1908 } else if (StrCmp (VariableName, EFI_LANG_CODES_VARIABLE_NAME) == 0) {\r
0c18794e 1909 //\r
1910 // LangCodes is a volatile variable, so it can not be updated at runtime.\r
1911 //\r
1912 if (AtRuntime ()) {\r
9bc5dabb 1913 return EFI_WRITE_PROTECTED;\r
0c18794e 1914 }\r
1915\r
1916 SetLanguageCodes = TRUE;\r
1917\r
1918 //\r
1919 // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only\r
1920 // Therefore, in variable driver, only store the original value for other use.\r
1921 //\r
1922 if (mVariableModuleGlobal->LangCodes != NULL) {\r
1923 FreePool (mVariableModuleGlobal->LangCodes);\r
1924 }\r
1925 mVariableModuleGlobal->LangCodes = AllocateRuntimeCopyPool (DataSize, Data);\r
1926 ASSERT (mVariableModuleGlobal->LangCodes != NULL);\r
1927 }\r
1928\r
2d3fb919 1929 if (SetLanguageCodes\r
0c18794e 1930 && (mVariableModuleGlobal->PlatformLangCodes != NULL)\r
1931 && (mVariableModuleGlobal->LangCodes != NULL)) {\r
1932 //\r
1933 // Update Lang if PlatformLang is already set\r
1934 // Update PlatformLang if Lang is already set\r
1935 //\r
6675a21f 1936 Status = FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
0c18794e 1937 if (!EFI_ERROR (Status)) {\r
1938 //\r
1939 // Update Lang\r
1940 //\r
6675a21f 1941 VariableName = EFI_PLATFORM_LANG_VARIABLE_NAME;\r
0c18794e 1942 Data = GetVariableDataPtr (Variable.CurrPtr);\r
1943 DataSize = Variable.CurrPtr->DataSize;\r
1944 } else {\r
6675a21f 1945 Status = FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
0c18794e 1946 if (!EFI_ERROR (Status)) {\r
1947 //\r
1948 // Update PlatformLang\r
1949 //\r
6675a21f 1950 VariableName = EFI_LANG_VARIABLE_NAME;\r
0c18794e 1951 Data = GetVariableDataPtr (Variable.CurrPtr);\r
1952 DataSize = Variable.CurrPtr->DataSize;\r
1953 } else {\r
1954 //\r
1955 // Neither PlatformLang nor Lang is set, directly return\r
1956 //\r
9bc5dabb 1957 return EFI_SUCCESS;\r
0c18794e 1958 }\r
1959 }\r
1960 }\r
2d3fb919 1961\r
9bc5dabb
SZ
1962 Status = EFI_SUCCESS;\r
1963\r
0c18794e 1964 //\r
1965 // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.\r
1966 //\r
1967 Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;\r
1968\r
6675a21f 1969 if (StrCmp (VariableName, EFI_PLATFORM_LANG_VARIABLE_NAME) == 0) {\r
0c18794e 1970 //\r
1971 // Update Lang when PlatformLangCodes/LangCodes were set.\r
1972 //\r
1973 if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {\r
1974 //\r
1975 // When setting PlatformLang, firstly get most matched language string from supported language codes.\r
1976 //\r
1977 BestPlatformLang = VariableGetBestLanguage (mVariableModuleGlobal->PlatformLangCodes, FALSE, Data, NULL);\r
1978 if (BestPlatformLang != NULL) {\r
1979 //\r
1980 // Get the corresponding index in language codes.\r
1981 //\r
1982 Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, BestPlatformLang, FALSE);\r
1983\r
1984 //\r
1985 // Get the corresponding ISO639 language tag according to RFC4646 language tag.\r
1986 //\r
1987 BestLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, Index, TRUE);\r
1988\r
1989 //\r
9a12e582 1990 // Check the variable space for both Lang and PlatformLang variable.\r
b2bd493e 1991 //\r
9a12e582 1992 VariableEntry[0].VariableSize = ISO_639_2_ENTRY_SIZE + 1;\r
b2bd493e
SZ
1993 VariableEntry[0].Guid = &gEfiGlobalVariableGuid;\r
1994 VariableEntry[0].Name = EFI_LANG_VARIABLE_NAME;\r
20333c6d 1995\r
9a12e582 1996 VariableEntry[1].VariableSize = AsciiStrSize (BestPlatformLang);\r
b2bd493e
SZ
1997 VariableEntry[1].Guid = &gEfiGlobalVariableGuid;\r
1998 VariableEntry[1].Name = EFI_PLATFORM_LANG_VARIABLE_NAME;\r
1999 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {\r
2000 //\r
2001 // No enough variable space to set both Lang and PlatformLang successfully.\r
2002 //\r
2003 Status = EFI_OUT_OF_RESOURCES;\r
2004 } else {\r
2005 //\r
2006 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.\r
2007 //\r
2008 FindVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
0c18794e 2009\r
b2bd493e
SZ
2010 Status = UpdateVariable (EFI_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestLang,\r
2011 ISO_639_2_ENTRY_SIZE + 1, Attributes, 0, 0, &Variable, NULL);\r
2012 }\r
0c18794e 2013\r
9bc5dabb 2014 DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a Status: %r\n", BestPlatformLang, BestLang, Status));\r
0c18794e 2015 }\r
2016 }\r
2017\r
6675a21f 2018 } else if (StrCmp (VariableName, EFI_LANG_VARIABLE_NAME) == 0) {\r
0c18794e 2019 //\r
2020 // Update PlatformLang when PlatformLangCodes/LangCodes were set.\r
2021 //\r
2022 if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {\r
2023 //\r
2024 // When setting Lang, firstly get most matched language string from supported language codes.\r
2025 //\r
2026 BestLang = VariableGetBestLanguage (mVariableModuleGlobal->LangCodes, TRUE, Data, NULL);\r
2027 if (BestLang != NULL) {\r
2028 //\r
2029 // Get the corresponding index in language codes.\r
2030 //\r
2031 Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, BestLang, TRUE);\r
2032\r
2033 //\r
2034 // Get the corresponding RFC4646 language tag according to ISO639 language tag.\r
2035 //\r
2036 BestPlatformLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, Index, FALSE);\r
2037\r
2038 //\r
9a12e582 2039 // Check the variable space for both PlatformLang and Lang variable.\r
0c18794e 2040 //\r
9a12e582 2041 VariableEntry[0].VariableSize = AsciiStrSize (BestPlatformLang);\r
b2bd493e
SZ
2042 VariableEntry[0].Guid = &gEfiGlobalVariableGuid;\r
2043 VariableEntry[0].Name = EFI_PLATFORM_LANG_VARIABLE_NAME;\r
9a12e582
DG
2044\r
2045 VariableEntry[1].VariableSize = ISO_639_2_ENTRY_SIZE + 1;\r
b2bd493e
SZ
2046 VariableEntry[1].Guid = &gEfiGlobalVariableGuid;\r
2047 VariableEntry[1].Name = EFI_LANG_VARIABLE_NAME;\r
2048 if (!CheckRemainingSpaceForConsistency (VARIABLE_ATTRIBUTE_NV_BS_RT, &VariableEntry[0], &VariableEntry[1], NULL)) {\r
2049 //\r
2050 // No enough variable space to set both PlatformLang and Lang successfully.\r
2051 //\r
2052 Status = EFI_OUT_OF_RESOURCES;\r
2053 } else {\r
2054 //\r
2055 // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.\r
2056 //\r
2057 FindVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
0c18794e 2058\r
b2bd493e
SZ
2059 Status = UpdateVariable (EFI_PLATFORM_LANG_VARIABLE_NAME, &gEfiGlobalVariableGuid, BestPlatformLang,\r
2060 AsciiStrSize (BestPlatformLang), Attributes, 0, 0, &Variable, NULL);\r
2061 }\r
0c18794e 2062\r
9bc5dabb 2063 DEBUG ((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a Status: %r\n", BestLang, BestPlatformLang, Status));\r
0c18794e 2064 }\r
2065 }\r
2066 }\r
9bc5dabb 2067\r
b2bd493e
SZ
2068 if (SetLanguageCodes) {\r
2069 //\r
2070 // Continue to set PlatformLangCodes or LangCodes.\r
2071 //\r
2072 return EFI_SUCCESS;\r
2073 } else {\r
2074 return Status;\r
2075 }\r
0c18794e 2076}\r
2077\r
2078/**\r
2079 Update the variable region with Variable information. If EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS is set,\r
2080 index of associated public key is needed.\r
2081\r
2082 @param[in] VariableName Name of variable.\r
2083 @param[in] VendorGuid Guid of variable.\r
2084 @param[in] Data Variable data.\r
2085 @param[in] DataSize Size of data. 0 means delete.\r
2086 @param[in] Attributes Attributes of the variable.\r
2087 @param[in] KeyIndex Index of associated public key.\r
2088 @param[in] MonotonicCount Value of associated monotonic count.\r
23b06935 2089 @param[in, out] CacheVariable The variable information which is used to keep track of variable usage.\r
0c18794e 2090 @param[in] TimeStamp Value of associated TimeStamp.\r
2d3fb919 2091\r
0c18794e 2092 @retval EFI_SUCCESS The update operation is success.\r
2093 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.\r
2094\r
2095**/\r
2096EFI_STATUS\r
2097UpdateVariable (\r
2098 IN CHAR16 *VariableName,\r
2099 IN EFI_GUID *VendorGuid,\r
2100 IN VOID *Data,\r
2101 IN UINTN DataSize,\r
2102 IN UINT32 Attributes OPTIONAL,\r
2103 IN UINT32 KeyIndex OPTIONAL,\r
2104 IN UINT64 MonotonicCount OPTIONAL,\r
23b06935 2105 IN OUT VARIABLE_POINTER_TRACK *CacheVariable,\r
0c18794e 2106 IN EFI_TIME *TimeStamp OPTIONAL\r
2107 )\r
2108{\r
2109 EFI_STATUS Status;\r
2110 VARIABLE_HEADER *NextVariable;\r
2111 UINTN ScratchSize;\r
732d199d 2112 UINTN MaxDataSize;\r
0c18794e 2113 UINTN VarNameOffset;\r
2114 UINTN VarDataOffset;\r
2115 UINTN VarNameSize;\r
2116 UINTN VarSize;\r
2117 BOOLEAN Volatile;\r
2118 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
2119 UINT8 State;\r
0c18794e 2120 VARIABLE_POINTER_TRACK *Variable;\r
2121 VARIABLE_POINTER_TRACK NvVariable;\r
2122 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
2123 UINTN CacheOffset;\r
fddbbc66
SZ
2124 UINT8 *BufferForMerge;\r
2125 UINTN MergedBufSize;\r
2126 BOOLEAN DataReady;\r
0c18794e 2127 UINTN DataOffset;\r
952ba83c
SZ
2128 BOOLEAN IsCommonVariable;\r
2129 BOOLEAN IsCommonUserVariable;\r
0c18794e 2130\r
2131 if (mVariableModuleGlobal->FvbInstance == NULL) {\r
2132 //\r
2133 // The FVB protocol is not installed, so the EFI_VARIABLE_WRITE_ARCH_PROTOCOL is not installed.\r
2134 //\r
2135 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
2136 //\r
2137 // Trying to update NV variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL\r
2138 //\r
2139 return EFI_NOT_AVAILABLE_YET;\r
2140 } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
2141 //\r
2142 // Trying to update volatile authenticated variable prior to the installation of EFI_VARIABLE_WRITE_ARCH_PROTOCOL\r
2143 // The authenticated variable perhaps is not initialized, just return here.\r
2144 //\r
2145 return EFI_NOT_AVAILABLE_YET;\r
2146 }\r
2147 }\r
2148\r
2149 if ((CacheVariable->CurrPtr == NULL) || CacheVariable->Volatile) {\r
2150 Variable = CacheVariable;\r
2151 } else {\r
2152 //\r
2153 // Update/Delete existing NV variable.\r
2154 // CacheVariable points to the variable in the memory copy of Flash area\r
2155 // Now let Variable points to the same variable in Flash area.\r
2156 //\r
2157 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
2d3fb919 2158 Variable = &NvVariable;\r
0c18794e 2159 Variable->StartPtr = GetStartPointer (VariableStoreHeader);\r
2160 Variable->EndPtr = GetEndPointer (VariableStoreHeader);\r
2161 Variable->CurrPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->CurrPtr - (UINTN)CacheVariable->StartPtr));\r
23b06935
SZ
2162 if (CacheVariable->InDeletedTransitionPtr != NULL) {\r
2163 Variable->InDeletedTransitionPtr = (VARIABLE_HEADER *)((UINTN)Variable->StartPtr + ((UINTN)CacheVariable->InDeletedTransitionPtr - (UINTN)CacheVariable->StartPtr));\r
2164 } else {\r
2165 Variable->InDeletedTransitionPtr = NULL;\r
2166 }\r
0c18794e 2167 Variable->Volatile = FALSE;\r
2d3fb919 2168 }\r
0c18794e 2169\r
2170 Fvb = mVariableModuleGlobal->FvbInstance;\r
0c18794e 2171\r
2172 //\r
2173 // Tricky part: Use scratch data area at the end of volatile variable store\r
2174 // as a temporary storage.\r
2175 //\r
2176 NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));\r
2177 ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
fddbbc66
SZ
2178 SetMem (NextVariable, ScratchSize, 0xff);\r
2179 DataReady = FALSE;\r
0c18794e 2180\r
2181 if (Variable->CurrPtr != NULL) {\r
2182 //\r
2183 // Update/Delete existing variable.\r
2184 //\r
2d3fb919 2185 if (AtRuntime ()) {\r
0c18794e 2186 //\r
2d3fb919 2187 // If AtRuntime and the variable is Volatile and Runtime Access,\r
2188 // the volatile is ReadOnly, and SetVariable should be aborted and\r
0c18794e 2189 // return EFI_WRITE_PROTECTED.\r
2190 //\r
2191 if (Variable->Volatile) {\r
2192 Status = EFI_WRITE_PROTECTED;\r
2193 goto Done;\r
2194 }\r
2195 //\r
2196 // Only variable that have NV attributes can be updated/deleted in Runtime.\r
2197 //\r
2198 if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
2199 Status = EFI_INVALID_PARAMETER;\r
2d3fb919 2200 goto Done;\r
0c18794e 2201 }\r
20333c6d 2202\r
ecc722ad 2203 //\r
2204 // Only variable that have RT attributes can be updated/deleted in Runtime.\r
2205 //\r
2206 if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) {\r
2207 Status = EFI_INVALID_PARAMETER;\r
2208 goto Done;\r
2209 }\r
0c18794e 2210 }\r
2211\r
2212 //\r
2213 // Setting a data variable with no access, or zero DataSize attributes\r
2214 // causes it to be deleted.\r
2d3fb919 2215 // When the EFI_VARIABLE_APPEND_WRITE attribute is set, DataSize of zero will\r
2216 // not delete the variable.\r
0c18794e 2217 //\r
2d3fb919 2218 if ((((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) && (DataSize == 0))|| ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0)) {\r
23b06935
SZ
2219 if (Variable->InDeletedTransitionPtr != NULL) {\r
2220 //\r
2221 // Both ADDED and IN_DELETED_TRANSITION variable are present,\r
2222 // set IN_DELETED_TRANSITION one to DELETED state first.\r
2223 //\r
2224 State = Variable->InDeletedTransitionPtr->State;\r
2225 State &= VAR_DELETED;\r
2226 Status = UpdateVariableStore (\r
2227 &mVariableModuleGlobal->VariableGlobal,\r
2228 Variable->Volatile,\r
2229 FALSE,\r
2230 Fvb,\r
2231 (UINTN) &Variable->InDeletedTransitionPtr->State,\r
2232 sizeof (UINT8),\r
2233 &State\r
2234 );\r
2235 if (!EFI_ERROR (Status)) {\r
2236 if (!Variable->Volatile) {\r
0cc565de 2237 ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
23b06935
SZ
2238 CacheVariable->InDeletedTransitionPtr->State = State;\r
2239 }\r
2240 } else {\r
2241 goto Done;\r
2242 }\r
2243 }\r
2244\r
0c18794e 2245 State = Variable->CurrPtr->State;\r
2246 State &= VAR_DELETED;\r
2247\r
2248 Status = UpdateVariableStore (\r
2249 &mVariableModuleGlobal->VariableGlobal,\r
2250 Variable->Volatile,\r
2251 FALSE,\r
2252 Fvb,\r
2253 (UINTN) &Variable->CurrPtr->State,\r
2254 sizeof (UINT8),\r
2255 &State\r
2d3fb919 2256 );\r
0c18794e 2257 if (!EFI_ERROR (Status)) {\r
2258 UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE);\r
2259 if (!Variable->Volatile) {\r
2260 CacheVariable->CurrPtr->State = State;\r
335e2681 2261 FlushHobVariableToFlash (VariableName, VendorGuid);\r
0c18794e 2262 }\r
2263 }\r
2d3fb919 2264 goto Done;\r
0c18794e 2265 }\r
2266 //\r
2267 // If the variable is marked valid, and the same data has been passed in,\r
2268 // then return to the caller immediately.\r
2269 //\r
2270 if (DataSizeOfVariable (Variable->CurrPtr) == DataSize &&\r
fddbbc66 2271 (CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0) &&\r
2d3fb919 2272 ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) &&\r
2273 (TimeStamp == NULL)) {\r
2274 //\r
2275 // Variable content unchanged and no need to update timestamp, just return.\r
2276 //\r
0c18794e 2277 UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE);\r
2278 Status = EFI_SUCCESS;\r
2279 goto Done;\r
2280 } else if ((Variable->CurrPtr->State == VAR_ADDED) ||\r
2281 (Variable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {\r
2282\r
2283 //\r
2284 // EFI_VARIABLE_APPEND_WRITE attribute only effects for existing variable\r
2285 //\r
2286 if ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0) {\r
2d3fb919 2287 //\r
fddbbc66
SZ
2288 // NOTE: From 0 to DataOffset of NextVariable is reserved for Variable Header and Name.\r
2289 // From DataOffset of NextVariable is to save the existing variable data.\r
2d3fb919 2290 //\r
2291 DataOffset = sizeof (VARIABLE_HEADER) + Variable->CurrPtr->NameSize + GET_PAD_SIZE (Variable->CurrPtr->NameSize);\r
fddbbc66
SZ
2292 BufferForMerge = (UINT8 *) ((UINTN) NextVariable + DataOffset);\r
2293 CopyMem (BufferForMerge, (UINT8 *) ((UINTN) Variable->CurrPtr + DataOffset), Variable->CurrPtr->DataSize);\r
2d3fb919 2294\r
732d199d 2295 //\r
20333c6d 2296 // Set Max Common Variable Data Size as default MaxDataSize\r
732d199d 2297 //\r
fddbbc66 2298 MaxDataSize = PcdGet32 (PcdMaxVariableSize) - DataOffset;\r
732d199d 2299\r
5767f22f 2300 if ((CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&\r
20333c6d
QL
2301 ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) || (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||\r
2302 (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0))) ||\r
2303 (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0))) {\r
2d3fb919 2304 //\r
5767f22f 2305 // For variables with formatted as EFI_SIGNATURE_LIST, the driver shall not perform an append of\r
2d3fb919 2306 // EFI_SIGNATURE_DATA values that are already part of the existing variable value.\r
2307 //\r
732d199d 2308 Status = AppendSignatureList (\r
fddbbc66 2309 BufferForMerge,\r
20333c6d 2310 Variable->CurrPtr->DataSize,\r
732d199d 2311 MaxDataSize - Variable->CurrPtr->DataSize,\r
fddbbc66
SZ
2312 Data,\r
2313 DataSize,\r
2314 &MergedBufSize\r
732d199d 2315 );\r
2316 if (Status == EFI_BUFFER_TOO_SMALL) {\r
2317 //\r
fddbbc66 2318 // Signature List is too long, Failed to Append.\r
732d199d 2319 //\r
2320 Status = EFI_INVALID_PARAMETER;\r
2321 goto Done;\r
2322 }\r
2323\r
fddbbc66 2324 if (MergedBufSize == Variable->CurrPtr->DataSize) {\r
2d3fb919 2325 if ((TimeStamp == NULL) || CompareTimeStamp (TimeStamp, &Variable->CurrPtr->TimeStamp)) {\r
2326 //\r
2327 // New EFI_SIGNATURE_DATA is not found and timestamp is not later\r
2328 // than current timestamp, return EFI_SUCCESS directly.\r
2329 //\r
2330 UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE);\r
2331 Status = EFI_SUCCESS;\r
2332 goto Done;\r
2333 }\r
2334 }\r
2335 } else {\r
2336 //\r
fddbbc66 2337 // For other Variables, append the new data to the end of existing data.\r
732d199d 2338 // Max Harware error record variable data size is different from common variable\r
2d3fb919 2339 //\r
732d199d 2340 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
fddbbc66 2341 MaxDataSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - DataOffset;\r
732d199d 2342 }\r
2343\r
2344 if (Variable->CurrPtr->DataSize + DataSize > MaxDataSize) {\r
2345 //\r
fddbbc66 2346 // Existing data size + new data size exceed maximum variable size limitation.\r
732d199d 2347 //\r
2348 Status = EFI_INVALID_PARAMETER;\r
2349 goto Done;\r
2350 }\r
fddbbc66
SZ
2351 CopyMem ((UINT8*) ((UINTN) BufferForMerge + Variable->CurrPtr->DataSize), Data, DataSize);\r
2352 MergedBufSize = Variable->CurrPtr->DataSize + DataSize;\r
2d3fb919 2353 }\r
2354\r
0c18794e 2355 //\r
fddbbc66 2356 // BufferForMerge(from DataOffset of NextVariable) has included the merged existing and new data.\r
0c18794e 2357 //\r
fddbbc66
SZ
2358 Data = BufferForMerge;\r
2359 DataSize = MergedBufSize;\r
2360 DataReady = TRUE;\r
0c18794e 2361 }\r
2362\r
2363 //\r
2364 // Mark the old variable as in delete transition.\r
2365 //\r
2366 State = Variable->CurrPtr->State;\r
2367 State &= VAR_IN_DELETED_TRANSITION;\r
2368\r
2369 Status = UpdateVariableStore (\r
2370 &mVariableModuleGlobal->VariableGlobal,\r
2371 Variable->Volatile,\r
2372 FALSE,\r
2373 Fvb,\r
2374 (UINTN) &Variable->CurrPtr->State,\r
2375 sizeof (UINT8),\r
2376 &State\r
2d3fb919 2377 );\r
0c18794e 2378 if (EFI_ERROR (Status)) {\r
2d3fb919 2379 goto Done;\r
2380 }\r
0c18794e 2381 if (!Variable->Volatile) {\r
2382 CacheVariable->CurrPtr->State = State;\r
2383 }\r
2d3fb919 2384 }\r
0c18794e 2385 } else {\r
2386 //\r
2387 // Not found existing variable. Create a new variable.\r
0c18794e 2388 //\r
2d3fb919 2389\r
2390 if ((DataSize == 0) && ((Attributes & EFI_VARIABLE_APPEND_WRITE) != 0)) {\r
2391 Status = EFI_SUCCESS;\r
0c18794e 2392 goto Done;\r
2393 }\r
2d3fb919 2394\r
0c18794e 2395 //\r
2396 // Make sure we are trying to create a new variable.\r
2d3fb919 2397 // Setting a data variable with zero DataSize or no access attributes means to delete it.\r
0c18794e 2398 //\r
2399 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {\r
2400 Status = EFI_NOT_FOUND;\r
2401 goto Done;\r
2402 }\r
2d3fb919 2403\r
0c18794e 2404 //\r
2405 // Only variable have NV|RT attribute can be created in Runtime.\r
2406 //\r
2407 if (AtRuntime () &&\r
2408 (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {\r
2409 Status = EFI_INVALID_PARAMETER;\r
2410 goto Done;\r
2d3fb919 2411 }\r
0c18794e 2412 }\r
2413\r
2414 //\r
2415 // Function part - create a new variable and copy the data.\r
2416 // Both update a variable and create a variable will come here.\r
fddbbc66 2417 //\r
0c18794e 2418 NextVariable->StartId = VARIABLE_DATA;\r
2419 //\r
2420 // NextVariable->State = VAR_ADDED;\r
2421 //\r
2422 NextVariable->Reserved = 0;\r
2423 NextVariable->PubKeyIndex = KeyIndex;\r
2424 NextVariable->MonotonicCount = MonotonicCount;\r
2d3fb919 2425 ZeroMem (&NextVariable->TimeStamp, sizeof (EFI_TIME));\r
0c18794e 2426\r
3b4151bc 2427 if (((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) &&\r
2d3fb919 2428 (TimeStamp != NULL)) {\r
3b4151bc 2429 if ((Attributes & EFI_VARIABLE_APPEND_WRITE) == 0) {\r
2430 CopyMem (&NextVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));\r
2431 } else {\r
0c18794e 2432 //\r
2433 // In the case when the EFI_VARIABLE_APPEND_WRITE attribute is set, only\r
2434 // when the new TimeStamp value is later than the current timestamp associated\r
2435 // with the variable, we need associate the new timestamp with the updated value.\r
2436 //\r
2d3fb919 2437 if (Variable->CurrPtr != NULL) {\r
2438 if (CompareTimeStamp (&Variable->CurrPtr->TimeStamp, TimeStamp)) {\r
2439 CopyMem (&NextVariable->TimeStamp, TimeStamp, sizeof (EFI_TIME));\r
2440 }\r
0c18794e 2441 }\r
3b4151bc 2442 }\r
0c18794e 2443 }\r
2444\r
2445 //\r
2d3fb919 2446 // The EFI_VARIABLE_APPEND_WRITE attribute will never be set in the returned\r
0c18794e 2447 // Attributes bitmask parameter of a GetVariable() call.\r
2448 //\r
2449 NextVariable->Attributes = Attributes & (~EFI_VARIABLE_APPEND_WRITE);\r
2d3fb919 2450\r
0c18794e 2451 VarNameOffset = sizeof (VARIABLE_HEADER);\r
2452 VarNameSize = StrSize (VariableName);\r
2453 CopyMem (\r
2454 (UINT8 *) ((UINTN) NextVariable + VarNameOffset),\r
2455 VariableName,\r
2456 VarNameSize\r
2457 );\r
2458 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);\r
fddbbc66
SZ
2459\r
2460 //\r
2461 // If DataReady is TRUE, it means the variable data has been saved into\r
2462 // NextVariable during EFI_VARIABLE_APPEND_WRITE operation preparation.\r
2463 //\r
2464 if (!DataReady) {\r
2465 CopyMem (\r
2466 (UINT8 *) ((UINTN) NextVariable + VarDataOffset),\r
2467 Data,\r
2468 DataSize\r
2469 );\r
2470 }\r
2471\r
0c18794e 2472 CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));\r
2473 //\r
2474 // There will be pad bytes after Data, the NextVariable->NameSize and\r
2475 // NextVariable->DataSize should not include pad size so that variable\r
2476 // service can get actual size in GetVariable.\r
2477 //\r
2478 NextVariable->NameSize = (UINT32)VarNameSize;\r
2479 NextVariable->DataSize = (UINT32)DataSize;\r
2480\r
2481 //\r
2482 // The actual size of the variable that stores in storage should\r
2483 // include pad size.\r
2484 //\r
2485 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);\r
2486 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
2487 //\r
2488 // Create a nonvolatile variable.\r
2489 //\r
2490 Volatile = FALSE;\r
952ba83c
SZ
2491\r
2492 IsCommonVariable = FALSE;\r
2493 IsCommonUserVariable = FALSE;\r
2494 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) {\r
2495 IsCommonVariable = TRUE;\r
2496 IsCommonUserVariable = IsUserVariable (NextVariable);\r
2497 }\r
2d3fb919 2498 if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)\r
0c18794e 2499 && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))\r
952ba83c
SZ
2500 || (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonVariableSpace))\r
2501 || (IsCommonVariable && AtRuntime () && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonRuntimeVariableSpace))\r
2502 || (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace))) {\r
0c18794e 2503 if (AtRuntime ()) {\r
952ba83c
SZ
2504 if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {\r
2505 RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName, VendorGuid, Attributes, VarSize);\r
2506 }\r
2507 if (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonRuntimeVariableSpace)) {\r
2508 RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName, VendorGuid, Attributes, VarSize);\r
2509 }\r
0c18794e 2510 Status = EFI_OUT_OF_RESOURCES;\r
2511 goto Done;\r
2512 }\r
2513 //\r
7baf3c69 2514 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.\r
0c18794e 2515 //\r
83758cdc 2516 Status = Reclaim (\r
2517 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
2518 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
2519 FALSE,\r
23b06935 2520 Variable,\r
7baf3c69
SZ
2521 NextVariable,\r
2522 HEADER_ALIGN (VarSize),\r
83758cdc 2523 FALSE\r
2524 );\r
7baf3c69
SZ
2525 if (!EFI_ERROR (Status)) {\r
2526 //\r
2527 // The new variable has been integrated successfully during reclaiming.\r
2528 //\r
2529 if (Variable->CurrPtr != NULL) {\r
2530 CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN) CacheVariable->StartPtr + ((UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr));\r
2531 CacheVariable->InDeletedTransitionPtr = NULL;\r
2532 }\r
2533 UpdateVariableInfo (VariableName, VendorGuid, FALSE, FALSE, TRUE, FALSE, FALSE);\r
2534 FlushHobVariableToFlash (VariableName, VendorGuid);\r
952ba83c
SZ
2535 } else {\r
2536 if (IsCommonUserVariable && ((VarSize + mVariableModuleGlobal->CommonUserVariableTotalSize) > mVariableModuleGlobal->CommonMaxUserVariableSpace)) {\r
2537 RecordVarErrorFlag (VAR_ERROR_FLAG_USER_ERROR, VariableName, VendorGuid, Attributes, VarSize);\r
17409b7a 2538 }\r
952ba83c
SZ
2539 if (IsCommonVariable && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > mVariableModuleGlobal->CommonVariableSpace)) {\r
2540 RecordVarErrorFlag (VAR_ERROR_FLAG_SYSTEM_ERROR, VariableName, VendorGuid, Attributes, VarSize);\r
2541 }\r
2542 }\r
7baf3c69 2543 goto Done;\r
0c18794e 2544 }\r
2545 //\r
2546 // Four steps\r
2547 // 1. Write variable header\r
2d3fb919 2548 // 2. Set variable state to header valid\r
0c18794e 2549 // 3. Write variable data\r
2550 // 4. Set variable state to valid\r
2551 //\r
2552 //\r
2553 // Step 1:\r
2554 //\r
2555 CacheOffset = mVariableModuleGlobal->NonVolatileLastVariableOffset;\r
2556 Status = UpdateVariableStore (\r
2557 &mVariableModuleGlobal->VariableGlobal,\r
2558 FALSE,\r
2559 TRUE,\r
2560 Fvb,\r
2561 mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
2562 sizeof (VARIABLE_HEADER),\r
2563 (UINT8 *) NextVariable\r
2564 );\r
2565\r
2566 if (EFI_ERROR (Status)) {\r
2567 goto Done;\r
2568 }\r
2569\r
2570 //\r
2571 // Step 2:\r
2572 //\r
2573 NextVariable->State = VAR_HEADER_VALID_ONLY;\r
2574 Status = UpdateVariableStore (\r
2575 &mVariableModuleGlobal->VariableGlobal,\r
2576 FALSE,\r
2577 TRUE,\r
2578 Fvb,\r
2579 mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
2580 sizeof (UINT8),\r
2581 &NextVariable->State\r
2582 );\r
2583\r
2584 if (EFI_ERROR (Status)) {\r
2585 goto Done;\r
2586 }\r
2587 //\r
2588 // Step 3:\r
2589 //\r
2590 Status = UpdateVariableStore (\r
2591 &mVariableModuleGlobal->VariableGlobal,\r
2592 FALSE,\r
2593 TRUE,\r
2594 Fvb,\r
2595 mVariableModuleGlobal->NonVolatileLastVariableOffset + sizeof (VARIABLE_HEADER),\r
2596 (UINT32) VarSize - sizeof (VARIABLE_HEADER),\r
2597 (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)\r
2598 );\r
2599\r
2600 if (EFI_ERROR (Status)) {\r
2601 goto Done;\r
2602 }\r
2603 //\r
2604 // Step 4:\r
2605 //\r
2606 NextVariable->State = VAR_ADDED;\r
2607 Status = UpdateVariableStore (\r
2608 &mVariableModuleGlobal->VariableGlobal,\r
2609 FALSE,\r
2610 TRUE,\r
2611 Fvb,\r
2612 mVariableModuleGlobal->NonVolatileLastVariableOffset + OFFSET_OF (VARIABLE_HEADER, State),\r
2613 sizeof (UINT8),\r
2614 &NextVariable->State\r
2615 );\r
2616\r
2617 if (EFI_ERROR (Status)) {\r
2618 goto Done;\r
2619 }\r
2620\r
2621 mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
2622\r
2623 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {\r
2624 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);\r
2625 } else {\r
2626 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);\r
952ba83c
SZ
2627 if (IsCommonUserVariable) {\r
2628 mVariableModuleGlobal->CommonUserVariableTotalSize += HEADER_ALIGN (VarSize);\r
17409b7a 2629 }\r
952ba83c 2630 }\r
0c18794e 2631 //\r
2632 // update the memory copy of Flash region.\r
2633 //\r
2634 CopyMem ((UINT8 *)mNvVariableCache + CacheOffset, (UINT8 *)NextVariable, VarSize);\r
2635 } else {\r
2636 //\r
2637 // Create a volatile variable.\r
2d3fb919 2638 //\r
0c18794e 2639 Volatile = TRUE;\r
2640\r
2641 if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >\r
2642 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) {\r
2643 //\r
7baf3c69 2644 // Perform garbage collection & reclaim operation, and integrate the new variable at the same time.\r
0c18794e 2645 //\r
83758cdc 2646 Status = Reclaim (\r
2647 mVariableModuleGlobal->VariableGlobal.VolatileVariableBase,\r
2648 &mVariableModuleGlobal->VolatileLastVariableOffset,\r
2649 TRUE,\r
23b06935 2650 Variable,\r
7baf3c69
SZ
2651 NextVariable,\r
2652 HEADER_ALIGN (VarSize),\r
83758cdc 2653 FALSE\r
2654 );\r
7baf3c69
SZ
2655 if (!EFI_ERROR (Status)) {\r
2656 //\r
2657 // The new variable has been integrated successfully during reclaiming.\r
2658 //\r
2659 if (Variable->CurrPtr != NULL) {\r
2660 CacheVariable->CurrPtr = (VARIABLE_HEADER *)((UINTN) CacheVariable->StartPtr + ((UINTN) Variable->CurrPtr - (UINTN) Variable->StartPtr));\r
2661 CacheVariable->InDeletedTransitionPtr = NULL;\r
2662 }\r
2663 UpdateVariableInfo (VariableName, VendorGuid, TRUE, FALSE, TRUE, FALSE, FALSE);\r
23b06935 2664 }\r
7baf3c69 2665 goto Done;\r
0c18794e 2666 }\r
2667\r
2668 NextVariable->State = VAR_ADDED;\r
2669 Status = UpdateVariableStore (\r
2670 &mVariableModuleGlobal->VariableGlobal,\r
2671 TRUE,\r
2672 TRUE,\r
2673 Fvb,\r
2674 mVariableModuleGlobal->VolatileLastVariableOffset,\r
2675 (UINT32) VarSize,\r
2676 (UINT8 *) NextVariable\r
2677 );\r
2678\r
2679 if (EFI_ERROR (Status)) {\r
2680 goto Done;\r
2681 }\r
2682\r
2683 mVariableModuleGlobal->VolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
2684 }\r
2685\r
2686 //\r
2687 // Mark the old variable as deleted.\r
2688 //\r
23b06935
SZ
2689 if (!EFI_ERROR (Status) && Variable->CurrPtr != NULL) {\r
2690 if (Variable->InDeletedTransitionPtr != NULL) {\r
2691 //\r
2692 // Both ADDED and IN_DELETED_TRANSITION old variable are present,\r
2693 // set IN_DELETED_TRANSITION one to DELETED state first.\r
2694 //\r
2695 State = Variable->InDeletedTransitionPtr->State;\r
2696 State &= VAR_DELETED;\r
2697 Status = UpdateVariableStore (\r
2698 &mVariableModuleGlobal->VariableGlobal,\r
2699 Variable->Volatile,\r
2700 FALSE,\r
2701 Fvb,\r
2702 (UINTN) &Variable->InDeletedTransitionPtr->State,\r
2703 sizeof (UINT8),\r
2704 &State\r
2705 );\r
2706 if (!EFI_ERROR (Status)) {\r
2707 if (!Variable->Volatile) {\r
0cc565de 2708 ASSERT (CacheVariable->InDeletedTransitionPtr != NULL);\r
23b06935
SZ
2709 CacheVariable->InDeletedTransitionPtr->State = State;\r
2710 }\r
2711 } else {\r
2712 goto Done;\r
2713 }\r
2714 }\r
2715\r
0c18794e 2716 State = Variable->CurrPtr->State;\r
2717 State &= VAR_DELETED;\r
2718\r
2719 Status = UpdateVariableStore (\r
2720 &mVariableModuleGlobal->VariableGlobal,\r
2721 Variable->Volatile,\r
2722 FALSE,\r
2723 Fvb,\r
2724 (UINTN) &Variable->CurrPtr->State,\r
2725 sizeof (UINT8),\r
2726 &State\r
2727 );\r
2d3fb919 2728 if (!EFI_ERROR (Status) && !Variable->Volatile) {\r
0c18794e 2729 CacheVariable->CurrPtr->State = State;\r
2730 }\r
2731 }\r
2732\r
2733 if (!EFI_ERROR (Status)) {\r
2734 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
335e2681
SZ
2735 if (!Volatile) {\r
2736 FlushHobVariableToFlash (VariableName, VendorGuid);\r
2737 }\r
0c18794e 2738 }\r
2739\r
2740Done:\r
2741 return Status;\r
2742}\r
2743\r
a5f15e30
SZ
2744/**\r
2745 Check if a Unicode character is a hexadecimal character.\r
2746\r
20333c6d
QL
2747 This function checks if a Unicode character is a\r
2748 hexadecimal character. The valid hexadecimal character is\r
a5f15e30
SZ
2749 L'0' to L'9', L'a' to L'f', or L'A' to L'F'.\r
2750\r
2751\r
2752 @param Char The character to check against.\r
2753\r
2754 @retval TRUE If the Char is a hexadecmial character.\r
2755 @retval FALSE If the Char is not a hexadecmial character.\r
2756\r
2757**/\r
2758BOOLEAN\r
2759EFIAPI\r
2760IsHexaDecimalDigitCharacter (\r
2761 IN CHAR16 Char\r
2762 )\r
2763{\r
2764 return (BOOLEAN) ((Char >= L'0' && Char <= L'9') || (Char >= L'A' && Char <= L'F') || (Char >= L'a' && Char <= L'f'));\r
2765}\r
2766\r
2767/**\r
2768\r
2769 This code checks if variable is hardware error record variable or not.\r
2770\r
2771 According to UEFI spec, hardware error record variable should use the EFI_HARDWARE_ERROR_VARIABLE VendorGuid\r
2772 and have the L"HwErrRec####" name convention, #### is a printed hex value and no 0x or h is included in the hex value.\r
2773\r
2774 @param VariableName Pointer to variable name.\r
2775 @param VendorGuid Variable Vendor Guid.\r
2776\r
2777 @retval TRUE Variable is hardware error record variable.\r
2778 @retval FALSE Variable is not hardware error record variable.\r
2779\r
2780**/\r
2781BOOLEAN\r
2782EFIAPI\r
2783IsHwErrRecVariable (\r
2784 IN CHAR16 *VariableName,\r
2785 IN EFI_GUID *VendorGuid\r
2786 )\r
2787{\r
2788 if (!CompareGuid (VendorGuid, &gEfiHardwareErrorVariableGuid) ||\r
2789 (StrLen (VariableName) != StrLen (L"HwErrRec####")) ||\r
2790 (StrnCmp(VariableName, L"HwErrRec", StrLen (L"HwErrRec")) != 0) ||\r
2791 !IsHexaDecimalDigitCharacter (VariableName[0x8]) ||\r
2792 !IsHexaDecimalDigitCharacter (VariableName[0x9]) ||\r
2793 !IsHexaDecimalDigitCharacter (VariableName[0xA]) ||\r
2794 !IsHexaDecimalDigitCharacter (VariableName[0xB])) {\r
2795 return FALSE;\r
2796 }\r
2797\r
2798 return TRUE;\r
2799}\r
2800\r
6ab9f441
RN
2801/**\r
2802 Mark a variable that will become read-only after leaving the DXE phase of execution.\r
2803\r
2804 @param[in] This The VARIABLE_LOCK_PROTOCOL instance.\r
2805 @param[in] VariableName A pointer to the variable name that will be made read-only subsequently.\r
2806 @param[in] VendorGuid A pointer to the vendor GUID that will be made read-only subsequently.\r
2807\r
2808 @retval EFI_SUCCESS The variable specified by the VariableName and the VendorGuid was marked\r
2809 as pending to be read-only.\r
2810 @retval EFI_INVALID_PARAMETER VariableName or VendorGuid is NULL.\r
2811 Or VariableName is an empty string.\r
2812 @retval EFI_ACCESS_DENIED EFI_END_OF_DXE_EVENT_GROUP_GUID or EFI_EVENT_GROUP_READY_TO_BOOT has\r
2813 already been signaled.\r
2814 @retval EFI_OUT_OF_RESOURCES There is not enough resource to hold the lock request.\r
2815**/\r
2816EFI_STATUS\r
2817EFIAPI\r
2818VariableLockRequestToLock (\r
2819 IN CONST EDKII_VARIABLE_LOCK_PROTOCOL *This,\r
2820 IN CHAR16 *VariableName,\r
2821 IN EFI_GUID *VendorGuid\r
2822 )\r
2823{\r
2824 VARIABLE_ENTRY *Entry;\r
17409b7a 2825 CHAR16 *Name;\r
6ab9f441
RN
2826\r
2827 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
2828 return EFI_INVALID_PARAMETER;\r
2829 }\r
2830\r
2831 if (mEndOfDxe) {\r
2832 return EFI_ACCESS_DENIED;\r
2833 }\r
2834\r
17409b7a 2835 Entry = AllocateRuntimeZeroPool (sizeof (*Entry) + StrSize (VariableName));\r
6ab9f441
RN
2836 if (Entry == NULL) {\r
2837 return EFI_OUT_OF_RESOURCES;\r
2838 }\r
2839\r
2840 DEBUG ((EFI_D_INFO, "[Variable] Lock: %g:%s\n", VendorGuid, VariableName));\r
2841\r
2842 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2843\r
17409b7a
SZ
2844 Name = (CHAR16 *) ((UINTN) Entry + sizeof (*Entry));\r
2845 StrnCpy (Name, VariableName, StrLen (VariableName));\r
6ab9f441
RN
2846 CopyGuid (&Entry->Guid, VendorGuid);\r
2847 InsertTailList (&mLockedVariableList, &Entry->Link);\r
2848\r
2849 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2850\r
2851 return EFI_SUCCESS;\r
2852}\r
2853\r
0c18794e 2854/**\r
2855\r
2856 This code finds variable in storage blocks (Volatile or Non-Volatile).\r
2857\r
dc204d5a
JY
2858 Caution: This function may receive untrusted input.\r
2859 This function may be invoked in SMM mode, and datasize is external input.\r
2860 This function will do basic validation, before parse the data.\r
2861\r
0c18794e 2862 @param VariableName Name of Variable to be found.\r
2863 @param VendorGuid Variable vendor GUID.\r
2864 @param Attributes Attribute value of the variable found.\r
2865 @param DataSize Size of Data found. If size is less than the\r
2866 data, this value contains the required size.\r
2867 @param Data Data pointer.\r
2d3fb919 2868\r
0c18794e 2869 @return EFI_INVALID_PARAMETER Invalid parameter.\r
2870 @return EFI_SUCCESS Find the specified variable.\r
2871 @return EFI_NOT_FOUND Not found.\r
2872 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
2873\r
2874**/\r
2875EFI_STATUS\r
2876EFIAPI\r
2877VariableServiceGetVariable (\r
2878 IN CHAR16 *VariableName,\r
2879 IN EFI_GUID *VendorGuid,\r
2880 OUT UINT32 *Attributes OPTIONAL,\r
2881 IN OUT UINTN *DataSize,\r
2882 OUT VOID *Data\r
2883 )\r
2884{\r
2885 EFI_STATUS Status;\r
2886 VARIABLE_POINTER_TRACK Variable;\r
2887 UINTN VarDataSize;\r
2888\r
2889 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
2890 return EFI_INVALID_PARAMETER;\r
2891 }\r
2892\r
2893 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2d3fb919 2894\r
ecc722ad 2895 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
0c18794e 2896 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
2897 goto Done;\r
2898 }\r
2899\r
2900 //\r
2901 // Get data size\r
2902 //\r
2903 VarDataSize = DataSizeOfVariable (Variable.CurrPtr);\r
2904 ASSERT (VarDataSize != 0);\r
2905\r
2906 if (*DataSize >= VarDataSize) {\r
2907 if (Data == NULL) {\r
2908 Status = EFI_INVALID_PARAMETER;\r
2909 goto Done;\r
2910 }\r
2911\r
2912 CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);\r
2913 if (Attributes != NULL) {\r
2914 *Attributes = Variable.CurrPtr->Attributes;\r
2915 }\r
2916\r
2917 *DataSize = VarDataSize;\r
2918 UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);\r
2d3fb919 2919\r
0c18794e 2920 Status = EFI_SUCCESS;\r
2921 goto Done;\r
2922 } else {\r
2923 *DataSize = VarDataSize;\r
2924 Status = EFI_BUFFER_TOO_SMALL;\r
2925 goto Done;\r
2926 }\r
2927\r
2928Done:\r
2929 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2930 return Status;\r
2931}\r
2932\r
2933\r
2934\r
2935/**\r
2936\r
2937 This code Finds the Next available variable.\r
2938\r
dc204d5a
JY
2939 Caution: This function may receive untrusted input.\r
2940 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.\r
2941\r
0c18794e 2942 @param VariableNameSize Size of the variable name.\r
2943 @param VariableName Pointer to variable name.\r
2944 @param VendorGuid Variable Vendor Guid.\r
2945\r
2946 @return EFI_INVALID_PARAMETER Invalid parameter.\r
2947 @return EFI_SUCCESS Find the specified variable.\r
2948 @return EFI_NOT_FOUND Not found.\r
2949 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result.\r
2950\r
2951**/\r
2952EFI_STATUS\r
2953EFIAPI\r
2954VariableServiceGetNextVariableName (\r
2955 IN OUT UINTN *VariableNameSize,\r
2956 IN OUT CHAR16 *VariableName,\r
2957 IN OUT EFI_GUID *VendorGuid\r
2958 )\r
2959{\r
9a000b46 2960 VARIABLE_STORE_TYPE Type;\r
0c18794e 2961 VARIABLE_POINTER_TRACK Variable;\r
9a000b46 2962 VARIABLE_POINTER_TRACK VariableInHob;\r
23b06935 2963 VARIABLE_POINTER_TRACK VariablePtrTrack;\r
0c18794e 2964 UINTN VarNameSize;\r
2965 EFI_STATUS Status;\r
9a000b46 2966 VARIABLE_STORE_HEADER *VariableStoreHeader[VariableStoreTypeMax];\r
0c18794e 2967\r
2968 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
2969 return EFI_INVALID_PARAMETER;\r
2970 }\r
2971\r
2972 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2973\r
ecc722ad 2974 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, FALSE);\r
0c18794e 2975 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
2976 goto Done;\r
2977 }\r
2978\r
2979 if (VariableName[0] != 0) {\r
2980 //\r
2981 // If variable name is not NULL, get next variable.\r
2982 //\r
2983 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
2984 }\r
2985\r
9a000b46
RN
2986 //\r
2987 // 0: Volatile, 1: HOB, 2: Non-Volatile.\r
2988 // The index and attributes mapping must be kept in this order as FindVariable\r
2989 // makes use of this mapping to implement search algorithm.\r
2990 //\r
2991 VariableStoreHeader[VariableStoreTypeVolatile] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
2992 VariableStoreHeader[VariableStoreTypeHob] = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;\r
2993 VariableStoreHeader[VariableStoreTypeNv] = mNvVariableCache;\r
2994\r
0c18794e 2995 while (TRUE) {\r
2996 //\r
9a000b46 2997 // Switch from Volatile to HOB, to Non-Volatile.\r
0c18794e 2998 //\r
6ebffb67 2999 while (!IsValidVariableHeader (Variable.CurrPtr, Variable.EndPtr)) {\r
9a000b46
RN
3000 //\r
3001 // Find current storage index\r
3002 //\r
3003 for (Type = (VARIABLE_STORE_TYPE) 0; Type < VariableStoreTypeMax; Type++) {\r
3004 if ((VariableStoreHeader[Type] != NULL) && (Variable.StartPtr == GetStartPointer (VariableStoreHeader[Type]))) {\r
3005 break;\r
3006 }\r
3007 }\r
3008 ASSERT (Type < VariableStoreTypeMax);\r
3009 //\r
3010 // Switch to next storage\r
3011 //\r
3012 for (Type++; Type < VariableStoreTypeMax; Type++) {\r
3013 if (VariableStoreHeader[Type] != NULL) {\r
3014 break;\r
3015 }\r
3016 }\r
3017 //\r
2d3fb919 3018 // Capture the case that\r
9a000b46
RN
3019 // 1. current storage is the last one, or\r
3020 // 2. no further storage\r
3021 //\r
3022 if (Type == VariableStoreTypeMax) {\r
0c18794e 3023 Status = EFI_NOT_FOUND;\r
3024 goto Done;\r
3025 }\r
9a000b46
RN
3026 Variable.StartPtr = GetStartPointer (VariableStoreHeader[Type]);\r
3027 Variable.EndPtr = GetEndPointer (VariableStoreHeader[Type]);\r
3028 Variable.CurrPtr = Variable.StartPtr;\r
0c18794e 3029 }\r
9a000b46 3030\r
0c18794e 3031 //\r
3032 // Variable is found\r
3033 //\r
23b06935
SZ
3034 if (Variable.CurrPtr->State == VAR_ADDED || Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
3035 if (!AtRuntime () || ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {\r
3036 if (Variable.CurrPtr->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
3037 //\r
3038 // If it is a IN_DELETED_TRANSITION variable,\r
3039 // and there is also a same ADDED one at the same time,\r
3040 // don't return it.\r
3041 //\r
3042 VariablePtrTrack.StartPtr = Variable.StartPtr;\r
3043 VariablePtrTrack.EndPtr = Variable.EndPtr;\r
3044 Status = FindVariableEx (\r
3045 GetVariableNamePtr (Variable.CurrPtr),\r
3046 &Variable.CurrPtr->VendorGuid,\r
3047 FALSE,\r
3048 &VariablePtrTrack\r
3049 );\r
3050 if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr->State == VAR_ADDED) {\r
3051 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
3052 continue;\r
3053 }\r
3054 }\r
9a000b46
RN
3055\r
3056 //\r
3057 // Don't return NV variable when HOB overrides it\r
3058 //\r
2d3fb919 3059 if ((VariableStoreHeader[VariableStoreTypeHob] != NULL) && (VariableStoreHeader[VariableStoreTypeNv] != NULL) &&\r
9a000b46
RN
3060 (Variable.StartPtr == GetStartPointer (VariableStoreHeader[VariableStoreTypeNv]))\r
3061 ) {\r
3062 VariableInHob.StartPtr = GetStartPointer (VariableStoreHeader[VariableStoreTypeHob]);\r
3063 VariableInHob.EndPtr = GetEndPointer (VariableStoreHeader[VariableStoreTypeHob]);\r
3064 Status = FindVariableEx (\r
3065 GetVariableNamePtr (Variable.CurrPtr),\r
3066 &Variable.CurrPtr->VendorGuid,\r
ecc722ad 3067 FALSE,\r
9a000b46
RN
3068 &VariableInHob\r
3069 );\r
3070 if (!EFI_ERROR (Status)) {\r
3071 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
3072 continue;\r
3073 }\r
3074 }\r
3075\r
0c18794e 3076 VarNameSize = NameSizeOfVariable (Variable.CurrPtr);\r
3077 ASSERT (VarNameSize != 0);\r
3078\r
3079 if (VarNameSize <= *VariableNameSize) {\r
9a000b46
RN
3080 CopyMem (VariableName, GetVariableNamePtr (Variable.CurrPtr), VarNameSize);\r
3081 CopyMem (VendorGuid, &Variable.CurrPtr->VendorGuid, sizeof (EFI_GUID));\r
0c18794e 3082 Status = EFI_SUCCESS;\r
3083 } else {\r
3084 Status = EFI_BUFFER_TOO_SMALL;\r
3085 }\r
3086\r
3087 *VariableNameSize = VarNameSize;\r
3088 goto Done;\r
3089 }\r
3090 }\r
3091\r
3092 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
3093 }\r
3094\r
3095Done:\r
3096 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
3097 return Status;\r
3098}\r
3099\r
3100/**\r
3101\r
3102 This code sets variable in storage blocks (Volatile or Non-Volatile).\r
3103\r
dc204d5a
JY
3104 Caution: This function may receive untrusted input.\r
3105 This function may be invoked in SMM mode, and datasize and data are external input.\r
3106 This function will do basic validation, before parse the data.\r
3107 This function will parse the authentication carefully to avoid security issues, like\r
3108 buffer overflow, integer overflow.\r
3109 This function will check attribute carefully to avoid authentication bypass.\r
3110\r
0c18794e 3111 @param VariableName Name of Variable to be found.\r
3112 @param VendorGuid Variable vendor GUID.\r
3113 @param Attributes Attribute value of the variable found\r
3114 @param DataSize Size of Data found. If size is less than the\r
3115 data, this value contains the required size.\r
3116 @param Data Data pointer.\r
3117\r
3118 @return EFI_INVALID_PARAMETER Invalid parameter.\r
3119 @return EFI_SUCCESS Set successfully.\r
3120 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable.\r
3121 @return EFI_NOT_FOUND Not found.\r
3122 @return EFI_WRITE_PROTECTED Variable is read-only.\r
3123\r
3124**/\r
3125EFI_STATUS\r
3126EFIAPI\r
3127VariableServiceSetVariable (\r
3128 IN CHAR16 *VariableName,\r
3129 IN EFI_GUID *VendorGuid,\r
3130 IN UINT32 Attributes,\r
3131 IN UINTN DataSize,\r
3132 IN VOID *Data\r
3133 )\r
3134{\r
3135 VARIABLE_POINTER_TRACK Variable;\r
3136 EFI_STATUS Status;\r
3137 VARIABLE_HEADER *NextVariable;\r
3138 EFI_PHYSICAL_ADDRESS Point;\r
3139 UINTN PayloadSize;\r
6ab9f441
RN
3140 LIST_ENTRY *Link;\r
3141 VARIABLE_ENTRY *Entry;\r
17409b7a 3142 CHAR16 *Name;\r
0c18794e 3143\r
3144 //\r
3145 // Check input parameters.\r
3146 //\r
3147 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
3148 return EFI_INVALID_PARAMETER;\r
2d3fb919 3149 }\r
0c18794e 3150\r
3151 if (DataSize != 0 && Data == NULL) {\r
3152 return EFI_INVALID_PARAMETER;\r
3153 }\r
3154\r
275beb2b 3155 //\r
3156 // Check for reserverd bit in variable attribute.\r
3157 //\r
3158 if ((Attributes & (~EFI_VARIABLE_ATTRIBUTES_MASK)) != 0) {\r
3159 return EFI_INVALID_PARAMETER;\r
3160 }\r
3161\r
0c18794e 3162 //\r
3163 // Make sure if runtime bit is set, boot service bit is set also.\r
3164 //\r
3165 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
3166 return EFI_INVALID_PARAMETER;\r
3167 }\r
3168\r
3169 //\r
2d3fb919 3170 // EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS and EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute\r
0c18794e 3171 // cannot be set both.\r
3172 //\r
2d3fb919 3173 if (((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS)\r
0c18794e 3174 && ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS)) {\r
3175 return EFI_INVALID_PARAMETER;\r
2d3fb919 3176 }\r
0c18794e 3177\r
3178 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) {\r
3179 if (DataSize < AUTHINFO_SIZE) {\r
3180 //\r
2d3fb919 3181 // Try to write Authenticated Variable without AuthInfo.\r
0c18794e 3182 //\r
3183 return EFI_SECURITY_VIOLATION;\r
2d3fb919 3184 }\r
3185 PayloadSize = DataSize - AUTHINFO_SIZE;\r
3186 } else if ((Attributes & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) {\r
3187 //\r
3188 // Sanity check for EFI_VARIABLE_AUTHENTICATION_2 descriptor.\r
3189 //\r
3190 if (DataSize < OFFSET_OF_AUTHINFO2_CERT_DATA ||\r
6bc4e19f 3191 ((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->AuthInfo.Hdr.dwLength > DataSize - (OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo)) ||\r
3192 ((EFI_VARIABLE_AUTHENTICATION_2 *) Data)->AuthInfo.Hdr.dwLength < OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)) {\r
2d3fb919 3193 return EFI_SECURITY_VIOLATION;\r
3194 }\r
3195 PayloadSize = DataSize - AUTHINFO2_SIZE (Data);\r
0c18794e 3196 } else {\r
2d3fb919 3197 PayloadSize = DataSize;\r
0c18794e 3198 }\r
2d3fb919 3199\r
56251c66 3200 if ((UINTN)(~0) - PayloadSize < StrSize(VariableName)){\r
3201 //\r
20333c6d
QL
3202 // Prevent whole variable size overflow\r
3203 //\r
56251c66 3204 return EFI_INVALID_PARAMETER;\r
3205 }\r
3206\r
0c18794e 3207 //\r
3208 // The size of the VariableName, including the Unicode Null in bytes plus\r
3209 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)\r
3210 // bytes for HwErrRec, and PcdGet32 (PcdMaxVariableSize) bytes for the others.\r
3211 //\r
3212 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
56251c66 3213 if (StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER)) {\r
0c18794e 3214 return EFI_INVALID_PARAMETER;\r
3215 }\r
a5f15e30 3216 if (!IsHwErrRecVariable(VariableName, VendorGuid)) {\r
0c18794e 3217 return EFI_INVALID_PARAMETER;\r
3218 }\r
3219 } else {\r
3220 //\r
3221 // The size of the VariableName, including the Unicode Null in bytes plus\r
3222 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxVariableSize) bytes.\r
3223 //\r
56251c66 3224 if (StrSize (VariableName) + PayloadSize > PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER)) {\r
0c18794e 3225 return EFI_INVALID_PARAMETER;\r
2d3fb919 3226 }\r
3227 }\r
0c18794e 3228\r
3229 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
3230\r
3231 //\r
3232 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated.\r
3233 //\r
3234 if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {\r
3235 Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
3236 //\r
3237 // Parse non-volatile variable data and get last variable offset.\r
3238 //\r
3239 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point);\r
6ebffb67 3240 while (IsValidVariableHeader (NextVariable, GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point))) {\r
0c18794e 3241 NextVariable = GetNextVariablePtr (NextVariable);\r
3242 }\r
3243 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;\r
3244 }\r
3245\r
6ab9f441
RN
3246 if (mEndOfDxe && mEnableLocking) {\r
3247 //\r
3248 // Treat the variables listed in the forbidden variable list as read-only after leaving DXE phase.\r
3249 //\r
3250 for ( Link = GetFirstNode (&mLockedVariableList)\r
3251 ; !IsNull (&mLockedVariableList, Link)\r
3252 ; Link = GetNextNode (&mLockedVariableList, Link)\r
3253 ) {\r
3254 Entry = BASE_CR (Link, VARIABLE_ENTRY, Link);\r
17409b7a
SZ
3255 Name = (CHAR16 *) ((UINTN) Entry + sizeof (*Entry));\r
3256 if (CompareGuid (&Entry->Guid, VendorGuid) && (StrCmp (Name, VariableName) == 0)) {\r
6ab9f441
RN
3257 Status = EFI_WRITE_PROTECTED;\r
3258 DEBUG ((EFI_D_INFO, "[Variable]: Changing readonly variable after leaving DXE phase - %g:%s\n", VendorGuid, VariableName));\r
3259 goto Done;\r
3260 }\r
3261 }\r
3262 }\r
3263\r
17409b7a
SZ
3264 Status = InternalVarCheckSetVariableCheck (VariableName, VendorGuid, Attributes, PayloadSize, (VOID *) ((UINTN) Data + DataSize - PayloadSize));\r
3265 if (EFI_ERROR (Status)) {\r
3266 goto Done;\r
3267 }\r
3268\r
0c18794e 3269 //\r
3270 // Check whether the input variable is already existed.\r
3271 //\r
ecc722ad 3272 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal, TRUE);\r
3273 if (!EFI_ERROR (Status)) {\r
3274 if (((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) && AtRuntime ()) {\r
6ab9f441
RN
3275 Status = EFI_WRITE_PROTECTED;\r
3276 goto Done;\r
ecc722ad 3277 }\r
6e67fec0
SZ
3278 if (Attributes != 0 && (Attributes & (~EFI_VARIABLE_APPEND_WRITE)) != Variable.CurrPtr->Attributes) {\r
3279 //\r
3280 // If a preexisting variable is rewritten with different attributes, SetVariable() shall not\r
3281 // modify the variable and shall return EFI_INVALID_PARAMETER. Two exceptions to this rule:\r
3282 // 1. No access attributes specified\r
3283 // 2. The only attribute differing is EFI_VARIABLE_APPEND_WRITE\r
3284 //\r
3285 Status = EFI_INVALID_PARAMETER;\r
952ba83c 3286 DEBUG ((EFI_D_INFO, "[Variable]: Rewritten a preexisting variable(0x%08x) with different attributes(0x%08x) - %g:%s\n", Variable.CurrPtr->Attributes, Attributes, VendorGuid, VariableName));\r
6e67fec0
SZ
3287 goto Done;\r
3288 }\r
ecc722ad 3289 }\r
b2bd493e
SZ
3290\r
3291 if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate)) {\r
9bc5dabb 3292 //\r
b2bd493e 3293 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang.\r
9bc5dabb 3294 //\r
b2bd493e
SZ
3295 Status = AutoUpdateLangVariable (VariableName, Data, DataSize);\r
3296 if (EFI_ERROR (Status)) {\r
3297 //\r
3298 // The auto update operation failed, directly return to avoid inconsistency between PlatformLang and Lang.\r
3299 //\r
3300 goto Done;\r
3301 }\r
9bc5dabb
SZ
3302 }\r
3303\r
0c18794e 3304 //\r
3305 // Process PK, KEK, Sigdb seperately.\r
3306 //\r
3307 if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_PLATFORM_KEY_NAME) == 0)){\r
3308 Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, TRUE);\r
3309 } else if (CompareGuid (VendorGuid, &gEfiGlobalVariableGuid) && (StrCmp (VariableName, EFI_KEY_EXCHANGE_KEY_NAME) == 0)) {\r
3310 Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, FALSE);\r
20333c6d 3311 } else if (CompareGuid (VendorGuid, &gEfiImageSecurityDatabaseGuid) &&\r
d547f31c
LE
3312 ((StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) ||\r
3313 (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE1) == 0) ||\r
3314 (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE2) == 0)\r
3315 )\r
3316 ) {\r
05a643f9 3317 Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes, FALSE);\r
3318 if (EFI_ERROR (Status)) {\r
3319 Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);\r
3320 }\r
0c18794e 3321 } else {\r
3322 Status = ProcessVariable (VariableName, VendorGuid, Data, DataSize, &Variable, Attributes);\r
3323 }\r
3324\r
6ab9f441 3325Done:\r
0c18794e 3326 InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);\r
3327 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
3328\r
c1d93242
JY
3329 if (!AtRuntime ()) {\r
3330 if (!EFI_ERROR (Status)) {\r
3331 SecureBootHook (\r
3332 VariableName,\r
3333 VendorGuid\r
3334 );\r
3335 }\r
3336 }\r
3337\r
0c18794e 3338 return Status;\r
3339}\r
3340\r
3341/**\r
3342\r
3343 This code returns information about the EFI variables.\r
3344\r
dc204d5a
JY
3345 Caution: This function may receive untrusted input.\r
3346 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.\r
3347\r
0c18794e 3348 @param Attributes Attributes bitmask to specify the type of variables\r
3349 on which to return information.\r
3350 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
3351 for the EFI variables associated with the attributes specified.\r
3352 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
3353 for EFI variables associated with the attributes specified.\r
3354 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables\r
3355 associated with the attributes specified.\r
3356\r
0c18794e 3357 @return EFI_SUCCESS Query successfully.\r
0c18794e 3358\r
3359**/\r
3360EFI_STATUS\r
3361EFIAPI\r
b2bd493e 3362VariableServiceQueryVariableInfoInternal (\r
0c18794e 3363 IN UINT32 Attributes,\r
3364 OUT UINT64 *MaximumVariableStorageSize,\r
3365 OUT UINT64 *RemainingVariableStorageSize,\r
3366 OUT UINT64 *MaximumVariableSize\r
3367 )\r
3368{\r
3369 VARIABLE_HEADER *Variable;\r
3370 VARIABLE_HEADER *NextVariable;\r
3371 UINT64 VariableSize;\r
3372 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
3373 UINT64 CommonVariableTotalSize;\r
3374 UINT64 HwErrVariableTotalSize;\r
b2bd493e
SZ
3375 EFI_STATUS Status;\r
3376 VARIABLE_POINTER_TRACK VariablePtrTrack;\r
0c18794e 3377\r
3378 CommonVariableTotalSize = 0;\r
3379 HwErrVariableTotalSize = 0;\r
3380\r
0c18794e 3381 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
3382 //\r
3383 // Query is Volatile related.\r
3384 //\r
3385 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
3386 } else {\r
3387 //\r
3388 // Query is Non-Volatile related.\r
3389 //\r
3390 VariableStoreHeader = mNvVariableCache;\r
3391 }\r
3392\r
3393 //\r
3394 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize\r
3395 // with the storage size (excluding the storage header size).\r
3396 //\r
3397 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
3398\r
3399 //\r
3400 // Harware error record variable needs larger size.\r
3401 //\r
3402 if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
3403 *MaximumVariableStorageSize = PcdGet32 (PcdHwErrStorageSize);\r
3404 *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);\r
3405 } else {\r
3406 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
952ba83c
SZ
3407 if (AtRuntime ()) {\r
3408 *MaximumVariableStorageSize = mVariableModuleGlobal->CommonRuntimeVariableSpace;\r
3409 } else {\r
3410 *MaximumVariableStorageSize = mVariableModuleGlobal->CommonVariableSpace;\r
3411 }\r
0c18794e 3412 }\r
3413\r
3414 //\r
3415 // Let *MaximumVariableSize be PcdGet32 (PcdMaxVariableSize) with the exception of the variable header size.\r
3416 //\r
3417 *MaximumVariableSize = PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);\r
3418 }\r
3419\r
3420 //\r
3421 // Point to the starting address of the variables.\r
3422 //\r
3423 Variable = GetStartPointer (VariableStoreHeader);\r
3424\r
3425 //\r
3426 // Now walk through the related variable store.\r
3427 //\r
6ebffb67 3428 while (IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))) {\r
0c18794e 3429 NextVariable = GetNextVariablePtr (Variable);\r
3430 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;\r
3431\r
3432 if (AtRuntime ()) {\r
3433 //\r
3434 // We don't take the state of the variables in mind\r
3435 // when calculating RemainingVariableStorageSize,\r
3436 // since the space occupied by variables not marked with\r
3437 // VAR_ADDED is not allowed to be reclaimed in Runtime.\r
3438 //\r
3439 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
3440 HwErrVariableTotalSize += VariableSize;\r
3441 } else {\r
3442 CommonVariableTotalSize += VariableSize;\r
3443 }\r
3444 } else {\r
3445 //\r
3446 // Only care about Variables with State VAR_ADDED, because\r
3447 // the space not marked as VAR_ADDED is reclaimable now.\r
3448 //\r
3449 if (Variable->State == VAR_ADDED) {\r
3450 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
3451 HwErrVariableTotalSize += VariableSize;\r
3452 } else {\r
3453 CommonVariableTotalSize += VariableSize;\r
3454 }\r
b2bd493e
SZ
3455 } else if (Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
3456 //\r
3457 // If it is a IN_DELETED_TRANSITION variable,\r
3458 // and there is not also a same ADDED one at the same time,\r
3459 // this IN_DELETED_TRANSITION variable is valid.\r
3460 //\r
3461 VariablePtrTrack.StartPtr = GetStartPointer (VariableStoreHeader);\r
3462 VariablePtrTrack.EndPtr = GetEndPointer (VariableStoreHeader);\r
3463 Status = FindVariableEx (\r
3464 GetVariableNamePtr (Variable),\r
3465 &Variable->VendorGuid,\r
3466 FALSE,\r
3467 &VariablePtrTrack\r
3468 );\r
3469 if (!EFI_ERROR (Status) && VariablePtrTrack.CurrPtr->State != VAR_ADDED) {\r
3470 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
3471 HwErrVariableTotalSize += VariableSize;\r
3472 } else {\r
3473 CommonVariableTotalSize += VariableSize;\r
3474 }\r
3475 }\r
0c18794e 3476 }\r
3477 }\r
3478\r
3479 //\r
3480 // Go to the next one.\r
3481 //\r
3482 Variable = NextVariable;\r
3483 }\r
3484\r
3485 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){\r
3486 *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;\r
952ba83c
SZ
3487 } else {\r
3488 if (*MaximumVariableStorageSize < CommonVariableTotalSize) {\r
3489 *RemainingVariableStorageSize = 0;\r
3490 } else {\r
3491 *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;\r
3492 }\r
0c18794e 3493 }\r
3494\r
3495 if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {\r
3496 *MaximumVariableSize = 0;\r
3497 } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {\r
3498 *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);\r
3499 }\r
3500\r
0c18794e 3501 return EFI_SUCCESS;\r
3502}\r
3503\r
b2bd493e
SZ
3504/**\r
3505\r
3506 This code returns information about the EFI variables.\r
3507\r
3508 Caution: This function may receive untrusted input.\r
3509 This function may be invoked in SMM mode. This function will do basic validation, before parse the data.\r
3510\r
3511 @param Attributes Attributes bitmask to specify the type of variables\r
3512 on which to return information.\r
3513 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
3514 for the EFI variables associated with the attributes specified.\r
3515 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
3516 for EFI variables associated with the attributes specified.\r
3517 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables\r
3518 associated with the attributes specified.\r
3519\r
3520 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.\r
3521 @return EFI_SUCCESS Query successfully.\r
3522 @return EFI_UNSUPPORTED The attribute is not supported on this platform.\r
3523\r
3524**/\r
3525EFI_STATUS\r
3526EFIAPI\r
3527VariableServiceQueryVariableInfo (\r
3528 IN UINT32 Attributes,\r
3529 OUT UINT64 *MaximumVariableStorageSize,\r
3530 OUT UINT64 *RemainingVariableStorageSize,\r
3531 OUT UINT64 *MaximumVariableSize\r
3532 )\r
3533{\r
3534 EFI_STATUS Status;\r
3535\r
3536 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
3537 return EFI_INVALID_PARAMETER;\r
3538 }\r
3539\r
952ba83c 3540 if ((Attributes & VARIABLE_ATTRIBUTE_NV_BS_RT_AT_HR_AW) == 0) {\r
b2bd493e
SZ
3541 //\r
3542 // Make sure the Attributes combination is supported by the platform.\r
3543 //\r
3544 return EFI_UNSUPPORTED;\r
3545 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
3546 //\r
3547 // Make sure if runtime bit is set, boot service bit is set also.\r
3548 //\r
3549 return EFI_INVALID_PARAMETER;\r
3550 } else if (AtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {\r
3551 //\r
3552 // Make sure RT Attribute is set if we are in Runtime phase.\r
3553 //\r
3554 return EFI_INVALID_PARAMETER;\r
3555 } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
3556 //\r
3557 // Make sure Hw Attribute is set with NV.\r
3558 //\r
3559 return EFI_INVALID_PARAMETER;\r
3560 }\r
3561\r
3562 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
3563\r
3564 Status = VariableServiceQueryVariableInfoInternal (\r
3565 Attributes,\r
3566 MaximumVariableStorageSize,\r
3567 RemainingVariableStorageSize,\r
3568 MaximumVariableSize\r
3569 );\r
3570\r
3571 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
3572 return Status;\r
3573}\r
0c18794e 3574\r
3575/**\r
3576 This function reclaims variable storage if free size is below the threshold.\r
2d3fb919 3577\r
876ac395 3578 Caution: This function may be invoked at SMM mode.\r
3579 Care must be taken to make sure not security issue.\r
dc204d5a 3580\r
0c18794e 3581**/\r
3582VOID\r
3583ReclaimForOS(\r
3584 VOID\r
3585 )\r
3586{\r
3587 EFI_STATUS Status;\r
952ba83c 3588 UINTN RemainingCommonRuntimeVariableSpace;\r
0c18794e 3589 UINTN RemainingHwErrVariableSpace;\r
3590\r
2d3fb919 3591 Status = EFI_SUCCESS;\r
0c18794e 3592\r
952ba83c
SZ
3593 if (mVariableModuleGlobal->CommonRuntimeVariableSpace < mVariableModuleGlobal->CommonVariableTotalSize) {\r
3594 RemainingCommonRuntimeVariableSpace = 0;\r
3595 } else {\r
3596 RemainingCommonRuntimeVariableSpace = mVariableModuleGlobal->CommonRuntimeVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;\r
3597 }\r
0c18794e 3598\r
3599 RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;\r
3600 //\r
952ba83c 3601 // Check if the free area is below a threshold.\r
0c18794e 3602 //\r
952ba83c 3603 if ((RemainingCommonRuntimeVariableSpace < PcdGet32 (PcdMaxVariableSize))\r
2d3fb919 3604 || ((PcdGet32 (PcdHwErrStorageSize) != 0) &&\r
0c18794e 3605 (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize)))){\r
3606 Status = Reclaim (\r
3607 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
3608 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
3609 FALSE,\r
335e2681 3610 NULL,\r
7baf3c69
SZ
3611 NULL,\r
3612 0,\r
335e2681 3613 FALSE\r
0c18794e 3614 );\r
3615 ASSERT_EFI_ERROR (Status);\r
3616 }\r
3617}\r
3618\r
039a40aa
SZ
3619/**\r
3620 Init non-volatile variable store.\r
3621\r
3622 @retval EFI_SUCCESS Function successfully executed.\r
3623 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r
3624 @retval EFI_VOLUME_CORRUPTED Variable Store or Firmware Volume for Variable Store is corrupted.\r
3625\r
3626**/\r
3627EFI_STATUS\r
3628InitNonVolatileVariableStore (\r
3629 VOID\r
3630 )\r
3631{\r
3632 EFI_FIRMWARE_VOLUME_HEADER *FvHeader;\r
952ba83c 3633 VARIABLE_HEADER *Variable;\r
039a40aa
SZ
3634 VARIABLE_HEADER *NextVariable;\r
3635 EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
3636 UINT64 VariableStoreLength;\r
3637 UINTN VariableSize;\r
3638 EFI_HOB_GUID_TYPE *GuidHob;\r
3639 EFI_PHYSICAL_ADDRESS NvStorageBase;\r
3640 UINT8 *NvStorageData;\r
3641 UINT32 NvStorageSize;\r
3642 FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *FtwLastWriteData;\r
3643 UINT32 BackUpOffset;\r
3644 UINT32 BackUpSize;\r
952ba83c
SZ
3645 UINT32 HwErrStorageSize;\r
3646 UINT32 MaxUserNvVariableSpaceSize;\r
3647 UINT32 BoottimeReservedNvVariableSpaceSize;\r
039a40aa
SZ
3648\r
3649 mVariableModuleGlobal->FvbInstance = NULL;\r
3650\r
039a40aa
SZ
3651 //\r
3652 // Allocate runtime memory used for a memory copy of the FLASH region.\r
3653 // Keep the memory and the FLASH in sync as updates occur.\r
3654 //\r
3655 NvStorageSize = PcdGet32 (PcdFlashNvStorageVariableSize);\r
3656 NvStorageData = AllocateRuntimeZeroPool (NvStorageSize);\r
3657 if (NvStorageData == NULL) {\r
3658 return EFI_OUT_OF_RESOURCES;\r
3659 }\r
3660\r
3661 NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
3662 if (NvStorageBase == 0) {\r
3663 NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
3664 }\r
3665 //\r
3666 // Copy NV storage data to the memory buffer.\r
3667 //\r
3668 CopyMem (NvStorageData, (UINT8 *) (UINTN) NvStorageBase, NvStorageSize);\r
3669\r
3670 //\r
3671 // Check the FTW last write data hob.\r
3672 //\r
3673 GuidHob = GetFirstGuidHob (&gEdkiiFaultTolerantWriteGuid);\r
3674 if (GuidHob != NULL) {\r
3675 FtwLastWriteData = (FAULT_TOLERANT_WRITE_LAST_WRITE_DATA *) GET_GUID_HOB_DATA (GuidHob);\r
3676 if (FtwLastWriteData->TargetAddress == NvStorageBase) {\r
3677 DEBUG ((EFI_D_INFO, "Variable: NV storage is backed up in spare block: 0x%x\n", (UINTN) FtwLastWriteData->SpareAddress));\r
3678 //\r
3679 // Copy the backed up NV storage data to the memory buffer from spare block.\r
3680 //\r
3681 CopyMem (NvStorageData, (UINT8 *) (UINTN) (FtwLastWriteData->SpareAddress), NvStorageSize);\r
3682 } else if ((FtwLastWriteData->TargetAddress > NvStorageBase) &&\r
3683 (FtwLastWriteData->TargetAddress < (NvStorageBase + NvStorageSize))) {\r
3684 //\r
3685 // Flash NV storage from the Offset is backed up in spare block.\r
3686 //\r
3687 BackUpOffset = (UINT32) (FtwLastWriteData->TargetAddress - NvStorageBase);\r
3688 BackUpSize = NvStorageSize - BackUpOffset;\r
3689 DEBUG ((EFI_D_INFO, "Variable: High partial NV storage from offset: %x is backed up in spare block: 0x%x\n", BackUpOffset, (UINTN) FtwLastWriteData->SpareAddress));\r
3690 //\r
3691 // Copy the partial backed up NV storage data to the memory buffer from spare block.\r
3692 //\r
3693 CopyMem (NvStorageData + BackUpOffset, (UINT8 *) (UINTN) FtwLastWriteData->SpareAddress, BackUpSize);\r
3694 }\r
3695 }\r
3696\r
3697 FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) NvStorageData;\r
3698\r
3699 //\r
3700 // Check if the Firmware Volume is not corrupted\r
3701 //\r
3702 if ((FvHeader->Signature != EFI_FVH_SIGNATURE) || (!CompareGuid (&gEfiSystemNvDataFvGuid, &FvHeader->FileSystemGuid))) {\r
3703 FreePool (NvStorageData);\r
3704 DEBUG ((EFI_D_ERROR, "Firmware Volume for Variable Store is corrupted\n"));\r
3705 return EFI_VOLUME_CORRUPTED;\r
3706 }\r
3707\r
3708 VariableStoreBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) FvHeader + FvHeader->HeaderLength);\r
3709 VariableStoreLength = (UINT64) (NvStorageSize - FvHeader->HeaderLength);\r
3710\r
3711 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
3712 mNvVariableCache = (VARIABLE_STORE_HEADER *) (UINTN) VariableStoreBase;\r
3713 if (GetVariableStoreStatus (mNvVariableCache) != EfiValid) {\r
3714 FreePool (NvStorageData);\r
3715 DEBUG((EFI_D_ERROR, "Variable Store header is corrupted\n"));\r
3716 return EFI_VOLUME_CORRUPTED;\r
3717 }\r
3718 ASSERT(mNvVariableCache->Size == VariableStoreLength);\r
3719\r
952ba83c
SZ
3720\r
3721 ASSERT (sizeof (VARIABLE_STORE_HEADER) <= VariableStoreLength);\r
3722\r
3723 HwErrStorageSize = PcdGet32 (PcdHwErrStorageSize);\r
3724 MaxUserNvVariableSpaceSize = PcdGet32 (PcdMaxUserNvVariableSpaceSize);\r
3725 BoottimeReservedNvVariableSpaceSize = PcdGet32 (PcdBoottimeReservedNvVariableSpaceSize);\r
3726\r
3727 //\r
3728 // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r
3729 // is stored with common variable in the same NV region. So the platform integrator should\r
3730 // ensure that the value of PcdHwErrStorageSize is less than the value of\r
3731 // VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)).\r
3732 //\r
3733 ASSERT (HwErrStorageSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)));\r
3734 //\r
3735 // Ensure that the value of PcdMaxUserNvVariableSpaceSize is less than the value of\r
3736 // VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).\r
3737 //\r
3738 ASSERT (MaxUserNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));\r
3739 //\r
3740 // Ensure that the value of PcdBoottimeReservedNvVariableSpaceSize is less than the value of\r
3741 // VariableStoreLength - sizeof (VARIABLE_STORE_HEADER)) - PcdGet32 (PcdHwErrStorageSize).\r
3742 //\r
3743 ASSERT (BoottimeReservedNvVariableSpaceSize < (VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize));\r
3744\r
3745 mVariableModuleGlobal->CommonVariableSpace = ((UINTN) VariableStoreLength - sizeof (VARIABLE_STORE_HEADER) - HwErrStorageSize);\r
3746 mVariableModuleGlobal->CommonMaxUserVariableSpace = ((MaxUserNvVariableSpaceSize != 0) ? MaxUserNvVariableSpaceSize : mVariableModuleGlobal->CommonVariableSpace);\r
3747 mVariableModuleGlobal->CommonRuntimeVariableSpace = mVariableModuleGlobal->CommonVariableSpace - BoottimeReservedNvVariableSpaceSize;\r
3748\r
3749 DEBUG ((EFI_D_INFO, "Variable driver common space: 0x%x 0x%x 0x%x\n", mVariableModuleGlobal->CommonVariableSpace, mVariableModuleGlobal->CommonMaxUserVariableSpace, mVariableModuleGlobal->CommonRuntimeVariableSpace));\r
3750\r
039a40aa
SZ
3751 //\r
3752 // The max variable or hardware error variable size should be < variable store size.\r
3753 //\r
3754 ASSERT(MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize)) < VariableStoreLength);\r
3755\r
3756 //\r
3757 // Parse non-volatile variable data and get last variable offset.\r
3758 //\r
952ba83c
SZ
3759 Variable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);\r
3760 while (IsValidVariableHeader (Variable, GetEndPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase))) {\r
3761 NextVariable = GetNextVariablePtr (Variable);\r
3762 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
3763 if ((Variable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
3764 mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
039a40aa 3765 } else {\r
952ba83c 3766 mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
039a40aa
SZ
3767 }\r
3768\r
952ba83c 3769 Variable = NextVariable;\r
039a40aa 3770 }\r
952ba83c 3771 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) Variable - (UINTN) VariableStoreBase;\r
039a40aa
SZ
3772\r
3773 return EFI_SUCCESS;\r
3774}\r
3775\r
335e2681
SZ
3776/**\r
3777 Flush the HOB variable to flash.\r
3778\r
3779 @param[in] VariableName Name of variable has been updated or deleted.\r
3780 @param[in] VendorGuid Guid of variable has been updated or deleted.\r
3781\r
3782**/\r
3783VOID\r
3784FlushHobVariableToFlash (\r
3785 IN CHAR16 *VariableName,\r
3786 IN EFI_GUID *VendorGuid\r
3787 )\r
3788{\r
3789 EFI_STATUS Status;\r
3790 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
3791 VARIABLE_HEADER *Variable;\r
3792 VOID *VariableData;\r
3793 BOOLEAN ErrorFlag;\r
3794\r
3795 ErrorFlag = FALSE;\r
3796\r
3797 //\r
3798 // Flush the HOB variable to flash.\r
3799 //\r
3800 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {\r
3801 VariableStoreHeader = (VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase;\r
3802 //\r
3803 // Set HobVariableBase to 0, it can avoid SetVariable to call back.\r
3804 //\r
3805 mVariableModuleGlobal->VariableGlobal.HobVariableBase = 0;\r
3806 for ( Variable = GetStartPointer (VariableStoreHeader)\r
6ebffb67 3807 ; IsValidVariableHeader (Variable, GetEndPointer (VariableStoreHeader))\r
335e2681
SZ
3808 ; Variable = GetNextVariablePtr (Variable)\r
3809 ) {\r
3810 if (Variable->State != VAR_ADDED) {\r
3811 //\r
3812 // The HOB variable has been set to DELETED state in local.\r
3813 //\r
3814 continue;\r
3815 }\r
3816 ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0);\r
3817 if (VendorGuid == NULL || VariableName == NULL ||\r
3818 !CompareGuid (VendorGuid, &Variable->VendorGuid) ||\r
3819 StrCmp (VariableName, GetVariableNamePtr (Variable)) != 0) {\r
3820 VariableData = GetVariableDataPtr (Variable);\r
3821 Status = VariableServiceSetVariable (\r
3822 GetVariableNamePtr (Variable),\r
3823 &Variable->VendorGuid,\r
3824 Variable->Attributes,\r
3825 Variable->DataSize,\r
3826 VariableData\r
3827 );\r
3828 DEBUG ((EFI_D_INFO, "Variable driver flush the HOB variable to flash: %g %s %r\n", &Variable->VendorGuid, GetVariableNamePtr (Variable), Status));\r
3829 } else {\r
3830 //\r
3831 // The updated or deleted variable is matched with the HOB variable.\r
3832 // Don't break here because we will try to set other HOB variables\r
3833 // since this variable could be set successfully.\r
3834 //\r
3835 Status = EFI_SUCCESS;\r
3836 }\r
3837 if (!EFI_ERROR (Status)) {\r
3838 //\r
3839 // If set variable successful, or the updated or deleted variable is matched with the HOB variable,\r
3840 // set the HOB variable to DELETED state in local.\r
3841 //\r
3842 DEBUG ((EFI_D_INFO, "Variable driver set the HOB variable to DELETED state in local: %g %s\n", &Variable->VendorGuid, GetVariableNamePtr (Variable)));\r
3843 Variable->State &= VAR_DELETED;\r
3844 } else {\r
3845 ErrorFlag = TRUE;\r
3846 }\r
3847 }\r
3848 if (ErrorFlag) {\r
3849 //\r
3850 // We still have HOB variable(s) not flushed in flash.\r
3851 //\r
3852 mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStoreHeader;\r
3853 } else {\r
3854 //\r
3855 // All HOB variables have been flushed in flash.\r
3856 //\r
3857 DEBUG ((EFI_D_INFO, "Variable driver: all HOB variables have been flushed in flash.\n"));\r
3858 if (!AtRuntime ()) {\r
3859 FreePool ((VOID *) VariableStoreHeader);\r
3860 }\r
3861 }\r
3862 }\r
3863\r
3864}\r
0c18794e 3865\r
3866/**\r
039a40aa 3867 Initializes variable write service after FTW was ready.\r
0c18794e 3868\r
3869 @retval EFI_SUCCESS Function successfully executed.\r
3870 @retval Others Fail to initialize the variable service.\r
3871\r
3872**/\r
3873EFI_STATUS\r
3874VariableWriteServiceInitialize (\r
3875 VOID\r
3876 )\r
3877{\r
3878 EFI_STATUS Status;\r
3879 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
3880 UINTN Index;\r
3881 UINT8 Data;\r
3882 EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
039a40aa
SZ
3883 EFI_PHYSICAL_ADDRESS NvStorageBase;\r
3884\r
3885 NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
3886 if (NvStorageBase == 0) {\r
3887 NvStorageBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
3888 }\r
3889 VariableStoreBase = NvStorageBase + (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(NvStorageBase))->HeaderLength);\r
0c18794e 3890\r
039a40aa
SZ
3891 //\r
3892 // Let NonVolatileVariableBase point to flash variable store base directly after FTW ready.\r
3893 //\r
3894 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
0c18794e 3895 VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
2d3fb919 3896\r
0c18794e 3897 //\r
3898 // Check if the free area is really free.\r
3899 //\r
9a000b46 3900 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {\r
0c18794e 3901 Data = ((UINT8 *) mNvVariableCache)[Index];\r
3902 if (Data != 0xff) {\r
3903 //\r
3904 // There must be something wrong in variable store, do reclaim operation.\r
3905 //\r
3906 Status = Reclaim (\r
3907 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
3908 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
3909 FALSE,\r
335e2681 3910 NULL,\r
7baf3c69
SZ
3911 NULL,\r
3912 0,\r
3913 FALSE\r
0c18794e 3914 );\r
3915 if (EFI_ERROR (Status)) {\r
3916 return Status;\r
3917 }\r
3918 break;\r
3919 }\r
3920 }\r
3921\r
335e2681 3922 FlushHobVariableToFlash (NULL, NULL);\r
9a000b46 3923\r
0c18794e 3924 //\r
3925 // Authenticated variable initialize.\r
3926 //\r
3927 Status = AutenticatedVariableServiceInitialize ();\r
3928\r
3929 return Status;\r
3930}\r
3931\r
3932\r
3933/**\r
3934 Initializes variable store area for non-volatile and volatile variable.\r
3935\r
3936 @retval EFI_SUCCESS Function successfully executed.\r
3937 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r
3938\r
3939**/\r
3940EFI_STATUS\r
3941VariableCommonInitialize (\r
3942 VOID\r
3943 )\r
3944{\r
3945 EFI_STATUS Status;\r
3946 VARIABLE_STORE_HEADER *VolatileVariableStore;\r
3947 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
0c18794e 3948 UINT64 VariableStoreLength;\r
3949 UINTN ScratchSize;\r
9a000b46 3950 EFI_HOB_GUID_TYPE *GuidHob;\r
0c18794e 3951\r
3952 //\r
3953 // Allocate runtime memory for variable driver global structure.\r
3954 //\r
3955 mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL));\r
3956 if (mVariableModuleGlobal == NULL) {\r
3957 return EFI_OUT_OF_RESOURCES;\r
3958 }\r
3959\r
3960 InitializeLock (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);\r
3961\r
9a000b46
RN
3962 //\r
3963 // Get HOB variable store.\r
3964 //\r
3965 GuidHob = GetFirstGuidHob (&gEfiAuthenticatedVariableGuid);\r
3966 if (GuidHob != NULL) {\r
3967 VariableStoreHeader = GET_GUID_HOB_DATA (GuidHob);\r
335e2681 3968 VariableStoreLength = (UINT64) (GuidHob->Header.HobLength - sizeof (EFI_HOB_GUID_TYPE));\r
9a000b46 3969 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
335e2681
SZ
3970 mVariableModuleGlobal->VariableGlobal.HobVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) AllocateRuntimeCopyPool ((UINTN) VariableStoreLength, (VOID *) VariableStoreHeader);\r
3971 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase == 0) {\r
039a40aa 3972 FreePool (mVariableModuleGlobal);\r
335e2681
SZ
3973 return EFI_OUT_OF_RESOURCES;\r
3974 }\r
9a000b46
RN
3975 } else {\r
3976 DEBUG ((EFI_D_ERROR, "HOB Variable Store header is corrupted!\n"));\r
3977 }\r
3978 }\r
3979\r
0c18794e 3980 //\r
3981 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.\r
3982 //\r
3983 ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
3984 VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);\r
3985 if (VolatileVariableStore == NULL) {\r
039a40aa
SZ
3986 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {\r
3987 FreePool ((VOID *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase);\r
3988 }\r
0c18794e 3989 FreePool (mVariableModuleGlobal);\r
3990 return EFI_OUT_OF_RESOURCES;\r
3991 }\r
3992\r
3993 SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);\r
3994\r
3995 //\r
3996 // Initialize Variable Specific Data.\r
3997 //\r
3998 mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
3999 mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;\r
0c18794e 4000\r
4001 CopyGuid (&VolatileVariableStore->Signature, &gEfiAuthenticatedVariableGuid);\r
4002 VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize);\r
4003 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;\r
4004 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;\r
4005 VolatileVariableStore->Reserved = 0;\r
4006 VolatileVariableStore->Reserved1 = 0;\r
4007\r
4008 //\r
039a40aa 4009 // Init non-volatile variable store.\r
0c18794e 4010 //\r
039a40aa 4011 Status = InitNonVolatileVariableStore ();\r
0c18794e 4012 if (EFI_ERROR (Status)) {\r
039a40aa
SZ
4013 if (mVariableModuleGlobal->VariableGlobal.HobVariableBase != 0) {\r
4014 FreePool ((VOID *) (UINTN) mVariableModuleGlobal->VariableGlobal.HobVariableBase);\r
4015 }\r
0c18794e 4016 FreePool (mVariableModuleGlobal);\r
4017 FreePool (VolatileVariableStore);\r
4018 }\r
4019\r
4020 return Status;\r
4021}\r
4022\r
4023\r
4024/**\r
4025 Get the proper fvb handle and/or fvb protocol by the given Flash address.\r
4026\r
4027 @param[in] Address The Flash address.\r
4028 @param[out] FvbHandle In output, if it is not NULL, it points to the proper FVB handle.\r
4029 @param[out] FvbProtocol In output, if it is not NULL, it points to the proper FVB protocol.\r
4030\r
4031**/\r
4032EFI_STATUS\r
4033GetFvbInfoByAddress (\r
4034 IN EFI_PHYSICAL_ADDRESS Address,\r
4035 OUT EFI_HANDLE *FvbHandle OPTIONAL,\r
4036 OUT EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL **FvbProtocol OPTIONAL\r
4037 )\r
4038{\r
4039 EFI_STATUS Status;\r
4040 EFI_HANDLE *HandleBuffer;\r
4041 UINTN HandleCount;\r
4042 UINTN Index;\r
4043 EFI_PHYSICAL_ADDRESS FvbBaseAddress;\r
4044 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
0c18794e 4045 EFI_FVB_ATTRIBUTES_2 Attributes;\r
931aae94
DG
4046 UINTN BlockSize;\r
4047 UINTN NumberOfBlocks;\r
2d3fb919 4048\r
d4193108 4049 HandleBuffer = NULL;\r
0c18794e 4050 //\r
4051 // Get all FVB handles.\r
4052 //\r
4053 Status = GetFvbCountAndBuffer (&HandleCount, &HandleBuffer);\r
4054 if (EFI_ERROR (Status)) {\r
4055 return EFI_NOT_FOUND;\r
4056 }\r
4057\r
4058 //\r
4059 // Get the FVB to access variable store.\r
4060 //\r
4061 Fvb = NULL;\r
4062 for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {\r
4063 Status = GetFvbByHandle (HandleBuffer[Index], &Fvb);\r
4064 if (EFI_ERROR (Status)) {\r
4065 Status = EFI_NOT_FOUND;\r
4066 break;\r
4067 }\r
4068\r
4069 //\r
4070 // Ensure this FVB protocol supported Write operation.\r
4071 //\r
4072 Status = Fvb->GetAttributes (Fvb, &Attributes);\r
4073 if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {\r
2d3fb919 4074 continue;\r
0c18794e 4075 }\r
2d3fb919 4076\r
0c18794e 4077 //\r
4078 // Compare the address and select the right one.\r
4079 //\r
4080 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
4081 if (EFI_ERROR (Status)) {\r
4082 continue;\r
4083 }\r
4084\r
931aae94
DG
4085 //\r
4086 // Assume one FVB has one type of BlockSize.\r
4087 //\r
4088 Status = Fvb->GetBlockSize (Fvb, 0, &BlockSize, &NumberOfBlocks);\r
4089 if (EFI_ERROR (Status)) {\r
4090 continue;\r
4091 }\r
4092\r
4093 if ((Address >= FvbBaseAddress) && (Address < (FvbBaseAddress + BlockSize * NumberOfBlocks))) {\r
0c18794e 4094 if (FvbHandle != NULL) {\r
4095 *FvbHandle = HandleBuffer[Index];\r
4096 }\r
4097 if (FvbProtocol != NULL) {\r
4098 *FvbProtocol = Fvb;\r
4099 }\r
4100 Status = EFI_SUCCESS;\r
4101 break;\r
4102 }\r
4103 }\r
4104 FreePool (HandleBuffer);\r
4105\r
4106 if (Fvb == NULL) {\r
4107 Status = EFI_NOT_FOUND;\r
4108 }\r
2d3fb919 4109\r
4110 return Status;\r
0c18794e 4111}\r