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