VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/VBoxPkg/VBoxVariable/EmuVariable.c@ 48674

Last change on this file since 48674 was 48674, checked in by vboxsync, 11 years ago

EFI: Export newly imported tinaocore UEFI sources to OSE.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 62.2 KB
Line 
1/* $Id: EmuVariable.c 48674 2013-09-25 08:26:15Z vboxsync $ */
2/** @file
3 * EmuVariable.c
4 */
5
6/*
7 * Copyright (C) 2012 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 */
26
27/** @file
28 Sample ACPI Platform Driver
29
30 Copyright (c) 2008 - 2011, Intel Corporation. All rights reserved.<BR>
31 This program and the accompanying materials
32 are licensed and made available under the terms and conditions of the BSD License
33 which accompanies this distribution. The full text of the license may be found at
34 http://opensource.org/licenses/bsd-license.php
35
36 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
37 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
38
39**/
40/** @file
41
42 Emulation Variable services operate on the runtime volatile memory.
43 The nonvolatile variable space doesn't exist.
44
45Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
46This program and the accompanying materials
47are licensed and made available under the terms and conditions of the BSD License
48which accompanies this distribution. The full text of the license may be found at
49http://opensource.org/licenses/bsd-license.php
50
51THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
52WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
53
54**/
55
56#include "Variable.h"
57
58///
59/// Don't use module globals after the SetVirtualAddress map is signaled
60///
61ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal;
62
63VARIABLE_INFO_ENTRY *gVariableInfo = NULL;
64
65///
66/// The size of a 3 character ISO639 language code.
67///
68#define ISO_639_2_ENTRY_SIZE 3
69
70/**
71 Update the variable region with Variable information. These are the same
72 arguments as the EFI Variable services.
73
74 @param[in] VariableName Name of variable
75
76 @param[in] VendorGuid Guid of variable
77
78 @param[in] Data Variable data
79
80 @param[in] DataSize Size of data. 0 means delete
81
82 @param[in] Attributes Attribues of the variable
83
84 @param[in] Variable The variable information which is used to keep track of variable usage.
85
86 @retval EFI_SUCCESS The update operation is success.
87
88 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
89
90**/
91EFI_STATUS
92EFIAPI
93UpdateVariable (
94 IN CHAR16 *VariableName,
95 IN EFI_GUID *VendorGuid,
96 IN VOID *Data,
97 IN UINTN DataSize,
98 IN UINT32 Attributes OPTIONAL,
99 IN VARIABLE_POINTER_TRACK *Variable
100 );
101
102/**
103 Finds variable in storage blocks of volatile and non-volatile storage areas.
104
105 This code finds variable in storage blocks of volatile and non-volatile storage areas.
106 If VariableName is an empty string, then we just return the first
107 qualified variable without comparing VariableName and VendorGuid.
108 Otherwise, VariableName and VendorGuid are compared.
109
110 @param VariableName Name of the variable to be found.
111 @param VendorGuid Vendor GUID to be found.
112 @param PtrTrack VARIABLE_POINTER_TRACK structure for output,
113 including the range searched and the target position.
114 @param Global Pointer to VARIABLE_GLOBAL structure, including
115 base of volatile variable storage area, base of
116 NV variable storage area, and a lock.
117
118 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
119 VendorGuid is NULL.
120 @retval EFI_SUCCESS Variable successfully found.
121 @retval EFI_NOT_FOUND Variable not found.
122
123**/
124EFI_STATUS
125FindVariable (
126 IN CHAR16 *VariableName,
127 IN EFI_GUID *VendorGuid,
128 OUT VARIABLE_POINTER_TRACK *PtrTrack,
129 IN VARIABLE_GLOBAL *Global
130 );
131
132/**
133 Acquires lock only at boot time. Simply returns at runtime.
134
135 This is a temperary function which will be removed when
136 EfiAcquireLock() in UefiLib can handle the call in UEFI
137 Runtimer driver in RT phase.
138 It calls EfiAcquireLock() at boot time, and simply returns
139 at runtime
140
141 @param Lock A pointer to the lock to acquire
142
143**/
144VOID
145AcquireLockOnlyAtBootTime (
146 IN EFI_LOCK *Lock
147 )
148{
149 if (!EfiAtRuntime ()) {
150 EfiAcquireLock (Lock);
151 }
152}
153
154/**
155 Releases lock only at boot time. Simply returns at runtime.
156
157 This is a temperary function which will be removed when
158 EfiReleaseLock() in UefiLib can handle the call in UEFI
159 Runtimer driver in RT phase.
160 It calls EfiReleaseLock() at boot time, and simply returns
161 at runtime
162
163 @param Lock A pointer to the lock to release
164
165**/
166VOID
167ReleaseLockOnlyAtBootTime (
168 IN EFI_LOCK *Lock
169 )
170{
171 if (!EfiAtRuntime ()) {
172 EfiReleaseLock (Lock);
173 }
174}
175
176/**
177 Gets pointer to the variable data.
178
179 This function gets the pointer to the variable data according
180 to the input pointer to the variable header.
181
182 @param Variable Pointer to the variable header.
183
184 @return Pointer to variable data
185
186**/
187UINT8 *
188GetVariableDataPtr (
189 IN VARIABLE_HEADER *Variable
190 )
191{
192 if (Variable->StartId != VARIABLE_DATA) {
193 return NULL;
194 }
195 //
196 // Be careful about pad size for alignment
197 //
198 return (UINT8 *) ((UINTN) GET_VARIABLE_NAME_PTR (Variable) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize));
199}
200
201/**
202 Gets pointer to header of the next potential variable.
203
204 This function gets the pointer to the next potential variable header
205 according to the input point to the variable header. The return value
206 is not a valid variable if the input variable was the last variable
207 in the variabl store.
208
209 @param Variable Pointer to header of the next variable
210
211 @return Pointer to next variable header.
212 @retval NULL Input was not a valid variable header.
213
214**/
215VARIABLE_HEADER *
216GetNextPotentialVariablePtr (
217 IN VARIABLE_HEADER *Variable
218 )
219{
220 VARIABLE_HEADER *VarHeader;
221
222 if (Variable->StartId != VARIABLE_DATA) {
223 return NULL;
224 }
225 //
226 // Be careful about pad size for alignment
227 //
228 VarHeader = (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) GetVariableDataPtr (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize));
229
230 return VarHeader;
231}
232
233/**
234 Gets pointer to header of the next variable.
235
236 This function gets the pointer to the next variable header according
237 to the input point to the variable header.
238
239 @param Variable Pointer to header of the next variable
240
241 @return Pointer to next variable header.
242
243**/
244VARIABLE_HEADER *
245GetNextVariablePtr (
246 IN VARIABLE_HEADER *Variable
247 )
248{
249 VARIABLE_HEADER *VarHeader;
250
251 VarHeader = GetNextPotentialVariablePtr (Variable);
252
253 if ((VarHeader == NULL) || (VarHeader->StartId != VARIABLE_DATA)) {
254 return NULL;
255 }
256
257 return VarHeader;
258}
259
260/**
261 Updates LastVariableOffset variable for the given variable store.
262
263 LastVariableOffset points to the offset to use for the next variable
264 when updating the variable store.
265
266 @param[in] VariableStore Pointer to the start of the variable store
267 @param[out] LastVariableOffset Offset to put the next new variable in
268
269**/
270VOID
271InitializeLocationForLastVariableOffset (
272 IN VARIABLE_STORE_HEADER *VariableStore,
273 OUT UINTN *LastVariableOffset
274 )
275{
276 VARIABLE_HEADER *VarHeader;
277
278 *LastVariableOffset = sizeof (VARIABLE_STORE_HEADER);
279 VarHeader = (VARIABLE_HEADER*) ((UINT8*)VariableStore + *LastVariableOffset);
280 while (VarHeader->StartId == VARIABLE_DATA) {
281 VarHeader = GetNextPotentialVariablePtr (VarHeader);
282
283 if (VarHeader != NULL) {
284 *LastVariableOffset = (UINTN) VarHeader - (UINTN) VariableStore;
285 } else {
286 return;
287 }
288 }
289}
290
291/**
292 Gets pointer to the end of the variable storage area.
293
294 This function gets pointer to the end of the variable storage
295 area, according to the input variable store header.
296
297 @param VolHeader Pointer to the variale store header
298
299 @return Pointer to the end of the variable storage area.
300
301**/
302VARIABLE_HEADER *
303GetEndPointer (
304 IN VARIABLE_STORE_HEADER *VolHeader
305 )
306{
307 //
308 // The end of variable store
309 //
310 return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VolHeader + VolHeader->Size);
311}
312
313/**
314 Routine used to track statistical information about variable usage.
315 The data is stored in the EFI system table so it can be accessed later.
316 VariableInfo.efi can dump out the table. Only Boot Services variable
317 accesses are tracked by this code. The PcdVariableCollectStatistics
318 build flag controls if this feature is enabled.
319
320 A read that hits in the cache will have Read and Cache true for
321 the transaction. Data is allocated by this routine, but never
322 freed.
323
324 @param[in] VariableName Name of the Variable to track
325 @param[in] VendorGuid Guid of the Variable to track
326 @param[in] Volatile TRUE if volatile FALSE if non-volatile
327 @param[in] Read TRUE if GetVariable() was called
328 @param[in] Write TRUE if SetVariable() was called
329 @param[in] Delete TRUE if deleted via SetVariable()
330 @param[in] Cache TRUE for a cache hit.
331
332**/
333VOID
334UpdateVariableInfo (
335 IN CHAR16 *VariableName,
336 IN EFI_GUID *VendorGuid,
337 IN BOOLEAN Volatile,
338 IN BOOLEAN Read,
339 IN BOOLEAN Write,
340 IN BOOLEAN Delete,
341 IN BOOLEAN Cache
342 )
343{
344 VARIABLE_INFO_ENTRY *Entry;
345
346 if (FeaturePcdGet (PcdVariableCollectStatistics)) {
347
348 if (EfiAtRuntime ()) {
349 // Don't collect statistics at runtime
350 return;
351 }
352
353 if (gVariableInfo == NULL) {
354 //
355 // on the first call allocate a entry and place a pointer to it in
356 // the EFI System Table
357 //
358 gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
359 ASSERT (gVariableInfo != NULL);
360
361 CopyGuid (&gVariableInfo->VendorGuid, VendorGuid);
362 gVariableInfo->Name = AllocatePool (StrSize (VariableName));
363 ASSERT (gVariableInfo->Name != NULL);
364 StrCpy (gVariableInfo->Name, VariableName);
365 gVariableInfo->Volatile = Volatile;
366
367 gBS->InstallConfigurationTable (&gEfiVariableGuid, gVariableInfo);
368 }
369
370
371 for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) {
372 if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {
373 if (StrCmp (VariableName, Entry->Name) == 0) {
374 if (Read) {
375 Entry->ReadCount++;
376 }
377 if (Write) {
378 Entry->WriteCount++;
379 }
380 if (Delete) {
381 Entry->DeleteCount++;
382 }
383 if (Cache) {
384 Entry->CacheCount++;
385 }
386
387 return;
388 }
389 }
390
391 if (Entry->Next == NULL) {
392 //
393 // If the entry is not in the table add it.
394 // Next iteration of the loop will fill in the data
395 //
396 Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
397 ASSERT (Entry->Next != NULL);
398
399 CopyGuid (&Entry->Next->VendorGuid, VendorGuid);
400 Entry->Next->Name = AllocatePool (StrSize (VariableName));
401 ASSERT (Entry->Next->Name != NULL);
402 StrCpy (Entry->Next->Name, VariableName);
403 Entry->Next->Volatile = Volatile;
404 }
405
406 }
407 }
408}
409
410/**
411 Get index from supported language codes according to language string.
412
413 This code is used to get corresponding index in supported language codes. It can handle
414 RFC4646 and ISO639 language tags.
415 In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.
416 In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.
417
418 For example:
419 SupportedLang = "engfraengfra"
420 Lang = "eng"
421 Iso639Language = TRUE
422 The return value is "0".
423 Another example:
424 SupportedLang = "en;fr;en-US;fr-FR"
425 Lang = "fr-FR"
426 Iso639Language = FALSE
427 The return value is "3".
428
429 @param SupportedLang Platform supported language codes.
430 @param Lang Configured language.
431 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
432
433 @retval the index of language in the language codes.
434
435**/
436UINTN
437GetIndexFromSupportedLangCodes(
438 IN CHAR8 *SupportedLang,
439 IN CHAR8 *Lang,
440 IN BOOLEAN Iso639Language
441 )
442{
443 UINTN Index;
444 UINTN CompareLength;
445 UINTN LanguageLength;
446
447 if (Iso639Language) {
448 CompareLength = ISO_639_2_ENTRY_SIZE;
449 for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {
450 if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {
451 //
452 // Successfully find the index of Lang string in SupportedLang string.
453 //
454 Index = Index / CompareLength;
455 return Index;
456 }
457 }
458 ASSERT (FALSE);
459 return 0;
460 } else {
461 //
462 // Compare RFC4646 language code
463 //
464 Index = 0;
465 for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++);
466
467 for (Index = 0; *SupportedLang != '\0'; Index++, SupportedLang += CompareLength) {
468 //
469 // Skip ';' characters in SupportedLang
470 //
471 for (; *SupportedLang != '\0' && *SupportedLang == ';'; SupportedLang++);
472 //
473 // Determine the length of the next language code in SupportedLang
474 //
475 for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++);
476
477 if ((CompareLength == LanguageLength) &&
478 (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0)) {
479 //
480 // Successfully find the index of Lang string in SupportedLang string.
481 //
482 return Index;
483 }
484 }
485 ASSERT (FALSE);
486 return 0;
487 }
488}
489
490/**
491 Get language string from supported language codes according to index.
492
493 This code is used to get corresponding language string in supported language codes. It can handle
494 RFC4646 and ISO639 language tags.
495 In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.
496 In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.
497
498 For example:
499 SupportedLang = "engfraengfra"
500 Index = "1"
501 Iso639Language = TRUE
502 The return value is "fra".
503 Another example:
504 SupportedLang = "en;fr;en-US;fr-FR"
505 Index = "1"
506 Iso639Language = FALSE
507 The return value is "fr".
508
509 @param SupportedLang Platform supported language codes.
510 @param Index the index in supported language codes.
511 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
512
513 @retval the language string in the language codes.
514
515**/
516CHAR8 *
517GetLangFromSupportedLangCodes (
518 IN CHAR8 *SupportedLang,
519 IN UINTN Index,
520 IN BOOLEAN Iso639Language
521)
522{
523 UINTN SubIndex;
524 UINTN CompareLength;
525 CHAR8 *Supported;
526
527 SubIndex = 0;
528 Supported = SupportedLang;
529 if (Iso639Language) {
530 //
531 // according to the index of Lang string in SupportedLang string to get the language.
532 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
533 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
534 //
535 CompareLength = ISO_639_2_ENTRY_SIZE;
536 mVariableModuleGlobal->Lang[CompareLength] = '\0';
537 return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength);
538
539 } else {
540 while (TRUE) {
541 //
542 // take semicolon as delimitation, sequentially traverse supported language codes.
543 //
544 for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {
545 Supported++;
546 }
547 if ((*Supported == '\0') && (SubIndex != Index)) {
548 //
549 // Have completed the traverse, but not find corrsponding string.
550 // This case is not allowed to happen.
551 //
552 ASSERT(FALSE);
553 return NULL;
554 }
555 if (SubIndex == Index) {
556 //
557 // according to the index of Lang string in SupportedLang string to get the language.
558 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.
559 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.
560 //
561 mVariableModuleGlobal->PlatformLang[CompareLength] = '\0';
562 return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - CompareLength, CompareLength);
563 }
564 SubIndex++;
565
566 //
567 // Skip ';' characters in Supported
568 //
569 for (; *Supported != '\0' && *Supported == ';'; Supported++);
570 }
571 }
572}
573
574/**
575 Returns a pointer to an allocated buffer that contains the best matching language
576 from a set of supported languages.
577
578 This function supports both ISO 639-2 and RFC 4646 language codes, but language
579 code types may not be mixed in a single call to this function. This function
580 supports a variable argument list that allows the caller to pass in a prioritized
581 list of language codes to test against all the language codes in SupportedLanguages.
582
583 If SupportedLanguages is NULL, then ASSERT().
584
585 @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that
586 contains a set of language codes in the format
587 specified by Iso639Language.
588 @param[in] Iso639Language If TRUE, then all language codes are assumed to be
589 in ISO 639-2 format. If FALSE, then all language
590 codes are assumed to be in RFC 4646 language format
591 @param[in] ... A variable argument list that contains pointers to
592 Null-terminated ASCII strings that contain one or more
593 language codes in the format specified by Iso639Language.
594 The first language code from each of these language
595 code lists is used to determine if it is an exact or
596 close match to any of the language codes in
597 SupportedLanguages. Close matches only apply to RFC 4646
598 language codes, and the matching algorithm from RFC 4647
599 is used to determine if a close match is present. If
600 an exact or close match is found, then the matching
601 language code from SupportedLanguages is returned. If
602 no matches are found, then the next variable argument
603 parameter is evaluated. The variable argument list
604 is terminated by a NULL.
605
606 @retval NULL The best matching language could not be found in SupportedLanguages.
607 @retval NULL There are not enough resources available to return the best matching
608 language.
609 @retval Other A pointer to a Null-terminated ASCII string that is the best matching
610 language in SupportedLanguages.
611
612**/
613CHAR8 *
614EFIAPI
615VariableGetBestLanguage (
616 IN CONST CHAR8 *SupportedLanguages,
617 IN BOOLEAN Iso639Language,
618 ...
619 )
620{
621 VA_LIST Args;
622 CHAR8 *Language;
623 UINTN CompareLength;
624 UINTN LanguageLength;
625 CONST CHAR8 *Supported;
626 CHAR8 *Buffer;
627
628 ASSERT (SupportedLanguages != NULL);
629
630 VA_START (Args, Iso639Language);
631 while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {
632 //
633 // Default to ISO 639-2 mode
634 //
635 CompareLength = 3;
636 LanguageLength = MIN (3, AsciiStrLen (Language));
637
638 //
639 // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language
640 //
641 if (!Iso639Language) {
642 for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++);
643 }
644
645 //
646 // Trim back the length of Language used until it is empty
647 //
648 while (LanguageLength > 0) {
649 //
650 // Loop through all language codes in SupportedLanguages
651 //
652 for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {
653 //
654 // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages
655 //
656 if (!Iso639Language) {
657 //
658 // Skip ';' characters in Supported
659 //
660 for (; *Supported != '\0' && *Supported == ';'; Supported++);
661 //
662 // Determine the length of the next language code in Supported
663 //
664 for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++);
665 //
666 // If Language is longer than the Supported, then skip to the next language
667 //
668 if (LanguageLength > CompareLength) {
669 continue;
670 }
671 }
672 //
673 // See if the first LanguageLength characters in Supported match Language
674 //
675 if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {
676 VA_END (Args);
677
678 Buffer = Iso639Language ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang;
679 Buffer[CompareLength] = '\0';
680 return CopyMem (Buffer, Supported, CompareLength);
681 }
682 }
683
684 if (Iso639Language) {
685 //
686 // If ISO 639 mode, then each language can only be tested once
687 //
688 LanguageLength = 0;
689 } else {
690 //
691 // If RFC 4646 mode, then trim Language from the right to the next '-' character
692 //
693 for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--);
694 }
695 }
696 }
697 VA_END (Args);
698
699 //
700 // No matches were found
701 //
702 return NULL;
703}
704
705/**
706 Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.
707
708 When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.
709
710 According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,
711 and are read-only. Therefore, in variable driver, only store the original value for other use.
712
713 @param[in] VariableName Name of variable
714
715 @param[in] Data Variable data
716
717 @param[in] DataSize Size of data. 0 means delete
718
719**/
720VOID
721AutoUpdateLangVariable(
722 IN CHAR16 *VariableName,
723 IN VOID *Data,
724 IN UINTN DataSize
725 )
726{
727 EFI_STATUS Status;
728 CHAR8 *BestPlatformLang;
729 CHAR8 *BestLang;
730 UINTN Index;
731 UINT32 Attributes;
732 VARIABLE_POINTER_TRACK Variable;
733 BOOLEAN SetLanguageCodes;
734
735 //
736 // Don't do updates for delete operation
737 //
738 if (DataSize == 0) {
739 return;
740 }
741
742 SetLanguageCodes = FALSE;
743
744 if (StrCmp (VariableName, L"PlatformLangCodes") == 0) {
745 //
746 // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.
747 //
748 if (EfiAtRuntime ()) {
749 return;
750 }
751
752 SetLanguageCodes = TRUE;
753
754 //
755 // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only
756 // Therefore, in variable driver, only store the original value for other use.
757 //
758 if (mVariableModuleGlobal->PlatformLangCodes != NULL) {
759 FreePool (mVariableModuleGlobal->PlatformLangCodes);
760 }
761 mVariableModuleGlobal->PlatformLangCodes = AllocateRuntimeCopyPool (DataSize, Data);
762 ASSERT (mVariableModuleGlobal->PlatformLangCodes != NULL);
763
764 //
765 // PlatformLang holds a single language from PlatformLangCodes,
766 // so the size of PlatformLangCodes is enough for the PlatformLang.
767 //
768 if (mVariableModuleGlobal->PlatformLang != NULL) {
769 FreePool (mVariableModuleGlobal->PlatformLang);
770 }
771 mVariableModuleGlobal->PlatformLang = AllocateRuntimePool (DataSize);
772 ASSERT (mVariableModuleGlobal->PlatformLang != NULL);
773
774 } else if (StrCmp (VariableName, L"LangCodes") == 0) {
775 //
776 // LangCodes is a volatile variable, so it can not be updated at runtime.
777 //
778 if (EfiAtRuntime ()) {
779 return;
780 }
781
782 SetLanguageCodes = TRUE;
783
784 //
785 // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only
786 // Therefore, in variable driver, only store the original value for other use.
787 //
788 if (mVariableModuleGlobal->LangCodes != NULL) {
789 FreePool (mVariableModuleGlobal->LangCodes);
790 }
791 mVariableModuleGlobal->LangCodes = AllocateRuntimeCopyPool (DataSize, Data);
792 ASSERT (mVariableModuleGlobal->LangCodes != NULL);
793 }
794
795 if (SetLanguageCodes
796 && (mVariableModuleGlobal->PlatformLangCodes != NULL)
797 && (mVariableModuleGlobal->LangCodes != NULL)) {
798 //
799 // Update Lang if PlatformLang is already set
800 // Update PlatformLang if Lang is already set
801 //
802 Status = FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *) mVariableModuleGlobal);
803 if (!EFI_ERROR (Status)) {
804 //
805 // Update Lang
806 //
807 VariableName = L"PlatformLang";
808 Data = GetVariableDataPtr (Variable.CurrPtr);
809 DataSize = Variable.CurrPtr->DataSize;
810 } else {
811 Status = FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *) mVariableModuleGlobal);
812 if (!EFI_ERROR (Status)) {
813 //
814 // Update PlatformLang
815 //
816 VariableName = L"Lang";
817 Data = GetVariableDataPtr (Variable.CurrPtr);
818 DataSize = Variable.CurrPtr->DataSize;
819 } else {
820 //
821 // Neither PlatformLang nor Lang is set, directly return
822 //
823 return;
824 }
825 }
826 }
827
828 //
829 // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.
830 //
831 Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
832
833 if (StrCmp (VariableName, L"PlatformLang") == 0) {
834 //
835 // Update Lang when PlatformLangCodes/LangCodes were set.
836 //
837 if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {
838 //
839 // When setting PlatformLang, firstly get most matched language string from supported language codes.
840 //
841 BestPlatformLang = VariableGetBestLanguage (mVariableModuleGlobal->PlatformLangCodes, FALSE, Data, NULL);
842 if (BestPlatformLang != NULL) {
843 //
844 // Get the corresponding index in language codes.
845 //
846 Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, BestPlatformLang, FALSE);
847
848 //
849 // Get the corresponding ISO639 language tag according to RFC4646 language tag.
850 //
851 BestLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, Index, TRUE);
852
853 //
854 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.
855 //
856 FindVariable (L"Lang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal);
857
858 Status = UpdateVariable (L"Lang", &gEfiGlobalVariableGuid, BestLang, ISO_639_2_ENTRY_SIZE + 1, Attributes, &Variable);
859
860 DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang));
861
862 ASSERT_EFI_ERROR(Status);
863 }
864 }
865
866 } else if (StrCmp (VariableName, L"Lang") == 0) {
867 //
868 // Update PlatformLang when PlatformLangCodes/LangCodes were set.
869 //
870 if ((mVariableModuleGlobal->PlatformLangCodes != NULL) && (mVariableModuleGlobal->LangCodes != NULL)) {
871 //
872 // When setting Lang, firstly get most matched language string from supported language codes.
873 //
874 BestLang = VariableGetBestLanguage (mVariableModuleGlobal->LangCodes, TRUE, Data, NULL);
875 if (BestLang != NULL) {
876 //
877 // Get the corresponding index in language codes.
878 //
879 Index = GetIndexFromSupportedLangCodes (mVariableModuleGlobal->LangCodes, BestLang, TRUE);
880
881 //
882 // Get the corresponding RFC4646 language tag according to ISO639 language tag.
883 //
884 BestPlatformLang = GetLangFromSupportedLangCodes (mVariableModuleGlobal->PlatformLangCodes, Index, FALSE);
885
886 //
887 // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.
888 //
889 FindVariable (L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal);
890
891 Status = UpdateVariable (L"PlatformLang", &gEfiGlobalVariableGuid, BestPlatformLang,
892 AsciiStrSize (BestPlatformLang), Attributes, &Variable);
893
894 DEBUG ((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a\n", BestLang, BestPlatformLang));
895 ASSERT_EFI_ERROR (Status);
896 }
897 }
898 }
899}
900
901/**
902 Update the variable region with Variable information. These are the same
903 arguments as the EFI Variable services.
904
905 @param[in] VariableName Name of variable
906
907 @param[in] VendorGuid Guid of variable
908
909 @param[in] Data Variable data
910
911 @param[in] DataSize Size of data. 0 means delete
912
913 @param[in] Attributes Attribues of the variable
914
915 @param[in] Variable The variable information which is used to keep track of variable usage.
916
917 @retval EFI_SUCCESS The update operation is success.
918
919 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.
920
921**/
922EFI_STATUS
923EFIAPI
924UpdateVariable (
925 IN CHAR16 *VariableName,
926 IN EFI_GUID *VendorGuid,
927 IN VOID *Data,
928 IN UINTN DataSize,
929 IN UINT32 Attributes OPTIONAL,
930 IN VARIABLE_POINTER_TRACK *Variable
931 )
932{
933 EFI_STATUS Status;
934 VARIABLE_HEADER *NextVariable;
935 UINTN VarNameSize;
936 UINTN VarNameOffset;
937 UINTN VarDataOffset;
938 UINTN VarSize;
939 VARIABLE_GLOBAL *Global;
940 UINTN NonVolatileVarableStoreSize;
941
942 Global = &mVariableModuleGlobal->VariableGlobal[Physical];
943
944 if (Variable->CurrPtr != NULL) {
945 //
946 // Update/Delete existing variable
947 //
948
949 if (EfiAtRuntime ()) {
950 //
951 // If EfiAtRuntime and the variable is Volatile and Runtime Access,
952 // the volatile is ReadOnly, and SetVariable should be aborted and
953 // return EFI_WRITE_PROTECTED.
954 //
955 if (Variable->Volatile) {
956 Status = EFI_WRITE_PROTECTED;
957 goto Done;
958 }
959 //
960 // Only variable have NV attribute can be updated/deleted in Runtime
961 //
962 if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
963 Status = EFI_INVALID_PARAMETER;
964 goto Done;
965 }
966 }
967
968 //
969 // Setting a data variable with no access, or zero DataSize attributes
970 // specified causes it to be deleted.
971 //
972 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
973 Variable->CurrPtr->State &= VAR_DELETED;
974 UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, FALSE, TRUE, FALSE);
975 Status = EFI_SUCCESS;
976 goto Done;
977 }
978
979 //
980 // If the variable is marked valid and the same data has been passed in
981 // then return to the caller immediately.
982 //
983 if (Variable->CurrPtr->DataSize == DataSize &&
984 CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0
985 ) {
986 Status = EFI_SUCCESS;
987 goto Done;
988 } else if (Variable->CurrPtr->State == VAR_ADDED) {
989 //
990 // Mark the old variable as in delete transition
991 //
992 Variable->CurrPtr->State &= VAR_IN_DELETED_TRANSITION;
993 }
994
995 } else {
996 //
997 // No found existing variable, Create a new variable
998 //
999
1000 //
1001 // Make sure we are trying to create a new variable.
1002 // Setting a data variable with no access, or zero DataSize attributes means to delete it.
1003 //
1004 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
1005 Status = EFI_NOT_FOUND;
1006 goto Done;
1007 }
1008
1009 //
1010 // Only variable have NV|RT attribute can be created in Runtime
1011 //
1012 if (EfiAtRuntime () &&
1013 (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {
1014 Status = EFI_INVALID_PARAMETER;
1015 goto Done;
1016 }
1017 }
1018
1019 //
1020 // Function part - create a new variable and copy the data.
1021 // Both update a variable and create a variable will come here.
1022 //
1023
1024 VarNameOffset = sizeof (VARIABLE_HEADER);
1025 VarNameSize = StrSize (VariableName);
1026 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);
1027 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
1028
1029 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
1030 NonVolatileVarableStoreSize = ((VARIABLE_STORE_HEADER *)(UINTN)(Global->NonVolatileVariableBase))->Size;
1031 if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0)
1032 && ((HEADER_ALIGN (VarSize) + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))
1033 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0)
1034 && ((HEADER_ALIGN (VarSize) + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize)))) {
1035 Status = EFI_OUT_OF_RESOURCES;
1036 goto Done;
1037 }
1038
1039 NextVariable = (VARIABLE_HEADER *) (UINT8 *) (mVariableModuleGlobal->NonVolatileLastVariableOffset
1040 + (UINTN) Global->NonVolatileVariableBase);
1041 mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);
1042
1043 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {
1044 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);
1045 } else {
1046 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);
1047 }
1048 } else {
1049 if ((UINT32) (HEADER_ALIGN (VarSize) + mVariableModuleGlobal->VolatileLastVariableOffset) >
1050 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size
1051 ) {
1052 Status = EFI_OUT_OF_RESOURCES;
1053 goto Done;
1054 }
1055
1056 NextVariable = (VARIABLE_HEADER *) (UINT8 *) (mVariableModuleGlobal->VolatileLastVariableOffset
1057 + (UINTN) Global->VolatileVariableBase);
1058 mVariableModuleGlobal->VolatileLastVariableOffset += HEADER_ALIGN (VarSize);
1059 }
1060
1061 NextVariable->StartId = VARIABLE_DATA;
1062 NextVariable->Attributes = Attributes;
1063 NextVariable->State = VAR_ADDED;
1064 NextVariable->Reserved = 0;
1065
1066 //
1067 // There will be pad bytes after Data, the NextVariable->NameSize and
1068 // NextVariable->NameSize should not include pad size so that variable
1069 // service can get actual size in GetVariable
1070 //
1071 NextVariable->NameSize = (UINT32)VarNameSize;
1072 NextVariable->DataSize = (UINT32)DataSize;
1073
1074 CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));
1075 CopyMem (
1076 (UINT8 *) ((UINTN) NextVariable + VarNameOffset),
1077 VariableName,
1078 VarNameSize
1079 );
1080 CopyMem (
1081 (UINT8 *) ((UINTN) NextVariable + VarDataOffset),
1082 Data,
1083 DataSize
1084 );
1085
1086 //
1087 // Mark the old variable as deleted
1088 //
1089 if (Variable->CurrPtr != NULL) {
1090 Variable->CurrPtr->State &= VAR_DELETED;
1091 }
1092
1093 UpdateVariableInfo (VariableName, VendorGuid, Variable->Volatile, FALSE, TRUE, FALSE, FALSE);
1094
1095 Status = EFI_SUCCESS;
1096
1097Done:
1098 return Status;
1099}
1100
1101/**
1102 Finds variable in storage blocks of volatile and non-volatile storage areas.
1103
1104 This code finds variable in storage blocks of volatile and non-volatile storage areas.
1105 If VariableName is an empty string, then we just return the first
1106 qualified variable without comparing VariableName and VendorGuid.
1107 Otherwise, VariableName and VendorGuid are compared.
1108
1109 @param VariableName Name of the variable to be found.
1110 @param VendorGuid Vendor GUID to be found.
1111 @param PtrTrack VARIABLE_POINTER_TRACK structure for output,
1112 including the range searched and the target position.
1113 @param Global Pointer to VARIABLE_GLOBAL structure, including
1114 base of volatile variable storage area, base of
1115 NV variable storage area, and a lock.
1116
1117 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
1118 VendorGuid is NULL.
1119 @retval EFI_SUCCESS Variable successfully found.
1120 @retval EFI_NOT_FOUND Variable not found.
1121
1122**/
1123EFI_STATUS
1124FindVariable (
1125 IN CHAR16 *VariableName,
1126 IN EFI_GUID *VendorGuid,
1127 OUT VARIABLE_POINTER_TRACK *PtrTrack,
1128 IN VARIABLE_GLOBAL *Global
1129 )
1130{
1131 VARIABLE_HEADER *Variable[2];
1132 VARIABLE_STORE_HEADER *VariableStoreHeader[2];
1133 UINTN Index;
1134
1135 //
1136 // 0: Non-Volatile, 1: Volatile
1137 //
1138 VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase);
1139 VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);
1140
1141 //
1142 // Start Pointers for the variable.
1143 // Actual Data Pointer where data can be written.
1144 //
1145 Variable[0] = (VARIABLE_HEADER *) HEADER_ALIGN (VariableStoreHeader[0] + 1);
1146 Variable[1] = (VARIABLE_HEADER *) HEADER_ALIGN (VariableStoreHeader[1] + 1);
1147
1148 if (VariableName[0] != 0 && VendorGuid == NULL) {
1149 return EFI_INVALID_PARAMETER;
1150 }
1151 //
1152 // Find the variable by walk through non-volatile and volatile variable store
1153 //
1154 for (Index = 0; Index < 2; Index++) {
1155 PtrTrack->StartPtr = (VARIABLE_HEADER *) HEADER_ALIGN (VariableStoreHeader[Index] + 1);
1156 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]);
1157
1158 while ((Variable[Index] < GetEndPointer (VariableStoreHeader[Index])) && (Variable[Index] != NULL)) {
1159 if (Variable[Index]->StartId == VARIABLE_DATA && Variable[Index]->State == VAR_ADDED) {
1160 if (!(EfiAtRuntime () && ((Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0))) {
1161 if (VariableName[0] == 0) {
1162 PtrTrack->CurrPtr = Variable[Index];
1163 PtrTrack->Volatile = (BOOLEAN) Index;
1164 return EFI_SUCCESS;
1165 } else {
1166 if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) {
1167 if (CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable[Index]), Variable[Index]->NameSize) == 0) {
1168 PtrTrack->CurrPtr = Variable[Index];
1169 PtrTrack->Volatile = (BOOLEAN) Index;
1170 return EFI_SUCCESS;
1171 }
1172 }
1173 }
1174 }
1175 }
1176
1177 Variable[Index] = GetNextVariablePtr (Variable[Index]);
1178 }
1179 }
1180 PtrTrack->CurrPtr = NULL;
1181 return EFI_NOT_FOUND;
1182}
1183
1184/**
1185 This code finds variable in storage blocks (Volatile or Non-Volatile).
1186
1187 @param VariableName A Null-terminated Unicode string that is the name of
1188 the vendor's variable.
1189 @param VendorGuid A unique identifier for the vendor.
1190 @param Attributes If not NULL, a pointer to the memory location to return the
1191 attributes bitmask for the variable.
1192 @param DataSize Size of Data found. If size is less than the
1193 data, this value contains the required size.
1194 @param Data On input, the size in bytes of the return Data buffer.
1195 On output, the size of data returned in Data.
1196 @param Global Pointer to VARIABLE_GLOBAL structure
1197
1198 @retval EFI_SUCCESS The function completed successfully.
1199 @retval EFI_NOT_FOUND The variable was not found.
1200 @retval EFI_BUFFER_TOO_SMALL DataSize is too small for the result. DataSize has
1201 been updated with the size needed to complete the request.
1202 @retval EFI_INVALID_PARAMETER VariableName or VendorGuid or DataSize is NULL.
1203
1204**/
1205EFI_STATUS
1206EFIAPI
1207EmuGetVariable (
1208 IN CHAR16 *VariableName,
1209 IN EFI_GUID *VendorGuid,
1210 OUT UINT32 *Attributes OPTIONAL,
1211 IN OUT UINTN *DataSize,
1212 OUT VOID *Data,
1213 IN VARIABLE_GLOBAL *Global
1214 )
1215{
1216 VARIABLE_POINTER_TRACK Variable;
1217 UINTN VarDataSize;
1218 EFI_STATUS Status;
1219 UINT8 *VariableDataPtr;
1220
1221 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
1222 return EFI_INVALID_PARAMETER;
1223 }
1224
1225 AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);
1226
1227 //
1228 // Find existing variable
1229 //
1230 Status = FindVariable (VariableName, VendorGuid, &Variable, Global);
1231
1232 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
1233 goto Done;
1234 }
1235 //
1236 // Get data size
1237 //
1238 VarDataSize = Variable.CurrPtr->DataSize;
1239 if (*DataSize >= VarDataSize) {
1240 if (Data == NULL) {
1241 Status = EFI_INVALID_PARAMETER;
1242 goto Done;
1243 }
1244 VariableDataPtr = GetVariableDataPtr (Variable.CurrPtr);
1245 ASSERT (VariableDataPtr != NULL);
1246
1247 CopyMem (Data, VariableDataPtr, VarDataSize);
1248 if (Attributes != NULL) {
1249 *Attributes = Variable.CurrPtr->Attributes;
1250 }
1251
1252 *DataSize = VarDataSize;
1253 UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);
1254 Status = EFI_SUCCESS;
1255 goto Done;
1256 } else {
1257 *DataSize = VarDataSize;
1258 Status = EFI_BUFFER_TOO_SMALL;
1259 goto Done;
1260 }
1261
1262Done:
1263 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
1264 return Status;
1265}
1266
1267/**
1268
1269 This code Finds the Next available variable.
1270
1271 @param VariableNameSize Size of the variable.
1272 @param VariableName On input, supplies the last VariableName that was returned by GetNextVariableName().
1273 On output, returns the Null-terminated Unicode string of the current variable.
1274 @param VendorGuid On input, supplies the last VendorGuid that was returned by GetNextVariableName().
1275 On output, returns the VendorGuid of the current variable.
1276 @param Global Pointer to VARIABLE_GLOBAL structure.
1277
1278 @retval EFI_SUCCESS The function completed successfully.
1279 @retval EFI_NOT_FOUND The next variable was not found.
1280 @retval EFI_BUFFER_TOO_SMALL VariableNameSize is too small for the result.
1281 VariableNameSize has been updated with the size needed to complete the request.
1282 @retval EFI_INVALID_PARAMETER VariableNameSize or VariableName or VendorGuid is NULL.
1283
1284**/
1285EFI_STATUS
1286EFIAPI
1287EmuGetNextVariableName (
1288 IN OUT UINTN *VariableNameSize,
1289 IN OUT CHAR16 *VariableName,
1290 IN OUT EFI_GUID *VendorGuid,
1291 IN VARIABLE_GLOBAL *Global
1292 )
1293{
1294 VARIABLE_POINTER_TRACK Variable;
1295 UINTN VarNameSize;
1296 EFI_STATUS Status;
1297
1298 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
1299 return EFI_INVALID_PARAMETER;
1300 }
1301
1302 AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);
1303
1304 Status = FindVariable (VariableName, VendorGuid, &Variable, Global);
1305
1306 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
1307 goto Done;
1308 }
1309
1310 while (TRUE) {
1311 if (VariableName[0] != 0) {
1312 //
1313 // If variable name is not NULL, get next variable
1314 //
1315 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
1316 }
1317 //
1318 // If both volatile and non-volatile variable store are parsed,
1319 // return not found
1320 //
1321 if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) {
1322 Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));
1323 if (Variable.Volatile) {
1324 Variable.StartPtr = (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) (Global->VolatileVariableBase + sizeof (VARIABLE_STORE_HEADER)));
1325 Variable.EndPtr = (VARIABLE_HEADER *) GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase));
1326 } else {
1327 Status = EFI_NOT_FOUND;
1328 goto Done;
1329 }
1330
1331 Variable.CurrPtr = Variable.StartPtr;
1332 if (Variable.CurrPtr->StartId != VARIABLE_DATA) {
1333 continue;
1334 }
1335 }
1336 //
1337 // Variable is found
1338 //
1339 if (Variable.CurrPtr->StartId == VARIABLE_DATA && Variable.CurrPtr->State == VAR_ADDED) {
1340 if (!(EfiAtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0))) {
1341 VarNameSize = Variable.CurrPtr->NameSize;
1342 if (VarNameSize <= *VariableNameSize) {
1343 CopyMem (
1344 VariableName,
1345 GET_VARIABLE_NAME_PTR (Variable.CurrPtr),
1346 VarNameSize
1347 );
1348 CopyMem (
1349 VendorGuid,
1350 &Variable.CurrPtr->VendorGuid,
1351 sizeof (EFI_GUID)
1352 );
1353 Status = EFI_SUCCESS;
1354 } else {
1355 Status = EFI_BUFFER_TOO_SMALL;
1356 }
1357
1358 *VariableNameSize = VarNameSize;
1359 goto Done;
1360 }
1361 }
1362 }
1363
1364Done:
1365 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
1366 return Status;
1367
1368}
1369
1370/**
1371
1372 This code sets variable in storage blocks (Volatile or Non-Volatile).
1373
1374 @param VariableName A Null-terminated Unicode string that is the name of the vendor's
1375 variable. Each VariableName is unique for each
1376 VendorGuid. VariableName must contain 1 or more
1377 Unicode characters. If VariableName is an empty Unicode
1378 string, then EFI_INVALID_PARAMETER is returned.
1379 @param VendorGuid A unique identifier for the vendor
1380 @param Attributes Attributes bitmask to set for the variable
1381 @param DataSize The size in bytes of the Data buffer. A size of zero causes the
1382 variable to be deleted.
1383 @param Data The contents for the variable
1384 @param Global Pointer to VARIABLE_GLOBAL structure
1385 @param VolatileOffset The offset of last volatile variable
1386 @param NonVolatileOffset The offset of last non-volatile variable
1387
1388 @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
1389 defined by the Attributes.
1390 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied, or the
1391 DataSize exceeds the maximum allowed, or VariableName is an empty
1392 Unicode string, or VendorGuid is NULL.
1393 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
1394 @retval EFI_DEVICE_ERROR The variable could not be saved due to a hardware failure.
1395 @retval EFI_WRITE_PROTECTED The variable in question is read-only or cannot be deleted.
1396 @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
1397
1398**/
1399EFI_STATUS
1400EFIAPI
1401EmuSetVariable (
1402 IN CHAR16 *VariableName,
1403 IN EFI_GUID *VendorGuid,
1404 IN UINT32 Attributes,
1405 IN UINTN DataSize,
1406 IN VOID *Data,
1407 IN VARIABLE_GLOBAL *Global,
1408 IN UINTN *VolatileOffset,
1409 IN UINTN *NonVolatileOffset
1410 )
1411{
1412 VARIABLE_POINTER_TRACK Variable;
1413 EFI_STATUS Status;
1414
1415 //
1416 // Check input parameters
1417 //
1418 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
1419 return EFI_INVALID_PARAMETER;
1420 }
1421
1422 if (DataSize != 0 && Data == NULL) {
1423 return EFI_INVALID_PARAMETER;
1424 }
1425
1426 //
1427 // Not support authenticated variable write yet.
1428 //
1429 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
1430 return EFI_INVALID_PARAMETER;
1431 }
1432
1433 //
1434 // Make sure if runtime bit is set, boot service bit is set also
1435 //
1436 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
1437 return EFI_INVALID_PARAMETER;
1438 }
1439 //
1440 // The size of the VariableName, including the Unicode Null in bytes plus
1441 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)
1442 // bytes for HwErrRec, and PcdGet32 (PcdMaxVariableSize) bytes for the others.
1443 //
1444 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1445 if ((DataSize > PcdGet32 (PcdMaxHardwareErrorVariableSize)) ||
1446 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxHardwareErrorVariableSize))) {
1447 return EFI_INVALID_PARAMETER;
1448 }
1449 //
1450 // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX"
1451 //
1452 if (StrnCmp(VariableName, L"HwErrRec", StrLen(L"HwErrRec")) != 0) {
1453 return EFI_INVALID_PARAMETER;
1454 }
1455 } else {
1456 //
1457 // The size of the VariableName, including the Unicode Null in bytes plus
1458 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxVariableSize) bytes.
1459 //
1460 if ((DataSize > PcdGet32 (PcdMaxVariableSize)) ||
1461 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxVariableSize))) {
1462 return EFI_INVALID_PARAMETER;
1463 }
1464 }
1465
1466 AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);
1467
1468 //
1469 // Check whether the input variable is already existed
1470 //
1471
1472 Status = FindVariable (VariableName, VendorGuid, &Variable, Global);
1473
1474 //
1475 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang
1476 //
1477 AutoUpdateLangVariable (VariableName, Data, DataSize);
1478
1479 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, &Variable);
1480
1481 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
1482 return Status;
1483}
1484
1485/**
1486
1487 This code returns information about the EFI variables.
1488
1489 @param Attributes Attributes bitmask to specify the type of variables
1490 on which to return information.
1491 @param MaximumVariableStorageSize On output the maximum size of the storage space available for
1492 the EFI variables associated with the attributes specified.
1493 @param RemainingVariableStorageSize Returns the remaining size of the storage space available for EFI
1494 variables associated with the attributes specified.
1495 @param MaximumVariableSize Returns the maximum size of an individual EFI variable
1496 associated with the attributes specified.
1497 @param Global Pointer to VARIABLE_GLOBAL structure.
1498
1499 @retval EFI_SUCCESS Valid answer returned.
1500 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied
1501 @retval EFI_UNSUPPORTED The attribute is not supported on this platform, and the
1502 MaximumVariableStorageSize, RemainingVariableStorageSize,
1503 MaximumVariableSize are undefined.
1504
1505**/
1506EFI_STATUS
1507EFIAPI
1508EmuQueryVariableInfo (
1509 IN UINT32 Attributes,
1510 OUT UINT64 *MaximumVariableStorageSize,
1511 OUT UINT64 *RemainingVariableStorageSize,
1512 OUT UINT64 *MaximumVariableSize,
1513 IN VARIABLE_GLOBAL *Global
1514 )
1515{
1516 VARIABLE_HEADER *Variable;
1517 VARIABLE_HEADER *NextVariable;
1518 UINT64 VariableSize;
1519 VARIABLE_STORE_HEADER *VariableStoreHeader;
1520 UINT64 CommonVariableTotalSize;
1521 UINT64 HwErrVariableTotalSize;
1522
1523 CommonVariableTotalSize = 0;
1524 HwErrVariableTotalSize = 0;
1525
1526 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
1527 return EFI_INVALID_PARAMETER;
1528 }
1529
1530 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {
1531 //
1532 // Make sure the Attributes combination is supported by the platform.
1533 //
1534 return EFI_UNSUPPORTED;
1535 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
1536 //
1537 // Make sure if runtime bit is set, boot service bit is set also.
1538 //
1539 return EFI_INVALID_PARAMETER;
1540 } else if (EfiAtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {
1541 //
1542 // Make sure RT Attribute is set if we are in Runtime phase.
1543 //
1544 return EFI_INVALID_PARAMETER;
1545 } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1546 //
1547 // Make sure Hw Attribute is set with NV.
1548 //
1549 return EFI_INVALID_PARAMETER;
1550 } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {
1551 //
1552 // Not support authentiated variable write yet.
1553 //
1554 return EFI_UNSUPPORTED;
1555 }
1556
1557 AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);
1558
1559 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
1560 //
1561 // Query is Volatile related.
1562 //
1563 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);
1564 } else {
1565 //
1566 // Query is Non-Volatile related.
1567 //
1568 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase);
1569 }
1570
1571 //
1572 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
1573 // with the storage size (excluding the storage header size)
1574 //
1575 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
1576
1577 //
1578 // Harware error record variable needs larger size.
1579 //
1580 if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {
1581 *MaximumVariableStorageSize = PcdGet32 (PcdHwErrStorageSize);
1582 *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);
1583 } else {
1584 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
1585 ASSERT (PcdGet32 (PcdHwErrStorageSize) < VariableStoreHeader->Size);
1586 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize);
1587 }
1588
1589 //
1590 // Let *MaximumVariableSize be PcdGet32 (PcdMaxVariableSize) with the exception of the variable header size.
1591 //
1592 *MaximumVariableSize = PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);
1593 }
1594
1595 //
1596 // Point to the starting address of the variables.
1597 //
1598 Variable = (VARIABLE_HEADER *) HEADER_ALIGN (VariableStoreHeader + 1);
1599
1600 //
1601 // Now walk through the related variable store.
1602 //
1603 while (Variable < GetEndPointer (VariableStoreHeader)) {
1604 NextVariable = GetNextVariablePtr(Variable);
1605 if (NextVariable == NULL) {
1606 break;
1607 }
1608 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;
1609
1610 if ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
1611 HwErrVariableTotalSize += VariableSize;
1612 } else {
1613 CommonVariableTotalSize += VariableSize;
1614 }
1615
1616 //
1617 // Go to the next one.
1618 //
1619 Variable = NextVariable;
1620 }
1621
1622 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){
1623 *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;
1624 } else {
1625 *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;
1626 }
1627
1628 if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {
1629 *MaximumVariableSize = 0;
1630 } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {
1631 *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);
1632 }
1633
1634 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
1635 return EFI_SUCCESS;
1636}
1637
1638/**
1639 Initializes variable store area.
1640
1641 This function allocates memory space for variable store area and initializes its attributes.
1642
1643 @param VolatileStore Indicates if the variable store is volatile.
1644
1645**/
1646EFI_STATUS
1647InitializeVariableStore (
1648 IN BOOLEAN VolatileStore
1649 )
1650{
1651 EFI_STATUS Status;
1652 VARIABLE_STORE_HEADER *VariableStore;
1653 BOOLEAN FullyInitializeStore;
1654 EFI_PHYSICAL_ADDRESS *VariableBase;
1655 UINTN *LastVariableOffset;
1656 VARIABLE_STORE_HEADER *VariableStoreHeader;
1657 VARIABLE_HEADER *Variable;
1658 VOID *VariableData;
1659 EFI_HOB_GUID_TYPE *GuidHob;
1660
1661 FullyInitializeStore = TRUE;
1662
1663 if (VolatileStore) {
1664 VariableBase = &mVariableModuleGlobal->VariableGlobal[Physical].VolatileVariableBase;
1665 LastVariableOffset = &mVariableModuleGlobal->VolatileLastVariableOffset;
1666 } else {
1667 VariableBase = &mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase;
1668 LastVariableOffset = &mVariableModuleGlobal->NonVolatileLastVariableOffset;
1669 }
1670
1671 //
1672 // Note that in EdkII variable driver implementation, Hardware Error Record type variable
1673 // is stored with common variable in the same NV region. So the platform integrator should
1674 // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of
1675 // PcdVariableStoreSize.
1676 //
1677 ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdVariableStoreSize));
1678
1679 //
1680 // Allocate memory for variable store.
1681 //
1682 if (VolatileStore || (PcdGet64 (PcdEmuVariableNvStoreReserved) == 0)) {
1683 VariableStore = (VARIABLE_STORE_HEADER *) AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize));
1684 } else {
1685 //
1686 // A memory location has been reserved for the NV variable store. Certain
1687 // platforms may be able to preserve a memory range across system resets,
1688 // thereby providing better NV variable emulation.
1689 //
1690 VariableStore =
1691 (VARIABLE_STORE_HEADER *)(VOID*)(UINTN)
1692 PcdGet64 (PcdEmuVariableNvStoreReserved);
1693 if (
1694 (VariableStore->Size == PcdGet32 (PcdVariableStoreSize)) &&
1695 (VariableStore->Format == VARIABLE_STORE_FORMATTED) &&
1696 (VariableStore->State == VARIABLE_STORE_HEALTHY)
1697 ) {
1698 DEBUG((
1699 EFI_D_INFO,
1700 "Variable Store reserved at %p appears to be valid\n",
1701 VariableStore
1702 ));
1703 FullyInitializeStore = FALSE;
1704 }
1705 }
1706
1707 if (NULL == VariableStore) {
1708 return EFI_OUT_OF_RESOURCES;
1709 }
1710
1711 if (FullyInitializeStore) {
1712 SetMem (VariableStore, PcdGet32 (PcdVariableStoreSize), 0xff);
1713 }
1714
1715 //
1716 // Variable Specific Data
1717 //
1718 *VariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore;
1719 InitializeLocationForLastVariableOffset (VariableStore, LastVariableOffset);
1720
1721 CopyGuid (&VariableStore->Signature, &gEfiVariableGuid);
1722 VariableStore->Size = PcdGet32 (PcdVariableStoreSize);
1723 VariableStore->Format = VARIABLE_STORE_FORMATTED;
1724 VariableStore->State = VARIABLE_STORE_HEALTHY;
1725 VariableStore->Reserved = 0;
1726 VariableStore->Reserved1 = 0;
1727
1728 if (!VolatileStore) {
1729 //
1730 // Get HOB variable store.
1731 //
1732 GuidHob = GetFirstGuidHob (&gEfiVariableGuid);
1733 if (GuidHob != NULL) {
1734 VariableStoreHeader = (VARIABLE_STORE_HEADER *) GET_GUID_HOB_DATA (GuidHob);
1735 if (CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) &&
1736 (VariableStoreHeader->Format == VARIABLE_STORE_FORMATTED) &&
1737 (VariableStoreHeader->State == VARIABLE_STORE_HEALTHY)
1738 ) {
1739 DEBUG ((EFI_D_INFO, "HOB Variable Store appears to be valid.\n"));
1740 //
1741 // Flush the HOB variable to Emulation Variable storage.
1742 //
1743 for ( Variable = (VARIABLE_HEADER *) HEADER_ALIGN (VariableStoreHeader + 1)
1744 ; (Variable < GetEndPointer (VariableStoreHeader) && (Variable != NULL))
1745 ; Variable = GetNextVariablePtr (Variable)
1746 ) {
1747 ASSERT (Variable->State == VAR_ADDED);
1748 ASSERT ((Variable->Attributes & EFI_VARIABLE_NON_VOLATILE) != 0);
1749 VariableData = GetVariableDataPtr (Variable);
1750 Status = EmuSetVariable (
1751 GET_VARIABLE_NAME_PTR (Variable),
1752 &Variable->VendorGuid,
1753 Variable->Attributes,
1754 Variable->DataSize,
1755 VariableData,
1756 &mVariableModuleGlobal->VariableGlobal[Physical],
1757 &mVariableModuleGlobal->VolatileLastVariableOffset,
1758 &mVariableModuleGlobal->NonVolatileLastVariableOffset
1759 );
1760 ASSERT_EFI_ERROR (Status);
1761 }
1762 }
1763 }
1764 }
1765
1766 return EFI_SUCCESS;
1767}
1768
1769/**
1770 Initializes variable store area for non-volatile and volatile variable.
1771
1772 This function allocates and initializes memory space for global context of ESAL
1773 variable service and variable store area for non-volatile and volatile variable.
1774
1775 @param ImageHandle The Image handle of this driver.
1776 @param SystemTable The pointer of EFI_SYSTEM_TABLE.
1777
1778 @retval EFI_SUCCESS Function successfully executed.
1779 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
1780
1781**/
1782EFI_STATUS
1783EFIAPI
1784VariableCommonInitialize (
1785 IN EFI_HANDLE ImageHandle,
1786 IN EFI_SYSTEM_TABLE *SystemTable
1787 )
1788{
1789 EFI_STATUS Status;
1790
1791 //
1792 // Allocate memory for mVariableModuleGlobal
1793 //
1794 mVariableModuleGlobal = (ESAL_VARIABLE_GLOBAL *) AllocateRuntimeZeroPool (
1795 sizeof (ESAL_VARIABLE_GLOBAL)
1796 );
1797 if (NULL == mVariableModuleGlobal) {
1798 return EFI_OUT_OF_RESOURCES;
1799 }
1800
1801 EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal[Physical].VariableServicesLock, TPL_NOTIFY);
1802
1803 //
1804 // Intialize volatile variable store
1805 //
1806 Status = InitializeVariableStore (TRUE);
1807 if (EFI_ERROR (Status)) {
1808 FreePool(mVariableModuleGlobal);
1809 return Status;
1810 }
1811 //
1812 // Intialize non volatile variable store
1813 //
1814 Status = InitializeVariableStore (FALSE);
1815
1816 return Status;
1817}
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette