]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
1. add EFI Firmware Management protocol definition in MdePkg.
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / Variable.c
CommitLineData
052ad7e1 1/** @file\r
504214c4
LG
2\r
3 Implement all four UEFI Runtime Variable services for the nonvolatile\r
4 and volatile storage space and install variable architecture protocol.\r
052ad7e1 5 \r
892b7f90 6Copyright (c) 2006 - 2009, Intel Corporation \r
504214c4
LG
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
8d3a5c82 14\r
052ad7e1 15**/\r
8d3a5c82 16\r
8d3a5c82 17#include "Variable.h"\r
33a5a666 18\r
7800593d 19VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;\r
052ad7e1
A
20EFI_EVENT mVirtualAddressChangeEvent = NULL;\r
21EFI_HANDLE mHandle = NULL;\r
72399dae 22///\r
23/// The size of a 3 character ISO639 language code.\r
24///\r
25#define ISO_639_2_ENTRY_SIZE 3\r
8d3a5c82 26\r
7c80e839 27///\r
28/// The current Hii implementation accesses this variable many times on every boot.\r
29/// Other common variables are only accessed once. This is why this cache algorithm\r
30/// only targets a single variable. Probably to get an performance improvement out of\r
31/// a Cache you would need a cache that improves the search performance for a variable.\r
32///\r
aa79b0b3 33VARIABLE_CACHE_ENTRY mVariableCache[] = {\r
34 {\r
35 &gEfiGlobalVariableGuid,\r
36 L"Lang",\r
37 0x00000000,\r
38 0x00,\r
39 NULL\r
72399dae 40 },\r
41 {\r
42 &gEfiGlobalVariableGuid,\r
43 L"PlatformLang",\r
44 0x00000000,\r
45 0x00,\r
46 NULL\r
aa79b0b3 47 }\r
48};\r
49\r
72399dae 50VARIABLE_INFO_ENTRY *gVariableInfo = NULL;\r
51EFI_EVENT mFvbRegistration = NULL;\r
52\r
53/**\r
54 Update the variable region with Variable information. These are the same \r
55 arguments as the EFI Variable services.\r
56\r
57 @param[in] VariableName Name of variable\r
58\r
59 @param[in] VendorGuid Guid of variable\r
60\r
61 @param[in] Data Variable data\r
62\r
63 @param[in] DataSize Size of data. 0 means delete\r
64\r
65 @param[in] Attributes Attribues of the variable\r
66\r
67 @param[in] Variable The variable information which is used to keep track of variable usage.\r
8a9e0b72 68\r
72399dae 69 @retval EFI_SUCCESS The update operation is success.\r
70\r
71 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.\r
72\r
73**/\r
74EFI_STATUS\r
75EFIAPI\r
76UpdateVariable (\r
77 IN CHAR16 *VariableName,\r
78 IN EFI_GUID *VendorGuid,\r
79 IN VOID *Data,\r
80 IN UINTN DataSize,\r
81 IN UINT32 Attributes OPTIONAL,\r
82 IN VARIABLE_POINTER_TRACK *Variable\r
83 );\r
aa79b0b3 84\r
7c80e839 85/**\r
86 Acquires lock only at boot time. Simply returns at runtime.\r
87\r
88 This is a temperary function which will be removed when\r
89 EfiAcquireLock() in UefiLib can handle the call in UEFI\r
90 Runtimer driver in RT phase.\r
91 It calls EfiAcquireLock() at boot time, and simply returns\r
92 at runtime.\r
93\r
94 @param Lock A pointer to the lock to acquire\r
95\r
96**/\r
8d3a5c82 97VOID\r
98AcquireLockOnlyAtBootTime (\r
99 IN EFI_LOCK *Lock\r
100 )\r
101{\r
102 if (!EfiAtRuntime ()) {\r
103 EfiAcquireLock (Lock);\r
104 }\r
105}\r
106\r
7c80e839 107/**\r
108 Releases lock only at boot time. Simply returns at runtime.\r
109\r
110 This is a temperary function which will be removed when\r
111 EfiReleaseLock() in UefiLib can handle the call in UEFI\r
112 Runtimer driver in RT phase.\r
113 It calls EfiReleaseLock() at boot time, and simply returns\r
114 at runtime.\r
115\r
116 @param Lock A pointer to the lock to release\r
117\r
118**/\r
8d3a5c82 119VOID\r
120ReleaseLockOnlyAtBootTime (\r
121 IN EFI_LOCK *Lock\r
122 )\r
123{\r
124 if (!EfiAtRuntime ()) {\r
125 EfiReleaseLock (Lock);\r
126 }\r
127}\r
128\r
33a5a666 129\r
052ad7e1
A
130/**\r
131 Routine used to track statistical information about variable usage. \r
132 The data is stored in the EFI system table so it can be accessed later.\r
133 VariableInfo.efi can dump out the table. Only Boot Services variable \r
134 accesses are tracked by this code. The PcdVariableCollectStatistics\r
135 build flag controls if this feature is enabled. \r
136\r
137 A read that hits in the cache will have Read and Cache true for \r
138 the transaction. Data is allocated by this routine, but never\r
139 freed.\r
140\r
141 @param[in] VariableName Name of the Variable to track\r
142 @param[in] VendorGuid Guid of the Variable to track\r
143 @param[in] Volatile TRUE if volatile FALSE if non-volatile\r
144 @param[in] Read TRUE if GetVariable() was called\r
145 @param[in] Write TRUE if SetVariable() was called\r
146 @param[in] Delete TRUE if deleted via SetVariable()\r
147 @param[in] Cache TRUE for a cache hit.\r
148\r
149**/\r
33a5a666
A
150VOID\r
151UpdateVariableInfo (\r
152 IN CHAR16 *VariableName,\r
153 IN EFI_GUID *VendorGuid,\r
154 IN BOOLEAN Volatile,\r
155 IN BOOLEAN Read,\r
156 IN BOOLEAN Write,\r
157 IN BOOLEAN Delete,\r
158 IN BOOLEAN Cache\r
159 )\r
160{\r
161 VARIABLE_INFO_ENTRY *Entry;\r
162\r
163 if (FeaturePcdGet (PcdVariableCollectStatistics)) {\r
164\r
165 if (EfiAtRuntime ()) {\r
166 // Don't collect statistics at runtime\r
167 return;\r
168 }\r
169\r
170 if (gVariableInfo == NULL) {\r
052ad7e1
A
171 //\r
172 // on the first call allocate a entry and place a pointer to it in\r
173 // the EFI System Table\r
174 //\r
33a5a666 175 gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
052ad7e1
A
176 ASSERT (gVariableInfo != NULL);\r
177\r
33a5a666 178 CopyGuid (&gVariableInfo->VendorGuid, VendorGuid);\r
bcd7070d 179 gVariableInfo->Name = AllocatePool (StrSize (VariableName));\r
e6c4ef13 180 ASSERT (gVariableInfo->Name != NULL);\r
33a5a666
A
181 StrCpy (gVariableInfo->Name, VariableName);\r
182 gVariableInfo->Volatile = Volatile;\r
183\r
3709c4cd 184 gBS->InstallConfigurationTable (&gEfiVariableGuid, gVariableInfo);\r
33a5a666
A
185 }\r
186\r
187 \r
188 for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) {\r
189 if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {\r
190 if (StrCmp (VariableName, Entry->Name) == 0) {\r
191 if (Read) {\r
192 Entry->ReadCount++;\r
193 }\r
194 if (Write) {\r
195 Entry->WriteCount++;\r
196 }\r
197 if (Delete) {\r
198 Entry->DeleteCount++;\r
199 }\r
200 if (Cache) {\r
201 Entry->CacheCount++;\r
202 }\r
203\r
204 return;\r
205 }\r
206 }\r
207\r
208 if (Entry->Next == NULL) {\r
052ad7e1
A
209 //\r
210 // If the entry is not in the table add it.\r
211 // Next iteration of the loop will fill in the data\r
212 //\r
33a5a666 213 Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
052ad7e1 214 ASSERT (Entry->Next != NULL);\r
33a5a666
A
215\r
216 CopyGuid (&Entry->Next->VendorGuid, VendorGuid);\r
bcd7070d 217 Entry->Next->Name = AllocatePool (StrSize (VariableName));\r
e6c4ef13 218 ASSERT (Entry->Next->Name != NULL);\r
33a5a666
A
219 StrCpy (Entry->Next->Name, VariableName);\r
220 Entry->Next->Volatile = Volatile;\r
221 }\r
222\r
223 }\r
224 }\r
225}\r
226\r
227\r
7c80e839 228/**\r
8d3a5c82 229\r
230 This code checks if variable header is valid or not.\r
231\r
7c80e839 232 @param Variable Pointer to the Variable Header.\r
8d3a5c82 233\r
7c80e839 234 @retval TRUE Variable header is valid.\r
235 @retval FALSE Variable header is not valid.\r
8d3a5c82 236\r
7c80e839 237**/\r
238BOOLEAN\r
239IsValidVariableHeader (\r
240 IN VARIABLE_HEADER *Variable\r
241 )\r
8d3a5c82 242{\r
fdb7765f 243 if (Variable == NULL || Variable->StartId != VARIABLE_DATA) {\r
8d3a5c82 244 return FALSE;\r
245 }\r
246\r
247 return TRUE;\r
248}\r
249\r
052ad7e1 250\r
7c80e839 251/**\r
252\r
253 This function writes data to the FWH at the correct LBA even if the LBAs\r
254 are fragmented.\r
255\r
256 @param Global Pointer to VARAIBLE_GLOBAL structure\r
257 @param Volatile Point out the Variable is Volatile or Non-Volatile\r
258 @param SetByIndex TRUE if target pointer is given as index\r
259 FALSE if target pointer is absolute\r
8a9e0b72 260 @param Fvb Pointer to the writable FVB protocol\r
7c80e839 261 @param DataPtrIndex Pointer to the Data from the end of VARIABLE_STORE_HEADER\r
262 structure\r
263 @param DataSize Size of data to be written\r
264 @param Buffer Pointer to the buffer from which data is written\r
265\r
266 @retval EFI_INVALID_PARAMETER Parameters not valid\r
267 @retval EFI_SUCCESS Variable store successfully updated\r
268\r
269**/\r
8d3a5c82 270EFI_STATUS\r
8d3a5c82 271UpdateVariableStore (\r
8a9e0b72 272 IN VARIABLE_GLOBAL *Global,\r
273 IN BOOLEAN Volatile,\r
274 IN BOOLEAN SetByIndex,\r
275 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,\r
276 IN UINTN DataPtrIndex,\r
277 IN UINT32 DataSize,\r
278 IN UINT8 *Buffer\r
8d3a5c82 279 )\r
8d3a5c82 280{\r
281 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
282 UINTN BlockIndex2;\r
283 UINTN LinearOffset;\r
284 UINTN CurrWriteSize;\r
285 UINTN CurrWritePtr;\r
286 UINT8 *CurrBuffer;\r
287 EFI_LBA LbaNumber;\r
288 UINTN Size;\r
289 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
290 VARIABLE_STORE_HEADER *VolatileBase;\r
291 EFI_PHYSICAL_ADDRESS FvVolHdr;\r
292 EFI_PHYSICAL_ADDRESS DataPtr;\r
293 EFI_STATUS Status;\r
294\r
295 FwVolHeader = NULL;\r
296 DataPtr = DataPtrIndex;\r
297\r
298 //\r
299 // Check if the Data is Volatile\r
300 //\r
301 if (!Volatile) {\r
8a9e0b72 302 Status = Fvb->GetPhysicalAddress(Fvb, &FvVolHdr);\r
303 ASSERT_EFI_ERROR (Status);\r
304\r
8d3a5c82 305 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);\r
306 //\r
307 // Data Pointer should point to the actual Address where data is to be\r
308 // written\r
309 //\r
310 if (SetByIndex) {\r
052ad7e1 311 DataPtr += mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
8d3a5c82 312 }\r
313\r
314 if ((DataPtr + DataSize) >= ((EFI_PHYSICAL_ADDRESS) (UINTN) ((UINT8 *) FwVolHeader + FwVolHeader->FvLength))) {\r
315 return EFI_INVALID_PARAMETER;\r
316 }\r
317 } else {\r
318 //\r
319 // Data Pointer should point to the actual Address where data is to be\r
320 // written\r
321 //\r
052ad7e1 322 VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
8d3a5c82 323 if (SetByIndex) {\r
052ad7e1 324 DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
8d3a5c82 325 }\r
326\r
327 if ((DataPtr + DataSize) >= ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) {\r
328 return EFI_INVALID_PARAMETER;\r
329 }\r
c6492839 330 \r
331 //\r
332 // If Volatile Variable just do a simple mem copy.\r
333 // \r
334 CopyMem ((UINT8 *)(UINTN)DataPtr, Buffer, DataSize);\r
8d3a5c82 335 return EFI_SUCCESS;\r
336 }\r
c6492839 337 \r
8d3a5c82 338 //\r
339 // If we are here we are dealing with Non-Volatile Variables\r
340 //\r
341 LinearOffset = (UINTN) FwVolHeader;\r
342 CurrWritePtr = (UINTN) DataPtr;\r
343 CurrWriteSize = DataSize;\r
344 CurrBuffer = Buffer;\r
345 LbaNumber = 0;\r
346\r
347 if (CurrWritePtr < LinearOffset) {\r
348 return EFI_INVALID_PARAMETER;\r
349 }\r
350\r
351 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
352 for (BlockIndex2 = 0; BlockIndex2 < PtrBlockMapEntry->NumBlocks; BlockIndex2++) {\r
353 //\r
354 // Check to see if the Variable Writes are spanning through multiple\r
355 // blocks.\r
356 //\r
357 if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) {\r
358 if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {\r
8a9e0b72 359 Status = Fvb->Write (\r
360 Fvb,\r
8d3a5c82 361 LbaNumber,\r
362 (UINTN) (CurrWritePtr - LinearOffset),\r
363 &CurrWriteSize,\r
364 CurrBuffer\r
365 );\r
8a9e0b72 366 return Status;\r
8d3a5c82 367 } else {\r
368 Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);\r
8a9e0b72 369 Status = Fvb->Write (\r
370 Fvb,\r
8d3a5c82 371 LbaNumber,\r
372 (UINTN) (CurrWritePtr - LinearOffset),\r
373 &Size,\r
374 CurrBuffer\r
375 );\r
376 if (EFI_ERROR (Status)) {\r
377 return Status;\r
378 }\r
379\r
380 CurrWritePtr = LinearOffset + PtrBlockMapEntry->Length;\r
381 CurrBuffer = CurrBuffer + Size;\r
382 CurrWriteSize = CurrWriteSize - Size;\r
383 }\r
384 }\r
385\r
386 LinearOffset += PtrBlockMapEntry->Length;\r
387 LbaNumber++;\r
388 }\r
389 }\r
390\r
391 return EFI_SUCCESS;\r
392}\r
393\r
052ad7e1 394\r
7c80e839 395/**\r
8d3a5c82 396\r
397 This code gets the current status of Variable Store.\r
398\r
7c80e839 399 @param VarStoreHeader Pointer to the Variable Store Header.\r
8d3a5c82 400\r
7c80e839 401 @retval EfiRaw Variable store status is raw\r
402 @retval EfiValid Variable store status is valid\r
403 @retval EfiInvalid Variable store status is invalid\r
8d3a5c82 404\r
7c80e839 405**/\r
406VARIABLE_STORE_STATUS\r
407GetVariableStoreStatus (\r
408 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
409 )\r
8d3a5c82 410{\r
3709c4cd 411 if (CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid) &&\r
8d3a5c82 412 VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&\r
413 VarStoreHeader->State == VARIABLE_STORE_HEALTHY\r
414 ) {\r
415\r
416 return EfiValid;\r
3709c4cd 417 } else if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff &&\r
418 ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff &&\r
419 ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff &&\r
420 ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff &&\r
421 VarStoreHeader->Size == 0xffffffff &&\r
422 VarStoreHeader->Format == 0xff &&\r
423 VarStoreHeader->State == 0xff\r
8d3a5c82 424 ) {\r
425\r
426 return EfiRaw;\r
427 } else {\r
428 return EfiInvalid;\r
429 }\r
430}\r
431\r
130e2569 432\r
7c80e839 433/**\r
130e2569 434\r
435 This code gets the size of name of variable.\r
436\r
7c80e839 437 @param Variable Pointer to the Variable Header\r
130e2569 438\r
7c80e839 439 @return UINTN Size of variable in bytes\r
130e2569 440\r
7c80e839 441**/\r
442UINTN\r
443NameSizeOfVariable (\r
444 IN VARIABLE_HEADER *Variable\r
445 )\r
130e2569 446{\r
447 if (Variable->State == (UINT8) (-1) ||\r
7c80e839 448 Variable->DataSize == (UINT32) (-1) ||\r
449 Variable->NameSize == (UINT32) (-1) ||\r
450 Variable->Attributes == (UINT32) (-1)) {\r
130e2569 451 return 0;\r
452 }\r
453 return (UINTN) Variable->NameSize;\r
454}\r
455\r
7c80e839 456/**\r
130e2569 457\r
7c80e839 458 This code gets the size of variable data.\r
130e2569 459\r
7c80e839 460 @param Variable Pointer to the Variable Header\r
130e2569 461\r
7c80e839 462 @return Size of variable in bytes\r
130e2569 463\r
7c80e839 464**/\r
465UINTN\r
466DataSizeOfVariable (\r
467 IN VARIABLE_HEADER *Variable\r
468 )\r
130e2569 469{\r
7c80e839 470 if (Variable->State == (UINT8) (-1) ||\r
471 Variable->DataSize == (UINT32) (-1) ||\r
472 Variable->NameSize == (UINT32) (-1) ||\r
473 Variable->Attributes == (UINT32) (-1)) {\r
130e2569 474 return 0;\r
475 }\r
476 return (UINTN) Variable->DataSize;\r
477}\r
478\r
7c80e839 479/**\r
130e2569 480\r
481 This code gets the pointer to the variable name.\r
482\r
7c80e839 483 @param Variable Pointer to the Variable Header\r
130e2569 484\r
7c80e839 485 @return Pointer to Variable Name which is Unicode encoding\r
130e2569 486\r
7c80e839 487**/\r
488CHAR16 *\r
489GetVariableNamePtr (\r
490 IN VARIABLE_HEADER *Variable\r
491 )\r
130e2569 492{\r
493\r
494 return (CHAR16 *) (Variable + 1);\r
495}\r
496\r
7c80e839 497/**\r
8d3a5c82 498\r
499 This code gets the pointer to the variable data.\r
500\r
7c80e839 501 @param Variable Pointer to the Variable Header\r
8d3a5c82 502\r
7c80e839 503 @return Pointer to Variable Data\r
8d3a5c82 504\r
7c80e839 505**/\r
506UINT8 *\r
507GetVariableDataPtr (\r
508 IN VARIABLE_HEADER *Variable\r
509 )\r
8d3a5c82 510{\r
130e2569 511 UINTN Value;\r
512 \r
8d3a5c82 513 //\r
514 // Be careful about pad size for alignment\r
515 //\r
130e2569 516 Value = (UINTN) GetVariableNamePtr (Variable);\r
517 Value += NameSizeOfVariable (Variable);\r
518 Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));\r
519\r
520 return (UINT8 *) Value;\r
8d3a5c82 521}\r
522\r
052ad7e1 523\r
7c80e839 524/**\r
8d3a5c82 525\r
526 This code gets the pointer to the next variable header.\r
527\r
7c80e839 528 @param Variable Pointer to the Variable Header\r
8d3a5c82 529\r
7c80e839 530 @return Pointer to next variable header\r
8d3a5c82 531\r
7c80e839 532**/\r
533VARIABLE_HEADER *\r
534GetNextVariablePtr (\r
535 IN VARIABLE_HEADER *Variable\r
536 )\r
8d3a5c82 537{\r
130e2569 538 UINTN Value;\r
539\r
8d3a5c82 540 if (!IsValidVariableHeader (Variable)) {\r
541 return NULL;\r
542 }\r
130e2569 543\r
544 Value = (UINTN) GetVariableDataPtr (Variable);\r
545 Value += DataSizeOfVariable (Variable);\r
546 Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));\r
547\r
8d3a5c82 548 //\r
549 // Be careful about pad size for alignment\r
550 //\r
130e2569 551 return (VARIABLE_HEADER *) HEADER_ALIGN (Value);\r
8d3a5c82 552}\r
553\r
7c80e839 554/**\r
9cad030b 555\r
7c80e839 556 Gets the pointer to the first variable header in given variable store area.\r
9cad030b 557\r
7c80e839 558 @param VarStoreHeader Pointer to the Variable Store Header.\r
9cad030b 559\r
7c80e839 560 @return Pointer to the first variable header\r
9cad030b 561\r
7c80e839 562**/\r
563VARIABLE_HEADER *\r
564GetStartPointer (\r
565 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
566 )\r
9cad030b 567{\r
568 //\r
569 // The end of variable store\r
570 //\r
571 return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);\r
572}\r
052ad7e1 573\r
7c80e839 574/**\r
8d3a5c82 575\r
7c80e839 576 Gets the pointer to the end of the variable storage area.\r
8d3a5c82 577\r
7c80e839 578 This function gets pointer to the end of the variable storage\r
579 area, according to the input variable store header.\r
8d3a5c82 580\r
7c80e839 581 @param VarStoreHeader Pointer to the Variable Store Header\r
8d3a5c82 582\r
7c80e839 583 @return Pointer to the end of the variable storage area \r
8d3a5c82 584\r
7c80e839 585**/\r
586VARIABLE_HEADER *\r
587GetEndPointer (\r
588 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
589 )\r
8d3a5c82 590{\r
591 //\r
592 // The end of variable store\r
593 //\r
9cad030b 594 return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);\r
8d3a5c82 595}\r
596\r
052ad7e1 597\r
7c80e839 598/**\r
599\r
600 Variable store garbage collection and reclaim operation.\r
601\r
602 @param VariableBase Base address of variable store\r
603 @param LastVariableOffset Offset of last variable\r
604 @param IsVolatile The variable store is volatile or not,\r
605 if it is non-volatile, need FTW\r
606 @param UpdatingVariable Pointer to updateing variable.\r
607\r
608 @return EFI_OUT_OF_RESOURCES\r
609 @return EFI_SUCCESS\r
610 @return Others\r
611\r
612**/\r
8d3a5c82 613EFI_STATUS\r
8d3a5c82 614Reclaim (\r
615 IN EFI_PHYSICAL_ADDRESS VariableBase,\r
616 OUT UINTN *LastVariableOffset,\r
814bae52 617 IN BOOLEAN IsVolatile,\r
618 IN VARIABLE_HEADER *UpdatingVariable\r
8d3a5c82 619 )\r
8d3a5c82 620{\r
621 VARIABLE_HEADER *Variable;\r
814bae52 622 VARIABLE_HEADER *AddedVariable;\r
8d3a5c82 623 VARIABLE_HEADER *NextVariable;\r
814bae52 624 VARIABLE_HEADER *NextAddedVariable;\r
8d3a5c82 625 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
626 UINT8 *ValidBuffer;\r
814bae52 627 UINTN MaximumBufferSize;\r
8d3a5c82 628 UINTN VariableSize;\r
49e70927 629 UINTN VariableNameSize;\r
630 UINTN UpdatingVariableNameSize;\r
814bae52 631 UINTN NameSize;\r
8d3a5c82 632 UINT8 *CurrPtr;\r
814bae52 633 VOID *Point0;\r
634 VOID *Point1;\r
635 BOOLEAN FoundAdded;\r
8d3a5c82 636 EFI_STATUS Status;\r
49e70927 637 CHAR16 *VariableNamePtr;\r
638 CHAR16 *UpdatingVariableNamePtr;\r
8d3a5c82 639\r
640 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);\r
2fcdca1d 641 //\r
642 // recaluate the total size of Common/HwErr type variables in non-volatile area.\r
643 //\r
644 if (!IsVolatile) {\r
645 mVariableModuleGlobal->CommonVariableTotalSize = 0;\r
646 mVariableModuleGlobal->HwErrVariableTotalSize = 0;\r
647 }\r
8d3a5c82 648\r
649 //\r
650 // Start Pointers for the variable.\r
651 //\r
814bae52 652 Variable = GetStartPointer (VariableStoreHeader);\r
653 MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);\r
8d3a5c82 654\r
655 while (IsValidVariableHeader (Variable)) {\r
656 NextVariable = GetNextVariablePtr (Variable);\r
814bae52 657 if (Variable->State == VAR_ADDED || \r
658 Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
659 ) {\r
8d3a5c82 660 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
814bae52 661 MaximumBufferSize += VariableSize;\r
8d3a5c82 662 }\r
663\r
664 Variable = NextVariable;\r
665 }\r
666\r
814bae52 667 //\r
668 // Reserve the 1 Bytes with Oxff to identify the \r
669 // end of the variable buffer. \r
670 // \r
671 MaximumBufferSize += 1;\r
672 ValidBuffer = AllocatePool (MaximumBufferSize);\r
8d3a5c82 673 if (ValidBuffer == NULL) {\r
674 return EFI_OUT_OF_RESOURCES;\r
675 }\r
676\r
814bae52 677 SetMem (ValidBuffer, MaximumBufferSize, 0xff);\r
8d3a5c82 678\r
679 //\r
680 // Copy variable store header\r
681 //\r
814bae52 682 CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));\r
683 CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
8d3a5c82 684\r
814bae52 685 //\r
5ead4a07 686 // Reinstall all ADDED variables as long as they are not identical to Updating Variable\r
814bae52 687 // \r
688 Variable = GetStartPointer (VariableStoreHeader);\r
8d3a5c82 689 while (IsValidVariableHeader (Variable)) {\r
690 NextVariable = GetNextVariablePtr (Variable);\r
691 if (Variable->State == VAR_ADDED) {\r
5ead4a07 692 if (UpdatingVariable != NULL) {\r
693 if (UpdatingVariable == Variable) {\r
694 Variable = NextVariable;\r
695 continue;\r
696 }\r
49e70927 697\r
698 VariableNameSize = NameSizeOfVariable(Variable);\r
699 UpdatingVariableNameSize = NameSizeOfVariable(UpdatingVariable);\r
700\r
701 VariableNamePtr = GetVariableNamePtr (Variable);\r
702 UpdatingVariableNamePtr = GetVariableNamePtr (UpdatingVariable);\r
5ead4a07 703 if (CompareGuid (&Variable->VendorGuid, &UpdatingVariable->VendorGuid) &&\r
49e70927 704 VariableNameSize == UpdatingVariableNameSize &&\r
705 CompareMem (VariableNamePtr, UpdatingVariableNamePtr, VariableNameSize) == 0 ) {\r
5ead4a07 706 Variable = NextVariable;\r
707 continue;\r
708 }\r
709 }\r
8d3a5c82 710 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
711 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
712 CurrPtr += VariableSize;\r
2fcdca1d 713 if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
714 mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
715 } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
716 mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
717 }\r
8d3a5c82 718 }\r
8d3a5c82 719 Variable = NextVariable;\r
720 }\r
5ead4a07 721\r
722 //\r
723 // Reinstall the variable being updated if it is not NULL\r
724 //\r
725 if (UpdatingVariable != NULL) {\r
726 VariableSize = (UINTN)(GetNextVariablePtr (UpdatingVariable)) - (UINTN)UpdatingVariable;\r
727 CopyMem (CurrPtr, (UINT8 *) UpdatingVariable, VariableSize);\r
728 CurrPtr += VariableSize;\r
2fcdca1d 729 if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
730 mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
731 } else if ((!IsVolatile) && ((UpdatingVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
732 mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
733 }\r
5ead4a07 734 }\r
735\r
814bae52 736 //\r
737 // Reinstall all in delete transition variables\r
738 // \r
739 Variable = GetStartPointer (VariableStoreHeader);\r
740 while (IsValidVariableHeader (Variable)) {\r
741 NextVariable = GetNextVariablePtr (Variable);\r
5ead4a07 742 if (Variable != UpdatingVariable && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
814bae52 743\r
744 //\r
745 // Buffer has cached all ADDED variable. \r
746 // Per IN_DELETED variable, we have to guarantee that\r
747 // no ADDED one in previous buffer. \r
748 // \r
749 \r
750 FoundAdded = FALSE;\r
751 AddedVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
752 while (IsValidVariableHeader (AddedVariable)) {\r
753 NextAddedVariable = GetNextVariablePtr (AddedVariable);\r
754 NameSize = NameSizeOfVariable (AddedVariable);\r
755 if (CompareGuid (&AddedVariable->VendorGuid, &Variable->VendorGuid) &&\r
756 NameSize == NameSizeOfVariable (Variable)\r
757 ) {\r
758 Point0 = (VOID *) GetVariableNamePtr (AddedVariable);\r
759 Point1 = (VOID *) GetVariableNamePtr (Variable);\r
5ead4a07 760 if (CompareMem (Point0, Point1, NameSizeOfVariable (AddedVariable)) == 0) {\r
814bae52 761 FoundAdded = TRUE;\r
762 break;\r
763 }\r
764 }\r
765 AddedVariable = NextAddedVariable;\r
766 }\r
767 if (!FoundAdded) {\r
5ead4a07 768 //\r
769 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED\r
770 //\r
814bae52 771 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
772 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
5ead4a07 773 ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;\r
814bae52 774 CurrPtr += VariableSize;\r
2fcdca1d 775 if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
776 mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
777 } else if ((!IsVolatile) && ((Variable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
778 mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
779 }\r
814bae52 780 }\r
781 }\r
782\r
783 Variable = NextVariable;\r
784 }\r
8d3a5c82 785\r
786 if (IsVolatile) {\r
787 //\r
788 // If volatile variable store, just copy valid buffer\r
789 //\r
790 SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader->Size, 0xff);\r
814bae52 791 CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - (UINT8 *) ValidBuffer));\r
8d3a5c82 792 Status = EFI_SUCCESS;\r
793 } else {\r
794 //\r
795 // If non-volatile variable store, perform FTW here.\r
796 //\r
797 Status = FtwVariableSpace (\r
798 VariableBase,\r
799 ValidBuffer,\r
814bae52 800 (UINTN) (CurrPtr - (UINT8 *) ValidBuffer)\r
8d3a5c82 801 );\r
8d3a5c82 802 }\r
814bae52 803 if (!EFI_ERROR (Status)) {\r
804 *LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer);\r
805 } else {\r
8d3a5c82 806 *LastVariableOffset = 0;\r
807 }\r
808\r
814bae52 809 FreePool (ValidBuffer);\r
810\r
8d3a5c82 811 return Status;\r
812}\r
813\r
33a5a666 814\r
052ad7e1
A
815/**\r
816 Update the Cache with Variable information. These are the same \r
817 arguments as the EFI Variable services.\r
818\r
819 @param[in] VariableName Name of variable\r
820 @param[in] VendorGuid Guid of variable\r
45f6c85b 821 @param[in] Attributes Attribues of the variable\r
052ad7e1
A
822 @param[in] DataSize Size of data. 0 means delete\r
823 @param[in] Data Variable data\r
824\r
825**/\r
33a5a666
A
826VOID\r
827UpdateVariableCache (\r
828 IN CHAR16 *VariableName,\r
829 IN EFI_GUID *VendorGuid,\r
052ad7e1
A
830 IN UINT32 Attributes,\r
831 IN UINTN DataSize,\r
832 IN VOID *Data\r
33a5a666
A
833 )\r
834{\r
835 VARIABLE_CACHE_ENTRY *Entry;\r
836 UINTN Index;\r
837\r
838 if (EfiAtRuntime ()) {\r
892b7f90 839 //\r
33a5a666 840 // Don't use the cache at runtime\r
892b7f90 841 // \r
33a5a666
A
842 return;\r
843 }\r
844\r
845 for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {\r
846 if (CompareGuid (VendorGuid, Entry->Guid)) {\r
847 if (StrCmp (VariableName, Entry->Name) == 0) { \r
848 Entry->Attributes = Attributes;\r
849 if (DataSize == 0) {\r
892b7f90 850 //\r
33a5a666 851 // Delete Case\r
892b7f90 852 //\r
33a5a666
A
853 if (Entry->DataSize != 0) {\r
854 FreePool (Entry->Data);\r
855 }\r
856 Entry->DataSize = DataSize;\r
857 } else if (DataSize == Entry->DataSize) {\r
858 CopyMem (Entry->Data, Data, DataSize);\r
859 } else {\r
860 Entry->Data = AllocatePool (DataSize);\r
892b7f90 861 ASSERT (Entry->Data != NULL);\r
862\r
33a5a666
A
863 Entry->DataSize = DataSize;\r
864 CopyMem (Entry->Data, Data, DataSize);\r
865 }\r
866 }\r
867 }\r
868 }\r
869}\r
870\r
871\r
052ad7e1 872/**\r
7c80e839 873 Search the cache to check if the variable is in it.\r
052ad7e1 874\r
7c80e839 875 This function searches the variable cache. If the variable to find exists, return its data\r
876 and attributes.\r
052ad7e1 877\r
7c80e839 878 @param VariableName A Null-terminated Unicode string that is the name of the vendor's\r
879 variable. Each VariableName is unique for each \r
880 VendorGuid.\r
881 @param VendorGuid A unique identifier for the vendor\r
882 @param Attributes Pointer to the attributes bitmask of the variable for output.\r
883 @param DataSize On input, size of the buffer of Data.\r
884 On output, size of the variable's data.\r
885 @param Data Pointer to the data buffer for output.\r
886\r
887 @retval EFI_SUCCESS VariableGuid & VariableName data was returned.\r
888 @retval EFI_NOT_FOUND No matching variable found in cache.\r
889 @retval EFI_BUFFER_TOO_SMALL *DataSize is smaller than size of the variable's data to return.\r
052ad7e1
A
890\r
891**/\r
33a5a666
A
892EFI_STATUS\r
893FindVariableInCache (\r
894 IN CHAR16 *VariableName,\r
895 IN EFI_GUID *VendorGuid,\r
896 OUT UINT32 *Attributes OPTIONAL,\r
897 IN OUT UINTN *DataSize,\r
898 OUT VOID *Data\r
899 )\r
900{\r
901 VARIABLE_CACHE_ENTRY *Entry;\r
902 UINTN Index;\r
903\r
904 if (EfiAtRuntime ()) {\r
905 // Don't use the cache at runtime\r
906 return EFI_NOT_FOUND;\r
907 }\r
908\r
909 for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {\r
910 if (CompareGuid (VendorGuid, Entry->Guid)) {\r
911 if (StrCmp (VariableName, Entry->Name) == 0) {\r
912 if (Entry->DataSize == 0) {\r
052ad7e1 913 // Variable was deleted so return not found\r
33a5a666 914 return EFI_NOT_FOUND;\r
aa09397b 915 } else if (Entry->DataSize > *DataSize) {\r
052ad7e1 916 // If the buffer is too small return correct size\r
33a5a666
A
917 *DataSize = Entry->DataSize;\r
918 return EFI_BUFFER_TOO_SMALL;\r
919 } else {\r
aa09397b 920 *DataSize = Entry->DataSize;\r
052ad7e1 921 // Return the data\r
33a5a666
A
922 CopyMem (Data, Entry->Data, Entry->DataSize);\r
923 if (Attributes != NULL) {\r
924 *Attributes = Entry->Attributes;\r
925 }\r
926 return EFI_SUCCESS;\r
927 }\r
928 }\r
929 }\r
930 }\r
931 \r
932 return EFI_NOT_FOUND;\r
933}\r
934\r
7c80e839 935/**\r
936 Finds variable in storage blocks of volatile and non-volatile storage areas.\r
937\r
938 This code finds variable in storage blocks of volatile and non-volatile storage areas.\r
939 If VariableName is an empty string, then we just return the first\r
940 qualified variable without comparing VariableName and VendorGuid.\r
941 Otherwise, VariableName and VendorGuid are compared.\r
942\r
943 @param VariableName Name of the variable to be found\r
944 @param VendorGuid Vendor GUID to be found.\r
945 @param PtrTrack VARIABLE_POINTER_TRACK structure for output,\r
946 including the range searched and the target position.\r
947 @param Global Pointer to VARIABLE_GLOBAL structure, including\r
948 base of volatile variable storage area, base of\r
949 NV variable storage area, and a lock.\r
950\r
951 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while\r
952 VendorGuid is NULL\r
953 @retval EFI_SUCCESS Variable successfully found\r
954 @retval EFI_INVALID_PARAMETER Variable not found\r
33a5a666 955\r
7c80e839 956**/\r
8d3a5c82 957EFI_STATUS\r
8d3a5c82 958FindVariable (\r
959 IN CHAR16 *VariableName,\r
960 IN EFI_GUID *VendorGuid,\r
961 OUT VARIABLE_POINTER_TRACK *PtrTrack,\r
962 IN VARIABLE_GLOBAL *Global\r
963 )\r
8d3a5c82 964{\r
814bae52 965 VARIABLE_HEADER *Variable[2];\r
966 VARIABLE_HEADER *InDeletedVariable;\r
967 VARIABLE_STORE_HEADER *VariableStoreHeader[2];\r
968 UINTN InDeletedStorageIndex;\r
969 UINTN Index;\r
970 VOID *Point;\r
8d3a5c82 971\r
8d3a5c82 972 //\r
33a5a666 973 // 0: Volatile, 1: Non-Volatile\r
36873a61 974 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName\r
975 // make use of this mapping to implement search algorithme.\r
8d3a5c82 976 //\r
052ad7e1
A
977 VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
978 VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
8d3a5c82 979\r
980 //\r
981 // Start Pointers for the variable.\r
982 // Actual Data Pointer where data can be written.\r
983 //\r
9cad030b 984 Variable[0] = GetStartPointer (VariableStoreHeader[0]);\r
985 Variable[1] = GetStartPointer (VariableStoreHeader[1]);\r
8d3a5c82 986\r
987 if (VariableName[0] != 0 && VendorGuid == NULL) {\r
988 return EFI_INVALID_PARAMETER;\r
989 }\r
814bae52 990\r
8d3a5c82 991 //\r
33a5a666 992 // Find the variable by walk through volatile and then non-volatile variable store\r
8d3a5c82 993 //\r
814bae52 994 InDeletedVariable = NULL;\r
995 InDeletedStorageIndex = 0;\r
8d3a5c82 996 for (Index = 0; Index < 2; Index++) {\r
79749182 997 while ((Variable[Index] < GetEndPointer (VariableStoreHeader[Index])) && IsValidVariableHeader (Variable[Index])) {\r
814bae52 998 if (Variable[Index]->State == VAR_ADDED || \r
999 Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
1000 ) {\r
8ed62a30 1001 if (!EfiAtRuntime () || ((Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {\r
8d3a5c82 1002 if (VariableName[0] == 0) {\r
814bae52 1003 if (Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
1004 InDeletedVariable = Variable[Index];\r
1005 InDeletedStorageIndex = Index;\r
1006 } else {\r
1007 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]);\r
1008 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]);\r
1009 PtrTrack->CurrPtr = Variable[Index];\r
1010 PtrTrack->Volatile = (BOOLEAN)(Index == 0);\r
1011\r
1012 return EFI_SUCCESS;\r
1013 }\r
8d3a5c82 1014 } else {\r
1015 if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) {\r
130e2569 1016 Point = (VOID *) GetVariableNamePtr (Variable[Index]);\r
1017\r
1018 ASSERT (NameSizeOfVariable (Variable[Index]) != 0);\r
c24b392c 1019 if (CompareMem (VariableName, Point, NameSizeOfVariable (Variable[Index])) == 0) {\r
814bae52 1020 if (Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
1021 InDeletedVariable = Variable[Index];\r
1022 InDeletedStorageIndex = Index;\r
1023 } else {\r
1024 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]);\r
1025 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]);\r
1026 PtrTrack->CurrPtr = Variable[Index];\r
1027 PtrTrack->Volatile = (BOOLEAN)(Index == 0);\r
1028\r
1029 return EFI_SUCCESS;\r
1030 }\r
8d3a5c82 1031 }\r
1032 }\r
1033 }\r
1034 }\r
1035 }\r
1036\r
1037 Variable[Index] = GetNextVariablePtr (Variable[Index]);\r
1038 }\r
814bae52 1039 if (InDeletedVariable != NULL) {\r
1040 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[InDeletedStorageIndex]);\r
1041 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[InDeletedStorageIndex]);\r
1042 PtrTrack->CurrPtr = InDeletedVariable;\r
1043 PtrTrack->Volatile = (BOOLEAN)(InDeletedStorageIndex == 0);\r
1044 return EFI_SUCCESS;\r
1045 }\r
8d3a5c82 1046 }\r
8d3a5c82 1047 PtrTrack->CurrPtr = NULL;\r
1048 return EFI_NOT_FOUND;\r
1049}\r
1050\r
7c80e839 1051/**\r
72399dae 1052 Get index from supported language codes according to language string.\r
1053\r
1054 This code is used to get corresponding index in supported language codes. It can handle\r
0254efc0 1055 RFC4646 and ISO639 language tags.\r
72399dae 1056 In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.\r
0254efc0 1057 In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.\r
72399dae 1058\r
1059 For example:\r
1060 SupportedLang = "engfraengfra"\r
1061 Lang = "eng"\r
1062 Iso639Language = TRUE\r
1063 The return value is "0".\r
1064 Another example:\r
1065 SupportedLang = "en;fr;en-US;fr-FR"\r
1066 Lang = "fr-FR"\r
1067 Iso639Language = FALSE\r
1068 The return value is "3".\r
1069\r
1070 @param SupportedLang Platform supported language codes.\r
1071 @param Lang Configured language.\r
0254efc0 1072 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
72399dae 1073\r
1074 @retval the index of language in the language codes.\r
8d3a5c82 1075\r
7c80e839 1076**/\r
72399dae 1077UINTN\r
052ad7e1 1078EFIAPI\r
72399dae 1079GetIndexFromSupportedLangCodes(\r
1080 IN CHAR8 *SupportedLang,\r
1081 IN CHAR8 *Lang,\r
1082 IN BOOLEAN Iso639Language\r
1083 ) \r
8d3a5c82 1084{\r
72399dae 1085 UINTN Index;\r
1086 UINT32 CompareLength;\r
1087 CHAR8 *Supported;\r
1088\r
1089 Index = 0;\r
1090 Supported = SupportedLang;\r
1091 if (Iso639Language) {\r
1092 CompareLength = 3;\r
1093 for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {\r
1094 if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {\r
1095 //\r
1096 // Successfully find the index of Lang string in SupportedLang string.\r
1097 //\r
1098 Index = Index / CompareLength;\r
1099 return Index;\r
1100 }\r
1101 }\r
1102 ASSERT (FALSE);\r
1103 return 0;\r
1104 } else {\r
1105 //\r
0254efc0 1106 // Compare RFC4646 language code\r
72399dae 1107 //\r
1108 while (*Supported != '\0') {\r
1109 //\r
1110 // take semicolon as delimitation, sequentially traverse supported language codes.\r
1111 //\r
1112 for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {\r
1113 Supported++;\r
1114 }\r
1115 if (AsciiStrnCmp (Lang, Supported - CompareLength, CompareLength) == 0) {\r
1116 //\r
1117 // Successfully find the index of Lang string in SupportedLang string.\r
1118 //\r
1119 return Index;\r
1120 }\r
1121 Index++;\r
1122 }\r
1123 ASSERT (FALSE);\r
1124 return 0;\r
8d3a5c82 1125 }\r
72399dae 1126}\r
33a5a666 1127\r
72399dae 1128/**\r
1129 Get language string from supported language codes according to index.\r
1130\r
1131 This code is used to get corresponding language string in supported language codes. It can handle\r
0254efc0 1132 RFC4646 and ISO639 language tags.\r
72399dae 1133 In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.\r
0254efc0 1134 In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.\r
72399dae 1135\r
1136 For example:\r
1137 SupportedLang = "engfraengfra"\r
1138 Index = "1"\r
1139 Iso639Language = TRUE\r
1140 The return value is "fra".\r
1141 Another example:\r
1142 SupportedLang = "en;fr;en-US;fr-FR"\r
1143 Index = "1"\r
1144 Iso639Language = FALSE\r
1145 The return value is "fr".\r
1146\r
1147 @param SupportedLang Platform supported language codes.\r
1148 @param Index the index in supported language codes.\r
0254efc0 1149 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
72399dae 1150\r
1151 @retval the language string in the language codes.\r
8d3a5c82 1152\r
72399dae 1153**/\r
1154CHAR8 *\r
1155EFIAPI\r
1156GetLangFromSupportedLangCodes (\r
1157 IN CHAR8 *SupportedLang,\r
1158 IN UINTN Index,\r
1159 IN BOOLEAN Iso639Language\r
1160)\r
1161{\r
1162 UINTN SubIndex;\r
1163 UINT32 CompareLength;\r
1164 CHAR8 *Supported;\r
8d3a5c82 1165\r
72399dae 1166 SubIndex = 0;\r
1167 Supported = SupportedLang;\r
1168 if (Iso639Language) {\r
1169 //\r
1170 // according to the index of Lang string in SupportedLang string to get the language.\r
1171 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.\r
1172 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
1173 //\r
1174 CompareLength = 3;\r
1175 SetMem (mVariableModuleGlobal->Lang, sizeof(mVariableModuleGlobal->Lang), 0);\r
1176 return CopyMem (mVariableModuleGlobal->Lang, SupportedLang + Index * CompareLength, CompareLength);\r
1177 \r
8d3a5c82 1178 } else {\r
72399dae 1179 while (TRUE) {\r
1180 //\r
1181 // take semicolon as delimitation, sequentially traverse supported language codes.\r
1182 //\r
1183 for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {\r
1184 Supported++;\r
1185 }\r
1186 if ((*Supported == '\0') && (SubIndex != Index)) {\r
1187 //\r
1188 // Have completed the traverse, but not find corrsponding string.\r
1189 // This case is not allowed to happen.\r
1190 //\r
1191 ASSERT(FALSE);\r
1192 return NULL;\r
1193 }\r
1194 if (SubIndex == Index) {\r
1195 //\r
1196 // according to the index of Lang string in SupportedLang string to get the language.\r
1197 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.\r
1198 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
1199 //\r
1200 SetMem (mVariableModuleGlobal->PlatformLang, sizeof (mVariableModuleGlobal->PlatformLang), 0);\r
1201 return CopyMem (mVariableModuleGlobal->PlatformLang, Supported - CompareLength, CompareLength);\r
1202 }\r
1203 SubIndex++;\r
1204 }\r
8d3a5c82 1205 }\r
8d3a5c82 1206}\r
1207\r
72399dae 1208/**\r
1209 Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.\r
052ad7e1 1210\r
72399dae 1211 When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.\r
052ad7e1 1212\r
72399dae 1213 According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,\r
1214 and are read-only. Therefore, in variable driver, only store the original value for other use.\r
8d3a5c82 1215\r
72399dae 1216 @param[in] VariableName Name of variable\r
8d3a5c82 1217\r
72399dae 1218 @param[in] Data Variable data\r
8d3a5c82 1219\r
72399dae 1220 @param[in] DataSize Size of data. 0 means delete\r
1221\r
1222 @retval EFI_SUCCESS auto update operation is successful.\r
8d3a5c82 1223\r
7c80e839 1224**/\r
052ad7e1
A
1225EFI_STATUS\r
1226EFIAPI\r
72399dae 1227AutoUpdateLangVariable(\r
1228 IN CHAR16 *VariableName,\r
1229 IN VOID *Data,\r
1230 IN UINTN DataSize\r
052ad7e1 1231 )\r
8d3a5c82 1232{\r
72399dae 1233 EFI_STATUS Status;\r
1234 CHAR8 *BestPlatformLang;\r
1235 CHAR8 *BestLang;\r
1236 UINTN Index;\r
1237 UINT32 Attributes;\r
1238 VARIABLE_POINTER_TRACK Variable;\r
8d3a5c82 1239\r
72399dae 1240 //\r
1241 // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.\r
1242 //\r
1243 Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;\r
8d3a5c82 1244\r
72399dae 1245 if (StrCmp (VariableName, L"PlatformLangCodes") == 0) {\r
1246 //\r
1247 // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only\r
1248 // Therefore, in variable driver, only store the original value for other use.\r
1249 //\r
1250 AsciiStrnCpy (mVariableModuleGlobal->PlatformLangCodes, Data, DataSize);\r
1251 } else if (StrCmp (VariableName, L"LangCodes") == 0) {\r
1252 //\r
1253 // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only\r
1254 // Therefore, in variable driver, only store the original value for other use.\r
1255 //\r
1256 AsciiStrnCpy (mVariableModuleGlobal->LangCodes, Data, DataSize);\r
1257 } else if (StrCmp (VariableName, L"PlatformLang") == 0) {\r
1258 ASSERT (AsciiStrLen (mVariableModuleGlobal->PlatformLangCodes) != 0);\r
fdb7765f 1259\r
72399dae 1260 //\r
1261 // When setting PlatformLang, firstly get most matched language string from supported language codes.\r
1262 //\r
bd397350 1263 BestPlatformLang = GetBestLanguage(mVariableModuleGlobal->PlatformLangCodes, FALSE, Data, NULL);\r
8d3a5c82 1264\r
8d3a5c82 1265 //\r
72399dae 1266 // Get the corresponding index in language codes.\r
8d3a5c82 1267 //\r
72399dae 1268 Index = GetIndexFromSupportedLangCodes(mVariableModuleGlobal->PlatformLangCodes, BestPlatformLang, FALSE);\r
8d3a5c82 1269\r
8d3a5c82 1270 //\r
0254efc0 1271 // Get the corresponding ISO639 language tag according to RFC4646 language tag.\r
8d3a5c82 1272 //\r
72399dae 1273 BestLang = GetLangFromSupportedLangCodes(mVariableModuleGlobal->LangCodes, Index, TRUE);\r
8d3a5c82 1274\r
8d3a5c82 1275 //\r
72399dae 1276 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.\r
8d3a5c82 1277 //\r
72399dae 1278 FindVariable(L"Lang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal);\r
fdb7765f 1279\r
72399dae 1280 Status = UpdateVariable(L"Lang", &gEfiGlobalVariableGuid, \r
1281 BestLang, ISO_639_2_ENTRY_SIZE + 1, Attributes, &Variable);\r
8d3a5c82 1282\r
72399dae 1283 DEBUG((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang));\r
8d3a5c82 1284\r
72399dae 1285 ASSERT_EFI_ERROR(Status);\r
1286 \r
1287 } else if (StrCmp (VariableName, L"Lang") == 0) {\r
1288 ASSERT (AsciiStrLen (mVariableModuleGlobal->LangCodes) != 0);\r
8d3a5c82 1289\r
72399dae 1290 //\r
1291 // When setting Lang, firstly get most matched language string from supported language codes.\r
1292 //\r
bd397350 1293 BestLang = GetBestLanguage(mVariableModuleGlobal->LangCodes, TRUE, Data, NULL);\r
72399dae 1294\r
1295 //\r
1296 // Get the corresponding index in language codes.\r
1297 //\r
1298 Index = GetIndexFromSupportedLangCodes(mVariableModuleGlobal->LangCodes, BestLang, TRUE);\r
1299\r
1300 //\r
0254efc0 1301 // Get the corresponding RFC4646 language tag according to ISO639 language tag.\r
72399dae 1302 //\r
1303 BestPlatformLang = GetLangFromSupportedLangCodes(mVariableModuleGlobal->PlatformLangCodes, Index, FALSE);\r
1304\r
1305 //\r
1306 // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.\r
1307 //\r
1308 FindVariable(L"PlatformLang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal);\r
1309\r
1310 Status = UpdateVariable(L"PlatformLang", &gEfiGlobalVariableGuid, \r
a1373617 1311 BestPlatformLang, AsciiStrSize (BestPlatformLang), Attributes, &Variable);\r
72399dae 1312\r
1313 DEBUG((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a\n", BestLang, BestPlatformLang));\r
1314 ASSERT_EFI_ERROR(Status);\r
1315 }\r
1316 return EFI_SUCCESS;\r
8d3a5c82 1317}\r
1318\r
7c80e839 1319/**\r
72399dae 1320 Update the variable region with Variable information. These are the same \r
1321 arguments as the EFI Variable services.\r
052ad7e1 1322\r
72399dae 1323 @param[in] VariableName Name of variable\r
8d3a5c82 1324\r
72399dae 1325 @param[in] VendorGuid Guid of variable\r
8d3a5c82 1326\r
72399dae 1327 @param[in] Data Variable data\r
1328\r
1329 @param[in] DataSize Size of data. 0 means delete\r
1330\r
1331 @param[in] Attributes Attribues of the variable\r
1332\r
1333 @param[in] Variable The variable information which is used to keep track of variable usage.\r
1334\r
1335 @retval EFI_SUCCESS The update operation is success.\r
1336\r
1337 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.\r
8d3a5c82 1338\r
7c80e839 1339**/\r
052ad7e1
A
1340EFI_STATUS\r
1341EFIAPI\r
72399dae 1342UpdateVariable (\r
1343 IN CHAR16 *VariableName,\r
1344 IN EFI_GUID *VendorGuid,\r
1345 IN VOID *Data,\r
1346 IN UINTN DataSize,\r
1347 IN UINT32 Attributes OPTIONAL,\r
1348 IN VARIABLE_POINTER_TRACK *Variable\r
052ad7e1 1349 )\r
8d3a5c82 1350{\r
8a9e0b72 1351 EFI_STATUS Status;\r
1352 VARIABLE_HEADER *NextVariable;\r
72399dae 1353 UINTN ScratchSize;\r
1354 UINTN NonVolatileVarableStoreSize;\r
8a9e0b72 1355 UINTN VarNameOffset;\r
1356 UINTN VarDataOffset;\r
72399dae 1357 UINTN VarNameSize;\r
8a9e0b72 1358 UINTN VarSize;\r
72399dae 1359 BOOLEAN Volatile;\r
1360 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
8a9e0b72 1361 UINT8 State;\r
1362 BOOLEAN Reclaimed;\r
fdb7765f 1363\r
8a9e0b72 1364 Fvb = mVariableModuleGlobal->FvbInstance;\r
72399dae 1365 Reclaimed = FALSE;\r
fdb7765f 1366\r
72399dae 1367 if (Variable->CurrPtr != NULL) {\r
8d3a5c82 1368 //\r
c6492839 1369 // Update/Delete existing variable\r
8d3a5c82 1370 //\r
72399dae 1371 Volatile = Variable->Volatile;\r
c6492839 1372 \r
1373 if (EfiAtRuntime ()) { \r
1374 //\r
1375 // If EfiAtRuntime and the variable is Volatile and Runtime Access, \r
1376 // the volatile is ReadOnly, and SetVariable should be aborted and \r
1377 // return EFI_WRITE_PROTECTED.\r
1378 //\r
72399dae 1379 if (Variable->Volatile) {\r
c6492839 1380 Status = EFI_WRITE_PROTECTED;\r
1381 goto Done;\r
1382 }\r
1383 //\r
1384 // Only variable have NV attribute can be updated/deleted in Runtime\r
1385 //\r
72399dae 1386 if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
c6492839 1387 Status = EFI_INVALID_PARAMETER;\r
1388 goto Done; \r
1389 }\r
1390 }\r
8d3a5c82 1391 //\r
c6492839 1392 // Setting a data variable with no access, or zero DataSize attributes\r
1393 // specified causes it to be deleted.\r
8d3a5c82 1394 //\r
c6492839 1395 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) { \r
72399dae 1396 State = Variable->CurrPtr->State;\r
c6492839 1397 State &= VAR_DELETED;\r
1398\r
1399 Status = UpdateVariableStore (\r
052ad7e1 1400 &mVariableModuleGlobal->VariableGlobal,\r
72399dae 1401 Variable->Volatile,\r
c6492839 1402 FALSE,\r
8a9e0b72 1403 Fvb,\r
72399dae 1404 (UINTN) &Variable->CurrPtr->State,\r
c6492839 1405 sizeof (UINT8),\r
1406 &State\r
1407 ); \r
33a5a666 1408 if (!EFI_ERROR (Status)) {\r
fd51bf70 1409 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, FALSE, TRUE, FALSE);\r
33a5a666
A
1410 UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
1411 }\r
c6492839 1412 goto Done; \r
1413 }\r
8d3a5c82 1414 //\r
c6492839 1415 // If the variable is marked valid and the same data has been passed in\r
1416 // then return to the caller immediately.\r
8d3a5c82 1417 //\r
72399dae 1418 if (DataSizeOfVariable (Variable->CurrPtr) == DataSize &&\r
1419 (CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0)) {\r
33a5a666 1420 \r
fd51bf70 1421 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
c6492839 1422 Status = EFI_SUCCESS;\r
1423 goto Done;\r
72399dae 1424 } else if ((Variable->CurrPtr->State == VAR_ADDED) ||\r
1425 (Variable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {\r
814bae52 1426\r
c6492839 1427 //\r
1428 // Mark the old variable as in delete transition\r
1429 //\r
72399dae 1430 State = Variable->CurrPtr->State;\r
c6492839 1431 State &= VAR_IN_DELETED_TRANSITION;\r
1432\r
1433 Status = UpdateVariableStore (\r
052ad7e1 1434 &mVariableModuleGlobal->VariableGlobal,\r
72399dae 1435 Variable->Volatile,\r
c6492839 1436 FALSE,\r
8a9e0b72 1437 Fvb,\r
72399dae 1438 (UINTN) &Variable->CurrPtr->State,\r
c6492839 1439 sizeof (UINT8),\r
1440 &State\r
1441 ); \r
1442 if (EFI_ERROR (Status)) {\r
1443 goto Done; \r
33a5a666 1444 } \r
c6492839 1445 } \r
72399dae 1446 } else {\r
8d3a5c82 1447 //\r
72399dae 1448 // Not found existing variable. Create a new variable\r
c6492839 1449 // \r
1450 \r
8d3a5c82 1451 //\r
c6492839 1452 // Make sure we are trying to create a new variable.\r
1453 // Setting a data variable with no access, or zero DataSize attributes means to delete it. \r
8d3a5c82 1454 //\r
c6492839 1455 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {\r
1456 Status = EFI_NOT_FOUND;\r
1457 goto Done;\r
1458 }\r
1459 \r
8d3a5c82 1460 //\r
c6492839 1461 // Only variable have NV|RT attribute can be created in Runtime\r
1462 //\r
1463 if (EfiAtRuntime () &&\r
45f6c85b 1464 (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {\r
c6492839 1465 Status = EFI_INVALID_PARAMETER;\r
1466 goto Done;\r
1467 } \r
c6492839 1468 }\r
1469\r
1470 //\r
1471 // Function part - create a new variable and copy the data.\r
1472 // Both update a variable and create a variable will come here.\r
1473 //\r
1474 // Tricky part: Use scratch data area at the end of volatile variable store\r
1475 // as a temporary storage.\r
1476 //\r
052ad7e1 1477 NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));\r
2fcdca1d 1478 ScratchSize = MAX(FixedPcdGet32(PcdMaxVariableSize), FixedPcdGet32(PcdMaxHardwareErrorVariableSize));\r
c6492839 1479\r
2fcdca1d 1480 SetMem (NextVariable, ScratchSize, 0xff);\r
c6492839 1481\r
1482 NextVariable->StartId = VARIABLE_DATA;\r
1483 NextVariable->Attributes = Attributes;\r
1484 //\r
1485 // NextVariable->State = VAR_ADDED;\r
1486 //\r
1487 NextVariable->Reserved = 0;\r
1488 VarNameOffset = sizeof (VARIABLE_HEADER);\r
1489 VarNameSize = StrSize (VariableName);\r
1490 CopyMem (\r
1491 (UINT8 *) ((UINTN) NextVariable + VarNameOffset),\r
1492 VariableName,\r
1493 VarNameSize\r
1494 );\r
1495 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);\r
1496 CopyMem (\r
1497 (UINT8 *) ((UINTN) NextVariable + VarDataOffset),\r
1498 Data,\r
1499 DataSize\r
1500 );\r
1501 CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));\r
1502 //\r
1503 // There will be pad bytes after Data, the NextVariable->NameSize and\r
1504 // NextVariable->DataSize should not include pad size so that variable\r
1505 // service can get actual size in GetVariable\r
1506 //\r
1507 NextVariable->NameSize = (UINT32)VarNameSize;\r
1508 NextVariable->DataSize = (UINT32)DataSize;\r
1509\r
1510 //\r
1511 // The actual size of the variable that stores in storage should\r
1512 // include pad size.\r
1513 //\r
1514 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);\r
45f6c85b 1515 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
8d3a5c82 1516 //\r
c6492839 1517 // Create a nonvolatile variable\r
8d3a5c82 1518 //\r
fd51bf70 1519 Volatile = FALSE;\r
2fcdca1d 1520 NonVolatileVarableStoreSize = ((VARIABLE_STORE_HEADER *)(UINTN)(mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase))->Size;\r
1521 if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \r
1522 && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > FixedPcdGet32(PcdHwErrStorageSize)))\r
1523 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
1524 && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - FixedPcdGet32(PcdHwErrStorageSize)))) {\r
c6492839 1525 if (EfiAtRuntime ()) {\r
1526 Status = EFI_OUT_OF_RESOURCES;\r
1527 goto Done;\r
1528 }\r
1529 //\r
1530 // Perform garbage collection & reclaim operation\r
1531 //\r
72399dae 1532 Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, \r
1533 &mVariableModuleGlobal->NonVolatileLastVariableOffset, FALSE, Variable->CurrPtr);\r
8d3a5c82 1534 if (EFI_ERROR (Status)) {\r
1535 goto Done;\r
1536 }\r
8d3a5c82 1537 //\r
c6492839 1538 // If still no enough space, return out of resources\r
8d3a5c82 1539 //\r
2fcdca1d 1540 if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \r
1541 && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > FixedPcdGet32(PcdHwErrStorageSize)))\r
1542 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
1543 && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - FixedPcdGet32(PcdHwErrStorageSize)))) {\r
c6492839 1544 Status = EFI_OUT_OF_RESOURCES;\r
8d3a5c82 1545 goto Done;\r
8d3a5c82 1546 }\r
c6492839 1547 Reclaimed = TRUE;\r
8d3a5c82 1548 }\r
1549 //\r
c6492839 1550 // Three steps\r
1551 // 1. Write variable header\r
130e2569 1552 // 2. Set variable state to header valid \r
1553 // 3. Write variable data\r
1554 // 4. Set variable state to valid\r
8d3a5c82 1555 //\r
8d3a5c82 1556 //\r
c6492839 1557 // Step 1:\r
8d3a5c82 1558 //\r
c6492839 1559 Status = UpdateVariableStore (\r
052ad7e1 1560 &mVariableModuleGlobal->VariableGlobal,\r
c6492839 1561 FALSE,\r
1562 TRUE,\r
8a9e0b72 1563 Fvb,\r
72399dae 1564 mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
c6492839 1565 sizeof (VARIABLE_HEADER),\r
1566 (UINT8 *) NextVariable\r
1567 );\r
1568\r
1569 if (EFI_ERROR (Status)) {\r
1570 goto Done;\r
1571 }\r
130e2569 1572\r
8d3a5c82 1573 //\r
c6492839 1574 // Step 2:\r
8d3a5c82 1575 //\r
130e2569 1576 NextVariable->State = VAR_HEADER_VALID_ONLY;\r
1577 Status = UpdateVariableStore (\r
1578 &mVariableModuleGlobal->VariableGlobal,\r
1579 FALSE,\r
1580 TRUE,\r
8a9e0b72 1581 Fvb,\r
72399dae 1582 mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
130e2569 1583 sizeof (VARIABLE_HEADER),\r
1584 (UINT8 *) NextVariable\r
1585 );\r
1586\r
1587 if (EFI_ERROR (Status)) {\r
1588 goto Done;\r
1589 }\r
1590 //\r
1591 // Step 3:\r
1592 //\r
c6492839 1593 Status = UpdateVariableStore (\r
052ad7e1 1594 &mVariableModuleGlobal->VariableGlobal,\r
c6492839 1595 FALSE,\r
1596 TRUE,\r
8a9e0b72 1597 Fvb,\r
72399dae 1598 mVariableModuleGlobal->NonVolatileLastVariableOffset + sizeof (VARIABLE_HEADER),\r
c6492839 1599 (UINT32) VarSize - sizeof (VARIABLE_HEADER),\r
1600 (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)\r
1601 );\r
1602\r
1603 if (EFI_ERROR (Status)) {\r
1604 goto Done;\r
1605 }\r
8d3a5c82 1606 //\r
130e2569 1607 // Step 4:\r
8d3a5c82 1608 //\r
c6492839 1609 NextVariable->State = VAR_ADDED;\r
1610 Status = UpdateVariableStore (\r
052ad7e1 1611 &mVariableModuleGlobal->VariableGlobal,\r
c6492839 1612 FALSE,\r
1613 TRUE,\r
8a9e0b72 1614 Fvb,\r
72399dae 1615 mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
c6492839 1616 sizeof (VARIABLE_HEADER),\r
1617 (UINT8 *) NextVariable\r
1618 );\r
1619\r
1620 if (EFI_ERROR (Status)) {\r
1621 goto Done;\r
1622 }\r
8d3a5c82 1623\r
72399dae 1624 mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
8d3a5c82 1625\r
2fcdca1d 1626 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {\r
1627 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);\r
1628 } else {\r
1629 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VarSize);\r
1630 }\r
c6492839 1631 } else {\r
1632 //\r
1633 // Create a volatile variable\r
1634 // \r
fd51bf70 1635 Volatile = TRUE;\r
c6492839 1636\r
72399dae 1637 if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >\r
052ad7e1 1638 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) {\r
8d3a5c82 1639 //\r
c6492839 1640 // Perform garbage collection & reclaim operation\r
8d3a5c82 1641 //\r
72399dae 1642 Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase, \r
1643 &mVariableModuleGlobal->VolatileLastVariableOffset, TRUE, Variable->CurrPtr);\r
8d3a5c82 1644 if (EFI_ERROR (Status)) {\r
1645 goto Done;\r
1646 }\r
1647 //\r
c6492839 1648 // If still no enough space, return out of resources\r
8d3a5c82 1649 //\r
72399dae 1650 if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >\r
052ad7e1 1651 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size\r
8d3a5c82 1652 ) {\r
c6492839 1653 Status = EFI_OUT_OF_RESOURCES;\r
8d3a5c82 1654 goto Done;\r
1655 }\r
c6492839 1656 Reclaimed = TRUE;\r
8d3a5c82 1657 }\r
8d3a5c82 1658\r
c6492839 1659 NextVariable->State = VAR_ADDED;\r
1660 Status = UpdateVariableStore (\r
052ad7e1 1661 &mVariableModuleGlobal->VariableGlobal,\r
c6492839 1662 TRUE,\r
1663 TRUE,\r
8a9e0b72 1664 Fvb,\r
72399dae 1665 mVariableModuleGlobal->VolatileLastVariableOffset,\r
c6492839 1666 (UINT32) VarSize,\r
1667 (UINT8 *) NextVariable\r
1668 );\r
1669\r
1670 if (EFI_ERROR (Status)) {\r
1671 goto Done;\r
8d3a5c82 1672 }\r
c6492839 1673\r
72399dae 1674 mVariableModuleGlobal->VolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
c6492839 1675 }\r
72399dae 1676\r
c6492839 1677 //\r
1678 // Mark the old variable as deleted\r
1679 //\r
72399dae 1680 if (!Reclaimed && !EFI_ERROR (Status) && Variable->CurrPtr != NULL) {\r
1681 State = Variable->CurrPtr->State;\r
c6492839 1682 State &= VAR_DELETED;\r
1683\r
1684 Status = UpdateVariableStore (\r
72399dae 1685 &mVariableModuleGlobal->VariableGlobal,\r
1686 Variable->Volatile,\r
1687 FALSE,\r
1688 Fvb,\r
1689 (UINTN) &Variable->CurrPtr->State,\r
1690 sizeof (UINT8),\r
1691 &State\r
1692 );\r
1693 }\r
1694\r
1695 if (!EFI_ERROR (Status)) {\r
1696 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
1697 UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
1698 }\r
1699\r
1700Done:\r
1701 return Status;\r
1702}\r
1703\r
1704/**\r
1705\r
1706 This code finds variable in storage blocks (Volatile or Non-Volatile).\r
1707\r
1708 @param VariableName Name of Variable to be found.\r
1709 @param VendorGuid Variable vendor GUID.\r
1710 @param Attributes Attribute value of the variable found.\r
1711 @param DataSize Size of Data found. If size is less than the\r
1712 data, this value contains the required size.\r
1713 @param Data Data pointer.\r
1714 \r
1715 @return EFI_INVALID_PARAMETER Invalid parameter\r
1716 @return EFI_SUCCESS Find the specified variable\r
1717 @return EFI_NOT_FOUND Not found\r
1718 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result\r
1719\r
1720**/\r
1721EFI_STATUS\r
1722EFIAPI\r
1723RuntimeServiceGetVariable (\r
1724 IN CHAR16 *VariableName,\r
1725 IN EFI_GUID *VendorGuid,\r
1726 OUT UINT32 *Attributes OPTIONAL,\r
1727 IN OUT UINTN *DataSize,\r
1728 OUT VOID *Data\r
1729 )\r
1730{\r
1731 EFI_STATUS Status;\r
1732 VARIABLE_POINTER_TRACK Variable;\r
1733 UINTN VarDataSize;\r
1734\r
1735 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
1736 return EFI_INVALID_PARAMETER;\r
1737 }\r
1738\r
1739 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
1740\r
1741 //\r
1742 // Find existing variable\r
1743 //\r
1744 Status = FindVariableInCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
1745 if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_SUCCESS)){\r
1746 // Hit in the Cache\r
1747 UpdateVariableInfo (VariableName, VendorGuid, FALSE, TRUE, FALSE, FALSE, TRUE);\r
1748 goto Done;\r
1749 }\r
1750 \r
1751 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
1752 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
1753 goto Done;\r
1754 }\r
1755\r
1756 //\r
1757 // Get data size\r
1758 //\r
1759 VarDataSize = DataSizeOfVariable (Variable.CurrPtr);\r
1760 ASSERT (VarDataSize != 0);\r
1761\r
1762 if (*DataSize >= VarDataSize) {\r
1763 if (Data == NULL) {\r
1764 Status = EFI_INVALID_PARAMETER;\r
1765 goto Done;\r
33a5a666 1766 }\r
72399dae 1767\r
1768 CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);\r
1769 if (Attributes != NULL) {\r
1770 *Attributes = Variable.CurrPtr->Attributes;\r
1771 }\r
1772\r
1773 *DataSize = VarDataSize;\r
1774 UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);\r
1775 UpdateVariableCache (VariableName, VendorGuid, Variable.CurrPtr->Attributes, VarDataSize, Data);\r
1776 \r
1777 Status = EFI_SUCCESS;\r
1778 goto Done;\r
1779 } else {\r
1780 *DataSize = VarDataSize;\r
1781 Status = EFI_BUFFER_TOO_SMALL;\r
1782 goto Done;\r
8d3a5c82 1783 }\r
1784\r
72399dae 1785Done:\r
1786 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
1787 return Status;\r
1788}\r
1789\r
1790\r
1791\r
1792/**\r
1793\r
1794 This code Finds the Next available variable.\r
1795\r
1796 @param VariableNameSize Size of the variable name\r
1797 @param VariableName Pointer to variable name\r
1798 @param VendorGuid Variable Vendor Guid\r
1799\r
1800 @return EFI_INVALID_PARAMETER Invalid parameter\r
1801 @return EFI_SUCCESS Find the specified variable\r
1802 @return EFI_NOT_FOUND Not found\r
1803 @return EFI_BUFFER_TO_SMALL DataSize is too small for the result\r
1804\r
1805**/\r
1806EFI_STATUS\r
1807EFIAPI\r
1808RuntimeServiceGetNextVariableName (\r
1809 IN OUT UINTN *VariableNameSize,\r
1810 IN OUT CHAR16 *VariableName,\r
1811 IN OUT EFI_GUID *VendorGuid\r
1812 )\r
1813{\r
1814 VARIABLE_POINTER_TRACK Variable;\r
1815 UINTN VarNameSize;\r
1816 EFI_STATUS Status;\r
1817\r
1818 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
1819 return EFI_INVALID_PARAMETER;\r
1820 }\r
1821\r
1822 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
1823\r
1824 Status = FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
1825 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {\r
1826 goto Done;\r
1827 }\r
1828\r
1829 if (VariableName[0] != 0) {\r
1830 //\r
1831 // If variable name is not NULL, get next variable\r
1832 //\r
1833 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
1834 }\r
1835\r
1836 while (TRUE) {\r
1837 //\r
1838 // If both volatile and non-volatile variable store are parsed,\r
1839 // return not found\r
1840 //\r
1841 if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) {\r
1842 Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));\r
1843 if (!Variable.Volatile) {\r
1844 Variable.StartPtr = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
1845 Variable.EndPtr = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase));\r
1846 } else {\r
1847 Status = EFI_NOT_FOUND;\r
1848 goto Done;\r
1849 }\r
1850\r
1851 Variable.CurrPtr = Variable.StartPtr;\r
1852 if (!IsValidVariableHeader (Variable.CurrPtr)) {\r
1853 continue;\r
1854 }\r
1855 }\r
1856 //\r
1857 // Variable is found\r
1858 //\r
1859 if (IsValidVariableHeader (Variable.CurrPtr) && Variable.CurrPtr->State == VAR_ADDED) {\r
1860 if ((EfiAtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) == 0) {\r
1861 VarNameSize = NameSizeOfVariable (Variable.CurrPtr);\r
1862 ASSERT (VarNameSize != 0);\r
1863\r
1864 if (VarNameSize <= *VariableNameSize) {\r
1865 CopyMem (\r
1866 VariableName,\r
1867 GetVariableNamePtr (Variable.CurrPtr),\r
1868 VarNameSize\r
1869 );\r
1870 CopyMem (\r
1871 VendorGuid,\r
1872 &Variable.CurrPtr->VendorGuid,\r
1873 sizeof (EFI_GUID)\r
1874 );\r
1875 Status = EFI_SUCCESS;\r
1876 } else {\r
1877 Status = EFI_BUFFER_TOO_SMALL;\r
1878 }\r
1879\r
1880 *VariableNameSize = VarNameSize;\r
1881 goto Done;\r
1882 }\r
1883 }\r
1884\r
1885 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
1886 }\r
33a5a666 1887\r
8d3a5c82 1888Done:\r
72399dae 1889 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
1890 return Status;\r
1891}\r
1892\r
1893/**\r
1894\r
1895 This code sets variable in storage blocks (Volatile or Non-Volatile).\r
1896\r
1897 @param VariableName Name of Variable to be found\r
1898 @param VendorGuid Variable vendor GUID\r
1899 @param Attributes Attribute value of the variable found\r
1900 @param DataSize Size of Data found. If size is less than the\r
1901 data, this value contains the required size.\r
1902 @param Data Data pointer\r
1903\r
1904 @return EFI_INVALID_PARAMETER Invalid parameter\r
1905 @return EFI_SUCCESS Set successfully\r
1906 @return EFI_OUT_OF_RESOURCES Resource not enough to set variable\r
1907 @return EFI_NOT_FOUND Not found\r
1908 @return EFI_WRITE_PROTECTED Variable is read-only\r
1909\r
1910**/\r
1911EFI_STATUS\r
1912EFIAPI\r
1913RuntimeServiceSetVariable (\r
1914 IN CHAR16 *VariableName,\r
1915 IN EFI_GUID *VendorGuid,\r
1916 IN UINT32 Attributes,\r
1917 IN UINTN DataSize,\r
1918 IN VOID *Data\r
1919 )\r
1920{\r
1921 VARIABLE_POINTER_TRACK Variable;\r
1922 EFI_STATUS Status;\r
1923 VARIABLE_HEADER *NextVariable;\r
1924 EFI_PHYSICAL_ADDRESS Point;\r
1925\r
1926 //\r
1927 // Check input parameters\r
1928 //\r
1929 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
1930 return EFI_INVALID_PARAMETER;\r
1931 } \r
1932 //\r
1933 // Make sure if runtime bit is set, boot service bit is set also\r
1934 //\r
1935 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
1936 return EFI_INVALID_PARAMETER;\r
1937 }\r
1938\r
1939 //\r
1940 // The size of the VariableName, including the Unicode Null in bytes plus\r
1941 // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxHardwareErrorVariableSize)\r
1942 // bytes for HwErrRec, and FixedPcdGet32(PcdMaxVariableSize) bytes for the others.\r
1943 //\r
1944 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
1945 if ((DataSize > FixedPcdGet32(PcdMaxHardwareErrorVariableSize)) ||\r
1946 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > FixedPcdGet32(PcdMaxHardwareErrorVariableSize))) {\r
1947 return EFI_INVALID_PARAMETER;\r
1948 }\r
1949 //\r
1950 // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX"\r
1951 //\r
1952 if (StrnCmp(VariableName, L"HwErrRec", StrLen(L"HwErrRec")) != 0) {\r
1953 return EFI_INVALID_PARAMETER;\r
1954 }\r
1955 } else {\r
1956 //\r
1957 // The size of the VariableName, including the Unicode Null in bytes plus\r
1958 // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxVariableSize) bytes.\r
1959 //\r
1960 if ((DataSize > FixedPcdGet32(PcdMaxVariableSize)) ||\r
1961 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > FixedPcdGet32(PcdMaxVariableSize))) {\r
1962 return EFI_INVALID_PARAMETER;\r
1963 } \r
1964 } \r
1965\r
1966 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
1967\r
1968 //\r
1969 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated;\r
1970 //\r
1971 if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {\r
1972 Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;;\r
1973 //\r
1974 // Parse non-volatile variable data and get last variable offset\r
1975 //\r
1976 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point);\r
1977 while ((NextVariable < GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point)) \r
1978 && IsValidVariableHeader (NextVariable)) {\r
1979 NextVariable = GetNextVariablePtr (NextVariable);\r
1980 }\r
1981 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;\r
1982 }\r
1983\r
1984 //\r
1985 // Check whether the input variable is already existed\r
1986 //\r
1987 FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
1988\r
1989 //\r
1990 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang\r
1991 //\r
1992 AutoUpdateLangVariable (VariableName, Data, DataSize);\r
1993\r
1994 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, &Variable);\r
1995\r
fdb7765f 1996 InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);\r
052ad7e1 1997 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
fdb7765f 1998\r
8d3a5c82 1999 return Status;\r
2000}\r
2001\r
7c80e839 2002/**\r
8d3a5c82 2003\r
2004 This code returns information about the EFI variables.\r
2005\r
7c80e839 2006 @param Attributes Attributes bitmask to specify the type of variables\r
2007 on which to return information.\r
2008 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
2009 for the EFI variables associated with the attributes specified.\r
2010 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
2011 for EFI variables associated with the attributes specified.\r
2012 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables\r
2013 associated with the attributes specified.\r
8d3a5c82 2014\r
7c80e839 2015 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.\r
2016 @return EFI_SUCCESS Query successfully.\r
2017 @return EFI_UNSUPPORTED The attribute is not supported on this platform.\r
8d3a5c82 2018\r
7c80e839 2019**/\r
052ad7e1
A
2020EFI_STATUS\r
2021EFIAPI\r
2022RuntimeServiceQueryVariableInfo (\r
2023 IN UINT32 Attributes,\r
2024 OUT UINT64 *MaximumVariableStorageSize,\r
2025 OUT UINT64 *RemainingVariableStorageSize,\r
2026 OUT UINT64 *MaximumVariableSize\r
2027 )\r
8d3a5c82 2028{\r
2029 VARIABLE_HEADER *Variable;\r
2030 VARIABLE_HEADER *NextVariable;\r
2031 UINT64 VariableSize;\r
2032 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
2fcdca1d 2033 UINT64 CommonVariableTotalSize;\r
2034 UINT64 HwErrVariableTotalSize;\r
2035\r
2036 CommonVariableTotalSize = 0;\r
2037 HwErrVariableTotalSize = 0;\r
8d3a5c82 2038\r
c6492839 2039 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
8d3a5c82 2040 return EFI_INVALID_PARAMETER;\r
2041 }\r
2fcdca1d 2042\r
c6492839 2043 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {\r
8d3a5c82 2044 //\r
2045 // Make sure the Attributes combination is supported by the platform.\r
2046 //\r
c6492839 2047 return EFI_UNSUPPORTED; \r
8d3a5c82 2048 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
2049 //\r
2050 // Make sure if runtime bit is set, boot service bit is set also.\r
2051 //\r
2052 return EFI_INVALID_PARAMETER;\r
45f6c85b 2053 } else if (EfiAtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {\r
8d3a5c82 2054 //\r
2055 // Make sure RT Attribute is set if we are in Runtime phase.\r
2056 //\r
2057 return EFI_INVALID_PARAMETER;\r
2fcdca1d 2058 } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2059 //\r
2060 // Make sure Hw Attribute is set with NV.\r
2061 //\r
2062 return EFI_INVALID_PARAMETER;\r
8d3a5c82 2063 }\r
2064\r
052ad7e1 2065 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
8d3a5c82 2066\r
2067 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
2068 //\r
2069 // Query is Volatile related.\r
2070 //\r
052ad7e1 2071 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
8d3a5c82 2072 } else {\r
2073 //\r
2074 // Query is Non-Volatile related.\r
2075 //\r
052ad7e1 2076 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
8d3a5c82 2077 }\r
2078\r
2079 //\r
2080 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize\r
2081 // with the storage size (excluding the storage header size).\r
2082 //\r
2083 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
c6492839 2084\r
2085 //\r
2086 // Harware error record variable needs larger size.\r
2087 //\r
2fcdca1d 2088 if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
2089 *MaximumVariableStorageSize = FixedPcdGet32(PcdHwErrStorageSize);\r
e5618791 2090 *MaximumVariableSize = FixedPcdGet32(PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);\r
2fcdca1d 2091 } else {\r
2092 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
2093 ASSERT (FixedPcdGet32(PcdHwErrStorageSize) < VariableStoreHeader->Size);\r
2094 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - FixedPcdGet32(PcdHwErrStorageSize);\r
2095 }\r
2096\r
2097 //\r
2098 // Let *MaximumVariableSize be FixedPcdGet32(PcdMaxVariableSize) with the exception of the variable header size.\r
2099 //\r
2100 *MaximumVariableSize = FixedPcdGet32(PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);\r
c6492839 2101 }\r
8d3a5c82 2102\r
2103 //\r
2104 // Point to the starting address of the variables.\r
2105 //\r
9cad030b 2106 Variable = GetStartPointer (VariableStoreHeader);\r
8d3a5c82 2107\r
2108 //\r
2109 // Now walk through the related variable store.\r
2110 //\r
6f90dfbc 2111 while ((Variable < GetEndPointer (VariableStoreHeader)) && IsValidVariableHeader (Variable)) {\r
8d3a5c82 2112 NextVariable = GetNextVariablePtr (Variable);\r
2113 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;\r
2114\r
2115 if (EfiAtRuntime ()) {\r
2116 //\r
2117 // we don't take the state of the variables in mind\r
2118 // when calculating RemainingVariableStorageSize,\r
2119 // since the space occupied by variables not marked with\r
2120 // VAR_ADDED is not allowed to be reclaimed in Runtime.\r
2121 //\r
2fcdca1d 2122 if ((NextVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2123 HwErrVariableTotalSize += VariableSize;\r
2124 } else {\r
2125 CommonVariableTotalSize += VariableSize;\r
2126 }\r
8d3a5c82 2127 } else {\r
2128 //\r
2129 // Only care about Variables with State VAR_ADDED,because\r
2130 // the space not marked as VAR_ADDED is reclaimable now.\r
2131 //\r
2132 if (Variable->State == VAR_ADDED) {\r
2fcdca1d 2133 if ((NextVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2134 HwErrVariableTotalSize += VariableSize;\r
2135 } else {\r
2136 CommonVariableTotalSize += VariableSize;\r
2137 }\r
8d3a5c82 2138 }\r
2139 }\r
2140\r
2141 //\r
2142 // Go to the next one\r
2143 //\r
2144 Variable = NextVariable;\r
2145 }\r
2146\r
2fcdca1d 2147 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){\r
2148 *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;\r
2149 }else {\r
2150 *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;\r
2151 }\r
2152\r
c6492839 2153 if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {\r
2154 *MaximumVariableSize = 0;\r
2155 } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {\r
2156 *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);\r
2157 }\r
2158\r
052ad7e1 2159 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
8d3a5c82 2160 return EFI_SUCCESS;\r
2161}\r
2162\r
7c80e839 2163\r
2164/**\r
2165 Notification function of EVT_GROUP_READY_TO_BOOT event group.\r
2166\r
2167 This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.\r
2168 When the Boot Manager is about to load and execute a boot option, it reclaims variable\r
2169 storage if free size is below the threshold.\r
2170\r
2171 @param Event Event whose notification function is being invoked\r
2172 @param Context Pointer to the notification function's context\r
2173\r
2174**/\r
7800593d
LG
2175VOID\r
2176EFIAPI\r
2177ReclaimForOS(\r
2178 EFI_EVENT Event,\r
2179 VOID *Context\r
2180 )\r
2181{\r
7800593d 2182 EFI_STATUS Status;\r
2fcdca1d 2183 UINTN CommonVariableSpace;\r
2184 UINTN RemainingCommonVariableSpace;\r
2185 UINTN RemainingHwErrVariableSpace;\r
7800593d 2186\r
7800593d
LG
2187 Status = EFI_SUCCESS; \r
2188\r
2fcdca1d 2189 CommonVariableSpace = ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize); //Allowable max size of common variable storage space\r
2190\r
2191 RemainingCommonVariableSpace = CommonVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;\r
2192\r
2193 RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;\r
7800593d
LG
2194 //\r
2195 // Check if the free area is blow a threshold\r
2196 //\r
2fcdca1d 2197 if ((RemainingCommonVariableSpace < PcdGet32 (PcdMaxVariableSize))\r
2198 || (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize))){\r
7800593d 2199 Status = Reclaim (\r
2fcdca1d 2200 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
2201 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
2202 FALSE,\r
2203 NULL\r
2204 );\r
7800593d
LG
2205 ASSERT_EFI_ERROR (Status);\r
2206 }\r
2207}\r
2208\r
7c80e839 2209/**\r
2210 Initializes variable store area for non-volatile and volatile variable.\r
2211\r
7c80e839 2212 @param SystemTable The pointer of EFI_SYSTEM_TABLE.\r
2213\r
2214 @retval EFI_SUCCESS Function successfully executed.\r
2215 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r
2216\r
2217**/\r
8d3a5c82 2218EFI_STATUS\r
8d3a5c82 2219VariableCommonInitialize (\r
8a9e0b72 2220 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol\r
8d3a5c82 2221 )\r
8d3a5c82 2222{\r
2223 EFI_STATUS Status;\r
8d3a5c82 2224 VARIABLE_STORE_HEADER *VolatileVariableStore;\r
2225 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
2226 VARIABLE_HEADER *NextVariable;\r
8a9e0b72 2227 EFI_PHYSICAL_ADDRESS TempVariableStoreHeader;\r
8d3a5c82 2228 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
8a9e0b72 2229 EFI_PHYSICAL_ADDRESS BaseAddress;\r
8d3a5c82 2230 UINT64 Length;\r
2231 UINTN Index;\r
2232 UINT8 Data;\r
8a9e0b72 2233 EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
052ad7e1 2234 UINT64 VariableStoreLength;\r
7800593d 2235 EFI_EVENT ReadyToBootEvent;\r
2fcdca1d 2236 UINTN ScratchSize;\r
8d3a5c82 2237\r
7800593d
LG
2238 Status = EFI_SUCCESS;\r
2239 //\r
2240 // Allocate runtime memory for variable driver global structure.\r
2241 //\r
72399dae 2242 mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL));\r
7800593d
LG
2243 if (mVariableModuleGlobal == NULL) {\r
2244 return EFI_OUT_OF_RESOURCES;\r
2245 }\r
8d3a5c82 2246\r
052ad7e1 2247 EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);\r
8d3a5c82 2248\r
48cd992a 2249 //\r
2250 // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r
2251 // is stored with common variable in the same NV region. So the platform integrator should\r
2252 // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of \r
2253 // PcdFlashNvStorageVariableSize.\r
2254 //\r
2255 ASSERT (FixedPcdGet32(PcdHwErrStorageSize) <= FixedPcdGet32(PcdFlashNvStorageVariableSize));\r
2256\r
8d3a5c82 2257 //\r
2fcdca1d 2258 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.\r
8d3a5c82 2259 //\r
2fcdca1d 2260 ScratchSize = MAX(FixedPcdGet32(PcdMaxVariableSize), FixedPcdGet32(PcdMaxHardwareErrorVariableSize));\r
2261 VolatileVariableStore = AllocateRuntimePool (FixedPcdGet32(PcdVariableStoreSize) + ScratchSize);\r
8d3a5c82 2262 if (VolatileVariableStore == NULL) {\r
2263 FreePool (mVariableModuleGlobal);\r
2264 return EFI_OUT_OF_RESOURCES;\r
2265 }\r
2266\r
2fcdca1d 2267 SetMem (VolatileVariableStore, FixedPcdGet32(PcdVariableStoreSize) + ScratchSize, 0xff);\r
8d3a5c82 2268\r
2269 //\r
2270 // Variable Specific Data\r
2271 //\r
052ad7e1 2272 mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
9cad030b 2273 mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;\r
8a9e0b72 2274 mVariableModuleGlobal->FvbInstance = FvbProtocol;\r
8d3a5c82 2275\r
3709c4cd 2276 CopyGuid (&VolatileVariableStore->Signature, &gEfiVariableGuid);\r
e5618791 2277 VolatileVariableStore->Size = FixedPcdGet32(PcdVariableStoreSize);\r
8d3a5c82 2278 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;\r
2279 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;\r
2280 VolatileVariableStore->Reserved = 0;\r
2281 VolatileVariableStore->Reserved1 = 0;\r
2282\r
2283 //\r
2284 // Get non volatile varaible store\r
2285 //\r
2286\r
8a9e0b72 2287 TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
052ad7e1 2288 VariableStoreBase = TempVariableStoreHeader + \\r
8a9e0b72 2289 (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
052ad7e1 2290 VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \\r
8a9e0b72 2291 (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
8d3a5c82 2292 //\r
2293 // Mark the variable storage region of the FLASH as RUNTIME\r
2294 //\r
052ad7e1
A
2295 BaseAddress = VariableStoreBase & (~EFI_PAGE_MASK);\r
2296 Length = VariableStoreLength + (VariableStoreBase - BaseAddress);\r
8d3a5c82 2297 Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);\r
2298\r
2299 Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);\r
2300 if (EFI_ERROR (Status)) {\r
7800593d 2301 goto Done;\r
8d3a5c82 2302 }\r
2303\r
2304 Status = gDS->SetMemorySpaceAttributes (\r
2305 BaseAddress,\r
2306 Length,\r
2307 GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME\r
2308 );\r
2309 if (EFI_ERROR (Status)) {\r
7800593d 2310 goto Done;\r
8d3a5c82 2311 }\r
2312 //\r
2313 // Get address of non volatile variable store base\r
2314 //\r
052ad7e1 2315 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
8a9e0b72 2316 VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
8d3a5c82 2317 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
2318 if (~VariableStoreHeader->Size == 0) {\r
2319 Status = UpdateVariableStore (\r
052ad7e1 2320 &mVariableModuleGlobal->VariableGlobal,\r
8d3a5c82 2321 FALSE,\r
2322 FALSE,\r
2323 mVariableModuleGlobal->FvbInstance,\r
2324 (UINTN) &VariableStoreHeader->Size,\r
2325 sizeof (UINT32),\r
052ad7e1 2326 (UINT8 *) &VariableStoreLength\r
8d3a5c82 2327 );\r
2328 //\r
2329 // As Variables are stored in NV storage, which are slow devices,such as flash.\r
2330 // Variable operation may skip checking variable program result to improve performance,\r
2331 // We can assume Variable program is OK through some check point.\r
2332 // Variable Store Size Setting should be the first Variable write operation,\r
2333 // We can assume all Read/Write is OK if we can set Variable store size successfully.\r
2334 // If write fail, we will assert here\r
2335 //\r
052ad7e1 2336 ASSERT(VariableStoreHeader->Size == VariableStoreLength);\r
8d3a5c82 2337\r
2338 if (EFI_ERROR (Status)) {\r
7800593d 2339 goto Done;\r
8d3a5c82 2340 }\r
2341 }\r
2342\r
8d3a5c82 2343 //\r
2344 // Parse non-volatile variable data and get last variable offset\r
2345 //\r
8a9e0b72 2346 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);\r
8d3a5c82 2347 Status = EFI_SUCCESS;\r
2348\r
2349 while (IsValidVariableHeader (NextVariable)) {\r
2fcdca1d 2350 UINTN VariableSize = 0;\r
2351 VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);\r
2352 if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
2353 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);\r
2354 } else {\r
2355 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);\r
2356 }\r
2357\r
8d3a5c82 2358 NextVariable = GetNextVariablePtr (NextVariable);\r
2359 }\r
2360\r
8a9e0b72 2361 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;\r
8d3a5c82 2362\r
8d3a5c82 2363 //\r
2364 // Check if the free area is really free.\r
2365 //\r
2366 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {\r
052ad7e1 2367 Data = ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)[Index];\r
8d3a5c82 2368 if (Data != 0xff) {\r
2369 //\r
2370 // There must be something wrong in variable store, do reclaim operation.\r
2371 //\r
2372 Status = Reclaim (\r
052ad7e1 2373 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
8d3a5c82 2374 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
814bae52 2375 FALSE,\r
2376 NULL\r
8d3a5c82 2377 );\r
7800593d
LG
2378\r
2379 if (EFI_ERROR (Status)) {\r
2380 goto Done;\r
2381 }\r
2382\r
8d3a5c82 2383 break;\r
2384 }\r
2385 }\r
7800593d
LG
2386\r
2387 //\r
2388 // Register the event handling function to reclaim variable for OS usage.\r
2389 //\r
2390 Status = EfiCreateEventReadyToBootEx (\r
2391 TPL_NOTIFY, \r
2392 ReclaimForOS, \r
2393 NULL, \r
2394 &ReadyToBootEvent\r
2395 );\r
5bb820af 2396 } else {\r
2397 Status = EFI_VOLUME_CORRUPTED;\r
2398 DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));\r
8d3a5c82 2399 }\r
2400\r
7800593d 2401Done:\r
8d3a5c82 2402 if (EFI_ERROR (Status)) {\r
2403 FreePool (mVariableModuleGlobal);\r
2404 FreePool (VolatileVariableStore);\r
2405 }\r
2406\r
2407 return Status;\r
2408}\r
052ad7e1 2409\r
7c80e839 2410/**\r
2411 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE\r
2412\r
2413 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
2414 It convers pointer to new virtual address.\r
2415\r
2416 @param Event Event whose notification function is being invoked\r
2417 @param Context Pointer to the notification function's context\r
2418\r
2419**/\r
052ad7e1
A
2420VOID\r
2421EFIAPI\r
2422VariableClassAddressChangeEvent (\r
2423 IN EFI_EVENT Event,\r
2424 IN VOID *Context\r
2425 )\r
2426{\r
8a9e0b72 2427 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);\r
2428 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);\r
2429 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);\r
2430 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes);\r
2431 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read);\r
2432 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write);\r
2433 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks);\r
2434 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance);\r
052ad7e1
A
2435 EfiConvertPointer (\r
2436 0x0,\r
2437 (VOID **) &mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase\r
2438 );\r
2439 EfiConvertPointer (\r
2440 0x0,\r
2441 (VOID **) &mVariableModuleGlobal->VariableGlobal.VolatileVariableBase\r
2442 );\r
2443 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal);\r
2444}\r
2445\r
8a9e0b72 2446VOID\r
2447EFIAPI\r
2448FvbNotificationEvent (\r
2449 IN EFI_EVENT Event,\r
2450 IN VOID *Context\r
2451 )\r
2452{\r
2453 EFI_STATUS Status;\r
2454 EFI_HANDLE *HandleBuffer;\r
8a9e0b72 2455 UINTN HandleCount;\r
2456 UINTN Index;\r
2457 EFI_PHYSICAL_ADDRESS FvbBaseAddress;\r
2458 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
2459 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
2460 EFI_FVB_ATTRIBUTES_2 Attributes;\r
2461 EFI_SYSTEM_TABLE *SystemTable;\r
2462 EFI_PHYSICAL_ADDRESS NvStorageVariableBase;\r
2463\r
2464 SystemTable = (EFI_SYSTEM_TABLE *)Context;\r
2465 Fvb = NULL;\r
8a9e0b72 2466 \r
2467 //\r
2468 // Locate all handles of Fvb protocol\r
2469 //\r
2470 Status = gBS->LocateHandleBuffer (\r
2471 ByProtocol,\r
2472 &gEfiFirmwareVolumeBlockProtocolGuid,\r
2473 NULL,\r
2474 &HandleCount,\r
2475 &HandleBuffer\r
2476 );\r
2477 if (EFI_ERROR (Status)) {\r
2478 return ;\r
2479 }\r
2480 \r
2481 //\r
2482 // Get the FVB to access variable store\r
2483 //\r
f0480ecf 2484 for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {\r
8a9e0b72 2485 Status = gBS->HandleProtocol (\r
2486 HandleBuffer[Index],\r
2487 &gEfiFirmwareVolumeBlockProtocolGuid,\r
2488 (VOID **) &Fvb\r
2489 );\r
2490 if (EFI_ERROR (Status)) {\r
2491 Status = EFI_NOT_FOUND;\r
2492 break;\r
2493 }\r
2494\r
2495 //\r
2496 // Ensure this FVB protocol supported Write operation.\r
2497 //\r
2498 Status = Fvb->GetAttributes (Fvb, &Attributes);\r
2499 if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {\r
2500 continue; \r
2501 }\r
2502 //\r
2503 // Compare the address and select the right one\r
2504 //\r
2505 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
2506 if (EFI_ERROR (Status)) {\r
2507 continue;\r
2508 }\r
2509\r
2510 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
2511 NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
2512 if ((NvStorageVariableBase >= FvbBaseAddress) && (NvStorageVariableBase < (FvbBaseAddress + FwVolHeader->FvLength))) {\r
8a9e0b72 2513 Status = EFI_SUCCESS;\r
2514 break;\r
2515 }\r
2516 }\r
2517\r
2518 FreePool (HandleBuffer);\r
f0480ecf 2519 if (!EFI_ERROR (Status) && Fvb != NULL) {\r
533020ef 2520 //\r
2521 // Close the notify event to avoid install gEfiVariableArchProtocolGuid & gEfiVariableWriteArchProtocolGuid again.\r
2522 //\r
2523 Status = gBS->CloseEvent (Event); \r
2524 ASSERT_EFI_ERROR (Status);\r
2525\r
8a9e0b72 2526 Status = VariableCommonInitialize (Fvb);\r
2527 ASSERT_EFI_ERROR (Status);\r
2528 \r
79749182 2529 SystemTable->RuntimeServices->GetVariable = RuntimeServiceGetVariable;\r
8a9e0b72 2530 SystemTable->RuntimeServices->GetNextVariableName = RuntimeServiceGetNextVariableName;\r
79749182 2531 SystemTable->RuntimeServices->SetVariable = RuntimeServiceSetVariable;\r
2532 SystemTable->RuntimeServices->QueryVariableInfo = RuntimeServiceQueryVariableInfo;\r
8a9e0b72 2533 \r
2534 //\r
2535 // Now install the Variable Runtime Architectural Protocol on a new handle\r
2536 //\r
2537 Status = gBS->InstallMultipleProtocolInterfaces (\r
2538 &mHandle,\r
2539 &gEfiVariableArchProtocolGuid, NULL,\r
2540 &gEfiVariableWriteArchProtocolGuid, NULL,\r
2541 NULL\r
2542 );\r
2543 ASSERT_EFI_ERROR (Status);\r
2544 \r
2545 Status = gBS->CreateEventEx (\r
2546 EVT_NOTIFY_SIGNAL,\r
2547 TPL_NOTIFY,\r
2548 VariableClassAddressChangeEvent,\r
2549 NULL,\r
2550 &gEfiEventVirtualAddressChangeGuid,\r
2551 &mVirtualAddressChangeEvent\r
2552 );\r
2553 ASSERT_EFI_ERROR (Status);\r
2554 }\r
2555\r
2556}\r
052ad7e1
A
2557\r
2558/**\r
2559 Variable Driver main entry point. The Variable driver places the 4 EFI\r
2560 runtime services in the EFI System Table and installs arch protocols \r
7c80e839 2561 for variable read and write services being availible. It also registers\r
2562 notification function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
052ad7e1
A
2563\r
2564 @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
2565 @param[in] SystemTable A pointer to the EFI System Table.\r
2566 \r
7c80e839 2567 @retval EFI_SUCCESS Variable service successfully initialized.\r
052ad7e1
A
2568\r
2569**/\r
2570EFI_STATUS\r
2571EFIAPI\r
2572VariableServiceInitialize (\r
2573 IN EFI_HANDLE ImageHandle,\r
2574 IN EFI_SYSTEM_TABLE *SystemTable\r
2575 )\r
2576{\r
052ad7e1 2577 //\r
8a9e0b72 2578 // Register FvbNotificationEvent () notify function.\r
2579 // \r
2580 EfiCreateProtocolNotifyEvent (\r
2581 &gEfiFirmwareVolumeBlockProtocolGuid,\r
2582 TPL_CALLBACK,\r
2583 FvbNotificationEvent,\r
2584 (VOID *)SystemTable,\r
2585 &mFvbRegistration\r
2586 );\r
052ad7e1
A
2587\r
2588 return EFI_SUCCESS;\r
2589}\r
2590\r