Add pointer check for NULL before dereference it.
[mirror_edk2.git] / SecurityPkg / VariableAuthenticated / EsalVariableDxeSal / Variable.c
1 /** @file
2 The implementation of Extended SAL variable services.
3
4 Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
9
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
12
13 **/
14
15 #include "Variable.h"
16 #include "AuthService.h"
17
18 //
19 // Don't use module globals after the SetVirtualAddress map is signaled
20 //
21 ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal;
22 CHAR16 *mVariableName[NUM_VAR_NAME] = {
23 L"PlatformLangCodes",
24 L"LangCodes",
25 L"PlatformLang",
26 L"Lang",
27 L"HwErrRec",
28 AUTHVAR_KEYDB_NAME,
29 EFI_SETUP_MODE_NAME,
30 EFI_PLATFORM_KEY_NAME,
31 EFI_KEY_EXCHANGE_KEY_NAME
32 };
33
34 GLOBAL_REMOVE_IF_UNREFERENCED VARIABLE_INFO_ENTRY *gVariableInfo = NULL;
35
36 //
37 // The current Hii implementation accesses this variable a larg # of times on every boot.
38 // Other common variables are only accessed a single time. This is why this cache algorithm
39 // only targets a single variable. Probably to get an performance improvement out of
40 // a Cache you would need a cache that improves the search performance for a variable.
41 //
42 VARIABLE_CACHE_ENTRY mVariableCache[] = {
43 {
44 &gEfiGlobalVariableGuid,
45 L"Lang",
46 0x00000000,
47 0x00,
48 NULL
49 },
50 {
51 &gEfiGlobalVariableGuid,
52 L"PlatformLang",
53 0x00000000,
54 0x00,
55 NULL
56 }
57 };
58
59 /**
60 Acquires lock only at boot time. Simply returns at runtime.
61
62 This is a temperary function which will be removed when
63 EfiAcquireLock() in UefiLib can handle the call in UEFI
64 Runtimer driver in RT phase.
65 It calls EfiAcquireLock() at boot time, and simply returns
66 at runtime.
67
68 @param[in] Lock A pointer to the lock to acquire.
69
70 **/
71 VOID
72 AcquireLockOnlyAtBootTime (
73 IN EFI_LOCK *Lock
74 )
75 {
76 if (!EfiAtRuntime ()) {
77 EfiAcquireLock (Lock);
78 }
79 }
80
81 /**
82 Releases lock only at boot time. Simply returns at runtime.
83
84 This is a temperary function which will be removed when
85 EfiReleaseLock() in UefiLib can handle the call in UEFI
86 Runtimer driver in RT phase.
87 It calls EfiReleaseLock() at boot time, and simply returns
88 at runtime
89
90 @param[in] Lock A pointer to the lock to release.
91
92 **/
93 VOID
94 ReleaseLockOnlyAtBootTime (
95 IN EFI_LOCK *Lock
96 )
97 {
98 if (!EfiAtRuntime ()) {
99 EfiReleaseLock (Lock);
100 }
101 }
102
103 /**
104 Reads/Writes variable storage, volatile or non-volatile.
105
106 This function reads or writes volatile or non-volatile variable stroage.
107 For volatile storage, it performs memory copy.
108 For non-volatile storage, it accesses data on firmware storage. Data
109 area to access can span multiple firmware blocks.
110
111 @param[in] Write TRUE - Write variable store.
112 FALSE - Read variable store.
113 @param[in] Global Pointer to VARAIBLE_GLOBAL structure.
114 @param[in] Volatile TRUE - Variable is volatile.
115 FALSE - Variable is non-volatile.
116 @param[in] Instance Instance of FV Block services.
117 @param[in] StartAddress Start address of data to access.
118 @param[in] DataSize Size of data to access.
119 @param[in, out] Buffer For write, pointer to the buffer from which data is written.
120 For read, pointer to the buffer to hold the data read.
121
122 @retval EFI_SUCCESS Variable store successfully accessed.
123 @retval EFI_INVALID_PARAMETER Data area to access exceeds valid variable storage.
124
125 **/
126 EFI_STATUS
127 AccessVariableStore (
128 IN BOOLEAN Write,
129 IN VARIABLE_GLOBAL *Global,
130 IN BOOLEAN Volatile,
131 IN UINTN Instance,
132 IN EFI_PHYSICAL_ADDRESS StartAddress,
133 IN UINT32 DataSize,
134 IN OUT VOID *Buffer
135 )
136 {
137 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;
138 UINTN BlockIndex;
139 UINTN LinearOffset;
140 UINTN CurrWriteSize;
141 UINTN CurrWritePtr;
142 UINT8 *CurrBuffer;
143 EFI_LBA LbaNumber;
144 UINTN Size;
145 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
146 VARIABLE_STORE_HEADER *VolatileBase;
147 EFI_PHYSICAL_ADDRESS FvVolHdr;
148 EFI_STATUS Status;
149 VARIABLE_STORE_HEADER *VariableStoreHeader;
150
151 FvVolHdr = 0;
152 FwVolHeader = NULL;
153
154 if (Volatile) {
155 //
156 // If data is volatile, simply calculate the data pointer and copy memory.
157 // Data pointer should point to the actual address where data is to be
158 // accessed.
159 //
160 VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);
161
162 if ((StartAddress + DataSize) > ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) {
163 return EFI_INVALID_PARAMETER;
164 }
165
166 //
167 // For volatile variable, a simple memory copy is enough.
168 //
169 if (Write) {
170 CopyMem ((VOID *) StartAddress, Buffer, DataSize);
171 } else {
172 CopyMem (Buffer, (VOID *) StartAddress, DataSize);
173 }
174
175 return EFI_SUCCESS;
176 }
177
178 //
179 // If data is non-volatile, calculate firmware volume header and data pointer.
180 //
181 Status = (EFI_STATUS) EsalCall (
182 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,
183 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,
184 GetPhysicalAddressFunctionId,
185 Instance,
186 (UINT64) &FvVolHdr,
187 0,
188 0,
189 0,
190 0,
191 0
192 ).Status;
193 ASSERT_EFI_ERROR (Status);
194
195 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);
196 ASSERT (FwVolHeader != NULL);
197 VariableStoreHeader = (VARIABLE_STORE_HEADER *)(FwVolHeader + 1);
198
199 if ((StartAddress + DataSize) > ((EFI_PHYSICAL_ADDRESS) (UINTN) ((CHAR8 *)VariableStoreHeader + VariableStoreHeader->Size))) {
200 return EFI_INVALID_PARAMETER;
201 }
202
203 LinearOffset = (UINTN) FwVolHeader;
204 CurrWritePtr = StartAddress;
205 CurrWriteSize = DataSize;
206 CurrBuffer = Buffer;
207 LbaNumber = 0;
208
209 if (CurrWritePtr < LinearOffset) {
210 return EFI_INVALID_PARAMETER;
211 }
212
213 //
214 // Traverse data blocks of this firmware storage to find the one where CurrWritePtr locates
215 //
216 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
217 for (BlockIndex = 0; BlockIndex < PtrBlockMapEntry->NumBlocks; BlockIndex++) {
218 if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) {
219 //
220 // Check to see if the data area to access spans multiple blocks.
221 //
222 if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {
223 //
224 // If data area to access is contained in one block, just access and return.
225 //
226 if (Write) {
227 Status = (EFI_STATUS) EsalCall (
228 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,
229 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,
230 WriteFunctionId,
231 Instance,
232 LbaNumber,
233 (CurrWritePtr - LinearOffset),
234 (UINT64) &CurrWriteSize,
235 (UINT64) CurrBuffer,
236 0,
237 0
238 ).Status;
239 } else {
240 Status = (EFI_STATUS) EsalCall (
241 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,
242 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,
243 ReadFunctionId,
244 Instance,
245 LbaNumber,
246 (CurrWritePtr - LinearOffset),
247 (UINT64) &CurrWriteSize,
248 (UINT64) CurrBuffer,
249 0,
250 0
251 ).Status;
252 }
253 return Status;
254 } else {
255 //
256 // If data area to access spans multiple blocks, access this one and adjust for the next one.
257 //
258 Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);
259 if (Write) {
260 Status = (EFI_STATUS) EsalCall (
261 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,
262 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,
263 WriteFunctionId,
264 Instance,
265 LbaNumber,
266 (CurrWritePtr - LinearOffset),
267 (UINT64) &Size,
268 (UINT64) CurrBuffer,
269 0,
270 0
271 ).Status;
272 } else {
273 Status = (EFI_STATUS) EsalCall (
274 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,
275 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,
276 ReadFunctionId,
277 Instance,
278 LbaNumber,
279 (CurrWritePtr - LinearOffset),
280 (UINT64) &Size,
281 (UINT64) CurrBuffer,
282 0,
283 0
284 ).Status;
285 }
286 if (EFI_ERROR (Status)) {
287 return Status;
288 }
289 //
290 // Adjust for the remaining data.
291 //
292 CurrWritePtr = LinearOffset + PtrBlockMapEntry->Length;
293 CurrBuffer = CurrBuffer + Size;
294 CurrWriteSize = CurrWriteSize - Size;
295 }
296 }
297
298 LinearOffset += PtrBlockMapEntry->Length;
299 LbaNumber++;
300 }
301 }
302
303 return EFI_SUCCESS;
304 }
305
306 /**
307 Retrieves header of volatile or non-volatile variable stroage.
308
309 @param[in] VarStoreAddress Start address of variable storage.
310 @param[in] Volatile TRUE - Variable storage is volatile.
311 FALSE - Variable storage is non-volatile.
312 @param[in] Global Pointer to VARAIBLE_GLOBAL structure.
313 @param[in] Instance Instance of FV Block services.
314 @param[out] VarStoreHeader Pointer to VARIABLE_STORE_HEADER for output.
315
316 **/
317 VOID
318 GetVarStoreHeader (
319 IN EFI_PHYSICAL_ADDRESS VarStoreAddress,
320 IN BOOLEAN Volatile,
321 IN VARIABLE_GLOBAL *Global,
322 IN UINTN Instance,
323 OUT VARIABLE_STORE_HEADER *VarStoreHeader
324 )
325 {
326 EFI_STATUS Status;
327
328 Status = AccessVariableStore (
329 FALSE,
330 Global,
331 Volatile,
332 Instance,
333 VarStoreAddress,
334 sizeof (VARIABLE_STORE_HEADER),
335 VarStoreHeader
336 );
337 ASSERT_EFI_ERROR (Status);
338 }
339
340 /**
341 Checks variable header.
342
343 This function checks if variable header is valid or not.
344
345 @param[in] VariableAddress Start address of variable header.
346 @param[in] Volatile TRUE - Variable is volatile.
347 FALSE - Variable is non-volatile.
348 @param[in] Global Pointer to VARAIBLE_GLOBAL structure.
349 @param[in] Instance Instance of FV Block services.
350 @param[out] VariableHeader Pointer to VARIABLE_HEADER for output.
351
352 @retval TRUE Variable header is valid.
353 @retval FALSE Variable header is not valid.
354
355 **/
356 BOOLEAN
357 IsValidVariableHeader (
358 IN EFI_PHYSICAL_ADDRESS VariableAddress,
359 IN BOOLEAN Volatile,
360 IN VARIABLE_GLOBAL *Global,
361 IN UINTN Instance,
362 OUT VARIABLE_HEADER *VariableHeader OPTIONAL
363 )
364 {
365 EFI_STATUS Status;
366 VARIABLE_HEADER LocalVariableHeader;
367
368 Status = AccessVariableStore (
369 FALSE,
370 Global,
371 Volatile,
372 Instance,
373 VariableAddress,
374 sizeof (VARIABLE_HEADER),
375 &LocalVariableHeader
376 );
377
378 if (EFI_ERROR (Status) || LocalVariableHeader.StartId != VARIABLE_DATA) {
379 return FALSE;
380 }
381
382 if (VariableHeader != NULL) {
383 CopyMem (VariableHeader, &LocalVariableHeader, sizeof (VARIABLE_HEADER));
384 }
385
386 return TRUE;
387 }
388
389 /**
390 Gets status of variable store.
391
392 This function gets the current status of variable store.
393
394 @param[in] VarStoreHeader Pointer to header of variable store.
395
396 @retval EfiRaw Variable store status is raw.
397 @retval EfiValid Variable store status is valid.
398 @retval EfiInvalid Variable store status is invalid.
399
400 **/
401 VARIABLE_STORE_STATUS
402 GetVariableStoreStatus (
403 IN VARIABLE_STORE_HEADER *VarStoreHeader
404 )
405 {
406
407 if (CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) &&
408 VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&
409 VarStoreHeader->State == VARIABLE_STORE_HEALTHY
410 ) {
411
412 return EfiValid;
413 } else if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff &&
414 ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff &&
415 ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff &&
416 ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff &&
417 VarStoreHeader->Size == 0xffffffff &&
418 VarStoreHeader->Format == 0xff &&
419 VarStoreHeader->State == 0xff
420 ) {
421
422 return EfiRaw;
423 } else {
424 return EfiInvalid;
425 }
426 }
427
428 /**
429 Gets the size of variable name.
430
431 This function gets the size of variable name.
432 The variable is specified by its variable header.
433 If variable header contains raw data, just return 0.
434
435 @param[in] Variable Pointer to the variable header.
436
437 @return Size of variable name in bytes.
438
439 **/
440 UINTN
441 NameSizeOfVariable (
442 IN VARIABLE_HEADER *Variable
443 )
444 {
445 if (Variable->State == (UINT8) (-1) ||
446 Variable->DataSize == (UINT32) -1 ||
447 Variable->NameSize == (UINT32) -1 ||
448 Variable->Attributes == (UINT32) -1) {
449 return 0;
450 }
451 return (UINTN) Variable->NameSize;
452 }
453
454 /**
455 Gets the size of variable data area.
456
457 This function gets the size of variable data area.
458 The variable is specified by its variable header.
459 If variable header contains raw data, just return 0.
460
461 @param[in] Variable Pointer to the variable header.
462
463 @return Size of variable data area in bytes.
464
465 **/
466 UINTN
467 DataSizeOfVariable (
468 IN VARIABLE_HEADER *Variable
469 )
470 {
471 if (Variable->State == (UINT8) -1 ||
472 Variable->DataSize == (UINT32) -1 ||
473 Variable->NameSize == (UINT32) -1 ||
474 Variable->Attributes == (UINT32) -1) {
475 return 0;
476 }
477 return (UINTN) Variable->DataSize;
478 }
479
480 /**
481 Gets the pointer to variable name.
482
483 This function gets the pointer to variable name.
484 The variable is specified by its variable header.
485
486 @param[in] VariableAddress Start address of variable header.
487 @param[in] Volatile TRUE - Variable is volatile.
488 FALSE - Variable is non-volatile.
489 @param[in] Global Pointer to VARAIBLE_GLOBAL structure.
490 @param[in] Instance Instance of FV Block services.
491 @param[out] VariableName Buffer to hold variable name for output.
492
493 **/
494 VOID
495 GetVariableNamePtr (
496 IN EFI_PHYSICAL_ADDRESS VariableAddress,
497 IN BOOLEAN Volatile,
498 IN VARIABLE_GLOBAL *Global,
499 IN UINTN Instance,
500 OUT CHAR16 *VariableName
501 )
502 {
503 EFI_STATUS Status;
504 EFI_PHYSICAL_ADDRESS Address;
505 VARIABLE_HEADER VariableHeader;
506 BOOLEAN IsValid;
507
508 IsValid = IsValidVariableHeader (VariableAddress, Volatile, Global, Instance, &VariableHeader);
509 ASSERT (IsValid);
510
511 //
512 // Name area follows variable header.
513 //
514 Address = VariableAddress + sizeof (VARIABLE_HEADER);
515
516 Status = AccessVariableStore (
517 FALSE,
518 Global,
519 Volatile,
520 Instance,
521 Address,
522 VariableHeader.NameSize,
523 VariableName
524 );
525 ASSERT_EFI_ERROR (Status);
526 }
527
528 /**
529 Gets the pointer to variable data area.
530
531 This function gets the pointer to variable data area.
532 The variable is specified by its variable header.
533
534 @param[in] VariableAddress Start address of variable header.
535 @param[in] Volatile TRUE - Variable is volatile.
536 FALSE - Variable is non-volatile.
537 @param[in] Global Pointer to VARAIBLE_GLOBAL structure.
538 @param[in] Instance Instance of FV Block services.
539 @param[out] VariableData Buffer to hold variable data for output.
540
541 **/
542 VOID
543 GetVariableDataPtr (
544 IN EFI_PHYSICAL_ADDRESS VariableAddress,
545 IN BOOLEAN Volatile,
546 IN VARIABLE_GLOBAL *Global,
547 IN UINTN Instance,
548 OUT CHAR16 *VariableData
549 )
550 {
551 EFI_STATUS Status;
552 EFI_PHYSICAL_ADDRESS Address;
553 VARIABLE_HEADER VariableHeader;
554 BOOLEAN IsValid;
555
556 IsValid = IsValidVariableHeader (VariableAddress, Volatile, Global, Instance, &VariableHeader);
557 ASSERT (IsValid);
558
559 //
560 // Data area follows variable name.
561 // Be careful about pad size for alignment
562 //
563 Address = VariableAddress + sizeof (VARIABLE_HEADER);
564 Address += NameSizeOfVariable (&VariableHeader);
565 Address += GET_PAD_SIZE (NameSizeOfVariable (&VariableHeader));
566
567 Status = AccessVariableStore (
568 FALSE,
569 Global,
570 Volatile,
571 Instance,
572 Address,
573 VariableHeader.DataSize,
574 VariableData
575 );
576 ASSERT_EFI_ERROR (Status);
577 }
578
579
580 /**
581 Gets the pointer to the next variable header.
582
583 This function gets the pointer to the next variable header.
584 The variable is specified by its variable header.
585
586 @param[in] VariableAddress Start address of variable header.
587 @param[in] Volatile TRUE - Variable is volatile.
588 FALSE - Variable is non-volatile.
589 @param[in] Global Pointer to VARAIBLE_GLOBAL structure.
590 @param[in] Instance Instance of FV Block services.
591
592 @return Pointer to the next variable header.
593 NULL if variable header is invalid.
594
595 **/
596 EFI_PHYSICAL_ADDRESS
597 GetNextVariablePtr (
598 IN EFI_PHYSICAL_ADDRESS VariableAddress,
599 IN BOOLEAN Volatile,
600 IN VARIABLE_GLOBAL *Global,
601 IN UINTN Instance
602 )
603 {
604 EFI_PHYSICAL_ADDRESS Address;
605 VARIABLE_HEADER VariableHeader;
606
607 if (!IsValidVariableHeader (VariableAddress, Volatile, Global, Instance, &VariableHeader)) {
608 return 0x0;
609 }
610
611 //
612 // Header of next variable follows data area of this variable
613 //
614 Address = VariableAddress + sizeof (VARIABLE_HEADER);
615 Address += NameSizeOfVariable (&VariableHeader);
616 Address += GET_PAD_SIZE (NameSizeOfVariable (&VariableHeader));
617 Address += DataSizeOfVariable (&VariableHeader);
618 Address += GET_PAD_SIZE (DataSizeOfVariable (&VariableHeader));
619
620 //
621 // Be careful about pad size for alignment
622 //
623 return HEADER_ALIGN (Address);
624 }
625
626 /**
627 Gets the pointer to the first variable header in given variable store area.
628
629 This function gets the pointer to the first variable header in given variable
630 store area. The variable store area is given by its start address.
631
632 @param[in] VarStoreHeaderAddress Pointer to the header of variable store area.
633
634 @return Pointer to the first variable header.
635
636 **/
637 EFI_PHYSICAL_ADDRESS
638 GetStartPointer (
639 IN EFI_PHYSICAL_ADDRESS VarStoreHeaderAddress
640 )
641 {
642 return HEADER_ALIGN (VarStoreHeaderAddress + sizeof (VARIABLE_STORE_HEADER));
643 }
644
645 /**
646 Gets the pointer to the end of given variable store area.
647
648 This function gets the pointer to the end of given variable store area.
649 The variable store area is given by its start address.
650
651 @param[in] VarStoreHeaderAddress Pointer to the header of variable store area.
652 @param[in] Volatile TRUE - Variable is volatile.
653 FALSE - Variable is non-volatile.
654 @param[in] Global Pointer to VARAIBLE_GLOBAL structure.
655 @param[in] Instance Instance of FV Block services.
656
657 @return Pointer to the end of given variable store area.
658
659 **/
660 EFI_PHYSICAL_ADDRESS
661 GetEndPointer (
662 IN EFI_PHYSICAL_ADDRESS VarStoreHeaderAddress,
663 IN BOOLEAN Volatile,
664 IN VARIABLE_GLOBAL *Global,
665 IN UINTN Instance
666 )
667 {
668 EFI_STATUS Status;
669 VARIABLE_STORE_HEADER VariableStoreHeader;
670
671 Status = AccessVariableStore (
672 FALSE,
673 Global,
674 Volatile,
675 Instance,
676 VarStoreHeaderAddress,
677 sizeof (VARIABLE_STORE_HEADER),
678 &VariableStoreHeader
679 );
680
681 ASSERT_EFI_ERROR (Status);
682 return HEADER_ALIGN (VarStoreHeaderAddress + VariableStoreHeader.Size);
683 }
684
685 /**
686 Updates variable info entry in EFI system table for statistical information.
687
688 Routine used to track statistical information about variable usage.
689 The data is stored in the EFI system table so it can be accessed later.
690 VariableInfo.efi can dump out the table. Only Boot Services variable
691 accesses are tracked by this code. The PcdVariableCollectStatistics
692 build flag controls if this feature is enabled.
693 A read that hits in the cache will have Read and Cache true for
694 the transaction. Data is allocated by this routine, but never
695 freed.
696
697 @param[in] VariableName Name of the Variable to track.
698 @param[in] VendorGuid Guid of the Variable to track.
699 @param[in] Volatile TRUE if volatile FALSE if non-volatile.
700 @param[in] Read TRUE if GetVariable() was called.
701 @param[in] Write TRUE if SetVariable() was called.
702 @param[in] Delete TRUE if deleted via SetVariable().
703 @param[in] Cache TRUE for a cache hit.
704
705 **/
706 VOID
707 UpdateVariableInfo (
708 IN CHAR16 *VariableName,
709 IN EFI_GUID *VendorGuid,
710 IN BOOLEAN Volatile,
711 IN BOOLEAN Read,
712 IN BOOLEAN Write,
713 IN BOOLEAN Delete,
714 IN BOOLEAN Cache
715 )
716 {
717 VARIABLE_INFO_ENTRY *Entry;
718
719 if (FeaturePcdGet (PcdVariableCollectStatistics)) {
720
721 if (EfiAtRuntime ()) {
722 //
723 // Don't collect statistics at runtime
724 //
725 return;
726 }
727
728 if (gVariableInfo == NULL) {
729 //
730 // on the first call allocate a entry and place a pointer to it in
731 // the EFI System Table
732 //
733 gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
734 ASSERT (gVariableInfo != NULL);
735
736 CopyGuid (&gVariableInfo->VendorGuid, VendorGuid);
737 gVariableInfo->Name = AllocatePool (StrSize (VariableName));
738 ASSERT (gVariableInfo->Name != NULL);
739 StrCpy (gVariableInfo->Name, VariableName);
740 gVariableInfo->Volatile = Volatile;
741
742 gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, gVariableInfo);
743 }
744
745
746 for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) {
747 if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {
748 if (StrCmp (VariableName, Entry->Name) == 0) {
749 //
750 // Find the entry matching both variable name and vender GUID,
751 // and update counters for all types.
752 //
753 if (Read) {
754 Entry->ReadCount++;
755 }
756 if (Write) {
757 Entry->WriteCount++;
758 }
759 if (Delete) {
760 Entry->DeleteCount++;
761 }
762 if (Cache) {
763 Entry->CacheCount++;
764 }
765
766 return;
767 }
768 }
769
770 if (Entry->Next == NULL) {
771 //
772 // If the entry is not in the table add it.
773 // Next iteration of the loop will fill in the data
774 //
775 Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
776 ASSERT (Entry->Next != NULL);
777
778 CopyGuid (&Entry->Next->VendorGuid, VendorGuid);
779 Entry->Next->Name = AllocatePool (StrSize (VariableName));
780 ASSERT (Entry->Next->Name != NULL);
781 StrCpy (Entry->Next->Name, VariableName);
782 Entry->Next->Volatile = Volatile;
783 }
784
785 }
786 }
787 }
788
789 /**
790 Updates variable in cache.
791
792 This function searches the variable cache. If the variable to set exists in the cache,
793 it updates the variable in cache. It has the same parameters with UEFI SetVariable()
794 service.
795
796 @param[in] VariableName A Null-terminated Unicode string that is the name of the vendor's
797 variable. Each VariableName is unique for each VendorGuid.
798 @param[in] VendorGuid A unique identifier for the vendor.
799 @param[in] Attributes Attributes bitmask to set for the variable.
800 @param[in] DataSize The size in bytes of the Data buffer. A size of zero causes the
801 variable to be deleted.
802 @param[in] Data The contents for the variable.
803
804 **/
805 VOID
806 UpdateVariableCache (
807 IN CHAR16 *VariableName,
808 IN EFI_GUID *VendorGuid,
809 IN UINT32 Attributes,
810 IN UINTN DataSize,
811 IN VOID *Data
812 )
813 {
814 VARIABLE_CACHE_ENTRY *Entry;
815 UINTN Index;
816
817 if (EfiAtRuntime ()) {
818 //
819 // Don't use the cache at runtime
820 //
821 return;
822 }
823
824 //
825 // Searches cache for the variable to update. If it exists, update it.
826 //
827 for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {
828 if (CompareGuid (VendorGuid, Entry->Guid)) {
829 if (StrCmp (VariableName, Entry->Name) == 0) {
830 Entry->Attributes = Attributes;
831 if (DataSize == 0) {
832 //
833 // If DataSize is 0, delete the variable.
834 //
835 if (Entry->DataSize != 0) {
836 FreePool (Entry->Data);
837 }
838 Entry->DataSize = DataSize;
839 } else if (DataSize == Entry->DataSize) {
840 //
841 // If size of data does not change, simply copy data
842 //
843 CopyMem (Entry->Data, Data, DataSize);
844 } else {
845 //
846 // If size of data changes, allocate pool and copy data.
847 //
848 Entry->Data = AllocatePool (DataSize);
849 ASSERT (Entry->Data != NULL);
850 Entry->DataSize = DataSize;
851 CopyMem (Entry->Data, Data, DataSize);
852 }
853 }
854 }
855 }
856 }
857
858
859 /**
860 Search the cache to check if the variable is in it.
861
862 This function searches the variable cache. If the variable to find exists, return its data
863 and attributes.
864
865 @param[in] VariableName A Null-terminated Unicode string that is the name of the vendor's
866 variable. Each VariableName is unique for each VendorGuid.
867 @param[in] VendorGuid A unique identifier for the vendor
868 @param[out] Attributes Pointer to the attributes bitmask of the variable for output.
869 @param[in, out] DataSize On input, size of the buffer of Data.
870 On output, size of the variable's data.
871 @param[out] Data Pointer to the data buffer for output.
872
873 @retval EFI_SUCCESS VariableGuid & VariableName data was returned.
874 @retval EFI_NOT_FOUND No matching variable found in cache.
875 @retval EFI_BUFFER_TOO_SMALL *DataSize is smaller than size of the variable's data to return.
876
877 **/
878 EFI_STATUS
879 FindVariableInCache (
880 IN CHAR16 *VariableName,
881 IN EFI_GUID *VendorGuid,
882 OUT UINT32 *Attributes OPTIONAL,
883 IN OUT UINTN *DataSize,
884 OUT VOID *Data
885 )
886 {
887 VARIABLE_CACHE_ENTRY *Entry;
888 UINTN Index;
889
890 if (EfiAtRuntime ()) {
891 //
892 // Don't use the cache at runtime
893 //
894 return EFI_NOT_FOUND;
895 }
896
897 //
898 // Searches cache for the variable
899 //
900 for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {
901 if (CompareGuid (VendorGuid, Entry->Guid)) {
902 if (StrCmp (VariableName, Entry->Name) == 0) {
903 if (Entry->DataSize == 0) {
904 //
905 // Variable has been deleted so return EFI_NOT_FOUND
906 //
907 return EFI_NOT_FOUND;
908 } else if (Entry->DataSize > *DataSize) {
909 //
910 // If buffer is too small, return the size needed and EFI_BUFFER_TOO_SMALL
911 //
912 *DataSize = Entry->DataSize;
913 return EFI_BUFFER_TOO_SMALL;
914 } else {
915 //
916 // If buffer is large enough, return the data
917 //
918 *DataSize = Entry->DataSize;
919 CopyMem (Data, Entry->Data, Entry->DataSize);
920 //
921 // If Attributes is not NULL, return the variable's attribute.
922 //
923 if (Attributes != NULL) {
924 *Attributes = Entry->Attributes;
925 }
926 return EFI_SUCCESS;
927 }
928 }
929 }
930 }
931
932 return EFI_NOT_FOUND;
933 }
934
935 /**
936 Finds variable in volatile and non-volatile storage areas.
937
938 This code finds variable in volatile and non-volatile storage areas.
939 If VariableName is an empty string, then we just return the first
940 qualified variable without comparing VariableName and VendorGuid.
941 Otherwise, VariableName and VendorGuid are compared.
942
943 @param[in] VariableName Name of the variable to be found.
944 @param[in] VendorGuid Vendor GUID to be found.
945 @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output,
946 including the range searched and the target position.
947 @param[in] Global Pointer to VARIABLE_GLOBAL structure, including
948 base of volatile variable storage area, base of
949 NV variable storage area, and a lock.
950 @param[in] Instance Instance of FV Block services.
951
952 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
953 VendorGuid is NULL.
954 @retval EFI_SUCCESS Variable successfully found.
955 @retval EFI_INVALID_PARAMETER Variable not found.
956
957 **/
958 EFI_STATUS
959 FindVariable (
960 IN CHAR16 *VariableName,
961 IN EFI_GUID *VendorGuid,
962 OUT VARIABLE_POINTER_TRACK *PtrTrack,
963 IN VARIABLE_GLOBAL *Global,
964 IN UINTN Instance
965 )
966 {
967 EFI_PHYSICAL_ADDRESS Variable[2];
968 EFI_PHYSICAL_ADDRESS InDeletedVariable;
969 EFI_PHYSICAL_ADDRESS VariableStoreHeader[2];
970 UINTN InDeletedStorageIndex;
971 UINTN Index;
972 CHAR16 LocalVariableName[MAX_NAME_SIZE];
973 BOOLEAN Volatile;
974 VARIABLE_HEADER VariableHeader;
975
976 //
977 // 0: Volatile, 1: Non-Volatile
978 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName
979 // make use of this mapping to implement search algorithme.
980 //
981 VariableStoreHeader[0] = Global->VolatileVariableBase;
982 VariableStoreHeader[1] = Global->NonVolatileVariableBase;
983
984 //
985 // Start Pointers for the variable.
986 // Actual Data Pointer where data can be written.
987 //
988 Variable[0] = GetStartPointer (VariableStoreHeader[0]);
989 Variable[1] = GetStartPointer (VariableStoreHeader[1]);
990
991 if (VariableName[0] != 0 && VendorGuid == NULL) {
992 return EFI_INVALID_PARAMETER;
993 }
994
995 //
996 // Find the variable by walk through volatile and then non-volatile variable store
997 //
998 InDeletedVariable = 0x0;
999 InDeletedStorageIndex = 0;
1000 Volatile = TRUE;
1001 for (Index = 0; Index < 2; Index++) {
1002 if (Index == 1) {
1003 Volatile = FALSE;
1004 }
1005 while (IsValidVariableHeader (Variable[Index], Volatile, Global, Instance, &VariableHeader)) {
1006 if (VariableHeader.State == VAR_ADDED ||
1007 VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)
1008 ) {
1009 if (!EfiAtRuntime () || ((VariableHeader.Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {
1010 if (VariableName[0] == 0) {
1011 //
1012 // If VariableName is an empty string, then we just find the first qualified variable
1013 // without comparing VariableName and VendorGuid
1014 //
1015 if (VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
1016 //
1017 // If variable is in delete transition, record it.
1018 //
1019 InDeletedVariable = Variable[Index];
1020 InDeletedStorageIndex = Index;
1021 } else {
1022 //
1023 // If variable is not in delete transition, return it.
1024 //
1025 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]);
1026 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index], Volatile, Global, Instance);
1027 PtrTrack->CurrPtr = Variable[Index];
1028 PtrTrack->Volatile = Volatile;
1029
1030 return EFI_SUCCESS;
1031 }
1032 } else {
1033 //
1034 // If VariableName is not an empty string, then VariableName and VendorGuid are compared.
1035 //
1036 if (CompareGuid (VendorGuid, &VariableHeader.VendorGuid)) {
1037 GetVariableNamePtr (
1038 Variable[Index],
1039 Volatile,
1040 Global,
1041 Instance,
1042 LocalVariableName
1043 );
1044
1045 ASSERT (NameSizeOfVariable (&VariableHeader) != 0);
1046 if (CompareMem (VariableName, LocalVariableName, NameSizeOfVariable (&VariableHeader)) == 0) {
1047 if (VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
1048 //
1049 // If variable is in delete transition, record it.
1050 // We will use if only no VAR_ADDED variable is found.
1051 //
1052 InDeletedVariable = Variable[Index];
1053 InDeletedStorageIndex = Index;
1054 } else {
1055 //
1056 // If variable is not in delete transition, return it.
1057 //
1058 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]);
1059 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index], Volatile, Global, Instance);
1060 PtrTrack->CurrPtr = Variable[Index];
1061 PtrTrack->Volatile = Volatile;
1062
1063 return EFI_SUCCESS;
1064 }
1065 }
1066 }
1067 }
1068 }
1069 }
1070
1071 Variable[Index] = GetNextVariablePtr (
1072 Variable[Index],
1073 Volatile,
1074 Global,
1075 Instance
1076 );
1077 }
1078 if (InDeletedVariable != 0x0) {
1079 //
1080 // If no VAR_ADDED variable is found, and only variable in delete transition, then use this one.
1081 //
1082 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[InDeletedStorageIndex]);
1083 PtrTrack->EndPtr = GetEndPointer (
1084 VariableStoreHeader[InDeletedStorageIndex],
1085 (BOOLEAN)(InDeletedStorageIndex == 0),
1086 Global,
1087 Instance
1088 );
1089 PtrTrack->CurrPtr = InDeletedVariable;
1090 PtrTrack->Volatile = (BOOLEAN)(InDeletedStorageIndex == 0);
1091 return EFI_SUCCESS;
1092 }
1093 }
1094 PtrTrack->CurrPtr = 0x0;
1095 return EFI_NOT_FOUND;
1096 }
1097
1098 /**
1099 Variable store garbage collection and reclaim operation.
1100
1101 @param[in] VariableBase Base address of variable store area.
1102 @param[out] LastVariableOffset Offset of last variable.
1103 @param[in] IsVolatile The variable store is volatile or not,
1104 if it is non-volatile, need FTW.
1105 @param[in] VirtualMode Current calling mode for this function.
1106 @param[in] Global Context of this Extended SAL Variable Services Class call.
1107 @param[in] UpdatingVariable Pointer to header of the variable that is being updated.
1108
1109 @retval EFI_SUCCESS Variable store successfully reclaimed.
1110 @retval EFI_OUT_OF_RESOURCES Fail to allocate memory buffer to hold all valid variables.
1111
1112 **/
1113 EFI_STATUS
1114 Reclaim (
1115 IN EFI_PHYSICAL_ADDRESS VariableBase,
1116 OUT UINTN *LastVariableOffset,
1117 IN BOOLEAN IsVolatile,
1118 IN BOOLEAN VirtualMode,
1119 IN ESAL_VARIABLE_GLOBAL *Global,
1120 IN EFI_PHYSICAL_ADDRESS UpdatingVariable
1121 )
1122 {
1123 EFI_PHYSICAL_ADDRESS Variable;
1124 EFI_PHYSICAL_ADDRESS AddedVariable;
1125 EFI_PHYSICAL_ADDRESS NextVariable;
1126 EFI_PHYSICAL_ADDRESS NextAddedVariable;
1127 VARIABLE_STORE_HEADER VariableStoreHeader;
1128 VARIABLE_HEADER VariableHeader;
1129 VARIABLE_HEADER AddedVariableHeader;
1130 CHAR16 VariableName[MAX_NAME_SIZE];
1131 CHAR16 AddedVariableName[MAX_NAME_SIZE];
1132 UINT8 *ValidBuffer;
1133 UINTN MaximumBufferSize;
1134 UINTN VariableSize;
1135 UINTN NameSize;
1136 UINT8 *CurrPtr;
1137 BOOLEAN FoundAdded;
1138 EFI_STATUS Status;
1139 VARIABLE_GLOBAL *VariableGlobal;
1140 UINT32 Instance;
1141
1142 VariableGlobal = &Global->VariableGlobal[VirtualMode];
1143 Instance = Global->FvbInstance;
1144
1145 GetVarStoreHeader (VariableBase, IsVolatile, VariableGlobal, Instance, &VariableStoreHeader);
1146 //
1147 // recaluate the total size of Common/HwErr type variables in non-volatile area.
1148 //
1149 if (!IsVolatile) {
1150 Global->CommonVariableTotalSize = 0;
1151 Global->HwErrVariableTotalSize = 0;
1152 }
1153
1154 //
1155 // Calculate the size of buffer needed to gather all valid variables
1156 //
1157 Variable = GetStartPointer (VariableBase);
1158 MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);
1159
1160 while (IsValidVariableHeader (Variable, IsVolatile, VariableGlobal, Instance, &VariableHeader)) {
1161 NextVariable = GetNextVariablePtr (Variable, IsVolatile, VariableGlobal, Instance);
1162 //
1163 // Collect VAR_ADDED variables, and variables in delete transition status.
1164 //
1165 if (VariableHeader.State == VAR_ADDED ||
1166 VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)
1167 ) {
1168 VariableSize = NextVariable - Variable;
1169 MaximumBufferSize += VariableSize;
1170 }
1171
1172 Variable = NextVariable;
1173 }
1174
1175 //
1176 // Reserve the 1 Bytes with Oxff to identify the
1177 // end of the variable buffer.
1178 //
1179 MaximumBufferSize += 1;
1180 ValidBuffer = AllocatePool (MaximumBufferSize);
1181 if (ValidBuffer == NULL) {
1182 return EFI_OUT_OF_RESOURCES;
1183 }
1184
1185 SetMem (ValidBuffer, MaximumBufferSize, 0xff);
1186
1187 //
1188 // Copy variable store header
1189 //
1190 CopyMem (ValidBuffer, &VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));
1191 CurrPtr = (UINT8 *) GetStartPointer ((EFI_PHYSICAL_ADDRESS) ValidBuffer);
1192
1193 //
1194 // Reinstall all ADDED variables
1195 //
1196 Variable = GetStartPointer (VariableBase);
1197 while (IsValidVariableHeader (Variable, IsVolatile, VariableGlobal, Instance, &VariableHeader)) {
1198 NextVariable = GetNextVariablePtr (Variable, IsVolatile, VariableGlobal, Instance);
1199 if (VariableHeader.State == VAR_ADDED) {
1200 VariableSize = NextVariable - Variable;
1201 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
1202 CurrPtr += VariableSize;
1203 if ((!IsVolatile) && ((((VARIABLE_HEADER*)Variable)->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
1204 Global->HwErrVariableTotalSize += VariableSize;
1205 } else if ((!IsVolatile) && ((((VARIABLE_HEADER*)Variable)->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
1206 Global->CommonVariableTotalSize += VariableSize;
1207 }
1208 }
1209 Variable = NextVariable;
1210 }
1211 //
1212 // Reinstall in delete transition variables
1213 //
1214 Variable = GetStartPointer (VariableBase);
1215 while (IsValidVariableHeader (Variable, IsVolatile, VariableGlobal, Instance, &VariableHeader)) {
1216 NextVariable = GetNextVariablePtr (Variable, IsVolatile, VariableGlobal, Instance);
1217 if (VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {
1218
1219 //
1220 // Buffer has cached all ADDED variable.
1221 // Per IN_DELETED variable, we have to guarantee that
1222 // no ADDED one in previous buffer.
1223 //
1224 FoundAdded = FALSE;
1225 AddedVariable = GetStartPointer ((EFI_PHYSICAL_ADDRESS) ValidBuffer);
1226 while (IsValidVariableHeader (AddedVariable, IsVolatile, VariableGlobal, Instance, &AddedVariableHeader)) {
1227 NextAddedVariable = GetNextVariablePtr (AddedVariable, IsVolatile, VariableGlobal, Instance);
1228 NameSize = NameSizeOfVariable (&AddedVariableHeader);
1229 if (CompareGuid (&AddedVariableHeader.VendorGuid, &VariableHeader.VendorGuid) &&
1230 NameSize == NameSizeOfVariable (&VariableHeader)
1231 ) {
1232 GetVariableNamePtr (Variable, IsVolatile, VariableGlobal, Instance, VariableName);
1233 GetVariableNamePtr (AddedVariable, IsVolatile, VariableGlobal, Instance, AddedVariableName);
1234 if (CompareMem (VariableName, AddedVariableName, NameSize) == 0) {
1235 //
1236 // If ADDED variable with the same name and vender GUID has been reinstalled,
1237 // then discard this IN_DELETED copy.
1238 //
1239 FoundAdded = TRUE;
1240 break;
1241 }
1242 }
1243 AddedVariable = NextAddedVariable;
1244 }
1245 //
1246 // Add IN_DELETE variables that have not been added to buffer
1247 //
1248 if (!FoundAdded) {
1249 VariableSize = NextVariable - Variable;
1250 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);
1251 if (Variable != UpdatingVariable) {
1252 //
1253 // Make this IN_DELETE instance valid if:
1254 // 1. No valid instance of this variable exists.
1255 // 2. It is not the variable that is going to be updated.
1256 //
1257 ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;
1258 }
1259 CurrPtr += VariableSize;
1260 if ((!IsVolatile) && ((((VARIABLE_HEADER*)Variable)->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
1261 Global->HwErrVariableTotalSize += VariableSize;
1262 } else if ((!IsVolatile) && ((((VARIABLE_HEADER*)Variable)->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
1263 Global->CommonVariableTotalSize += VariableSize;
1264 }
1265 }
1266 }
1267 Variable = NextVariable;
1268 }
1269
1270 if (IsVolatile) {
1271 //
1272 // If volatile variable store, just copy valid buffer
1273 //
1274 SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader.Size, 0xff);
1275 CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - (UINT8 *) ValidBuffer));
1276 Status = EFI_SUCCESS;
1277 } else {
1278 //
1279 // If non-volatile variable store, perform FTW here.
1280 // Write ValidBuffer to destination specified by VariableBase.
1281 //
1282 Status = FtwVariableSpace (
1283 VariableBase,
1284 ValidBuffer,
1285 (UINTN) (CurrPtr - (UINT8 *) ValidBuffer)
1286 );
1287 }
1288 if (!EFI_ERROR (Status)) {
1289 *LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer);
1290 } else {
1291 *LastVariableOffset = 0;
1292 }
1293
1294 FreePool (ValidBuffer);
1295
1296 return Status;
1297 }
1298
1299 /**
1300 Get index from supported language codes according to language string.
1301
1302 This code is used to get corresponding index in supported language codes. It can handle
1303 RFC4646 and ISO639 language tags.
1304 In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.
1305 In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.
1306
1307 For example:
1308 SupportedLang = "engfraengfra"
1309 Lang = "eng"
1310 Iso639Language = TRUE
1311 The return value is "0".
1312 Another example:
1313 SupportedLang = "en;fr;en-US;fr-FR"
1314 Lang = "fr-FR"
1315 Iso639Language = FALSE
1316 The return value is "3".
1317
1318 @param[in] SupportedLang Platform supported language codes.
1319 @param[in] Lang Configured language.
1320 @param[in] Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
1321
1322 @return The index of language in the language codes.
1323
1324 **/
1325 UINTN
1326 GetIndexFromSupportedLangCodes(
1327 IN CHAR8 *SupportedLang,
1328 IN CHAR8 *Lang,
1329 IN BOOLEAN Iso639Language
1330 )
1331 {
1332 UINTN Index;
1333 UINTN CompareLength;
1334 UINTN LanguageLength;
1335
1336 if (Iso639Language) {
1337 CompareLength = ISO_639_2_ENTRY_SIZE;
1338 for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {
1339 if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {
1340 //
1341 // Successfully find the index of Lang string in SupportedLang string.
1342 //
1343 Index = Index / CompareLength;
1344 return Index;
1345 }
1346 }
1347 ASSERT (FALSE);
1348 return 0;
1349 } else {
1350 //
1351 // Compare RFC4646 language code
1352 //
1353 Index = 0;
1354 for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++);
1355
1356 for (Index = 0; *SupportedLang != '\0'; Index++, SupportedLang += CompareLength) {
1357 //
1358 // Skip ';' characters in SupportedLang
1359 //
1360 for (; *SupportedLang != '\0' && *SupportedLang == ';'; SupportedLang++);
1361 //
1362 // Determine the length of the next language code in SupportedLang
1363 //
1364 for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++);
1365
1366 if ((CompareLength == LanguageLength) &&
1367 (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0)) {
1368 //
1369 // Successfully find the index of Lang string in SupportedLang string.
1370 //
1371 return Index;
1372 }
1373 }
1374 ASSERT (FALSE);
1375 return 0;
1376 }
1377 }
1378
1379 /**
1380 Get language string from supported language codes according to index.
1381
1382 This code is used to get corresponding language string in supported language codes. It can handle
1383 RFC4646 and ISO639 language tags.
1384 In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.
1385 In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.
1386
1387 For example:
1388 SupportedLang = "engfraengfra"
1389 Index = "1"
1390 Iso639Language = TRUE
1391 The return value is "fra".
1392 Another example:
1393 SupportedLang = "en;fr;en-US;fr-FR"
1394 Index = "1"
1395 Iso639Language = FALSE
1396 The return value is "fr".
1397
1398 @param[in] SupportedLang Platform supported language codes.
1399 @param[in] Index the index in supported language codes.
1400 @param[in] Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
1401 @param[in] VirtualMode Current calling mode for this function.
1402 @param[in] Global Context of this Extended SAL Variable Services Class call.
1403
1404 @return The language string in the language codes.
1405
1406 **/
1407 CHAR8 *
1408 GetLangFromSupportedLangCodes (
1409 IN CHAR8 *SupportedLang,
1410 IN UINTN Index,
1411 IN BOOLEAN Iso639Language,
1412 IN BOOLEAN VirtualMode,
1413 IN ESAL_VARIABLE_GLOBAL *Global
1414 )
1415 {
1416 UINTN SubIndex;
1417 UINTN CompareLength;
1418 CHAR8 *Supported;
1419
1420 SubIndex = 0;
1421 Supported = SupportedLang;
1422 if (Iso639Language) {
1423 //
1424 // according to the index of Lang string in SupportedLang string to get the language.
1425 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
1426 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1427 //
1428 CompareLength = ISO_639_2_ENTRY_SIZE;
1429 Global->Lang[CompareLength] = '\0';
1430 return CopyMem (Global->Lang, SupportedLang + Index * CompareLength, CompareLength);
1431
1432 } else {
1433 while (TRUE) {
1434 //
1435 // take semicolon as delimitation, sequentially traverse supported language codes.
1436 //
1437 for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {
1438 Supported++;
1439 }
1440 if ((*Supported == '\0') && (SubIndex != Index)) {
1441 //
1442 // Have completed the traverse, but not find corrsponding string.
1443 // This case is not allowed to happen.
1444 //
1445 ASSERT(FALSE);
1446 return NULL;
1447 }
1448 if (SubIndex == Index) {
1449 //
1450 // according to the index of Lang string in SupportedLang string to get the language.
1451 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
1452 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
1453 //
1454 Global->PlatformLang[VirtualMode][CompareLength] = '\0';
1455 return CopyMem (Global->PlatformLang[VirtualMode], Supported - CompareLength, CompareLength);
1456 }
1457 SubIndex++;
1458
1459 //
1460 // Skip ';' characters in Supported
1461 //
1462 for (; *Supported != '\0' && *Supported == ';'; Supported++);
1463 }
1464 }
1465 }
1466
1467 /**
1468 Returns a pointer to an allocated buffer that contains the best matching language
1469 from a set of supported languages.
1470
1471 This function supports both ISO 639-2 and RFC 4646 language codes, but language
1472 code types may not be mixed in a single call to this function. This function
1473 supports a variable argument list that allows the caller to pass in a prioritized
1474 list of language codes to test against all the language codes in SupportedLanguages.
1475
1476 If SupportedLanguages is NULL, then ASSERT().
1477
1478 @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that
1479 contains a set of language codes in the format
1480 specified by Iso639Language.
1481 @param[in] Iso639Language If TRUE, then all language codes are assumed to be
1482 in ISO 639-2 format. If FALSE, then all language
1483 codes are assumed to be in RFC 4646 language format.
1484 @param[in] VirtualMode Current calling mode for this function.
1485 @param[in] ... A variable argument list that contains pointers to
1486 Null-terminated ASCII strings that contain one or more
1487 language codes in the format specified by Iso639Language.
1488 The first language code from each of these language
1489 code lists is used to determine if it is an exact or
1490 close match to any of the language codes in
1491 SupportedLanguages. Close matches only apply to RFC 4646
1492 language codes, and the matching algorithm from RFC 4647
1493 is used to determine if a close match is present. If
1494 an exact or close match is found, then the matching
1495 language code from SupportedLanguages is returned. If
1496 no matches are found, then the next variable argument
1497 parameter is evaluated. The variable argument list
1498 is terminated by a NULL.
1499
1500 @retval NULL The best matching language could not be found in SupportedLanguages.
1501 @retval NULL There are not enough resources available to return the best matching
1502 language.
1503 @retval Other A pointer to a Null-terminated ASCII string that is the best matching
1504 language in SupportedLanguages.
1505
1506 **/
1507 CHAR8 *
1508 VariableGetBestLanguage (
1509 IN CONST CHAR8 *SupportedLanguages,
1510 IN BOOLEAN Iso639Language,
1511 IN BOOLEAN VirtualMode,
1512 ...
1513 )
1514 {
1515 VA_LIST Args;
1516 CHAR8 *Language;
1517 UINTN CompareLength;
1518 UINTN LanguageLength;
1519 CONST CHAR8 *Supported;
1520 CHAR8 *Buffer;
1521
1522 ASSERT (SupportedLanguages != NULL);
1523
1524 VA_START (Args, VirtualMode);
1525 while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {
1526 //
1527 // Default to ISO 639-2 mode
1528 //
1529 CompareLength = 3;
1530 LanguageLength = MIN (3, AsciiStrLen (Language));
1531
1532 //
1533 // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
1534 //
1535 if (!Iso639Language) {
1536 for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++);
1537 }
1538
1539 //
1540 // Trim back the length of Language used until it is empty
1541 //
1542 while (LanguageLength > 0) {
1543 //
1544 // Loop through all language codes in SupportedLanguages
1545 //
1546 for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {
1547 //
1548 // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
1549 //
1550 if (!Iso639Language) {
1551 //
1552 // Skip ';' characters in Supported
1553 //
1554 for (; *Supported != '\0' && *Supported == ';'; Supported++);
1555 //
1556 // Determine the length of the next language code in Supported
1557 //
1558 for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++);
1559 //
1560 // If Language is longer than the Supported, then skip to the next language
1561 //
1562 if (LanguageLength > CompareLength) {
1563 continue;
1564 }
1565 }
1566 //
1567 // See if the first LanguageLength characters in Supported match Language
1568 //
1569 if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {
1570 VA_END (Args);
1571
1572 Buffer = Iso639Language ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang[VirtualMode];
1573 Buffer[CompareLength] = '\0';
1574 return CopyMem (Buffer, Supported, CompareLength);
1575 }
1576 }
1577
1578 if (Iso639Language) {
1579 //
1580 // If ISO 639 mode, then each language can only be tested once
1581 //
1582 LanguageLength = 0;
1583 } else {
1584 //
1585 // If RFC 4646 mode, then trim Language from the right to the next '-' character
1586 //
1587 for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--);
1588 }
1589 }
1590 }
1591 VA_END (Args);
1592
1593 //
1594 // No matches were found
1595 //
1596 return NULL;
1597 }
1598
1599 /**
1600 Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.
1601
1602 When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.
1603 According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,
1604 and are read-only. Therefore, in variable driver, only store the original value for other use.
1605
1606 @param[in] VariableName Name of variable.
1607 @param[in] Data Variable data.
1608 @param[in] DataSize Size of data. 0 means delete.
1609 @param[in] VirtualMode Current calling mode for this function.
1610 @param[in] Global Context of this Extended SAL Variable Services Class call.
1611
1612 **/
1613 VOID
1614 AutoUpdateLangVariable(
1615 IN CHAR16 *VariableName,
1616 IN VOID *Data,
1617 IN UINTN DataSize,
1618 IN BOOLEAN VirtualMode,
1619 IN ESAL_VARIABLE_GLOBAL *Global
1620 )
1621 {
1622 EFI_STATUS Status;
1623 CHAR8 *BestPlatformLang;
1624 CHAR8 *BestLang;
1625 UINTN Index;
1626 UINT32 Attributes;
1627 VARIABLE_POINTER_TRACK Variable;
1628 BOOLEAN SetLanguageCodes;
1629 CHAR16 **PredefinedVariableName;
1630 VARIABLE_GLOBAL *VariableGlobal;
1631 UINT32 Instance;
1632
1633 //
1634 // Don't do updates for delete operation
1635 //
1636 if (DataSize == 0) {
1637 return;
1638 }
1639
1640 SetLanguageCodes = FALSE;
1641 VariableGlobal = &Global->VariableGlobal[VirtualMode];
1642 Instance = Global->FvbInstance;
1643
1644
1645 PredefinedVariableName = &Global->VariableName[VirtualMode][0];
1646 if (StrCmp (VariableName, PredefinedVariableName[VAR_PLATFORM_LANG_CODES]) == 0) {
1647 //
1648 // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.
1649 //
1650 if (EfiAtRuntime ()) {
1651 return;
1652 }
1653
1654 SetLanguageCodes = TRUE;
1655
1656 //
1657 // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
1658 // Therefore, in variable driver, only store the original value for other use.
1659 //
1660 if (Global->PlatformLangCodes[VirtualMode] != NULL) {
1661 FreePool (Global->PlatformLangCodes[VirtualMode]);
1662 }
1663 Global->PlatformLangCodes[VirtualMode] = AllocateRuntimeCopyPool (DataSize, Data);
1664 ASSERT (mVariableModuleGlobal->PlatformLangCodes[VirtualMode] != NULL);
1665
1666 //
1667 // PlatformLang holds a single language from PlatformLangCodes,
1668 // so the size of PlatformLangCodes is enough for the PlatformLang.
1669 //
1670 if (Global->PlatformLang[VirtualMode] != NULL) {
1671 FreePool (Global->PlatformLang[VirtualMode]);
1672 }
1673 Global->PlatformLang[VirtualMode] = AllocateRuntimePool (DataSize);
1674 ASSERT (Global->PlatformLang[VirtualMode] != NULL);
1675
1676 } else if (StrCmp (VariableName, PredefinedVariableName[VAR_LANG_CODES]) == 0) {
1677 //
1678 // LangCodes is a volatile variable, so it can not be updated at runtime.
1679 //
1680 if (EfiAtRuntime ()) {
1681 return;
1682 }
1683
1684 SetLanguageCodes = TRUE;
1685
1686 //
1687 // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
1688 // Therefore, in variable driver, only store the original value for other use.
1689 //
1690 if (Global->LangCodes[VirtualMode] != NULL) {
1691 FreePool (Global->LangCodes[VirtualMode]);
1692 }
1693 Global->LangCodes[VirtualMode] = AllocateRuntimeCopyPool (DataSize, Data);
1694 ASSERT (Global->LangCodes[VirtualMode] != NULL);
1695 }
1696
1697 if (SetLanguageCodes
1698 && (Global->PlatformLangCodes[VirtualMode] != NULL)
1699 && (Global->LangCodes[VirtualMode] != NULL)) {
1700 //
1701 // Update Lang if PlatformLang is already set
1702 // Update PlatformLang if Lang is already set
1703 //
1704 Status = FindVariable (PredefinedVariableName[VAR_PLATFORM_LANG], Global->GlobalVariableGuid[VirtualMode], &Variable, VariableGlobal, Instance);
1705 if (!EFI_ERROR (Status)) {
1706 //
1707 // Update Lang
1708 //
1709 VariableName = PredefinedVariableName[VAR_PLATFORM_LANG];
1710 } else {
1711 Status = FindVariable (PredefinedVariableName[VAR_LANG], Global->GlobalVariableGuid[VirtualMode], &Variable, VariableGlobal, Instance);
1712 if (!EFI_ERROR (Status)) {
1713 //
1714 // Update PlatformLang
1715 //
1716 VariableName = PredefinedVariableName[VAR_LANG];
1717 } else {
1718 //
1719 // Neither PlatformLang nor Lang is set, directly return
1720 //
1721 return;
1722 }
1723 }
1724 Data = (VOID *) GetEndPointer (VariableGlobal->VolatileVariableBase, TRUE, VariableGlobal, Instance);
1725 GetVariableDataPtr ((EFI_PHYSICAL_ADDRESS) Variable.CurrPtr, Variable.Volatile, VariableGlobal, Instance, (CHAR16 *) Data);
1726
1727 Status = AccessVariableStore (
1728 FALSE,
1729 VariableGlobal,
1730 Variable.Volatile,
1731 Instance,
1732 (UINTN) &(((VARIABLE_HEADER *)Variable.CurrPtr)->DataSize),
1733 sizeof (DataSize),
1734 &DataSize
1735 );
1736 ASSERT_EFI_ERROR (Status);
1737 }
1738
1739 //
1740 // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
1741 //
1742 Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
1743
1744 if (StrCmp (VariableName, PredefinedVariableName[VAR_PLATFORM_LANG]) == 0) {
1745 //
1746 // Update Lang when PlatformLangCodes/LangCodes were set.
1747 //
1748 if ((Global->PlatformLangCodes[VirtualMode] != NULL) && (Global->LangCodes[VirtualMode] != NULL)) {
1749 //
1750 // When setting PlatformLang, firstly get most matched language string from supported language codes.
1751 //
1752 BestPlatformLang = VariableGetBestLanguage (Global->PlatformLangCodes[VirtualMode], FALSE, VirtualMode, Data, NULL);
1753 if (BestPlatformLang != NULL) {
1754 //
1755 // Get the corresponding index in language codes.
1756 //
1757 Index = GetIndexFromSupportedLangCodes (Global->PlatformLangCodes[VirtualMode], BestPlatformLang, FALSE);
1758
1759 //
1760 // Get the corresponding ISO639 language tag according to RFC4646 language tag.
1761 //
1762 BestLang = GetLangFromSupportedLangCodes (Global->LangCodes[VirtualMode], Index, TRUE, VirtualMode, Global);
1763
1764 //
1765 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
1766 //
1767 FindVariable (PredefinedVariableName[VAR_LANG], Global->GlobalVariableGuid[VirtualMode], &Variable, VariableGlobal, Instance);
1768
1769 Status = UpdateVariable (
1770 PredefinedVariableName[VAR_LANG],
1771 Global->GlobalVariableGuid[VirtualMode],
1772 BestLang,
1773 ISO_639_2_ENTRY_SIZE + 1,
1774 Attributes,
1775 0,
1776 0,
1777 VirtualMode,
1778 Global,
1779 &Variable
1780 );
1781
1782 DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang));
1783
1784 ASSERT_EFI_ERROR (Status);
1785 }
1786 }
1787
1788 } else if (StrCmp (VariableName, PredefinedVariableName[VAR_LANG]) == 0) {
1789 //
1790 // Update PlatformLang when PlatformLangCodes/LangCodes were set.
1791 //
1792 if ((Global->PlatformLangCodes[VirtualMode] != NULL) && (Global->LangCodes[VirtualMode] != NULL)) {
1793 //
1794 // When setting Lang, firstly get most matched language string from supported language codes.
1795 //
1796 BestLang = VariableGetBestLanguage (Global->LangCodes[VirtualMode], TRUE, VirtualMode, Data, NULL);
1797 if (BestLang != NULL) {
1798 //
1799 // Get the corresponding index in language codes.
1800 //
1801 Index = GetIndexFromSupportedLangCodes (Global->LangCodes[VirtualMode], BestLang, TRUE);
1802
1803 //
1804 // Get the corresponding RFC4646 language tag according to ISO639 language tag.
1805 //
1806 BestPlatformLang = GetLangFromSupportedLangCodes (Global->PlatformLangCodes[VirtualMode], Index, FALSE, VirtualMode, Global);
1807
1808 //
1809 // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
1810 //
1811 FindVariable (PredefinedVariableName[VAR_PLATFORM_LANG], Global->GlobalVariableGuid[VirtualMode], &Variable, VariableGlobal, Instance);
1812
1813 Status = UpdateVariable (
1814 PredefinedVariableName[VAR_PLATFORM_LANG],
1815 Global->GlobalVariableGuid[VirtualMode],
1816 BestPlatformLang,
1817 AsciiStrSize (BestPlatformLang),
1818 Attributes,
1819 0,
1820 0,
1821 VirtualMode,
1822 Global,
1823 &Variable
1824 );
1825
1826 DEBUG ((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a\n", BestLang, BestPlatformLang));
1827 ASSERT_EFI_ERROR (Status);
1828 }
1829 }
1830 }
1831 }
1832
1833 /**
1834 Update the variable region with Variable information. These are the same
1835 arguments as the EFI Variable services.
1836
1837 @param[in] VariableName Name of variable.
1838 @param[in] VendorGuid Guid of variable.
1839 @param[in] Data Variable data.
1840 @param[in] DataSize Size of data. 0 means delete.
1841 @param[in] Attributes Attributes of the variable.
1842 @param[in] KeyIndex Index of associated public key.
1843 @param[in] MonotonicCount Value of associated monotonic count.
1844 @param[in] VirtualMode Current calling mode for this function.
1845 @param[in] Global Context of this Extended SAL Variable Services Class call.
1846 @param[in] Variable The variable information which is used to keep track of variable usage.
1847
1848 @retval EFI_SUCCESS The update operation is success.
1849 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
1850
1851 **/
1852 EFI_STATUS
1853 EFIAPI
1854 UpdateVariable (
1855 IN CHAR16 *VariableName,
1856 IN EFI_GUID *VendorGuid,
1857 IN VOID *Data,
1858 IN UINTN DataSize,
1859 IN UINT32 Attributes OPTIONAL,
1860 IN UINT32 KeyIndex OPTIONAL,
1861 IN UINT64 MonotonicCount OPTIONAL,
1862 IN BOOLEAN VirtualMode,
1863 IN ESAL_VARIABLE_GLOBAL *Global,
1864 IN VARIABLE_POINTER_TRACK *Variable
1865 )
1866 {
1867 EFI_STATUS Status;
1868 VARIABLE_HEADER *NextVariable;
1869 UINTN VarNameOffset;
1870 UINTN VarDataOffset;
1871 UINTN VarNameSize;
1872 UINTN VarSize;
1873 BOOLEAN Volatile;
1874 UINT8 State;
1875 VARIABLE_HEADER VariableHeader;
1876 VARIABLE_HEADER *NextVariableHeader;
1877 BOOLEAN Valid;
1878 BOOLEAN Reclaimed;
1879 VARIABLE_STORE_HEADER VariableStoreHeader;
1880 UINTN ScratchSize;
1881 VARIABLE_GLOBAL *VariableGlobal;
1882 UINT32 Instance;
1883
1884 VariableGlobal = &Global->VariableGlobal[VirtualMode];
1885 Instance = Global->FvbInstance;
1886
1887 Reclaimed = FALSE;
1888
1889 if (Variable->CurrPtr != 0) {
1890
1891 Valid = IsValidVariableHeader (Variable->CurrPtr, Variable->Volatile, VariableGlobal, Instance, &VariableHeader);
1892 if (!Valid) {
1893 Status = EFI_NOT_FOUND;
1894 goto Done;
1895 }
1896
1897 //
1898 // Update/Delete existing variable
1899 //
1900 Volatile = Variable->Volatile;
1901
1902 if (EfiAtRuntime ()) {
1903 //
1904 // If EfiAtRuntime and the variable is Volatile and Runtime Access,
1905 // the volatile is ReadOnly, and SetVariable should be aborted and
1906 // return EFI_WRITE_PROTECTED.
1907 //
1908 if (Variable->Volatile) {
1909 Status = EFI_WRITE_PROTECTED;
1910 goto Done;
1911 }
1912 //
1913 // Only variable have NV attribute can be updated/deleted in Runtime
1914 //
1915 if ((VariableHeader.Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
1916 Status = EFI_INVALID_PARAMETER;
1917 goto Done;
1918 }
1919 }
1920 //
1921 // Setting a data variable with no access, or zero DataSize attributes
1922 // specified causes it to be deleted.
1923 //
1924 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
1925 State = VariableHeader.State;
1926 State &= VAR_DELETED;
1927
1928 Status = AccessVariableStore (
1929 TRUE,
1930 VariableGlobal,
1931 Variable->Volatile,
1932 Instance,
1933 (UINTN) &(((VARIABLE_HEADER *)Variable->CurrPtr)->State),
1934 sizeof (UINT8),
1935 &State
1936 );
1937 if (!EFI_ERROR (Status)) {
1938 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, FALSE, TRUE, FALSE);
1939 UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);
1940 }
1941 goto Done;
1942 }
1943 //
1944 // Logic comes here to update variable.
1945 // If the variable is marked valid and the same data has been passed in
1946 // then return to the caller immediately.
1947 //
1948 if (DataSizeOfVariable (&VariableHeader) == DataSize) {
1949 NextVariable = (VARIABLE_HEADER *)GetEndPointer (VariableGlobal->VolatileVariableBase, TRUE, VariableGlobal, Instance);
1950 GetVariableDataPtr (Variable->CurrPtr, Variable->Volatile, VariableGlobal, Instance, (CHAR16 *) NextVariable);
1951 if (CompareMem (Data, (VOID *) NextVariable, DataSize) == 0) {
1952 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);
1953 Status = EFI_SUCCESS;
1954 goto Done;
1955 }
1956 }
1957 if ((VariableHeader.State == VAR_ADDED) ||
1958 (VariableHeader.State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {
1959 //
1960 // If new data is different from the old one, mark the old one as VAR_IN_DELETED_TRANSITION.
1961 // It will be deleted if new variable is successfully written.
1962 //
1963 State = VariableHeader.State;
1964 State &= VAR_IN_DELETED_TRANSITION;
1965
1966 Status = AccessVariableStore (
1967 TRUE,
1968 VariableGlobal,
1969 Variable->Volatile,
1970 Instance,
1971 (UINTN) &(((VARIABLE_HEADER *)Variable->CurrPtr)->State),
1972 sizeof (UINT8),
1973 &State
1974 );
1975 if (EFI_ERROR (Status)) {
1976 goto Done;
1977 }
1978 }
1979 } else {
1980 //
1981 // Create a new variable
1982 //
1983
1984 //
1985 // Make sure we are trying to create a new variable.
1986 // Setting a data variable with no access, or zero DataSize attributes means to delete it.
1987 //
1988 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
1989 Status = EFI_NOT_FOUND;
1990 goto Done;
1991 }
1992
1993 //
1994 // Only variable have NV|RT attribute can be created in Runtime
1995 //
1996 if (EfiAtRuntime () &&
1997 (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {
1998 Status = EFI_INVALID_PARAMETER;
1999 goto Done;
2000 }
2001 }
2002
2003 //
2004 // Function part - create a new variable and copy the data.
2005 // Both update a variable and create a variable will come here.
2006 //
2007 // Tricky part: Use scratch data area at the end of volatile variable store
2008 // as a temporary storage.
2009 //
2010 NextVariable = (VARIABLE_HEADER *)GetEndPointer (VariableGlobal->VolatileVariableBase, TRUE, VariableGlobal, Instance);
2011 ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));
2012 NextVariableHeader = (VARIABLE_HEADER *) NextVariable;
2013
2014 SetMem (NextVariableHeader, ScratchSize, 0xff);
2015
2016 NextVariableHeader->StartId = VARIABLE_DATA;
2017 NextVariableHeader->Attributes = Attributes;
2018 NextVariableHeader->PubKeyIndex = KeyIndex;
2019 NextVariableHeader->MonotonicCount = MonotonicCount;
2020 NextVariableHeader->Reserved = 0;
2021 VarNameOffset = sizeof (VARIABLE_HEADER);
2022 VarNameSize = StrSize (VariableName);
2023 CopyMem (
2024 (UINT8 *) ((UINTN)NextVariable + VarNameOffset),
2025 VariableName,
2026 VarNameSize
2027 );
2028 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);
2029 CopyMem (
2030 (UINT8 *) ((UINTN)NextVariable + VarDataOffset),
2031 Data,
2032 DataSize
2033 );
2034 CopyMem (&NextVariableHeader->VendorGuid, VendorGuid, sizeof (EFI_GUID));
2035 //
2036 // There will be pad bytes after Data, the NextVariable->NameSize and
2037 // NextVariable->DataSize should not include pad size so that variable
2038 // service can get actual size in GetVariable.
2039 //
2040 NextVariableHeader->NameSize = (UINT32)VarNameSize;
2041 NextVariableHeader->DataSize = (UINT32)DataSize;
2042
2043 //
2044 // The actual size of the variable that stores in storage should
2045 // include pad size.
2046 //
2047 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
2048 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
2049 //
2050 // Create a nonvolatile variable
2051 //
2052 Volatile = FALSE;
2053
2054 GetVarStoreHeader (VariableGlobal->NonVolatileVariableBase, FALSE, VariableGlobal, Instance, &VariableStoreHeader);
2055 if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)
2056 && ((HEADER_ALIGN (VarSize) + Global->HwErrVariableTotalSize) > PcdGet32(PcdHwErrStorageSize)))
2057 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0)
2058 && ((HEADER_ALIGN (VarSize) + Global->CommonVariableTotalSize) > VariableStoreHeader.Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize)))) {
2059 if (EfiAtRuntime ()) {
2060 Status = EFI_OUT_OF_RESOURCES;
2061 goto Done;
2062 }
2063 //
2064 // Perform garbage collection & reclaim operation
2065 //
2066 Status = Reclaim (VariableGlobal->NonVolatileVariableBase, &(Global->NonVolatileLastVariableOffset), FALSE, VirtualMode, Global, Variable->CurrPtr);
2067 if (EFI_ERROR (Status)) {
2068 goto Done;
2069 }
2070
2071 Reclaimed = TRUE;
2072 //
2073 // If still no enough space, return out of resources
2074 //
2075 if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)
2076 && ((HEADER_ALIGN (VarSize) + Global->HwErrVariableTotalSize) > PcdGet32(PcdHwErrStorageSize)))
2077 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0)
2078 && ((HEADER_ALIGN (VarSize) + Global->CommonVariableTotalSize) > VariableStoreHeader.Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize)))) {
2079 Status = EFI_OUT_OF_RESOURCES;
2080 goto Done;
2081 }
2082 }
2083 //
2084 // Four steps
2085 // 1. Write variable header
2086 // 2. Set variable state to header valid
2087 // 3. Write variable data
2088 // 4. Set variable state to valid
2089 //
2090 //
2091 // Step 1:
2092 //
2093 Status = AccessVariableStore (
2094 TRUE,
2095 VariableGlobal,
2096 FALSE,
2097 Instance,
2098 VariableGlobal->NonVolatileVariableBase + Global->NonVolatileLastVariableOffset,
2099 sizeof (VARIABLE_HEADER),
2100 (UINT8 *) NextVariable
2101 );
2102
2103 if (EFI_ERROR (Status)) {
2104 goto Done;
2105 }
2106
2107 //
2108 // Step 2:
2109 //
2110 NextVariableHeader->State = VAR_HEADER_VALID_ONLY;
2111 Status = AccessVariableStore (
2112 TRUE,
2113 VariableGlobal,
2114 FALSE,
2115 Instance,
2116 VariableGlobal->NonVolatileVariableBase + Global->NonVolatileLastVariableOffset,
2117 sizeof (VARIABLE_HEADER),
2118 (UINT8 *) NextVariable
2119 );
2120
2121 if (EFI_ERROR (Status)) {
2122 goto Done;
2123 }
2124 //
2125 // Step 3:
2126 //
2127 Status = AccessVariableStore (
2128 TRUE,
2129 VariableGlobal,
2130 FALSE,
2131 Instance,
2132 VariableGlobal->NonVolatileVariableBase + Global->NonVolatileLastVariableOffset + sizeof (VARIABLE_HEADER),
2133 (UINT32) VarSize - sizeof (VARIABLE_HEADER),
2134 (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)
2135 );
2136
2137 if (EFI_ERROR (Status)) {
2138 goto Done;
2139 }
2140 //
2141 // Step 4:
2142 //
2143 NextVariableHeader->State = VAR_ADDED;
2144 Status = AccessVariableStore (
2145 TRUE,
2146 VariableGlobal,
2147 FALSE,
2148 Instance,
2149 VariableGlobal->NonVolatileVariableBase + Global->NonVolatileLastVariableOffset,
2150 sizeof (VARIABLE_HEADER),
2151 (UINT8 *) NextVariable
2152 );
2153
2154 if (EFI_ERROR (Status)) {
2155 goto Done;
2156 }
2157
2158 Global->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);
2159
2160 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
2161 Global->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);
2162 } else {
2163 Global->CommonVariableTotalSize += HEADER_ALIGN (VarSize);
2164 }
2165 } else {
2166 //
2167 // Create a volatile variable
2168 //
2169 Volatile = TRUE;
2170
2171 if ((UINT32) (HEADER_ALIGN(VarSize) + Global->VolatileLastVariableOffset) >
2172 ((VARIABLE_STORE_HEADER *) ((UINTN) (VariableGlobal->VolatileVariableBase)))->Size) {
2173 //
2174 // Perform garbage collection & reclaim operation
2175 //
2176 Status = Reclaim (VariableGlobal->VolatileVariableBase, &Global->VolatileLastVariableOffset, TRUE, VirtualMode, Global, Variable->CurrPtr);
2177 if (EFI_ERROR (Status)) {
2178 goto Done;
2179 }
2180 //
2181 // If still no enough space, return out of resources
2182 //
2183 if ((UINT32) (HEADER_ALIGN (VarSize) + Global->VolatileLastVariableOffset) >
2184 ((VARIABLE_STORE_HEADER *) ((UINTN) (VariableGlobal->VolatileVariableBase)))->Size
2185 ) {
2186 Status = EFI_OUT_OF_RESOURCES;
2187 goto Done;
2188 }
2189 Reclaimed = TRUE;
2190 }
2191
2192 NextVariableHeader->State = VAR_ADDED;
2193 Status = AccessVariableStore (
2194 TRUE,
2195 VariableGlobal,
2196 TRUE,
2197 Instance,
2198 VariableGlobal->VolatileVariableBase + Global->VolatileLastVariableOffset,
2199 (UINT32) VarSize,
2200 (UINT8 *) NextVariable
2201 );
2202
2203 if (EFI_ERROR (Status)) {
2204 goto Done;
2205 }
2206
2207 Global->VolatileLastVariableOffset += HEADER_ALIGN (VarSize);
2208 }
2209 //
2210 // Mark the old variable as deleted
2211 // If storage has just been reclaimed, the old variable marked as VAR_IN_DELETED_TRANSITION
2212 // has already been eliminated, so no need to delete it.
2213 //
2214 if (!Reclaimed && !EFI_ERROR (Status) && Variable->CurrPtr != 0) {
2215 State = ((VARIABLE_HEADER *)Variable->CurrPtr)->State;
2216 State &= VAR_DELETED;
2217
2218 Status = AccessVariableStore (
2219 TRUE,
2220 VariableGlobal,
2221 Variable->Volatile,
2222 Instance,
2223 (UINTN) &(((VARIABLE_HEADER *)Variable->CurrPtr)->State),
2224 sizeof (UINT8),
2225 &State
2226 );
2227 }
2228
2229 if (!EFI_ERROR (Status)) {
2230 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);
2231 UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);
2232 }
2233
2234 Done:
2235 return Status;
2236 }
2237
2238 /**
2239 Implements EsalGetVariable function of Extended SAL Variable Services Class.
2240
2241 This function implements EsalGetVariable function of Extended SAL Variable Services Class.
2242 It is equivalent in functionality to the EFI Runtime Service GetVariable().
2243
2244 @param[in] VariableName A Null-terminated Unicode string that is the name of
2245 the vendor's variable.
2246 @param[in] VendorGuid A unique identifier for the vendor.
2247 @param[out] Attributes If not NULL, a pointer to the memory location to return the
2248 attributes bitmask for the variable.
2249 @param[in, out] DataSize Size of Data found. If size is less than the
2250 data, this value contains the required size.
2251 @param[out] Data On input, the size in bytes of the return Data buffer.
2252 On output, the size of data returned in Data.
2253 @param[in] VirtualMode Current calling mode for this function.
2254 @param[in] Global Context of this Extended SAL Variable Services Class call.
2255
2256 @retval EFI_SUCCESS The function completed successfully.
2257 @retval EFI_NOT_FOUND The variable was not found.
2258 @retval EFI_BUFFER_TOO_SMALL DataSize is too small for the result. DataSize has
2259 been updated with the size needed to complete the request.
2260 @retval EFI_INVALID_PARAMETER VariableName is NULL.
2261 @retval EFI_INVALID_PARAMETER VendorGuid is NULL.
2262 @retval EFI_INVALID_PARAMETER DataSize is NULL.
2263 @retval EFI_INVALID_PARAMETER DataSize is not too small and Data is NULL.
2264 @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
2265 @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
2266
2267 **/
2268 EFI_STATUS
2269 EFIAPI
2270 EsalGetVariable (
2271 IN CHAR16 *VariableName,
2272 IN EFI_GUID *VendorGuid,
2273 OUT UINT32 *Attributes OPTIONAL,
2274 IN OUT UINTN *DataSize,
2275 OUT VOID *Data,
2276 IN BOOLEAN VirtualMode,
2277 IN ESAL_VARIABLE_GLOBAL *Global
2278 )
2279 {
2280 VARIABLE_POINTER_TRACK Variable;
2281 UINTN VarDataSize;
2282 EFI_STATUS Status;
2283 VARIABLE_HEADER VariableHeader;
2284 BOOLEAN Valid;
2285 VARIABLE_GLOBAL *VariableGlobal;
2286 UINT32 Instance;
2287
2288 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
2289 return EFI_INVALID_PARAMETER;
2290 }
2291
2292 VariableGlobal = &Global->VariableGlobal[VirtualMode];
2293 Instance = Global->FvbInstance;
2294
2295 AcquireLockOnlyAtBootTime(&VariableGlobal->VariableServicesLock);
2296
2297 //
2298 // Check if this variable exists in cache.
2299 //
2300 Status = FindVariableInCache (VariableName, VendorGuid, Attributes, DataSize, Data);
2301 if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_SUCCESS)){
2302 //
2303 // If variable exists in cache, just update statistical information for it and finish.
2304 // Here UpdateVariableInfo() has already retrieved data & attributes for output.
2305 //
2306 UpdateVariableInfo (VariableName, VendorGuid, FALSE, TRUE, FALSE, FALSE, TRUE);
2307 goto Done;
2308 }
2309 //
2310 // If variable does not exist in cache, search for it in variable storage area.
2311 //
2312 Status = FindVariable (VariableName, VendorGuid, &Variable, VariableGlobal, Instance);
2313 if (Variable.CurrPtr == 0x0 || EFI_ERROR (Status)) {
2314 //
2315 // If it cannot be found in variable storage area, goto Done.
2316 //
2317 goto Done;
2318 }
2319
2320 Valid = IsValidVariableHeader (Variable.CurrPtr, Variable.Volatile, VariableGlobal, Instance, &VariableHeader);
2321 if (!Valid) {
2322 Status = EFI_NOT_FOUND;
2323 goto Done;
2324 }
2325 //
2326 // If variable exists, but not in cache, get its data and attributes, update
2327 // statistical information, and update cache.
2328 //
2329 VarDataSize = DataSizeOfVariable (&VariableHeader);
2330 ASSERT (VarDataSize != 0);
2331
2332 if (*DataSize >= VarDataSize) {
2333 if (Data == NULL) {
2334 Status = EFI_INVALID_PARAMETER;
2335 goto Done;
2336 }
2337
2338 GetVariableDataPtr (
2339 Variable.CurrPtr,
2340 Variable.Volatile,
2341 VariableGlobal,
2342 Instance,
2343 Data
2344 );
2345 if (Attributes != NULL) {
2346 *Attributes = VariableHeader.Attributes;
2347 }
2348
2349 *DataSize = VarDataSize;
2350 UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);
2351 UpdateVariableCache (VariableName, VendorGuid, VariableHeader.Attributes, VarDataSize, Data);
2352
2353 Status = EFI_SUCCESS;
2354 goto Done;
2355 } else {
2356 //
2357 // If DataSize is too small for the result, return EFI_BUFFER_TOO_SMALL.
2358 //
2359 *DataSize = VarDataSize;
2360 Status = EFI_BUFFER_TOO_SMALL;
2361 goto Done;
2362 }
2363
2364 Done:
2365 ReleaseLockOnlyAtBootTime (&VariableGlobal->VariableServicesLock);
2366 return Status;
2367 }
2368
2369 /**
2370 Implements EsalGetNextVariableName function of Extended SAL Variable Services Class.
2371
2372 This function implements EsalGetNextVariableName function of Extended SAL Variable Services Class.
2373 It is equivalent in functionality to the EFI Runtime Service GetNextVariableName().
2374
2375 @param[in, out] VariableNameSize Size of the variable
2376 @param[in, out] VariableName On input, supplies the last VariableName that was returned by GetNextVariableName().
2377 On output, returns the Null-terminated Unicode string of the current variable.
2378 @param[in, out] VendorGuid On input, supplies the last VendorGuid that was returned by GetNextVariableName().
2379 On output, returns the VendorGuid of the current variable.
2380 @param[in] VirtualMode Current calling mode for this function.
2381 @param[in] Global Context of this Extended SAL Variable Services Class call.
2382
2383 @retval EFI_SUCCESS The function completed successfully.
2384 @retval EFI_NOT_FOUND The next variable was not found.
2385 @retval EFI_BUFFER_TOO_SMALL VariableNameSize is too small for the result.
2386 VariableNameSize has been updated with the size needed to complete the request.
2387 @retval EFI_INVALID_PARAMETER VariableNameSize is NULL.
2388 @retval EFI_INVALID_PARAMETER VariableName is NULL.
2389 @retval EFI_INVALID_PARAMETER VendorGuid is NULL.
2390 @retval EFI_DEVICE_ERROR The variable name could not be retrieved due to a hardware error.
2391
2392 **/
2393 EFI_STATUS
2394 EFIAPI
2395 EsalGetNextVariableName (
2396 IN OUT UINTN *VariableNameSize,
2397 IN OUT CHAR16 *VariableName,
2398 IN OUT EFI_GUID *VendorGuid,
2399 IN BOOLEAN VirtualMode,
2400 IN ESAL_VARIABLE_GLOBAL *Global
2401 )
2402 {
2403 VARIABLE_POINTER_TRACK Variable;
2404 UINTN VarNameSize;
2405 EFI_STATUS Status;
2406 VARIABLE_HEADER VariableHeader;
2407 VARIABLE_GLOBAL *VariableGlobal;
2408 UINT32 Instance;
2409
2410 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
2411 return EFI_INVALID_PARAMETER;
2412 }
2413
2414 VariableGlobal = &Global->VariableGlobal[VirtualMode];
2415 Instance = Global->FvbInstance;
2416
2417 AcquireLockOnlyAtBootTime(&VariableGlobal->VariableServicesLock);
2418
2419 Status = FindVariable (VariableName, VendorGuid, &Variable, VariableGlobal, Instance);
2420 //
2421 // If the variable does not exist, goto Done and return.
2422 //
2423 if (Variable.CurrPtr == 0x0 || EFI_ERROR (Status)) {
2424 goto Done;
2425 }
2426
2427 if (VariableName[0] != 0) {
2428 //
2429 // If variable name is not NULL, get next variable
2430 //
2431 Variable.CurrPtr = GetNextVariablePtr (
2432 Variable.CurrPtr,
2433 Variable.Volatile,
2434 VariableGlobal,
2435 Instance
2436 );
2437 }
2438
2439 while (TRUE) {
2440 if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == 0x0) {
2441 //
2442 // If fail to find a variable in current area, reverse the volatile attribute of area to search.
2443 //
2444 Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));
2445 //
2446 // Here we depend on the searching sequence of FindVariable().
2447 // It first searches volatile area, then NV area.
2448 // So if the volatile attribute after switching is non-volatile, it means that we have finished searching volatile area,
2449 // and EFI_NOT_FOUND is returnd.
2450 // Otherwise, it means that we have finished searchig non-volatile area, and we will continue to search volatile area.
2451 //
2452 if (!Variable.Volatile) {
2453 Variable.StartPtr = GetStartPointer (VariableGlobal->NonVolatileVariableBase);
2454 Variable.EndPtr = GetEndPointer (VariableGlobal->NonVolatileVariableBase, FALSE, VariableGlobal, Instance);
2455 } else {
2456 Status = EFI_NOT_FOUND;
2457 goto Done;
2458 }
2459
2460 Variable.CurrPtr = Variable.StartPtr;
2461 if (!IsValidVariableHeader (Variable.CurrPtr, Variable.Volatile, VariableGlobal, Instance, NULL)) {
2462 continue;
2463 }
2464 }
2465 //
2466 // Variable is found
2467 //
2468 if (IsValidVariableHeader (Variable.CurrPtr, Variable.Volatile, VariableGlobal, Instance, &VariableHeader)) {
2469 if ((VariableHeader.State == VAR_ADDED) &&
2470 (!(EfiAtRuntime () && ((VariableHeader.Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)))) {
2471 VarNameSize = NameSizeOfVariable (&VariableHeader);
2472 ASSERT (VarNameSize != 0);
2473
2474 if (VarNameSize <= *VariableNameSize) {
2475 GetVariableNamePtr (
2476 Variable.CurrPtr,
2477 Variable.Volatile,
2478 VariableGlobal,
2479 Instance,
2480 VariableName
2481 );
2482 CopyMem (
2483 VendorGuid,
2484 &VariableHeader.VendorGuid,
2485 sizeof (EFI_GUID)
2486 );
2487 Status = EFI_SUCCESS;
2488 } else {
2489 Status = EFI_BUFFER_TOO_SMALL;
2490 }
2491
2492 *VariableNameSize = VarNameSize;
2493 goto Done;
2494 }
2495 }
2496
2497 Variable.CurrPtr = GetNextVariablePtr (
2498 Variable.CurrPtr,
2499 Variable.Volatile,
2500 VariableGlobal,
2501 Instance
2502 );
2503 }
2504
2505 Done:
2506 ReleaseLockOnlyAtBootTime (&VariableGlobal->VariableServicesLock);
2507 return Status;
2508 }
2509
2510 /**
2511 Implements EsalSetVariable function of Extended SAL Variable Services Class.
2512
2513 This function implements EsalSetVariable function of Extended SAL Variable Services Class.
2514 It is equivalent in functionality to the EFI Runtime Service SetVariable().
2515
2516 @param[in] VariableName A Null-terminated Unicode string that is the name of the vendor's
2517 variable. Each VariableName is unique for each
2518 VendorGuid. VariableName must contain 1 or more
2519 Unicode characters. If VariableName is an empty Unicode
2520 string, then EFI_INVALID_PARAMETER is returned.
2521 @param[in] VendorGuid A unique identifier for the vendor.
2522 @param[in] Attributes Attributes bitmask to set for the variable.
2523 @param[in] DataSize The size in bytes of the Data buffer. A size of zero causes the
2524 variable to be deleted.
2525 @param[in] Data The contents for the variable.
2526 @param[in] VirtualMode Current calling mode for this function.
2527 @param[in] Global Context of this Extended SAL Variable Services Class call.
2528
2529 @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
2530 defined by the Attributes.
2531 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied, or the
2532 DataSize exceeds the maximum allowed.
2533 @retval EFI_INVALID_PARAMETER VariableName is an empty Unicode string.
2534 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
2535 @retval EFI_DEVICE_ERROR The variable could not be saved due to a hardware failure.
2536 @retval EFI_WRITE_PROTECTED The variable in question is read-only.
2537 @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
2538 @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.
2539 @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
2540
2541 **/
2542 EFI_STATUS
2543 EFIAPI
2544 EsalSetVariable (
2545 IN CHAR16 *VariableName,
2546 IN EFI_GUID *VendorGuid,
2547 IN UINT32 Attributes,
2548 IN UINTN DataSize,
2549 IN VOID *Data,
2550 IN BOOLEAN VirtualMode,
2551 IN ESAL_VARIABLE_GLOBAL *Global
2552 )
2553 {
2554 VARIABLE_POINTER_TRACK Variable;
2555 EFI_STATUS Status;
2556 EFI_PHYSICAL_ADDRESS NextVariable;
2557 EFI_PHYSICAL_ADDRESS Point;
2558 VARIABLE_GLOBAL *VariableGlobal;
2559 UINT32 Instance;
2560 UINT32 KeyIndex;
2561 UINT64 MonotonicCount;
2562 UINTN PayloadSize;
2563
2564 //
2565 // Check input parameters
2566 //
2567 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
2568 return EFI_INVALID_PARAMETER;
2569 }
2570
2571 if (DataSize != 0 && Data == NULL) {
2572 return EFI_INVALID_PARAMETER;
2573 }
2574
2575 //
2576 // EFI_VARIABLE_RUNTIME_ACCESS bit cannot be set without EFI_VARIABLE_BOOTSERVICE_ACCESS bit.
2577 //
2578 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
2579 return EFI_INVALID_PARAMETER;
2580 }
2581
2582 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) {
2583 if (DataSize < AUTHINFO_SIZE) {
2584 //
2585 // Try to write Authencated Variable without AuthInfo
2586 //
2587 return EFI_SECURITY_VIOLATION;
2588 }
2589 PayloadSize = DataSize - AUTHINFO_SIZE;
2590 } else {
2591 PayloadSize = DataSize;
2592 }
2593
2594 VariableGlobal = &Global->VariableGlobal[VirtualMode];
2595 Instance = Global->FvbInstance;
2596
2597 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
2598 //
2599 // For variable for hardware error record, the size of the VariableName, including the Unicode Null
2600 // in bytes plus the DataSize is limited to maximum size of PcdGet32(PcdMaxHardwareErrorVariableSize) bytes.
2601 //
2602 if ((PayloadSize > PcdGet32(PcdMaxHardwareErrorVariableSize)) ||
2603 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + PayloadSize > PcdGet32(PcdMaxHardwareErrorVariableSize))) {
2604 return EFI_INVALID_PARAMETER;
2605 }
2606 //
2607 // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX"
2608 //
2609 if (StrnCmp (VariableName, \
2610 Global->VariableName[VirtualMode][VAR_HW_ERR_REC], \
2611 StrLen(Global->VariableName[VirtualMode][VAR_HW_ERR_REC])) != 0) {
2612 return EFI_INVALID_PARAMETER;
2613 }
2614 } else {
2615 //
2616 // For variable not for hardware error record, the size of the VariableName, including the
2617 // Unicode Null in bytes plus the DataSize is limited to maximum size of PcdGet32(PcdMaxVariableSize) bytes.
2618 //
2619 if ((PayloadSize > PcdGet32(PcdMaxVariableSize)) ||
2620 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + PayloadSize > PcdGet32(PcdMaxVariableSize))) {
2621 return EFI_INVALID_PARAMETER;
2622 }
2623 }
2624
2625 AcquireLockOnlyAtBootTime(&VariableGlobal->VariableServicesLock);
2626
2627 //
2628 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated;
2629 //
2630 if (InterlockedIncrement (&Global->ReentrantState) > 1) {
2631 Point = VariableGlobal->NonVolatileVariableBase;;
2632 //
2633 // Parse non-volatile variable data and get last variable offset
2634 //
2635 NextVariable = GetStartPointer (Point);
2636 while (IsValidVariableHeader (NextVariable, FALSE, VariableGlobal, Instance, NULL)) {
2637 NextVariable = GetNextVariablePtr (NextVariable, FALSE, VariableGlobal, Instance);
2638 }
2639 Global->NonVolatileLastVariableOffset = NextVariable - Point;
2640 }
2641
2642 //
2643 // Check whether the input variable exists
2644 //
2645
2646 Status = FindVariable (VariableName, VendorGuid, &Variable, VariableGlobal, Instance);
2647
2648 //
2649 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang
2650 //
2651 AutoUpdateLangVariable (VariableName, Data, PayloadSize, VirtualMode, Global);
2652
2653 //
2654 // Process PK, KEK, Sigdb seperately
2655 //
2656 if (CompareGuid (VendorGuid, Global->GlobalVariableGuid[VirtualMode]) && (StrCmp (VariableName, Global->VariableName[VirtualMode][VAR_PLATFORM_KEY]) == 0)) {
2657 Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, VirtualMode, Global, &Variable, Attributes, TRUE);
2658 } else if (CompareGuid (VendorGuid, Global->GlobalVariableGuid[VirtualMode]) && (StrCmp (VariableName, Global->VariableName[VirtualMode][VAR_KEY_EXCHANGE_KEY]) == 0)) {
2659 Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, VirtualMode, Global, &Variable, Attributes, FALSE);
2660 } else if (CompareGuid (VendorGuid, Global->ImageSecurityDatabaseGuid[VirtualMode])) {
2661 Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, VirtualMode, Global, &Variable, Attributes);
2662 } else {
2663 Status = VerifyVariable (Data, DataSize, VirtualMode, Global, &Variable, Attributes, &KeyIndex, &MonotonicCount);
2664 if (!EFI_ERROR(Status)) {
2665 //
2666 // Verification pass
2667 //
2668 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
2669 //
2670 // Cut the certificate size before set
2671 //
2672 Status = UpdateVariable (
2673 VariableName,
2674 VendorGuid,
2675 (UINT8*)Data + AUTHINFO_SIZE,
2676 DataSize - AUTHINFO_SIZE,
2677 Attributes,
2678 KeyIndex,
2679 MonotonicCount,
2680 VirtualMode,
2681 Global,
2682 &Variable
2683 );
2684 } else {
2685 //
2686 // Update variable as usual
2687 //
2688 Status = UpdateVariable (
2689 VariableName,
2690 VendorGuid,
2691 Data,
2692 DataSize,
2693 Attributes,
2694 0,
2695 0,
2696 VirtualMode,
2697 Global,
2698 &Variable
2699 );
2700 }
2701 }
2702 }
2703
2704 InterlockedDecrement (&Global->ReentrantState);
2705 ReleaseLockOnlyAtBootTime (&VariableGlobal->VariableServicesLock);
2706 return Status;
2707 }
2708
2709 /**
2710 Implements EsalQueryVariableInfo function of Extended SAL Variable Services Class.
2711
2712 This function implements EsalQueryVariableInfo function of Extended SAL Variable Services Class.
2713 It is equivalent in functionality to the EFI Runtime Service QueryVariableInfo().
2714
2715 @param[in] Attributes Attributes bitmask to specify the type of variables
2716 on which to return information.
2717 @param[out] MaximumVariableStorageSize On output the maximum size of the storage space available for
2718 the EFI variables associated with the attributes specified.
2719 @param[out] RemainingVariableStorageSize Returns the remaining size of the storage space available for EFI
2720 variables associated with the attributes specified.
2721 @param[out] MaximumVariableSize Returns the maximum size of an individual EFI variable
2722 associated with the attributes specified.
2723 @param[in] VirtualMode Current calling mode for this function
2724 @param[in] Global Context of this Extended SAL Variable Services Class call
2725
2726 @retval EFI_SUCCESS Valid answer returned.
2727 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.
2728 @retval EFI_UNSUPPORTED The attribute is not supported on this platform, and the
2729 MaximumVariableStorageSize, RemainingVariableStorageSize,
2730 MaximumVariableSize are undefined.
2731 **/
2732 EFI_STATUS
2733 EFIAPI
2734 EsalQueryVariableInfo (
2735 IN UINT32 Attributes,
2736 OUT UINT64 *MaximumVariableStorageSize,
2737 OUT UINT64 *RemainingVariableStorageSize,
2738 OUT UINT64 *MaximumVariableSize,
2739 IN BOOLEAN VirtualMode,
2740 IN ESAL_VARIABLE_GLOBAL *Global
2741 )
2742 {
2743 EFI_PHYSICAL_ADDRESS Variable;
2744 EFI_PHYSICAL_ADDRESS NextVariable;
2745 UINT64 VariableSize;
2746 EFI_PHYSICAL_ADDRESS VariableStoreHeaderAddress;
2747 BOOLEAN Volatile;
2748 VARIABLE_STORE_HEADER VarStoreHeader;
2749 VARIABLE_HEADER VariableHeader;
2750 UINT64 CommonVariableTotalSize;
2751 UINT64 HwErrVariableTotalSize;
2752 VARIABLE_GLOBAL *VariableGlobal;
2753 UINT32 Instance;
2754
2755 CommonVariableTotalSize = 0;
2756 HwErrVariableTotalSize = 0;
2757
2758 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
2759 return EFI_INVALID_PARAMETER;
2760 }
2761
2762 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {
2763 //
2764 // Make sure the Attributes combination is supported by the platform.
2765 //
2766 return EFI_UNSUPPORTED;
2767 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
2768 //
2769 // Make sure if runtime bit is set, boot service bit is set also.
2770 //
2771 return EFI_INVALID_PARAMETER;
2772 } else if (EfiAtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {
2773 //
2774 // Make sure RT Attribute is set if we are in Runtime phase.
2775 //
2776 return EFI_INVALID_PARAMETER;
2777 } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
2778 //
2779 // Make sure Hw Attribute is set with NV.
2780 //
2781 return EFI_INVALID_PARAMETER;
2782 }
2783
2784 VariableGlobal = &Global->VariableGlobal[VirtualMode];
2785 Instance = Global->FvbInstance;
2786
2787 AcquireLockOnlyAtBootTime(&VariableGlobal->VariableServicesLock);
2788
2789 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
2790 //
2791 // Query is Volatile related.
2792 //
2793 Volatile = TRUE;
2794 VariableStoreHeaderAddress = VariableGlobal->VolatileVariableBase;
2795 } else {
2796 //
2797 // Query is Non-Volatile related.
2798 //
2799 Volatile = FALSE;
2800 VariableStoreHeaderAddress = VariableGlobal->NonVolatileVariableBase;
2801 }
2802
2803 //
2804 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
2805 // with the storage size (excluding the storage header size).
2806 //
2807 GetVarStoreHeader (VariableStoreHeaderAddress, Volatile, VariableGlobal, Instance, &VarStoreHeader);
2808
2809 *MaximumVariableStorageSize = VarStoreHeader.Size - sizeof (VARIABLE_STORE_HEADER);
2810
2811 // Harware error record variable needs larger size.
2812 //
2813 if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
2814 *MaximumVariableStorageSize = PcdGet32(PcdHwErrStorageSize);
2815 *MaximumVariableSize = PcdGet32(PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);
2816 } else {
2817 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
2818 ASSERT (PcdGet32(PcdHwErrStorageSize) < VarStoreHeader.Size);
2819 *MaximumVariableStorageSize = VarStoreHeader.Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize);
2820 }
2821
2822 //
2823 // Let *MaximumVariableSize be PcdGet32(PcdMaxVariableSize) with the exception of the variable header size.
2824 //
2825 *MaximumVariableSize = PcdGet32(PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);
2826 }
2827
2828 //
2829 // Point to the starting address of the variables.
2830 //
2831 Variable = GetStartPointer (VariableStoreHeaderAddress);
2832
2833 //
2834 // Now walk through the related variable store.
2835 //
2836 while (IsValidVariableHeader (Variable, Volatile, VariableGlobal, Instance, &VariableHeader) &&
2837 (Variable < GetEndPointer (VariableStoreHeaderAddress, Volatile, VariableGlobal, Instance))) {
2838 NextVariable = GetNextVariablePtr (Variable, Volatile, VariableGlobal, Instance);
2839 VariableSize = NextVariable - Variable;
2840
2841 if (EfiAtRuntime ()) {
2842 //
2843 // we don't take the state of the variables in mind
2844 // when calculating RemainingVariableStorageSize,
2845 // since the space occupied by variables not marked with
2846 // VAR_ADDED is not allowed to be reclaimed in Runtime.
2847 //
2848 if ((VariableHeader.Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
2849 HwErrVariableTotalSize += VariableSize;
2850 } else {
2851 CommonVariableTotalSize += VariableSize;
2852 }
2853 } else {
2854 //
2855 // Only care about Variables with State VAR_ADDED,because
2856 // the space not marked as VAR_ADDED is reclaimable now.
2857 //
2858 if (VariableHeader.State == VAR_ADDED) {
2859 if ((VariableHeader.Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
2860 HwErrVariableTotalSize += VariableSize;
2861 } else {
2862 CommonVariableTotalSize += VariableSize;
2863 }
2864 }
2865 }
2866
2867 //
2868 // Go to the next one
2869 //
2870 Variable = NextVariable;
2871 }
2872
2873 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){
2874 *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;
2875 }else {
2876 *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;
2877 }
2878
2879 if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {
2880 *MaximumVariableSize = 0;
2881 } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {
2882 *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);
2883 }
2884
2885 ReleaseLockOnlyAtBootTime (&VariableGlobal->VariableServicesLock);
2886 return EFI_SUCCESS;
2887 }
2888
2889 /**
2890 Notification function of EVT_GROUP_READY_TO_BOOT event group.
2891
2892 This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.
2893 When the Boot Manager is about to load and execute a boot option, it reclaims variable
2894 storage if free size is below the threshold.
2895
2896 @param[in] Event Event whose notification function is being invoked.
2897 @param[in] Context Pointer to the notification function's context.
2898
2899 **/
2900 VOID
2901 EFIAPI
2902 ReclaimForOS(
2903 IN EFI_EVENT Event,
2904 IN VOID *Context
2905 )
2906 {
2907 UINT32 VarSize;
2908 EFI_STATUS Status;
2909 UINTN CommonVariableSpace;
2910 UINTN RemainingCommonVariableSpace;
2911 UINTN RemainingHwErrVariableSpace;
2912
2913 VarSize = ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase))->Size;
2914 Status = EFI_SUCCESS;
2915 //
2916 //Allowable max size of common variable storage space
2917 //
2918 CommonVariableSpace = VarSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize);
2919
2920 RemainingCommonVariableSpace = CommonVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;
2921
2922 RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;
2923 //
2924 // If the free area is below a threshold, then performs reclaim operation.
2925 //
2926 if ((RemainingCommonVariableSpace < PcdGet32 (PcdMaxVariableSize))
2927 || ((PcdGet32 (PcdHwErrStorageSize) != 0) &&
2928 (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize)))){
2929 Status = Reclaim (
2930 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,
2931 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
2932 FALSE,
2933 Physical,
2934 mVariableModuleGlobal,
2935 0x0
2936 );
2937 ASSERT_EFI_ERROR (Status);
2938 }
2939 }
2940
2941 /**
2942 Initializes variable store area for non-volatile and volatile variable.
2943
2944 This function allocates and initializes memory space for global context of ESAL
2945 variable service and variable store area for non-volatile and volatile variable.
2946
2947 @param[in] ImageHandle The Image handle of this driver.
2948 @param[in] SystemTable The pointer of EFI_SYSTEM_TABLE.
2949
2950 @retval EFI_SUCCESS Function successfully executed.
2951 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
2952
2953 **/
2954 EFI_STATUS
2955 VariableCommonInitialize (
2956 IN EFI_HANDLE ImageHandle,
2957 IN EFI_SYSTEM_TABLE *SystemTable
2958 )
2959 {
2960 EFI_STATUS Status;
2961 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
2962 EFI_PHYSICAL_ADDRESS CurrPtr;
2963 VARIABLE_STORE_HEADER *VolatileVariableStore;
2964 VARIABLE_STORE_HEADER *VariableStoreHeader;
2965 EFI_PHYSICAL_ADDRESS Variable;
2966 EFI_PHYSICAL_ADDRESS NextVariable;
2967 UINTN VariableSize;
2968 UINT32 Instance;
2969 EFI_PHYSICAL_ADDRESS FvVolHdr;
2970 EFI_PHYSICAL_ADDRESS TempVariableStoreHeader;
2971 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;
2972 UINT64 BaseAddress;
2973 UINT64 Length;
2974 UINTN Index;
2975 UINT8 Data;
2976 EFI_PHYSICAL_ADDRESS VariableStoreBase;
2977 UINT64 VariableStoreLength;
2978 EFI_EVENT ReadyToBootEvent;
2979 UINTN ScratchSize;
2980
2981 //
2982 // Allocate memory for mVariableModuleGlobal
2983 //
2984 mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (ESAL_VARIABLE_GLOBAL));
2985 if (mVariableModuleGlobal == NULL) {
2986 return EFI_OUT_OF_RESOURCES;
2987 }
2988
2989 mVariableModuleGlobal->GlobalVariableGuid[Physical] = &gEfiGlobalVariableGuid;
2990 CopyMem (
2991 mVariableModuleGlobal->VariableName[Physical],
2992 mVariableName,
2993 sizeof (mVariableName)
2994 );
2995
2996 EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal[Physical].VariableServicesLock, TPL_NOTIFY);
2997
2998 //
2999 // Note that in EdkII variable driver implementation, Hardware Error Record type variable
3000 // is stored with common variable in the same NV region. So the platform integrator should
3001 // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of
3002 // PcdFlashNvStorageVariableSize.
3003 //
3004 ASSERT (PcdGet32(PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));
3005
3006 //
3007 // Allocate memory for volatile variable store
3008 //
3009 ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));
3010 VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);
3011 if (VolatileVariableStore == NULL) {
3012 FreePool (mVariableModuleGlobal);
3013 return EFI_OUT_OF_RESOURCES;
3014 }
3015
3016 SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);
3017
3018 //
3019 // Variable Specific Data
3020 //
3021 mVariableModuleGlobal->VariableGlobal[Physical].VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;
3022 mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer ((EFI_PHYSICAL_ADDRESS) VolatileVariableStore) - (UINTN) VolatileVariableStore;
3023
3024 CopyGuid (&VolatileVariableStore->Signature, &gEfiAuthenticatedVariableGuid);
3025 VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize);
3026 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;
3027 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;
3028 VolatileVariableStore->Reserved = 0;
3029 VolatileVariableStore->Reserved1 = 0;
3030
3031 //
3032 // Get non volatile varaible store
3033 //
3034 TempVariableStoreHeader = (UINT64) PcdGet32 (PcdFlashNvStorageVariableBase);
3035 VariableStoreBase = TempVariableStoreHeader + \
3036 (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);
3037 VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \
3038 (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);
3039 //
3040 // Mark the variable storage region of the FLASH as RUNTIME
3041 //
3042 BaseAddress = VariableStoreBase & (~EFI_PAGE_MASK);
3043 Length = VariableStoreLength + (VariableStoreBase - BaseAddress);
3044 Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);
3045
3046 Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);
3047 if (EFI_ERROR (Status)) {
3048 goto Done;
3049 }
3050
3051 Status = gDS->SetMemorySpaceAttributes (
3052 BaseAddress,
3053 Length,
3054 GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME
3055 );
3056 if (EFI_ERROR (Status)) {
3057 goto Done;
3058 }
3059 //
3060 // Get address of non volatile variable store base.
3061 //
3062 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = VariableStoreBase;
3063
3064 //
3065 // Check Integrity
3066 //
3067 //
3068 // Find the Correct Instance of the FV Block Service.
3069 //
3070 Instance = 0;
3071 CurrPtr = mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase;
3072
3073 do {
3074 FvVolHdr = 0;
3075 Status = (EFI_STATUS) EsalCall (
3076 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,
3077 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,
3078 GetPhysicalAddressFunctionId,
3079 Instance,
3080 (UINT64) &FvVolHdr,
3081 0,
3082 0,
3083 0,
3084 0,
3085 0
3086 ).Status;
3087 if (EFI_ERROR (Status)) {
3088 break;
3089 }
3090 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);
3091 ASSERT (FwVolHeader != NULL);
3092 if (CurrPtr >= (EFI_PHYSICAL_ADDRESS) FwVolHeader &&
3093 CurrPtr < ((EFI_PHYSICAL_ADDRESS) FwVolHeader + FwVolHeader->FvLength)) {
3094 mVariableModuleGlobal->FvbInstance = Instance;
3095 break;
3096 }
3097
3098 Instance++;
3099 } while (Status == EFI_SUCCESS);
3100
3101 VariableStoreHeader = (VARIABLE_STORE_HEADER *) CurrPtr;
3102 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {
3103 if (~VariableStoreHeader->Size == 0) {
3104 Status = AccessVariableStore (
3105 TRUE,
3106 &mVariableModuleGlobal->VariableGlobal[Physical],
3107 FALSE,
3108 mVariableModuleGlobal->FvbInstance,
3109 (UINTN) &VariableStoreHeader->Size,
3110 sizeof (UINT32),
3111 (UINT8 *) &VariableStoreLength
3112 );
3113 //
3114 // As Variables are stored in NV storage, which are slow devices,such as flash.
3115 // Variable operation may skip checking variable program result to improve performance,
3116 // We can assume Variable program is OK through some check point.
3117 // Variable Store Size Setting should be the first Variable write operation,
3118 // We can assume all Read/Write is OK if we can set Variable store size successfully.
3119 // If write fail, we will assert here.
3120 //
3121 ASSERT(VariableStoreHeader->Size == VariableStoreLength);
3122
3123 if (EFI_ERROR (Status)) {
3124 goto Done;
3125 }
3126 }
3127
3128 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) CurrPtr);
3129 //
3130 // Parse non-volatile variable data and get last variable offset.
3131 //
3132 Variable = GetStartPointer (CurrPtr);
3133 Status = EFI_SUCCESS;
3134
3135 while (IsValidVariableHeader (Variable, FALSE, &(mVariableModuleGlobal->VariableGlobal[Physical]), Instance, NULL)) {
3136 NextVariable = GetNextVariablePtr (
3137 Variable,
3138 FALSE,
3139 &(mVariableModuleGlobal->VariableGlobal[Physical]),
3140 Instance
3141 );
3142 VariableSize = NextVariable - Variable;
3143 if ((((VARIABLE_HEADER *)Variable)->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
3144 mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;
3145 } else {
3146 mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;
3147 }
3148
3149 Variable = NextVariable;
3150 }
3151
3152 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) Variable - (UINTN) CurrPtr;
3153
3154 //
3155 // Check if the free area is really free.
3156 //
3157 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {
3158 Data = ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase)[Index];
3159 if (Data != 0xff) {
3160 //
3161 // There must be something wrong in variable store, do reclaim operation.
3162 //
3163 Status = Reclaim (
3164 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,
3165 &mVariableModuleGlobal->NonVolatileLastVariableOffset,
3166 FALSE,
3167 Physical,
3168 mVariableModuleGlobal,
3169 0x0
3170 );
3171 if (EFI_ERROR (Status)) {
3172 goto Done;
3173 }
3174 break;
3175 }
3176 }
3177
3178 //
3179 // Register the event handling function to reclaim variable for OS usage.
3180 //
3181 Status = EfiCreateEventReadyToBootEx (
3182 TPL_NOTIFY,
3183 ReclaimForOS,
3184 NULL,
3185 &ReadyToBootEvent
3186 );
3187 } else {
3188 Status = EFI_VOLUME_CORRUPTED;
3189 DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));
3190 }
3191
3192 Done:
3193 if (EFI_ERROR (Status)) {
3194 FreePool (mVariableModuleGlobal);
3195 FreePool (VolatileVariableStore);
3196 }
3197
3198 return Status;
3199 }