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