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