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