]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Variable/EmuRuntimeDxe/EmuVariable.c
228d7d8cffadcb8cdb4ec00f3303591a19466eb9
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / EmuRuntimeDxe / EmuVariable.c
1 /** @file
2
3 Emulation Variable services operate on the runtime volatile memory.
4 The nonvolatile variable space doesn't exist.
5
6 Copyright (c) 2006 - 2008, Intel Corporation
7 All rights reserved. This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "Variable.h"
18
19 ///
20 /// Don't use module globals after the SetVirtualAddress map is signaled
21 ///
22 ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal;
23
24 VARIABLE_INFO_ENTRY *gVariableInfo = NULL;
25
26 ///
27 /// The size of a 3 character ISO639 language code.
28 ///
29 #define ISO_639_2_ENTRY_SIZE 3
30
31 /**
32 Update the variable region with Variable information. These are the same
33 arguments as the EFI Variable services.
34
35 @param[in] VariableName Name of variable
36
37 @param[in] VendorGuid Guid of variable
38
39 @param[in] Data Variable data
40
41 @param[in] DataSize Size of data. 0 means delete
42
43 @param[in] Attributes Attribues of the variable
44
45 @param[in] Variable The variable information which is used to keep track of variable usage.
46
47 @retval EFI_SUCCESS The update operation is success.
48
49 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
50
51 **/
52 EFI_STATUS
53 EFIAPI
54 UpdateVariable (
55 IN CHAR16 *VariableName,
56 IN EFI_GUID *VendorGuid,
57 IN VOID *Data,
58 IN UINTN DataSize,
59 IN UINT32 Attributes OPTIONAL,
60 IN VARIABLE_POINTER_TRACK *Variable
61 );
62
63 /**
64 Finds variable in storage blocks of volatile and non-volatile storage areas.
65
66 This code finds variable in storage blocks of volatile and non-volatile storage areas.
67 If VariableName is an empty string, then we just return the first
68 qualified variable without comparing VariableName and VendorGuid.
69 Otherwise, VariableName and VendorGuid are compared.
70
71 @param VariableName Name of the variable to be found.
72 @param VendorGuid Vendor GUID to be found.
73 @param PtrTrack VARIABLE_POINTER_TRACK structure for output,
74 including the range searched and the target position.
75 @param Global Pointer to VARIABLE_GLOBAL structure, including
76 base of volatile variable storage area, base of
77 NV variable storage area, and a lock.
78
79 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
80 VendorGuid is NULL.
81 @retval EFI_SUCCESS Variable successfully found.
82 @retval EFI_NOT_FOUND Variable not found.
83
84 **/
85 EFI_STATUS
86 FindVariable (
87 IN CHAR16 *VariableName,
88 IN EFI_GUID *VendorGuid,
89 OUT VARIABLE_POINTER_TRACK *PtrTrack,
90 IN VARIABLE_GLOBAL *Global
91 );
92
93 /**
94 Acquires lock only at boot time. Simply returns at runtime.
95
96 This is a temperary function which will be removed when
97 EfiAcquireLock() in UefiLib can handle the call in UEFI
98 Runtimer driver in RT phase.
99 It calls EfiAcquireLock() at boot time, and simply returns
100 at runtime
101
102 @param Lock A pointer to the lock to acquire
103
104 **/
105 VOID
106 AcquireLockOnlyAtBootTime (
107 IN EFI_LOCK *Lock
108 )
109 {
110 if (!EfiAtRuntime ()) {
111 EfiAcquireLock (Lock);
112 }
113 }
114
115 /**
116 Releases lock only at boot time. Simply returns at runtime.
117
118 This is a temperary function which will be removed when
119 EfiReleaseLock() in UefiLib can handle the call in UEFI
120 Runtimer driver in RT phase.
121 It calls EfiReleaseLock() at boot time, and simply returns
122 at runtime
123
124 @param Lock A pointer to the lock to release
125
126 **/
127 VOID
128 ReleaseLockOnlyAtBootTime (
129 IN EFI_LOCK *Lock
130 )
131 {
132 if (!EfiAtRuntime ()) {
133 EfiReleaseLock (Lock);
134 }
135 }
136
137 /**
138 Gets pointer to the variable data.
139
140 This function gets the pointer to the variable data according
141 to the input pointer to the variable header.
142
143 @param Variable Pointer to the variable header.
144
145 @return Pointer to variable data
146
147 **/
148 UINT8 *
149 GetVariableDataPtr (
150 IN VARIABLE_HEADER *Variable
151 )
152 {
153 if (Variable->StartId != VARIABLE_DATA) {
154 return NULL;
155 }
156 //
157 // Be careful about pad size for alignment
158 //
159 return (UINT8 *) ((UINTN) GET_VARIABLE_NAME_PTR (Variable) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize));
160 }
161
162 /**
163 Gets pointer to header of the next variable.
164
165 This function gets the pointer to the next variable header according
166 to the input point to the variable header.
167
168 @param Variable Pointer to header of the next variable
169
170 @return Pointer to next variable header.
171
172 **/
173 VARIABLE_HEADER *
174 GetNextVariablePtr (
175 IN VARIABLE_HEADER *Variable
176 )
177 {
178 VARIABLE_HEADER *VarHeader;
179
180 if (Variable->StartId != VARIABLE_DATA) {
181 return NULL;
182 }
183 //
184 // Be careful about pad size for alignment
185 //
186 VarHeader = (VARIABLE_HEADER *) (GetVariableDataPtr (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize));
187
188 if (VarHeader->StartId != VARIABLE_DATA) {
189 return NULL;
190 }
191
192 return VarHeader;
193 }
194
195 /**
196 Gets pointer to the end of the variable storage area.
197
198 This function gets pointer to the end of the variable storage
199 area, according to the input variable store header.
200
201 @param VolHeader Pointer to the variale store header
202
203 @return Pointer to the end of the variable storage area.
204
205 **/
206 VARIABLE_HEADER *
207 GetEndPointer (
208 IN VARIABLE_STORE_HEADER *VolHeader
209 )
210 {
211 //
212 // The end of variable store
213 //
214 return (VARIABLE_HEADER *) ((UINTN) VolHeader + VolHeader->Size);
215 }
216
217 /**
218 Routine used to track statistical information about variable usage.
219 The data is stored in the EFI system table so it can be accessed later.
220 VariableInfo.efi can dump out the table. Only Boot Services variable
221 accesses are tracked by this code. The PcdVariableCollectStatistics
222 build flag controls if this feature is enabled.
223
224 A read that hits in the cache will have Read and Cache true for
225 the transaction. Data is allocated by this routine, but never
226 freed.
227
228 @param[in] VariableName Name of the Variable to track
229 @param[in] VendorGuid Guid of the Variable to track
230 @param[in] Volatile TRUE if volatile FALSE if non-volatile
231 @param[in] Read TRUE if GetVariable() was called
232 @param[in] Write TRUE if SetVariable() was called
233 @param[in] Delete TRUE if deleted via SetVariable()
234 @param[in] Cache TRUE for a cache hit.
235
236 **/
237 VOID
238 UpdateVariableInfo (
239 IN CHAR16 *VariableName,
240 IN EFI_GUID *VendorGuid,
241 IN BOOLEAN Volatile,
242 IN BOOLEAN Read,
243 IN BOOLEAN Write,
244 IN BOOLEAN Delete,
245 IN BOOLEAN Cache
246 )
247 {
248 VARIABLE_INFO_ENTRY *Entry;
249
250 if (FeaturePcdGet (PcdVariableCollectStatistics)) {
251
252 if (EfiAtRuntime ()) {
253 // Don't collect statistics at runtime
254 return;
255 }
256
257 if (gVariableInfo == NULL) {
258 //
259 // on the first call allocate a entry and place a pointer to it in
260 // the EFI System Table
261 //
262 gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
263 ASSERT (gVariableInfo != NULL);
264
265 CopyGuid (&gVariableInfo->VendorGuid, VendorGuid);
266 gVariableInfo->Name = AllocatePool (StrSize (VariableName));
267 ASSERT (gVariableInfo->Name != NULL);
268 StrCpy (gVariableInfo->Name, VariableName);
269 gVariableInfo->Volatile = Volatile;
270
271 gBS->InstallConfigurationTable (&gEfiVariableGuid, gVariableInfo);
272 }
273
274
275 for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) {
276 if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {
277 if (StrCmp (VariableName, Entry->Name) == 0) {
278 if (Read) {
279 Entry->ReadCount++;
280 }
281 if (Write) {
282 Entry->WriteCount++;
283 }
284 if (Delete) {
285 Entry->DeleteCount++;
286 }
287 if (Cache) {
288 Entry->CacheCount++;
289 }
290
291 return;
292 }
293 }
294
295 if (Entry->Next == NULL) {
296 //
297 // If the entry is not in the table add it.
298 // Next iteration of the loop will fill in the data
299 //
300 Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
301 ASSERT (Entry->Next != NULL);
302
303 CopyGuid (&Entry->Next->VendorGuid, VendorGuid);
304 Entry->Next->Name = AllocatePool (StrSize (VariableName));
305 ASSERT (Entry->Next->Name != NULL);
306 StrCpy (Entry->Next->Name, VariableName);
307 Entry->Next->Volatile = Volatile;
308 }
309
310 }
311 }
312 }
313
314 /**
315 Get index from supported language codes according to language string.
316
317 This code is used to get corresponding index in supported language codes. It can handle
318 RFC4646 and ISO639 language tags.
319 In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.
320 In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.
321
322 For example:
323 SupportedLang = "engfraengfra"
324 Lang = "eng"
325 Iso639Language = TRUE
326 The return value is "0".
327 Another example:
328 SupportedLang = "en;fr;en-US;fr-FR"
329 Lang = "fr-FR"
330 Iso639Language = FALSE
331 The return value is "3".
332
333 @param SupportedLang Platform supported language codes.
334 @param Lang Configured language.
335 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
336
337 @retval the index of language in the language codes.
338
339 **/
340 UINTN
341 EFIAPI
342 GetIndexFromSupportedLangCodes(
343 IN CHAR8 *SupportedLang,
344 IN CHAR8 *Lang,
345 IN BOOLEAN Iso639Language
346 )
347 {
348 UINTN Index;
349 UINT32 CompareLength;
350 CHAR8 *Supported;
351
352 Index = 0;
353 Supported = SupportedLang;
354 if (Iso639Language) {
355 CompareLength = 3;
356 for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {
357 if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {
358 //
359 // Successfully find the index of Lang string in SupportedLang string.
360 //
361 Index = Index / CompareLength;
362 return Index;
363 }
364 }
365 ASSERT (FALSE);
366 return 0;
367 } else {
368 //
369 // Compare RFC4646 language code
370 //
371 while (*Supported != '\0') {
372 //
373 // take semicolon as delimitation, sequentially traverse supported language codes.
374 //
375 for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {
376 Supported++;
377 }
378 if (AsciiStrnCmp (Lang, Supported - CompareLength, CompareLength) == 0) {
379 //
380 // Successfully find the index of Lang string in SupportedLang string.
381 //
382 return Index;
383 }
384 Index++;
385 }
386 ASSERT (FALSE);
387 return 0;
388 }
389 }
390
391 /**
392 Get language string from supported language codes according to index.
393
394 This code is used to get corresponding language string in supported language codes. It can handle
395 RFC4646 and ISO639 language tags.
396 In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.
397 In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.
398
399 For example:
400 SupportedLang = "engfraengfra"
401 Index = "1"
402 Iso639Language = TRUE
403 The return value is "fra".
404 Another example:
405 SupportedLang = "en;fr;en-US;fr-FR"
406 Index = "1"
407 Iso639Language = FALSE
408 The return value is "fr".
409
410 @param SupportedLang Platform supported language codes.
411 @param Index the index in supported language codes.
412 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
413
414 @retval the language string in the language codes.
415
416 **/
417 CHAR8 *
418 EFIAPI
419 GetLangFromSupportedLangCodes (
420 IN CHAR8 *SupportedLang,
421 IN UINTN Index,
422 IN BOOLEAN Iso639Language
423 )
424 {
425 UINTN SubIndex;
426 UINT32 CompareLength;
427 CHAR8 *Supported;
428
429 SubIndex = 0;
430 Supported = SupportedLang;
431 if (Iso639Language) {
432 //
433 // according to the index of Lang string in SupportedLang string to get the language.
434 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
435 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
436 //
437 CompareLength = 3;
438 SetMem (mVariableModuleGlobal->Lang, sizeof(mVariableModuleGlobal->Lang), 0);
439 return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength);
440
441 } else {
442 while (TRUE) {
443 //
444 // take semicolon as delimitation, sequentially traverse supported language codes.
445 //
446 for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {
447 Supported++;
448 }
449 if ((*Supported == '\0') && (SubIndex != Index)) {
450 //
451 // Have completed the traverse, but not find corrsponding string.
452 // This case is not allowed to happen.
453 //
454 ASSERT(FALSE);
455 return NULL;
456 }
457 if (SubIndex == Index) {
458 //
459 // according to the index of Lang string in SupportedLang string to get the language.
460 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
461 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
462 //
463 SetMem (mVariableModuleGlobal->PlatformLang, sizeof (mVariableModuleGlobal->PlatformLang), 0);
464 return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - CompareLength, CompareLength);
465 }
466 SubIndex++;
467 }
468 }
469 }
470
471 /**
472 Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.
473
474 When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.
475
476 According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,
477 and are read-only. Therefore, in variable driver, only store the original value for other use.
478
479 @param[in] VariableName Name of variable
480
481 @param[in] Data Variable data
482
483 @param[in] DataSize Size of data. 0 means delete
484
485 @retval EFI_SUCCESS auto update operation is successful.
486
487 **/
488 EFI_STATUS
489 EFIAPI
490 AutoUpdateLangVariable(
491 IN CHAR16 *VariableName,
492 IN VOID *Data,
493 IN UINTN DataSize
494 )
495 {
496 EFI_STATUS Status;
497 CHAR8 *BestPlatformLang;
498 CHAR8 *BestLang;
499 UINTN Index;
500 UINT32 Attributes;
501 VARIABLE_POINTER_TRACK Variable;
502
503 //
504 // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
505 //
506 Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
507
508 if (StrCmp (VariableName, L"PlatformLangCodes") == 0) {
509 //
510 // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
511 // Therefore, in variable driver, only store the original value for other use.
512 //
513 AsciiStrnCpy (mVariableModuleGlobal->PlatformLangCodes, Data, DataSize);
514 } else if (StrCmp (VariableName, L"LangCodes") == 0) {
515 //
516 // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
517 // Therefore, in variable driver, only store the original value for other use.
518 //
519 AsciiStrnCpy (mVariableModuleGlobal->LangCodes, Data, DataSize);
520 } else if (StrCmp (VariableName, L"PlatformLang") == 0) {
521 ASSERT (AsciiStrLen (mVariableModuleGlobal->PlatformLangCodes) != 0);
522
523 //
524 // When setting PlatformLang, firstly get most matched language string from supported language codes.
525 //
526 BestPlatformLang = GetBestLanguage(mVariableModuleGlobal->PlatformLangCodes, FALSE, Data, NULL);
527
528 //
529 // Get the corresponding index in language codes.
530 //
531 Index = GetIndexFromSupportedLangCodes(mVariableModuleGlobal->PlatformLangCodes, BestPlatformLang, FALSE);
532
533 //
534 // Get the corresponding ISO639 language tag according to RFC4646 language tag.
535 //
536 BestLang = GetLangFromSupportedLangCodes(mVariableModuleGlobal->LangCodes, Index, TRUE);
537
538 //
539 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
540 //
541 FindVariable(L"Lang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal);
542
543 Status = UpdateVariable(L"Lang", &gEfiGlobalVariableGuid,
544 BestLang, ISO_639_2_ENTRY_SIZE + 1, Attributes, &Variable);
545
546 DEBUG((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang));
547
548 ASSERT_EFI_ERROR(Status);
549
550 } else if (StrCmp (VariableName, L"Lang") == 0) {
551 ASSERT (AsciiStrLen (mVariableModuleGlobal->LangCodes) != 0);
552
553 //
554 // When setting Lang, firstly get most matched language string from supported language codes.
555 //
556 BestLang = GetBestLanguage(mVariableModuleGlobal->LangCodes, TRUE, Data, NULL);
557
558 //
559 // Get the corresponding index in language codes.
560 //
561 Index = GetIndexFromSupportedLangCodes(mVariableModuleGlobal->LangCodes, BestLang, TRUE);
562
563 //
564 // Get the corresponding RFC4646 language tag according to ISO639 language tag.
565 //
566 BestPlatformLang = GetLangFromSupportedLangCodes(mVariableModuleGlobal->PlatformLangCodes, Index, FALSE);
567
568 //
569 // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
570 //
571 FindVariable(L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal);
572
573 Status = UpdateVariable(L"PlatformLang", &gEfiGlobalVariableGuid,
574 BestPlatformLang, AsciiStrSize (BestPlatformLang), Attributes, &Variable);
575
576 DEBUG((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a\n", BestLang, BestPlatformLang));
577 ASSERT_EFI_ERROR(Status);
578 }
579 return EFI_SUCCESS;
580 }
581
582 /**
583 Update the variable region with Variable information. These are the same
584 arguments as the EFI Variable services.
585
586 @param[in] VariableName Name of variable
587
588 @param[in] VendorGuid Guid of variable
589
590 @param[in] Data Variable data
591
592 @param[in] DataSize Size of data. 0 means delete
593
594 @param[in] Attributes Attribues of the variable
595
596 @param[in] Variable The variable information which is used to keep track of variable usage.
597
598 @retval EFI_SUCCESS The update operation is success.
599
600 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
601
602 **/
603 EFI_STATUS
604 EFIAPI
605 UpdateVariable (
606 IN CHAR16 *VariableName,
607 IN EFI_GUID *VendorGuid,
608 IN VOID *Data,
609 IN UINTN DataSize,
610 IN UINT32 Attributes OPTIONAL,
611 IN VARIABLE_POINTER_TRACK *Variable
612 )
613 {
614 EFI_STATUS Status;
615 VARIABLE_HEADER *NextVariable;
616 UINTN VarNameSize;
617 UINTN VarNameOffset;
618 UINTN VarDataOffset;
619 UINTN VarSize;
620 VARIABLE_GLOBAL *Global;
621 UINTN NonVolatileVarableStoreSize;
622
623 Global = &mVariableModuleGlobal->VariableGlobal[Physical];
624
625 if (Variable->CurrPtr != NULL) {
626 //
627 // Update/Delete existing variable
628 //
629
630 if (EfiAtRuntime ()) {
631 //
632 // If EfiAtRuntime and the variable is Volatile and Runtime Access,
633 // the volatile is ReadOnly, and SetVariable should be aborted and
634 // return EFI_WRITE_PROTECTED.
635 //
636 if (Variable->Volatile) {
637 Status = EFI_WRITE_PROTECTED;
638 goto Done;
639 }
640 //
641 // Only variable have NV attribute can be updated/deleted in Runtime
642 //
643 if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
644 Status = EFI_INVALID_PARAMETER;
645 goto Done;
646 }
647 }
648
649 //
650 // Setting a data variable with no access, or zero DataSize attributes
651 // specified causes it to be deleted.
652 //
653 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
654 Variable->CurrPtr->State &= VAR_DELETED;
655 UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE);
656 Status = EFI_SUCCESS;
657 goto Done;
658 }
659
660 //
661 // If the variable is marked valid and the same data has been passed in
662 // then return to the caller immediately.
663 //
664 if (Variable->CurrPtr->DataSize == DataSize &&
665 CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0
666 ) {
667 Status = EFI_SUCCESS;
668 goto Done;
669 } else if (Variable->CurrPtr->State == VAR_ADDED) {
670 //
671 // Mark the old variable as in delete transition
672 //
673 Variable->CurrPtr->State &= VAR_IN_DELETED_TRANSITION;
674 }
675
676 } else {
677 //
678 // No found existing variable, Create a new variable
679 //
680
681 //
682 // Make sure we are trying to create a new variable.
683 // Setting a data variable with no access, or zero DataSize attributes means to delete it.
684 //
685 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
686 Status = EFI_NOT_FOUND;
687 goto Done;
688 }
689
690 //
691 // Only variable have NV|RT attribute can be created in Runtime
692 //
693 if (EfiAtRuntime () &&
694 (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {
695 Status = EFI_INVALID_PARAMETER;
696 goto Done;
697 }
698 }
699
700 //
701 // Function part - create a new variable and copy the data.
702 // Both update a variable and create a variable will come here.
703 //
704
705 VarNameOffset = sizeof (VARIABLE_HEADER);
706 VarNameSize = StrSize (VariableName);
707 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);
708 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
709
710 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
711 NonVolatileVarableStoreSize = ((VARIABLE_STORE_HEADER *)(UINTN)(Global->NonVolatileVariableBase))->Size;
712 if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)
713 && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > FixedPcdGet32(PcdHwErrStorageSize)))
714 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0)
715 && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - FixedPcdGet32(PcdHwErrStorageSize)))) {
716 Status = EFI_OUT_OF_RESOURCES;
717 goto Done;
718 }
719
720 NextVariable = (VARIABLE_HEADER *) (UINT8 *) (mVariableModuleGlobal->NonVolatileLastVariableOffset
721 + (UINTN) Global->NonVolatileVariableBase);
722 mVariableModuleGlobal->NonVolatileLastVariableOffset += VarSize;
723
724 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
725 mVariableModuleGlobal->HwErrVariableTotalSize += VarSize;
726 } else {
727 mVariableModuleGlobal->CommonVariableTotalSize += VarSize;
728 }
729 } else {
730 if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >
731 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size
732 ) {
733 Status = EFI_OUT_OF_RESOURCES;
734 goto Done;
735 }
736
737 NextVariable = (VARIABLE_HEADER *) (UINT8 *) (mVariableModuleGlobal->VolatileLastVariableOffset
738 + (UINTN) Global->VolatileVariableBase);
739 mVariableModuleGlobal->VolatileLastVariableOffset += VarSize;
740 }
741
742 NextVariable->StartId = VARIABLE_DATA;
743 NextVariable->Attributes = Attributes;
744 NextVariable->State = VAR_ADDED;
745 NextVariable->Reserved = 0;
746
747 //
748 // There will be pad bytes after Data, the NextVariable->NameSize and
749 // NextVariable->NameSize should not include pad size so that variable
750 // service can get actual size in GetVariable
751 //
752 NextVariable->NameSize = (UINT32)VarNameSize;
753 NextVariable->DataSize = (UINT32)DataSize;
754
755 CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));
756 CopyMem (
757 (UINT8 *) ((UINTN) NextVariable + VarNameOffset),
758 VariableName,
759 VarNameSize
760 );
761 CopyMem (
762 (UINT8 *) ((UINTN) NextVariable + VarDataOffset),
763 Data,
764 DataSize
765 );
766
767 //
768 // Mark the old variable as deleted
769 //
770 if (Variable->CurrPtr != NULL) {
771 Variable->CurrPtr->State &= VAR_DELETED;
772 }
773
774 UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE);
775
776 Status = EFI_SUCCESS;
777
778 Done:
779 return Status;
780 }
781
782 /**
783 Finds variable in storage blocks of volatile and non-volatile storage areas.
784
785 This code finds variable in storage blocks of volatile and non-volatile storage areas.
786 If VariableName is an empty string, then we just return the first
787 qualified variable without comparing VariableName and VendorGuid.
788 Otherwise, VariableName and VendorGuid are compared.
789
790 @param VariableName Name of the variable to be found.
791 @param VendorGuid Vendor GUID to be found.
792 @param PtrTrack VARIABLE_POINTER_TRACK structure for output,
793 including the range searched and the target position.
794 @param Global Pointer to VARIABLE_GLOBAL structure, including
795 base of volatile variable storage area, base of
796 NV variable storage area, and a lock.
797
798 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
799 VendorGuid is NULL.
800 @retval EFI_SUCCESS Variable successfully found.
801 @retval EFI_NOT_FOUND Variable not found.
802
803 **/
804 EFI_STATUS
805 FindVariable (
806 IN CHAR16 *VariableName,
807 IN EFI_GUID *VendorGuid,
808 OUT VARIABLE_POINTER_TRACK *PtrTrack,
809 IN VARIABLE_GLOBAL *Global
810 )
811 {
812 VARIABLE_HEADER *Variable[2];
813 VARIABLE_STORE_HEADER *VariableStoreHeader[2];
814 UINTN Index;
815
816 //
817 // 0: Non-Volatile, 1: Volatile
818 //
819 VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase);
820 VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);
821
822 //
823 // Start Pointers for the variable.
824 // Actual Data Pointer where data can be written.
825 //
826 Variable[0] = (VARIABLE_HEADER *) (VariableStoreHeader[0] + 1);
827 Variable[1] = (VARIABLE_HEADER *) (VariableStoreHeader[1] + 1);
828
829 if (VariableName[0] != 0 && VendorGuid == NULL) {
830 return EFI_INVALID_PARAMETER;
831 }
832 //
833 // Find the variable by walk through non-volatile and volatile variable store
834 //
835 for (Index = 0; Index < 2; Index++) {
836 PtrTrack->StartPtr = (VARIABLE_HEADER *) (VariableStoreHeader[Index] + 1);
837 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]);
838
839 while ((Variable[Index] < GetEndPointer (VariableStoreHeader[Index])) && (Variable[Index] != NULL)) {
840 if (Variable[Index]->StartId == VARIABLE_DATA && Variable[Index]->State == VAR_ADDED) {
841 if (!(EfiAtRuntime () && ((Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0))) {
842 if (VariableName[0] == 0) {
843 PtrTrack->CurrPtr = Variable[Index];
844 PtrTrack->Volatile = (BOOLEAN) Index;
845 return EFI_SUCCESS;
846 } else {
847 if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) {
848 if (CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable[Index]), Variable[Index]->NameSize) == 0) {
849 PtrTrack->CurrPtr = Variable[Index];
850 PtrTrack->Volatile = (BOOLEAN) Index;
851 return EFI_SUCCESS;
852 }
853 }
854 }
855 }
856 }
857
858 Variable[Index] = GetNextVariablePtr (Variable[Index]);
859 }
860 }
861 PtrTrack->CurrPtr = NULL;
862 return EFI_NOT_FOUND;
863 }
864
865 /**
866 This code finds variable in storage blocks (Volatile or Non-Volatile).
867
868 @param VariableName A Null-terminated Unicode string that is the name of
869 the vendor's variable.
870 @param VendorGuid A unique identifier for the vendor.
871 @param Attributes If not NULL, a pointer to the memory location to return the
872 attributes bitmask for the variable.
873 @param DataSize Size of Data found. If size is less than the
874 data, this value contains the required size.
875 @param Data On input, the size in bytes of the return Data buffer.
876 On output, the size of data returned in Data.
877 @param Global Pointer to VARIABLE_GLOBAL structure
878
879 @retval EFI_SUCCESS The function completed successfully.
880 @retval EFI_NOT_FOUND The variable was not found.
881 @retval EFI_BUFFER_TOO_SMALL DataSize is too small for the result. DataSize has
882 been updated with the size needed to complete the request.
883 @retval EFI_INVALID_PARAMETER VariableName or VendorGuid or DataSize is NULL.
884
885 **/
886 EFI_STATUS
887 EFIAPI
888 EmuGetVariable (
889 IN CHAR16 *VariableName,
890 IN EFI_GUID *VendorGuid,
891 OUT UINT32 *Attributes OPTIONAL,
892 IN OUT UINTN *DataSize,
893 OUT VOID *Data,
894 IN VARIABLE_GLOBAL *Global
895 )
896 {
897 VARIABLE_POINTER_TRACK Variable;
898 UINTN VarDataSize;
899 EFI_STATUS Status;
900
901 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
902 return EFI_INVALID_PARAMETER;
903 }
904
905 AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);
906
907 //
908 // Find existing variable
909 //
910 Status = FindVariable (VariableName, VendorGuid, &Variable, Global);
911
912 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
913 goto Done;
914 }
915 //
916 // Get data size
917 //
918 VarDataSize = Variable.CurrPtr->DataSize;
919 if (*DataSize >= VarDataSize) {
920 if (Data == NULL) {
921 Status = EFI_INVALID_PARAMETER;
922 goto Done;
923 }
924
925 CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);
926 if (Attributes != NULL) {
927 *Attributes = Variable.CurrPtr->Attributes;
928 }
929
930 *DataSize = VarDataSize;
931 UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);
932 Status = EFI_SUCCESS;
933 goto Done;
934 } else {
935 *DataSize = VarDataSize;
936 Status = EFI_BUFFER_TOO_SMALL;
937 goto Done;
938 }
939
940 Done:
941 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
942 return Status;
943 }
944
945 /**
946
947 This code Finds the Next available variable.
948
949 @param VariableNameSize Size of the variable.
950 @param VariableName On input, supplies the last VariableName that was returned by GetNextVariableName().
951 On output, returns the Null-terminated Unicode string of the current variable.
952 @param VendorGuid On input, supplies the last VendorGuid that was returned by GetNextVariableName().
953 On output, returns the VendorGuid of the current variable.
954 @param Global Pointer to VARIABLE_GLOBAL structure.
955
956 @retval EFI_SUCCESS The function completed successfully.
957 @retval EFI_NOT_FOUND The next variable was not found.
958 @retval EFI_BUFFER_TOO_SMALL VariableNameSize is too small for the result.
959 VariableNameSize has been updated with the size needed to complete the request.
960 @retval EFI_INVALID_PARAMETER VariableNameSize or VariableName or VendorGuid is NULL.
961
962 **/
963 EFI_STATUS
964 EFIAPI
965 EmuGetNextVariableName (
966 IN OUT UINTN *VariableNameSize,
967 IN OUT CHAR16 *VariableName,
968 IN OUT EFI_GUID *VendorGuid,
969 IN VARIABLE_GLOBAL *Global
970 )
971 {
972 VARIABLE_POINTER_TRACK Variable;
973 UINTN VarNameSize;
974 EFI_STATUS Status;
975
976 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
977 return EFI_INVALID_PARAMETER;
978 }
979
980 AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);
981
982 Status = FindVariable (VariableName, VendorGuid, &Variable, Global);
983
984 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
985 goto Done;
986 }
987
988 while (TRUE) {
989 if (VariableName[0] != 0) {
990 //
991 // If variable name is not NULL, get next variable
992 //
993 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
994 }
995 //
996 // If both volatile and non-volatile variable store are parsed,
997 // return not found
998 //
999 if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) {
1000 Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));
1001 if (Variable.Volatile) {
1002 Variable.StartPtr = (VARIABLE_HEADER *) ((UINTN) (Global->VolatileVariableBase + sizeof (VARIABLE_STORE_HEADER)));
1003 Variable.EndPtr = (VARIABLE_HEADER *) GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase));
1004 } else {
1005 Status = EFI_NOT_FOUND;
1006 goto Done;
1007 }
1008
1009 Variable.CurrPtr = Variable.StartPtr;
1010 if (Variable.CurrPtr->StartId != VARIABLE_DATA) {
1011 continue;
1012 }
1013 }
1014 //
1015 // Variable is found
1016 //
1017 if (Variable.CurrPtr->StartId == VARIABLE_DATA && Variable.CurrPtr->State == VAR_ADDED) {
1018 if (!(EfiAtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0))) {
1019 VarNameSize = Variable.CurrPtr->NameSize;
1020 if (VarNameSize <= *VariableNameSize) {
1021 CopyMem (
1022 VariableName,
1023 GET_VARIABLE_NAME_PTR (Variable.CurrPtr),
1024 VarNameSize
1025 );
1026 CopyMem (
1027 VendorGuid,
1028 &Variable.CurrPtr->VendorGuid,
1029 sizeof (EFI_GUID)
1030 );
1031 Status = EFI_SUCCESS;
1032 } else {
1033 Status = EFI_BUFFER_TOO_SMALL;
1034 }
1035
1036 *VariableNameSize = VarNameSize;
1037 goto Done;
1038 }
1039 }
1040 }
1041
1042 Done:
1043 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
1044 return Status;
1045
1046 }
1047
1048 /**
1049
1050 This code sets variable in storage blocks (Volatile or Non-Volatile).
1051
1052 @param VariableName A Null-terminated Unicode string that is the name of the vendor's
1053 variable. Each VariableName is unique for each
1054 VendorGuid. VariableName must contain 1 or more
1055 Unicode characters. If VariableName is an empty Unicode
1056 string, then EFI_INVALID_PARAMETER is returned.
1057 @param VendorGuid A unique identifier for the vendor
1058 @param Attributes Attributes bitmask to set for the variable
1059 @param DataSize The size in bytes of the Data buffer. A size of zero causes the
1060 variable to be deleted.
1061 @param Data The contents for the variable
1062 @param Global Pointer to VARIABLE_GLOBAL structure
1063 @param VolatileOffset The offset of last volatile variable
1064 @param NonVolatileOffset The offset of last non-volatile variable
1065
1066 @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
1067 defined by the Attributes.
1068 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied, or the
1069 DataSize exceeds the maximum allowed, or VariableName is an empty
1070 Unicode string, or VendorGuid is NULL.
1071 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
1072 @retval EFI_DEVICE_ERROR The variable could not be saved due to a hardware failure.
1073 @retval EFI_WRITE_PROTECTED The variable in question is read-only or cannot be deleted.
1074 @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
1075
1076 **/
1077 EFI_STATUS
1078 EFIAPI
1079 EmuSetVariable (
1080 IN CHAR16 *VariableName,
1081 IN EFI_GUID *VendorGuid,
1082 IN UINT32 Attributes,
1083 IN UINTN DataSize,
1084 IN VOID *Data,
1085 IN VARIABLE_GLOBAL *Global,
1086 IN UINTN *VolatileOffset,
1087 IN UINTN *NonVolatileOffset
1088 )
1089 {
1090 VARIABLE_POINTER_TRACK Variable;
1091 EFI_STATUS Status;
1092
1093 //
1094 // Check input parameters
1095 //
1096 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
1097 return EFI_INVALID_PARAMETER;
1098 }
1099 //
1100 // Make sure if runtime bit is set, boot service bit is set also
1101 //
1102 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
1103 return EFI_INVALID_PARAMETER;
1104 }
1105 //
1106 // The size of the VariableName, including the Unicode Null in bytes plus
1107 // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxHardwareErrorVariableSize)
1108 // bytes for HwErrRec, and FixedPcdGet32(PcdMaxVariableSize) bytes for the others.
1109 //
1110 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1111 if ((DataSize > FixedPcdGet32(PcdMaxHardwareErrorVariableSize)) ||
1112 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > FixedPcdGet32(PcdMaxHardwareErrorVariableSize))) {
1113 return EFI_INVALID_PARAMETER;
1114 }
1115 //
1116 // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX"
1117 //
1118 if (StrnCmp(VariableName, L"HwErrRec", StrLen(L"HwErrRec")) != 0) {
1119 return EFI_INVALID_PARAMETER;
1120 }
1121 } else {
1122 //
1123 // The size of the VariableName, including the Unicode Null in bytes plus
1124 // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxVariableSize) bytes.
1125 //
1126 if ((DataSize > FixedPcdGet32(PcdMaxVariableSize)) ||
1127 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > FixedPcdGet32(PcdMaxVariableSize))) {
1128 return EFI_INVALID_PARAMETER;
1129 }
1130 }
1131
1132 AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);
1133
1134 //
1135 // Check whether the input variable is already existed
1136 //
1137
1138 Status = FindVariable (VariableName, VendorGuid, &Variable, Global);
1139
1140 //
1141 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang
1142 //
1143 AutoUpdateLangVariable (VariableName, Data, DataSize);
1144
1145 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, &Variable);
1146
1147 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
1148 return Status;
1149 }
1150
1151 /**
1152
1153 This code returns information about the EFI variables.
1154
1155 @param Attributes Attributes bitmask to specify the type of variables
1156 on which to return information.
1157 @param MaximumVariableStorageSize On output the maximum size of the storage space available for
1158 the EFI variables associated with the attributes specified.
1159 @param RemainingVariableStorageSize Returns the remaining size of the storage space available for EFI
1160 variables associated with the attributes specified.
1161 @param MaximumVariableSize Returns the maximum size of an individual EFI variable
1162 associated with the attributes specified.
1163 @param Global Pointer to VARIABLE_GLOBAL structure.
1164
1165 @retval EFI_SUCCESS Valid answer returned.
1166 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied
1167 @retval EFI_UNSUPPORTED The attribute is not supported on this platform, and the
1168 MaximumVariableStorageSize, RemainingVariableStorageSize,
1169 MaximumVariableSize are undefined.
1170
1171 **/
1172 EFI_STATUS
1173 EFIAPI
1174 EmuQueryVariableInfo (
1175 IN UINT32 Attributes,
1176 OUT UINT64 *MaximumVariableStorageSize,
1177 OUT UINT64 *RemainingVariableStorageSize,
1178 OUT UINT64 *MaximumVariableSize,
1179 IN VARIABLE_GLOBAL *Global
1180 )
1181 {
1182 VARIABLE_HEADER *Variable;
1183 VARIABLE_HEADER *NextVariable;
1184 UINT64 VariableSize;
1185 VARIABLE_STORE_HEADER *VariableStoreHeader;
1186 UINT64 CommonVariableTotalSize;
1187 UINT64 HwErrVariableTotalSize;
1188
1189 CommonVariableTotalSize = 0;
1190 HwErrVariableTotalSize = 0;
1191
1192 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
1193 return EFI_INVALID_PARAMETER;
1194 }
1195
1196 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {
1197 //
1198 // Make sure the Attributes combination is supported by the platform.
1199 //
1200 return EFI_UNSUPPORTED;
1201 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
1202 //
1203 // Make sure if runtime bit is set, boot service bit is set also.
1204 //
1205 return EFI_INVALID_PARAMETER;
1206 } else if (EfiAtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {
1207 //
1208 // Make sure RT Attribute is set if we are in Runtime phase.
1209 //
1210 return EFI_INVALID_PARAMETER;
1211 } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1212 //
1213 // Make sure Hw Attribute is set with NV.
1214 //
1215 return EFI_INVALID_PARAMETER;
1216 }
1217
1218 AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);
1219
1220 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
1221 //
1222 // Query is Volatile related.
1223 //
1224 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);
1225 } else {
1226 //
1227 // Query is Non-Volatile related.
1228 //
1229 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase);
1230 }
1231
1232 //
1233 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
1234 // with the storage size (excluding the storage header size)
1235 //
1236 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
1237
1238 //
1239 // Harware error record variable needs larger size.
1240 //
1241 if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
1242 *MaximumVariableStorageSize = FixedPcdGet32(PcdHwErrStorageSize);
1243 *MaximumVariableSize = FixedPcdGet32(PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);
1244 } else {
1245 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
1246 ASSERT (FixedPcdGet32(PcdHwErrStorageSize) < VariableStoreHeader->Size);
1247 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - FixedPcdGet32(PcdHwErrStorageSize);
1248 }
1249
1250 //
1251 // Let *MaximumVariableSize be FixedPcdGet32(PcdMaxVariableSize) with the exception of the variable header size.
1252 //
1253 *MaximumVariableSize = FixedPcdGet32(PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);
1254 }
1255
1256 //
1257 // Point to the starting address of the variables.
1258 //
1259 Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
1260
1261 //
1262 // Now walk through the related variable store.
1263 //
1264 while (Variable < GetEndPointer (VariableStoreHeader)) {
1265 NextVariable = GetNextVariablePtr(Variable);
1266 if (NextVariable == NULL) {
1267 break;
1268 }
1269 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;
1270
1271 if ((NextVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1272 HwErrVariableTotalSize += VariableSize;
1273 } else {
1274 CommonVariableTotalSize += VariableSize;
1275 }
1276
1277 //
1278 // Go to the next one.
1279 //
1280 Variable = NextVariable;
1281 }
1282
1283 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){
1284 *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;
1285 } else {
1286 *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;
1287 }
1288
1289 if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {
1290 *MaximumVariableSize = 0;
1291 } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {
1292 *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);
1293 }
1294
1295 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
1296 return EFI_SUCCESS;
1297 }
1298
1299 /**
1300 Initializes variable store area.
1301
1302 This function allocates memory space for variable store area and initializes its attributes.
1303
1304 @param VariableBase Base of the variable store area created
1305 @param LastVariableOffset Size of VARIABLE_STORE_HEADER
1306
1307 **/
1308 EFI_STATUS
1309 InitializeVariableStore (
1310 OUT EFI_PHYSICAL_ADDRESS *VariableBase,
1311 OUT UINTN *LastVariableOffset
1312 )
1313 {
1314 VARIABLE_STORE_HEADER *VariableStore;
1315
1316 //
1317 // Allocate memory for volatile variable store
1318 //
1319 VariableStore = (VARIABLE_STORE_HEADER *) AllocateRuntimePool (
1320 FixedPcdGet32(PcdVariableStoreSize)
1321 );
1322 if (NULL == VariableStore) {
1323 return EFI_OUT_OF_RESOURCES;
1324 }
1325
1326 SetMem (VariableStore, FixedPcdGet32(PcdVariableStoreSize), 0xff);
1327
1328 //
1329 // Variable Specific Data
1330 //
1331 *VariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore;
1332 *LastVariableOffset = sizeof (VARIABLE_STORE_HEADER);
1333
1334 CopyGuid (&VariableStore->Signature, &gEfiVariableGuid);
1335 VariableStore->Size = FixedPcdGet32(PcdVariableStoreSize);
1336 VariableStore->Format = VARIABLE_STORE_FORMATTED;
1337 VariableStore->State = VARIABLE_STORE_HEALTHY;
1338 VariableStore->Reserved = 0;
1339 VariableStore->Reserved1 = 0;
1340
1341 return EFI_SUCCESS;
1342 }
1343
1344 /**
1345 Initializes variable store area for non-volatile and volatile variable.
1346
1347 This function allocates and initializes memory space for global context of ESAL
1348 variable service and variable store area for non-volatile and volatile variable.
1349
1350 @param ImageHandle The Image handle of this driver.
1351 @param SystemTable The pointer of EFI_SYSTEM_TABLE.
1352
1353 @retval EFI_SUCCESS Function successfully executed.
1354 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
1355
1356 **/
1357 EFI_STATUS
1358 EFIAPI
1359 VariableCommonInitialize (
1360 IN EFI_HANDLE ImageHandle,
1361 IN EFI_SYSTEM_TABLE *SystemTable
1362 )
1363 {
1364 EFI_STATUS Status;
1365
1366 //
1367 // Allocate memory for mVariableModuleGlobal
1368 //
1369 mVariableModuleGlobal = (ESAL_VARIABLE_GLOBAL *) AllocateRuntimeZeroPool (
1370 sizeof (ESAL_VARIABLE_GLOBAL)
1371 );
1372 if (NULL == mVariableModuleGlobal) {
1373 return EFI_OUT_OF_RESOURCES;
1374 }
1375
1376 EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal[Physical].VariableServicesLock, TPL_NOTIFY);
1377
1378 //
1379 // Intialize volatile variable store
1380 //
1381 Status = InitializeVariableStore (
1382 &mVariableModuleGlobal->VariableGlobal[Physical].VolatileVariableBase,
1383 &mVariableModuleGlobal->VolatileLastVariableOffset
1384 );
1385
1386 if (EFI_ERROR (Status)) {
1387 FreePool(mVariableModuleGlobal);
1388 return Status;
1389 }
1390 //
1391 // Intialize non volatile variable store
1392 //
1393 Status = InitializeVariableStore (
1394 &mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,
1395 &mVariableModuleGlobal->NonVolatileLastVariableOffset
1396 );
1397
1398 return Status;
1399 }