]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Universal/Variable/RuntimeDxe/Variable.c
Update the file description in IpSec.h to refer to an accurate UEFI version.
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / RuntimeDxe / Variable.c
... / ...
CommitLineData
1/** @file\r
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
5 \r
6Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>\r
7This program and the accompanying materials \r
8are licensed and made available under the terms and conditions of the BSD License \r
9which accompanies this distribution. The full text of the license may be found at \r
10http://opensource.org/licenses/bsd-license.php \r
11\r
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. \r
14\r
15**/\r
16\r
17#include "Variable.h"\r
18\r
19VARIABLE_MODULE_GLOBAL *mVariableModuleGlobal;\r
20EFI_EVENT mVirtualAddressChangeEvent = NULL;\r
21EFI_HANDLE mHandle = NULL;\r
22///\r
23/// The size of a 3 character ISO639 language code.\r
24///\r
25#define ISO_639_2_ENTRY_SIZE 3\r
26\r
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
33VARIABLE_CACHE_ENTRY mVariableCache[] = {\r
34 {\r
35 &gEfiGlobalVariableGuid,\r
36 L"Lang",\r
37 0x00000000,\r
38 0x00,\r
39 NULL\r
40 },\r
41 {\r
42 &gEfiGlobalVariableGuid,\r
43 L"PlatformLang",\r
44 0x00000000,\r
45 0x00,\r
46 NULL\r
47 }\r
48};\r
49\r
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
68\r
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
84\r
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
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
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
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
129\r
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
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
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
175 gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
176 ASSERT (gVariableInfo != NULL);\r
177\r
178 CopyGuid (&gVariableInfo->VendorGuid, VendorGuid);\r
179 gVariableInfo->Name = AllocatePool (StrSize (VariableName));\r
180 ASSERT (gVariableInfo->Name != NULL);\r
181 StrCpy (gVariableInfo->Name, VariableName);\r
182 gVariableInfo->Volatile = Volatile;\r
183\r
184 gBS->InstallConfigurationTable (&gEfiVariableGuid, gVariableInfo);\r
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
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
213 Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
214 ASSERT (Entry->Next != NULL);\r
215\r
216 CopyGuid (&Entry->Next->VendorGuid, VendorGuid);\r
217 Entry->Next->Name = AllocatePool (StrSize (VariableName));\r
218 ASSERT (Entry->Next->Name != NULL);\r
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
228/**\r
229\r
230 This code checks if variable header is valid or not.\r
231\r
232 @param Variable Pointer to the Variable Header.\r
233\r
234 @retval TRUE Variable header is valid.\r
235 @retval FALSE Variable header is not valid.\r
236\r
237**/\r
238BOOLEAN\r
239IsValidVariableHeader (\r
240 IN VARIABLE_HEADER *Variable\r
241 )\r
242{\r
243 if (Variable == NULL || Variable->StartId != VARIABLE_DATA) {\r
244 return FALSE;\r
245 }\r
246\r
247 return TRUE;\r
248}\r
249\r
250\r
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
260 @param Fvb Pointer to the writable FVB protocol\r
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
270EFI_STATUS\r
271UpdateVariableStore (\r
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
279 )\r
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
302 Status = Fvb->GetPhysicalAddress(Fvb, &FvVolHdr);\r
303 ASSERT_EFI_ERROR (Status);\r
304\r
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
311 DataPtr += mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;\r
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
322 VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
323 if (SetByIndex) {\r
324 DataPtr += mVariableModuleGlobal->VariableGlobal.VolatileVariableBase;\r
325 }\r
326\r
327 if ((DataPtr + DataSize) >= ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) {\r
328 return EFI_INVALID_PARAMETER;\r
329 }\r
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
335 return EFI_SUCCESS;\r
336 }\r
337 \r
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
359 Status = Fvb->Write (\r
360 Fvb,\r
361 LbaNumber,\r
362 (UINTN) (CurrWritePtr - LinearOffset),\r
363 &CurrWriteSize,\r
364 CurrBuffer\r
365 );\r
366 return Status;\r
367 } else {\r
368 Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);\r
369 Status = Fvb->Write (\r
370 Fvb,\r
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
394\r
395/**\r
396\r
397 This code gets the current status of Variable Store.\r
398\r
399 @param VarStoreHeader Pointer to the Variable Store Header.\r
400\r
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
404\r
405**/\r
406VARIABLE_STORE_STATUS\r
407GetVariableStoreStatus (\r
408 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
409 )\r
410{\r
411 if (CompareGuid (&VarStoreHeader->Signature, &gEfiVariableGuid) &&\r
412 VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&\r
413 VarStoreHeader->State == VARIABLE_STORE_HEALTHY\r
414 ) {\r
415\r
416 return EfiValid;\r
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
424 ) {\r
425\r
426 return EfiRaw;\r
427 } else {\r
428 return EfiInvalid;\r
429 }\r
430}\r
431\r
432\r
433/**\r
434\r
435 This code gets the size of name of variable.\r
436\r
437 @param Variable Pointer to the Variable Header\r
438\r
439 @return UINTN Size of variable in bytes\r
440\r
441**/\r
442UINTN\r
443NameSizeOfVariable (\r
444 IN VARIABLE_HEADER *Variable\r
445 )\r
446{\r
447 if (Variable->State == (UINT8) (-1) ||\r
448 Variable->DataSize == (UINT32) (-1) ||\r
449 Variable->NameSize == (UINT32) (-1) ||\r
450 Variable->Attributes == (UINT32) (-1)) {\r
451 return 0;\r
452 }\r
453 return (UINTN) Variable->NameSize;\r
454}\r
455\r
456/**\r
457\r
458 This code gets the size of variable data.\r
459\r
460 @param Variable Pointer to the Variable Header\r
461\r
462 @return Size of variable in bytes\r
463\r
464**/\r
465UINTN\r
466DataSizeOfVariable (\r
467 IN VARIABLE_HEADER *Variable\r
468 )\r
469{\r
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
474 return 0;\r
475 }\r
476 return (UINTN) Variable->DataSize;\r
477}\r
478\r
479/**\r
480\r
481 This code gets the pointer to the variable name.\r
482\r
483 @param Variable Pointer to the Variable Header\r
484\r
485 @return Pointer to Variable Name which is Unicode encoding\r
486\r
487**/\r
488CHAR16 *\r
489GetVariableNamePtr (\r
490 IN VARIABLE_HEADER *Variable\r
491 )\r
492{\r
493\r
494 return (CHAR16 *) (Variable + 1);\r
495}\r
496\r
497/**\r
498\r
499 This code gets the pointer to the variable data.\r
500\r
501 @param Variable Pointer to the Variable Header\r
502\r
503 @return Pointer to Variable Data\r
504\r
505**/\r
506UINT8 *\r
507GetVariableDataPtr (\r
508 IN VARIABLE_HEADER *Variable\r
509 )\r
510{\r
511 UINTN Value;\r
512 \r
513 //\r
514 // Be careful about pad size for alignment\r
515 //\r
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
521}\r
522\r
523\r
524/**\r
525\r
526 This code gets the pointer to the next variable header.\r
527\r
528 @param Variable Pointer to the Variable Header\r
529\r
530 @return Pointer to next variable header\r
531\r
532**/\r
533VARIABLE_HEADER *\r
534GetNextVariablePtr (\r
535 IN VARIABLE_HEADER *Variable\r
536 )\r
537{\r
538 UINTN Value;\r
539\r
540 if (!IsValidVariableHeader (Variable)) {\r
541 return NULL;\r
542 }\r
543\r
544 Value = (UINTN) GetVariableDataPtr (Variable);\r
545 Value += DataSizeOfVariable (Variable);\r
546 Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));\r
547\r
548 //\r
549 // Be careful about pad size for alignment\r
550 //\r
551 return (VARIABLE_HEADER *) HEADER_ALIGN (Value);\r
552}\r
553\r
554/**\r
555\r
556 Gets the pointer to the first variable header in given variable store area.\r
557\r
558 @param VarStoreHeader Pointer to the Variable Store Header.\r
559\r
560 @return Pointer to the first variable header\r
561\r
562**/\r
563VARIABLE_HEADER *\r
564GetStartPointer (\r
565 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
566 )\r
567{\r
568 //\r
569 // The end of variable store\r
570 //\r
571 return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);\r
572}\r
573\r
574/**\r
575\r
576 Gets the pointer to the end of the variable storage area.\r
577\r
578 This function gets pointer to the end of the variable storage\r
579 area, according to the input variable store header.\r
580\r
581 @param VarStoreHeader Pointer to the Variable Store Header\r
582\r
583 @return Pointer to the end of the variable storage area \r
584\r
585**/\r
586VARIABLE_HEADER *\r
587GetEndPointer (\r
588 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
589 )\r
590{\r
591 //\r
592 // The end of variable store\r
593 //\r
594 return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);\r
595}\r
596\r
597\r
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
613EFI_STATUS\r
614Reclaim (\r
615 IN EFI_PHYSICAL_ADDRESS VariableBase,\r
616 OUT UINTN *LastVariableOffset,\r
617 IN BOOLEAN IsVolatile,\r
618 IN VARIABLE_HEADER *UpdatingVariable\r
619 )\r
620{\r
621 VARIABLE_HEADER *Variable;\r
622 VARIABLE_HEADER *AddedVariable;\r
623 VARIABLE_HEADER *NextVariable;\r
624 VARIABLE_HEADER *NextAddedVariable;\r
625 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
626 UINT8 *ValidBuffer;\r
627 UINTN MaximumBufferSize;\r
628 UINTN VariableSize;\r
629 UINTN VariableNameSize;\r
630 UINTN UpdatingVariableNameSize;\r
631 UINTN NameSize;\r
632 UINT8 *CurrPtr;\r
633 VOID *Point0;\r
634 VOID *Point1;\r
635 BOOLEAN FoundAdded;\r
636 EFI_STATUS Status;\r
637 CHAR16 *VariableNamePtr;\r
638 CHAR16 *UpdatingVariableNamePtr;\r
639\r
640 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) VariableBase);\r
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
648\r
649 //\r
650 // Start Pointers for the variable.\r
651 //\r
652 Variable = GetStartPointer (VariableStoreHeader);\r
653 MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);\r
654\r
655 while (IsValidVariableHeader (Variable)) {\r
656 NextVariable = GetNextVariablePtr (Variable);\r
657 if (Variable->State == VAR_ADDED || \r
658 Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
659 ) {\r
660 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
661 MaximumBufferSize += VariableSize;\r
662 }\r
663\r
664 Variable = NextVariable;\r
665 }\r
666\r
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
673 if (ValidBuffer == NULL) {\r
674 return EFI_OUT_OF_RESOURCES;\r
675 }\r
676\r
677 SetMem (ValidBuffer, MaximumBufferSize, 0xff);\r
678\r
679 //\r
680 // Copy variable store header\r
681 //\r
682 CopyMem (ValidBuffer, VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));\r
683 CurrPtr = (UINT8 *) GetStartPointer ((VARIABLE_STORE_HEADER *) ValidBuffer);\r
684\r
685 //\r
686 // Reinstall all ADDED variables as long as they are not identical to Updating Variable\r
687 // \r
688 Variable = GetStartPointer (VariableStoreHeader);\r
689 while (IsValidVariableHeader (Variable)) {\r
690 NextVariable = GetNextVariablePtr (Variable);\r
691 if (Variable->State == VAR_ADDED) {\r
692 if (UpdatingVariable != NULL) {\r
693 if (UpdatingVariable == Variable) {\r
694 Variable = NextVariable;\r
695 continue;\r
696 }\r
697\r
698 VariableNameSize = NameSizeOfVariable(Variable);\r
699 UpdatingVariableNameSize = NameSizeOfVariable(UpdatingVariable);\r
700\r
701 VariableNamePtr = GetVariableNamePtr (Variable);\r
702 UpdatingVariableNamePtr = GetVariableNamePtr (UpdatingVariable);\r
703 if (CompareGuid (&Variable->VendorGuid, &UpdatingVariable->VendorGuid) &&\r
704 VariableNameSize == UpdatingVariableNameSize &&\r
705 CompareMem (VariableNamePtr, UpdatingVariableNamePtr, VariableNameSize) == 0 ) {\r
706 Variable = NextVariable;\r
707 continue;\r
708 }\r
709 }\r
710 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
711 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
712 CurrPtr += VariableSize;\r
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
718 }\r
719 Variable = NextVariable;\r
720 }\r
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
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
734 }\r
735\r
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
742 if (Variable != UpdatingVariable && Variable->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
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
760 if (CompareMem (Point0, Point1, NameSizeOfVariable (AddedVariable)) == 0) {\r
761 FoundAdded = TRUE;\r
762 break;\r
763 }\r
764 }\r
765 AddedVariable = NextAddedVariable;\r
766 }\r
767 if (!FoundAdded) {\r
768 //\r
769 // Promote VAR_IN_DELETED_TRANSITION to VAR_ADDED\r
770 //\r
771 VariableSize = (UINTN) NextVariable - (UINTN) Variable;\r
772 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
773 ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;\r
774 CurrPtr += VariableSize;\r
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
780 }\r
781 }\r
782\r
783 Variable = NextVariable;\r
784 }\r
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
791 CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - (UINT8 *) ValidBuffer));\r
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
800 (UINTN) (CurrPtr - (UINT8 *) ValidBuffer)\r
801 );\r
802 }\r
803 if (!EFI_ERROR (Status)) {\r
804 *LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer);\r
805 } else {\r
806 *LastVariableOffset = 0;\r
807 }\r
808\r
809 FreePool (ValidBuffer);\r
810\r
811 return Status;\r
812}\r
813\r
814\r
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
821 @param[in] Attributes Attribues of the variable\r
822 @param[in] DataSize Size of data. 0 means delete\r
823 @param[in] Data Variable data\r
824\r
825**/\r
826VOID\r
827UpdateVariableCache (\r
828 IN CHAR16 *VariableName,\r
829 IN EFI_GUID *VendorGuid,\r
830 IN UINT32 Attributes,\r
831 IN UINTN DataSize,\r
832 IN VOID *Data\r
833 )\r
834{\r
835 VARIABLE_CACHE_ENTRY *Entry;\r
836 UINTN Index;\r
837\r
838 if (EfiAtRuntime ()) {\r
839 //\r
840 // Don't use the cache at runtime\r
841 // \r
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
850 //\r
851 // Delete Case\r
852 //\r
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
861 ASSERT (Entry->Data != NULL);\r
862\r
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
872/**\r
873 Search the cache to check if the variable is in it.\r
874\r
875 This function searches the variable cache. If the variable to find exists, return its data\r
876 and attributes.\r
877\r
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
890\r
891**/\r
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
913 // Variable was deleted so return not found\r
914 return EFI_NOT_FOUND;\r
915 } else if (Entry->DataSize > *DataSize) {\r
916 // If the buffer is too small return correct size\r
917 *DataSize = Entry->DataSize;\r
918 return EFI_BUFFER_TOO_SMALL;\r
919 } else {\r
920 *DataSize = Entry->DataSize;\r
921 // Return the data\r
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
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
955\r
956**/\r
957EFI_STATUS\r
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
964{\r
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
971\r
972 //\r
973 // 0: Volatile, 1: Non-Volatile\r
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
976 //\r
977 VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
978 VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
979\r
980 //\r
981 // Start Pointers for the variable.\r
982 // Actual Data Pointer where data can be written.\r
983 //\r
984 Variable[0] = GetStartPointer (VariableStoreHeader[0]);\r
985 Variable[1] = GetStartPointer (VariableStoreHeader[1]);\r
986\r
987 if (VariableName[0] != 0 && VendorGuid == NULL) {\r
988 return EFI_INVALID_PARAMETER;\r
989 }\r
990\r
991 //\r
992 // Find the variable by walk through volatile and then non-volatile variable store\r
993 //\r
994 InDeletedVariable = NULL;\r
995 InDeletedStorageIndex = 0;\r
996 for (Index = 0; Index < 2; Index++) {\r
997 while ((Variable[Index] < GetEndPointer (VariableStoreHeader[Index])) && IsValidVariableHeader (Variable[Index])) {\r
998 if (Variable[Index]->State == VAR_ADDED || \r
999 Variable[Index]->State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
1000 ) {\r
1001 if (!EfiAtRuntime () || ((Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {\r
1002 if (VariableName[0] == 0) {\r
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
1014 } else {\r
1015 if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) {\r
1016 Point = (VOID *) GetVariableNamePtr (Variable[Index]);\r
1017\r
1018 ASSERT (NameSizeOfVariable (Variable[Index]) != 0);\r
1019 if (CompareMem (VariableName, Point, NameSizeOfVariable (Variable[Index])) == 0) {\r
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
1031 }\r
1032 }\r
1033 }\r
1034 }\r
1035 }\r
1036\r
1037 Variable[Index] = GetNextVariablePtr (Variable[Index]);\r
1038 }\r
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
1046 }\r
1047 PtrTrack->CurrPtr = NULL;\r
1048 return EFI_NOT_FOUND;\r
1049}\r
1050\r
1051/**\r
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
1055 RFC4646 and ISO639 language tags.\r
1056 In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.\r
1057 In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.\r
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
1072 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
1073\r
1074 @retval the index of language in the language codes.\r
1075\r
1076**/\r
1077UINTN\r
1078EFIAPI\r
1079GetIndexFromSupportedLangCodes(\r
1080 IN CHAR8 *SupportedLang,\r
1081 IN CHAR8 *Lang,\r
1082 IN BOOLEAN Iso639Language\r
1083 ) \r
1084{\r
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
1106 // Compare RFC4646 language code\r
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
1125 }\r
1126}\r
1127\r
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
1132 RFC4646 and ISO639 language tags.\r
1133 In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.\r
1134 In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.\r
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
1149 @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
1150\r
1151 @retval the language string in the language codes.\r
1152\r
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
1165\r
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
1178 } else {\r
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
1205 }\r
1206}\r
1207\r
1208/**\r
1209 Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.\r
1210\r
1211 When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.\r
1212\r
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
1215\r
1216 @param[in] VariableName Name of variable\r
1217\r
1218 @param[in] Data Variable data\r
1219\r
1220 @param[in] DataSize Size of data. 0 means delete\r
1221\r
1222 @retval EFI_SUCCESS auto update operation is successful.\r
1223\r
1224**/\r
1225EFI_STATUS\r
1226EFIAPI\r
1227AutoUpdateLangVariable(\r
1228 IN CHAR16 *VariableName,\r
1229 IN VOID *Data,\r
1230 IN UINTN DataSize\r
1231 )\r
1232{\r
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
1239\r
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
1244\r
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) && (DataSize != 0)) {\r
1258 ASSERT (AsciiStrLen (mVariableModuleGlobal->PlatformLangCodes) != 0);\r
1259\r
1260 //\r
1261 // When setting PlatformLang, firstly get most matched language string from supported language codes.\r
1262 //\r
1263 BestPlatformLang = GetBestLanguage(mVariableModuleGlobal->PlatformLangCodes, FALSE, Data, NULL);\r
1264\r
1265 //\r
1266 // Get the corresponding index in language codes.\r
1267 //\r
1268 Index = GetIndexFromSupportedLangCodes(mVariableModuleGlobal->PlatformLangCodes, BestPlatformLang, FALSE);\r
1269\r
1270 //\r
1271 // Get the corresponding ISO639 language tag according to RFC4646 language tag.\r
1272 //\r
1273 BestLang = GetLangFromSupportedLangCodes(mVariableModuleGlobal->LangCodes, Index, TRUE);\r
1274\r
1275 //\r
1276 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.\r
1277 //\r
1278 FindVariable(L"Lang", &gEfiGlobalVariableGuid, &Variable, (VARIABLE_GLOBAL *)mVariableModuleGlobal);\r
1279\r
1280 Status = UpdateVariable(L"Lang", &gEfiGlobalVariableGuid, \r
1281 BestLang, ISO_639_2_ENTRY_SIZE + 1, Attributes, &Variable);\r
1282\r
1283 DEBUG((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang));\r
1284\r
1285 ASSERT_EFI_ERROR(Status);\r
1286 \r
1287 } else if ((StrCmp (VariableName, L"Lang") == 0) && (DataSize != 0)) {\r
1288 ASSERT (AsciiStrLen (mVariableModuleGlobal->LangCodes) != 0);\r
1289\r
1290 //\r
1291 // When setting Lang, firstly get most matched language string from supported language codes.\r
1292 //\r
1293 BestLang = GetBestLanguage(mVariableModuleGlobal->LangCodes, TRUE, Data, NULL);\r
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
1301 // Get the corresponding RFC4646 language tag according to ISO639 language tag.\r
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
1311 BestPlatformLang, AsciiStrSize (BestPlatformLang), Attributes, &Variable);\r
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
1317}\r
1318\r
1319/**\r
1320 Update the variable region with Variable information. These are the same \r
1321 arguments as the EFI Variable services.\r
1322\r
1323 @param[in] VariableName Name of variable\r
1324\r
1325 @param[in] VendorGuid Guid of variable\r
1326\r
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
1338\r
1339**/\r
1340EFI_STATUS\r
1341EFIAPI\r
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
1349 )\r
1350{\r
1351 EFI_STATUS Status;\r
1352 VARIABLE_HEADER *NextVariable;\r
1353 UINTN ScratchSize;\r
1354 UINTN NonVolatileVarableStoreSize;\r
1355 UINTN VarNameOffset;\r
1356 UINTN VarDataOffset;\r
1357 UINTN VarNameSize;\r
1358 UINTN VarSize;\r
1359 BOOLEAN Volatile;\r
1360 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
1361 UINT8 State;\r
1362 BOOLEAN Reclaimed;\r
1363\r
1364 Fvb = mVariableModuleGlobal->FvbInstance;\r
1365 Reclaimed = FALSE;\r
1366\r
1367 if (Variable->CurrPtr != NULL) {\r
1368 //\r
1369 // Update/Delete existing variable\r
1370 //\r
1371 Volatile = Variable->Volatile;\r
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
1379 if (Variable->Volatile) {\r
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
1386 if ((Variable->CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
1387 Status = EFI_INVALID_PARAMETER;\r
1388 goto Done; \r
1389 }\r
1390 }\r
1391 //\r
1392 // Setting a data variable with no access, or zero DataSize attributes\r
1393 // specified causes it to be deleted.\r
1394 //\r
1395 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) { \r
1396 State = Variable->CurrPtr->State;\r
1397 State &= VAR_DELETED;\r
1398\r
1399 Status = UpdateVariableStore (\r
1400 &mVariableModuleGlobal->VariableGlobal,\r
1401 Variable->Volatile,\r
1402 FALSE,\r
1403 Fvb,\r
1404 (UINTN) &Variable->CurrPtr->State,\r
1405 sizeof (UINT8),\r
1406 &State\r
1407 ); \r
1408 if (!EFI_ERROR (Status)) {\r
1409 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, FALSE, TRUE, FALSE);\r
1410 UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
1411 }\r
1412 goto Done; \r
1413 }\r
1414 //\r
1415 // If the variable is marked valid and the same data has been passed in\r
1416 // then return to the caller immediately.\r
1417 //\r
1418 if (DataSizeOfVariable (Variable->CurrPtr) == DataSize &&\r
1419 (CompareMem (Data, GetVariableDataPtr (Variable->CurrPtr), DataSize) == 0)) {\r
1420 \r
1421 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
1422 Status = EFI_SUCCESS;\r
1423 goto Done;\r
1424 } else if ((Variable->CurrPtr->State == VAR_ADDED) ||\r
1425 (Variable->CurrPtr->State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {\r
1426\r
1427 //\r
1428 // Mark the old variable as in delete transition\r
1429 //\r
1430 State = Variable->CurrPtr->State;\r
1431 State &= VAR_IN_DELETED_TRANSITION;\r
1432\r
1433 Status = UpdateVariableStore (\r
1434 &mVariableModuleGlobal->VariableGlobal,\r
1435 Variable->Volatile,\r
1436 FALSE,\r
1437 Fvb,\r
1438 (UINTN) &Variable->CurrPtr->State,\r
1439 sizeof (UINT8),\r
1440 &State\r
1441 ); \r
1442 if (EFI_ERROR (Status)) {\r
1443 goto Done; \r
1444 } \r
1445 } \r
1446 } else {\r
1447 //\r
1448 // Not found existing variable. Create a new variable\r
1449 // \r
1450 \r
1451 //\r
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
1454 //\r
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
1460 //\r
1461 // Only variable have NV|RT attribute can be created in Runtime\r
1462 //\r
1463 if (EfiAtRuntime () &&\r
1464 (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {\r
1465 Status = EFI_INVALID_PARAMETER;\r
1466 goto Done;\r
1467 } \r
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
1477 NextVariable = GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase));\r
1478 ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
1479\r
1480 SetMem (NextVariable, ScratchSize, 0xff);\r
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
1515 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
1516 //\r
1517 // Create a nonvolatile variable\r
1518 //\r
1519 Volatile = FALSE;\r
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) > PcdGet32 (PcdHwErrStorageSize)))\r
1523 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
1524 && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize)))) {\r
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
1532 Status = Reclaim (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase, \r
1533 &mVariableModuleGlobal->NonVolatileLastVariableOffset, FALSE, Variable->CurrPtr);\r
1534 if (EFI_ERROR (Status)) {\r
1535 goto Done;\r
1536 }\r
1537 //\r
1538 // If still no enough space, return out of resources\r
1539 //\r
1540 if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \r
1541 && ((VarSize + mVariableModuleGlobal->HwErrVariableTotalSize) > PcdGet32 (PcdHwErrStorageSize)))\r
1542 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
1543 && ((VarSize + mVariableModuleGlobal->CommonVariableTotalSize) > NonVolatileVarableStoreSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize)))) {\r
1544 Status = EFI_OUT_OF_RESOURCES;\r
1545 goto Done;\r
1546 }\r
1547 Reclaimed = TRUE;\r
1548 }\r
1549 //\r
1550 // Three steps\r
1551 // 1. Write variable header\r
1552 // 2. Set variable state to header valid \r
1553 // 3. Write variable data\r
1554 // 4. Set variable state to valid\r
1555 //\r
1556 //\r
1557 // Step 1:\r
1558 //\r
1559 Status = UpdateVariableStore (\r
1560 &mVariableModuleGlobal->VariableGlobal,\r
1561 FALSE,\r
1562 TRUE,\r
1563 Fvb,\r
1564 mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
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
1572\r
1573 //\r
1574 // Step 2:\r
1575 //\r
1576 NextVariable->State = VAR_HEADER_VALID_ONLY;\r
1577 Status = UpdateVariableStore (\r
1578 &mVariableModuleGlobal->VariableGlobal,\r
1579 FALSE,\r
1580 TRUE,\r
1581 Fvb,\r
1582 mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
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
1593 Status = UpdateVariableStore (\r
1594 &mVariableModuleGlobal->VariableGlobal,\r
1595 FALSE,\r
1596 TRUE,\r
1597 Fvb,\r
1598 mVariableModuleGlobal->NonVolatileLastVariableOffset + sizeof (VARIABLE_HEADER),\r
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
1606 //\r
1607 // Step 4:\r
1608 //\r
1609 NextVariable->State = VAR_ADDED;\r
1610 Status = UpdateVariableStore (\r
1611 &mVariableModuleGlobal->VariableGlobal,\r
1612 FALSE,\r
1613 TRUE,\r
1614 Fvb,\r
1615 mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
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
1623\r
1624 mVariableModuleGlobal->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
1625\r
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
1631 } else {\r
1632 //\r
1633 // Create a volatile variable\r
1634 // \r
1635 Volatile = TRUE;\r
1636\r
1637 if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >\r
1638 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size) {\r
1639 //\r
1640 // Perform garbage collection & reclaim operation\r
1641 //\r
1642 Status = Reclaim (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase, \r
1643 &mVariableModuleGlobal->VolatileLastVariableOffset, TRUE, Variable->CurrPtr);\r
1644 if (EFI_ERROR (Status)) {\r
1645 goto Done;\r
1646 }\r
1647 //\r
1648 // If still no enough space, return out of resources\r
1649 //\r
1650 if ((UINT32) (VarSize + mVariableModuleGlobal->VolatileLastVariableOffset) >\r
1651 ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.VolatileVariableBase)))->Size\r
1652 ) {\r
1653 Status = EFI_OUT_OF_RESOURCES;\r
1654 goto Done;\r
1655 }\r
1656 Reclaimed = TRUE;\r
1657 }\r
1658\r
1659 NextVariable->State = VAR_ADDED;\r
1660 Status = UpdateVariableStore (\r
1661 &mVariableModuleGlobal->VariableGlobal,\r
1662 TRUE,\r
1663 TRUE,\r
1664 Fvb,\r
1665 mVariableModuleGlobal->VolatileLastVariableOffset,\r
1666 (UINT32) VarSize,\r
1667 (UINT8 *) NextVariable\r
1668 );\r
1669\r
1670 if (EFI_ERROR (Status)) {\r
1671 goto Done;\r
1672 }\r
1673\r
1674 mVariableModuleGlobal->VolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
1675 }\r
1676\r
1677 //\r
1678 // Mark the old variable as deleted\r
1679 //\r
1680 if (!Reclaimed && !EFI_ERROR (Status) && Variable->CurrPtr != NULL) {\r
1681 State = Variable->CurrPtr->State;\r
1682 State &= VAR_DELETED;\r
1683\r
1684 Status = UpdateVariableStore (\r
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
1766 }\r
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
1783 }\r
1784\r
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
1887\r
1888Done:\r
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 if (DataSize != 0 && Data == NULL) {\r
1934 return EFI_INVALID_PARAMETER;\r
1935 }\r
1936\r
1937 //\r
1938 // Not support authenticated variable write yet.\r
1939 //\r
1940 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
1941 return EFI_INVALID_PARAMETER;\r
1942 }\r
1943\r
1944 //\r
1945 // Make sure if runtime bit is set, boot service bit is set also\r
1946 //\r
1947 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
1948 return EFI_INVALID_PARAMETER;\r
1949 }\r
1950\r
1951 //\r
1952 // The size of the VariableName, including the Unicode Null in bytes plus\r
1953 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxHardwareErrorVariableSize)\r
1954 // bytes for HwErrRec, and PcdGet32 (PcdMaxVariableSize) bytes for the others.\r
1955 //\r
1956 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
1957 if ((DataSize > PcdGet32 (PcdMaxHardwareErrorVariableSize)) ||\r
1958 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxHardwareErrorVariableSize))) {\r
1959 return EFI_INVALID_PARAMETER;\r
1960 }\r
1961 //\r
1962 // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX"\r
1963 //\r
1964 if (StrnCmp(VariableName, L"HwErrRec", StrLen(L"HwErrRec")) != 0) {\r
1965 return EFI_INVALID_PARAMETER;\r
1966 }\r
1967 } else {\r
1968 //\r
1969 // The size of the VariableName, including the Unicode Null in bytes plus\r
1970 // the DataSize is limited to maximum size of PcdGet32 (PcdMaxVariableSize) bytes.\r
1971 //\r
1972 if ((DataSize > PcdGet32 (PcdMaxVariableSize)) ||\r
1973 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > PcdGet32 (PcdMaxVariableSize))) {\r
1974 return EFI_INVALID_PARAMETER;\r
1975 } \r
1976 } \r
1977\r
1978 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
1979\r
1980 //\r
1981 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated;\r
1982 //\r
1983 if (1 < InterlockedIncrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState)) {\r
1984 Point = mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase;;\r
1985 //\r
1986 // Parse non-volatile variable data and get last variable offset\r
1987 //\r
1988 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point);\r
1989 while ((NextVariable < GetEndPointer ((VARIABLE_STORE_HEADER *) (UINTN) Point)) \r
1990 && IsValidVariableHeader (NextVariable)) {\r
1991 NextVariable = GetNextVariablePtr (NextVariable);\r
1992 }\r
1993 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) Point;\r
1994 }\r
1995\r
1996 //\r
1997 // Check whether the input variable is already existed\r
1998 //\r
1999 FindVariable (VariableName, VendorGuid, &Variable, &mVariableModuleGlobal->VariableGlobal);\r
2000\r
2001 //\r
2002 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang\r
2003 //\r
2004 AutoUpdateLangVariable (VariableName, Data, DataSize);\r
2005\r
2006 Status = UpdateVariable (VariableName, VendorGuid, Data, DataSize, Attributes, &Variable);\r
2007\r
2008 InterlockedDecrement (&mVariableModuleGlobal->VariableGlobal.ReentrantState);\r
2009 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2010\r
2011 return Status;\r
2012}\r
2013\r
2014/**\r
2015\r
2016 This code returns information about the EFI variables.\r
2017\r
2018 @param Attributes Attributes bitmask to specify the type of variables\r
2019 on which to return information.\r
2020 @param MaximumVariableStorageSize Pointer to the maximum size of the storage space available\r
2021 for the EFI variables associated with the attributes specified.\r
2022 @param RemainingVariableStorageSize Pointer to the remaining size of the storage space available\r
2023 for EFI variables associated with the attributes specified.\r
2024 @param MaximumVariableSize Pointer to the maximum size of an individual EFI variables\r
2025 associated with the attributes specified.\r
2026\r
2027 @return EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.\r
2028 @return EFI_SUCCESS Query successfully.\r
2029 @return EFI_UNSUPPORTED The attribute is not supported on this platform.\r
2030\r
2031**/\r
2032EFI_STATUS\r
2033EFIAPI\r
2034RuntimeServiceQueryVariableInfo (\r
2035 IN UINT32 Attributes,\r
2036 OUT UINT64 *MaximumVariableStorageSize,\r
2037 OUT UINT64 *RemainingVariableStorageSize,\r
2038 OUT UINT64 *MaximumVariableSize\r
2039 )\r
2040{\r
2041 VARIABLE_HEADER *Variable;\r
2042 VARIABLE_HEADER *NextVariable;\r
2043 UINT64 VariableSize;\r
2044 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
2045 UINT64 CommonVariableTotalSize;\r
2046 UINT64 HwErrVariableTotalSize;\r
2047\r
2048 CommonVariableTotalSize = 0;\r
2049 HwErrVariableTotalSize = 0;\r
2050\r
2051 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
2052 return EFI_INVALID_PARAMETER;\r
2053 }\r
2054\r
2055 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {\r
2056 //\r
2057 // Make sure the Attributes combination is supported by the platform.\r
2058 //\r
2059 return EFI_UNSUPPORTED; \r
2060 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
2061 //\r
2062 // Make sure if runtime bit is set, boot service bit is set also.\r
2063 //\r
2064 return EFI_INVALID_PARAMETER;\r
2065 } else if (EfiAtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {\r
2066 //\r
2067 // Make sure RT Attribute is set if we are in Runtime phase.\r
2068 //\r
2069 return EFI_INVALID_PARAMETER;\r
2070 } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2071 //\r
2072 // Make sure Hw Attribute is set with NV.\r
2073 //\r
2074 return EFI_INVALID_PARAMETER;\r
2075 } else if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
2076 //\r
2077 // Not support authentiated variable write yet.\r
2078 //\r
2079 return EFI_UNSUPPORTED;\r
2080 }\r
2081\r
2082 AcquireLockOnlyAtBootTime(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2083\r
2084 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
2085 //\r
2086 // Query is Volatile related.\r
2087 //\r
2088 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.VolatileVariableBase);\r
2089 } else {\r
2090 //\r
2091 // Query is Non-Volatile related.\r
2092 //\r
2093 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase);\r
2094 }\r
2095\r
2096 //\r
2097 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize\r
2098 // with the storage size (excluding the storage header size).\r
2099 //\r
2100 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);\r
2101\r
2102 //\r
2103 // Harware error record variable needs larger size.\r
2104 //\r
2105 if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
2106 *MaximumVariableStorageSize = PcdGet32 (PcdHwErrStorageSize);\r
2107 *MaximumVariableSize = PcdGet32 (PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);\r
2108 } else {\r
2109 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
2110 ASSERT (PcdGet32 (PcdHwErrStorageSize) < VariableStoreHeader->Size);\r
2111 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32 (PcdHwErrStorageSize);\r
2112 }\r
2113\r
2114 //\r
2115 // Let *MaximumVariableSize be PcdGet32 (PcdMaxVariableSize) with the exception of the variable header size.\r
2116 //\r
2117 *MaximumVariableSize = PcdGet32 (PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);\r
2118 }\r
2119\r
2120 //\r
2121 // Point to the starting address of the variables.\r
2122 //\r
2123 Variable = GetStartPointer (VariableStoreHeader);\r
2124\r
2125 //\r
2126 // Now walk through the related variable store.\r
2127 //\r
2128 while ((Variable < GetEndPointer (VariableStoreHeader)) && IsValidVariableHeader (Variable)) {\r
2129 NextVariable = GetNextVariablePtr (Variable);\r
2130 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;\r
2131\r
2132 if (EfiAtRuntime ()) {\r
2133 //\r
2134 // we don't take the state of the variables in mind\r
2135 // when calculating RemainingVariableStorageSize,\r
2136 // since the space occupied by variables not marked with\r
2137 // VAR_ADDED is not allowed to be reclaimed in Runtime.\r
2138 //\r
2139 if ((NextVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2140 HwErrVariableTotalSize += VariableSize;\r
2141 } else {\r
2142 CommonVariableTotalSize += VariableSize;\r
2143 }\r
2144 } else {\r
2145 //\r
2146 // Only care about Variables with State VAR_ADDED,because\r
2147 // the space not marked as VAR_ADDED is reclaimable now.\r
2148 //\r
2149 if (Variable->State == VAR_ADDED) {\r
2150 if ((NextVariable->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2151 HwErrVariableTotalSize += VariableSize;\r
2152 } else {\r
2153 CommonVariableTotalSize += VariableSize;\r
2154 }\r
2155 }\r
2156 }\r
2157\r
2158 //\r
2159 // Go to the next one\r
2160 //\r
2161 Variable = NextVariable;\r
2162 }\r
2163\r
2164 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){\r
2165 *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;\r
2166 }else {\r
2167 *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;\r
2168 }\r
2169\r
2170 if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {\r
2171 *MaximumVariableSize = 0;\r
2172 } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {\r
2173 *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);\r
2174 }\r
2175\r
2176 ReleaseLockOnlyAtBootTime (&mVariableModuleGlobal->VariableGlobal.VariableServicesLock);\r
2177 return EFI_SUCCESS;\r
2178}\r
2179\r
2180\r
2181/**\r
2182 Notification function of EVT_GROUP_READY_TO_BOOT event group.\r
2183\r
2184 This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.\r
2185 When the Boot Manager is about to load and execute a boot option, it reclaims variable\r
2186 storage if free size is below the threshold.\r
2187\r
2188 @param Event Event whose notification function is being invoked\r
2189 @param Context Pointer to the notification function's context\r
2190\r
2191**/\r
2192VOID\r
2193EFIAPI\r
2194ReclaimForOS(\r
2195 EFI_EVENT Event,\r
2196 VOID *Context\r
2197 )\r
2198{\r
2199 EFI_STATUS Status;\r
2200 UINTN CommonVariableSpace;\r
2201 UINTN RemainingCommonVariableSpace;\r
2202 UINTN RemainingHwErrVariableSpace;\r
2203\r
2204 Status = EFI_SUCCESS; \r
2205\r
2206 CommonVariableSpace = ((VARIABLE_STORE_HEADER *) ((UINTN) (mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)))->Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize); //Allowable max size of common variable storage space\r
2207\r
2208 RemainingCommonVariableSpace = CommonVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;\r
2209\r
2210 RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;\r
2211 //\r
2212 // Check if the free area is blow a threshold.\r
2213 //\r
2214 if ((RemainingCommonVariableSpace < PcdGet32 (PcdMaxVariableSize))\r
2215 || ((PcdGet32 (PcdHwErrStorageSize) != 0) && \r
2216 (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize)))){\r
2217 Status = Reclaim (\r
2218 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
2219 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
2220 FALSE,\r
2221 NULL\r
2222 );\r
2223 ASSERT_EFI_ERROR (Status);\r
2224 }\r
2225}\r
2226\r
2227/**\r
2228 Initializes variable store area for non-volatile and volatile variable.\r
2229\r
2230 @param FvbProtocol Pointer to an instance of EFI Firmware Volume Block Protocol.\r
2231\r
2232 @retval EFI_SUCCESS Function successfully executed.\r
2233 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r
2234\r
2235**/\r
2236EFI_STATUS\r
2237VariableCommonInitialize (\r
2238 IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol\r
2239 )\r
2240{\r
2241 EFI_STATUS Status;\r
2242 VARIABLE_STORE_HEADER *VolatileVariableStore;\r
2243 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
2244 VARIABLE_HEADER *NextVariable;\r
2245 EFI_PHYSICAL_ADDRESS TempVariableStoreHeader;\r
2246 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
2247 EFI_PHYSICAL_ADDRESS BaseAddress;\r
2248 UINT64 Length;\r
2249 UINTN Index;\r
2250 UINT8 Data;\r
2251 EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
2252 UINT64 VariableStoreLength;\r
2253 EFI_EVENT ReadyToBootEvent;\r
2254 UINTN ScratchSize;\r
2255 UINTN VariableSize;\r
2256\r
2257 Status = EFI_SUCCESS;\r
2258 //\r
2259 // Allocate runtime memory for variable driver global structure.\r
2260 //\r
2261 mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (VARIABLE_MODULE_GLOBAL));\r
2262 if (mVariableModuleGlobal == NULL) {\r
2263 return EFI_OUT_OF_RESOURCES;\r
2264 }\r
2265\r
2266 EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal.VariableServicesLock, TPL_NOTIFY);\r
2267\r
2268 //\r
2269 // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r
2270 // is stored with common variable in the same NV region. So the platform integrator should\r
2271 // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of \r
2272 // PcdFlashNvStorageVariableSize.\r
2273 //\r
2274 ASSERT (PcdGet32 (PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));\r
2275\r
2276 //\r
2277 // Allocate memory for volatile variable store, note that there is a scratch space to store scratch data.\r
2278 //\r
2279 ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
2280 VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);\r
2281 if (VolatileVariableStore == NULL) {\r
2282 FreePool (mVariableModuleGlobal);\r
2283 return EFI_OUT_OF_RESOURCES;\r
2284 }\r
2285\r
2286 SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);\r
2287\r
2288 //\r
2289 // Variable Specific Data\r
2290 //\r
2291 mVariableModuleGlobal->VariableGlobal.VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
2292 mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer (VolatileVariableStore) - (UINTN) VolatileVariableStore;\r
2293 mVariableModuleGlobal->FvbInstance = FvbProtocol;\r
2294\r
2295 CopyGuid (&VolatileVariableStore->Signature, &gEfiVariableGuid);\r
2296 VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize);\r
2297 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;\r
2298 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;\r
2299 VolatileVariableStore->Reserved = 0;\r
2300 VolatileVariableStore->Reserved1 = 0;\r
2301\r
2302 //\r
2303 // Get non volatile varaible store\r
2304 //\r
2305\r
2306 TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
2307 if (TempVariableStoreHeader == 0) {\r
2308 TempVariableStoreHeader = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
2309 }\r
2310 \r
2311 VariableStoreBase = TempVariableStoreHeader + \\r
2312 (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
2313 VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \\r
2314 (((EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)(TempVariableStoreHeader)) -> HeaderLength);\r
2315 //\r
2316 // Mark the variable storage region of the FLASH as RUNTIME\r
2317 //\r
2318 BaseAddress = VariableStoreBase & (~EFI_PAGE_MASK);\r
2319 Length = VariableStoreLength + (VariableStoreBase - BaseAddress);\r
2320 Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);\r
2321\r
2322 Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);\r
2323 if (EFI_ERROR (Status)) {\r
2324 goto Done;\r
2325 }\r
2326\r
2327 Status = gDS->SetMemorySpaceAttributes (\r
2328 BaseAddress,\r
2329 Length,\r
2330 GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME\r
2331 );\r
2332 if (EFI_ERROR (Status)) {\r
2333 goto Done;\r
2334 }\r
2335 //\r
2336 // Get address of non volatile variable store base\r
2337 //\r
2338 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase = VariableStoreBase;\r
2339 VariableStoreHeader = (VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase;\r
2340 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
2341 if (~VariableStoreHeader->Size == 0) {\r
2342 Status = UpdateVariableStore (\r
2343 &mVariableModuleGlobal->VariableGlobal,\r
2344 FALSE,\r
2345 FALSE,\r
2346 mVariableModuleGlobal->FvbInstance,\r
2347 (UINTN) &VariableStoreHeader->Size,\r
2348 sizeof (UINT32),\r
2349 (UINT8 *) &VariableStoreLength\r
2350 );\r
2351 //\r
2352 // As Variables are stored in NV storage, which are slow devices,such as flash.\r
2353 // Variable operation may skip checking variable program result to improve performance,\r
2354 // We can assume Variable program is OK through some check point.\r
2355 // Variable Store Size Setting should be the first Variable write operation,\r
2356 // We can assume all Read/Write is OK if we can set Variable store size successfully.\r
2357 // If write fail, we will assert here\r
2358 //\r
2359 ASSERT(VariableStoreHeader->Size == VariableStoreLength);\r
2360\r
2361 if (EFI_ERROR (Status)) {\r
2362 goto Done;\r
2363 }\r
2364 }\r
2365\r
2366 //\r
2367 // Parse non-volatile variable data and get last variable offset\r
2368 //\r
2369 NextVariable = GetStartPointer ((VARIABLE_STORE_HEADER *)(UINTN)VariableStoreBase);\r
2370 Status = EFI_SUCCESS;\r
2371\r
2372 while (IsValidVariableHeader (NextVariable)) {\r
2373 VariableSize = NextVariable->NameSize + NextVariable->DataSize + sizeof (VARIABLE_HEADER);\r
2374 if ((NextVariable->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
2375 mVariableModuleGlobal->HwErrVariableTotalSize += HEADER_ALIGN (VariableSize);\r
2376 } else {\r
2377 mVariableModuleGlobal->CommonVariableTotalSize += HEADER_ALIGN (VariableSize);\r
2378 }\r
2379\r
2380 NextVariable = GetNextVariablePtr (NextVariable);\r
2381 }\r
2382\r
2383 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) NextVariable - (UINTN) VariableStoreBase;\r
2384\r
2385 //\r
2386 // Check if the free area is really free.\r
2387 //\r
2388 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {\r
2389 Data = ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase)[Index];\r
2390 if (Data != 0xff) {\r
2391 //\r
2392 // There must be something wrong in variable store, do reclaim operation.\r
2393 //\r
2394 Status = Reclaim (\r
2395 mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase,\r
2396 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
2397 FALSE,\r
2398 NULL\r
2399 );\r
2400\r
2401 if (EFI_ERROR (Status)) {\r
2402 goto Done;\r
2403 }\r
2404\r
2405 break;\r
2406 }\r
2407 }\r
2408\r
2409 //\r
2410 // Register the event handling function to reclaim variable for OS usage.\r
2411 //\r
2412 Status = EfiCreateEventReadyToBootEx (\r
2413 TPL_NOTIFY, \r
2414 ReclaimForOS, \r
2415 NULL, \r
2416 &ReadyToBootEvent\r
2417 );\r
2418 } else {\r
2419 Status = EFI_VOLUME_CORRUPTED;\r
2420 DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));\r
2421 }\r
2422\r
2423Done:\r
2424 if (EFI_ERROR (Status)) {\r
2425 FreePool (mVariableModuleGlobal);\r
2426 FreePool (VolatileVariableStore);\r
2427 }\r
2428\r
2429 return Status;\r
2430}\r
2431\r
2432/**\r
2433 Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE\r
2434\r
2435 This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
2436 It convers pointer to new virtual address.\r
2437\r
2438 @param Event Event whose notification function is being invoked\r
2439 @param Context Pointer to the notification function's context\r
2440\r
2441**/\r
2442VOID\r
2443EFIAPI\r
2444VariableClassAddressChangeEvent (\r
2445 IN EFI_EVENT Event,\r
2446 IN VOID *Context\r
2447 )\r
2448{\r
2449 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetBlockSize);\r
2450 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetPhysicalAddress);\r
2451 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->GetAttributes);\r
2452 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->SetAttributes);\r
2453 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Read);\r
2454 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->Write);\r
2455 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance->EraseBlocks);\r
2456 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal->FvbInstance);\r
2457 EfiConvertPointer (\r
2458 0x0,\r
2459 (VOID **) &mVariableModuleGlobal->VariableGlobal.NonVolatileVariableBase\r
2460 );\r
2461 EfiConvertPointer (\r
2462 0x0,\r
2463 (VOID **) &mVariableModuleGlobal->VariableGlobal.VolatileVariableBase\r
2464 );\r
2465 EfiConvertPointer (0x0, (VOID **) &mVariableModuleGlobal);\r
2466}\r
2467\r
2468/**\r
2469 Firmware Volume Block Protocol notification event handler.\r
2470\r
2471 Discover NV Variable Store and install Variable Arch Protocol.\r
2472\r
2473 @param[in] Event Event whose notification function is being invoked.\r
2474 @param[in] Context Pointer to the notification function's context.\r
2475**/\r
2476VOID\r
2477EFIAPI\r
2478FvbNotificationEvent (\r
2479 IN EFI_EVENT Event,\r
2480 IN VOID *Context\r
2481 )\r
2482{\r
2483 EFI_STATUS Status;\r
2484 EFI_HANDLE *HandleBuffer;\r
2485 UINTN HandleCount;\r
2486 UINTN Index;\r
2487 EFI_PHYSICAL_ADDRESS FvbBaseAddress;\r
2488 EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;\r
2489 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
2490 EFI_FVB_ATTRIBUTES_2 Attributes;\r
2491 EFI_SYSTEM_TABLE *SystemTable;\r
2492 EFI_PHYSICAL_ADDRESS NvStorageVariableBase;\r
2493\r
2494 SystemTable = (EFI_SYSTEM_TABLE *)Context;\r
2495 Fvb = NULL;\r
2496 \r
2497 //\r
2498 // Locate all handles of Fvb protocol\r
2499 //\r
2500 Status = gBS->LocateHandleBuffer (\r
2501 ByProtocol,\r
2502 &gEfiFirmwareVolumeBlockProtocolGuid,\r
2503 NULL,\r
2504 &HandleCount,\r
2505 &HandleBuffer\r
2506 );\r
2507 if (EFI_ERROR (Status)) {\r
2508 return ;\r
2509 }\r
2510 \r
2511 //\r
2512 // Get the FVB to access variable store\r
2513 //\r
2514 for (Index = 0; Index < HandleCount; Index += 1, Status = EFI_NOT_FOUND, Fvb = NULL) {\r
2515 Status = gBS->HandleProtocol (\r
2516 HandleBuffer[Index],\r
2517 &gEfiFirmwareVolumeBlockProtocolGuid,\r
2518 (VOID **) &Fvb\r
2519 );\r
2520 if (EFI_ERROR (Status)) {\r
2521 Status = EFI_NOT_FOUND;\r
2522 break;\r
2523 }\r
2524\r
2525 //\r
2526 // Ensure this FVB protocol supported Write operation.\r
2527 //\r
2528 Status = Fvb->GetAttributes (Fvb, &Attributes);\r
2529 if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {\r
2530 continue; \r
2531 }\r
2532 //\r
2533 // Compare the address and select the right one\r
2534 //\r
2535 Status = Fvb->GetPhysicalAddress (Fvb, &FvbBaseAddress);\r
2536 if (EFI_ERROR (Status)) {\r
2537 continue;\r
2538 }\r
2539\r
2540 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvbBaseAddress);\r
2541 NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
2542 if (NvStorageVariableBase == 0) {\r
2543 NvStorageVariableBase = (EFI_PHYSICAL_ADDRESS) PcdGet32 (PcdFlashNvStorageVariableBase);\r
2544 }\r
2545 \r
2546 if ((NvStorageVariableBase >= FvbBaseAddress) && (NvStorageVariableBase < (FvbBaseAddress + FwVolHeader->FvLength))) {\r
2547 Status = EFI_SUCCESS;\r
2548 break;\r
2549 }\r
2550 }\r
2551\r
2552 FreePool (HandleBuffer);\r
2553 if (!EFI_ERROR (Status) && Fvb != NULL) {\r
2554 //\r
2555 // Close the notify event to avoid install gEfiVariableArchProtocolGuid & gEfiVariableWriteArchProtocolGuid again.\r
2556 //\r
2557 Status = gBS->CloseEvent (Event); \r
2558 ASSERT_EFI_ERROR (Status);\r
2559\r
2560 Status = VariableCommonInitialize (Fvb);\r
2561 ASSERT_EFI_ERROR (Status);\r
2562 \r
2563 SystemTable->RuntimeServices->GetVariable = RuntimeServiceGetVariable;\r
2564 SystemTable->RuntimeServices->GetNextVariableName = RuntimeServiceGetNextVariableName;\r
2565 SystemTable->RuntimeServices->SetVariable = RuntimeServiceSetVariable;\r
2566 SystemTable->RuntimeServices->QueryVariableInfo = RuntimeServiceQueryVariableInfo;\r
2567 \r
2568 //\r
2569 // Now install the Variable Runtime Architectural Protocol on a new handle\r
2570 //\r
2571 Status = gBS->InstallMultipleProtocolInterfaces (\r
2572 &mHandle,\r
2573 &gEfiVariableArchProtocolGuid, NULL,\r
2574 &gEfiVariableWriteArchProtocolGuid, NULL,\r
2575 NULL\r
2576 );\r
2577 ASSERT_EFI_ERROR (Status);\r
2578 \r
2579 Status = gBS->CreateEventEx (\r
2580 EVT_NOTIFY_SIGNAL,\r
2581 TPL_NOTIFY,\r
2582 VariableClassAddressChangeEvent,\r
2583 NULL,\r
2584 &gEfiEventVirtualAddressChangeGuid,\r
2585 &mVirtualAddressChangeEvent\r
2586 );\r
2587 ASSERT_EFI_ERROR (Status);\r
2588 }\r
2589\r
2590}\r
2591\r
2592/**\r
2593 Variable Driver main entry point. The Variable driver places the 4 EFI\r
2594 runtime services in the EFI System Table and installs arch protocols \r
2595 for variable read and write services being availible. It also registers\r
2596 notification function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE event.\r
2597\r
2598 @param[in] ImageHandle The firmware allocated handle for the EFI image. \r
2599 @param[in] SystemTable A pointer to the EFI System Table.\r
2600 \r
2601 @retval EFI_SUCCESS Variable service successfully initialized.\r
2602\r
2603**/\r
2604EFI_STATUS\r
2605EFIAPI\r
2606VariableServiceInitialize (\r
2607 IN EFI_HANDLE ImageHandle,\r
2608 IN EFI_SYSTEM_TABLE *SystemTable\r
2609 )\r
2610{\r
2611 //\r
2612 // Register FvbNotificationEvent () notify function.\r
2613 // \r
2614 EfiCreateProtocolNotifyEvent (\r
2615 &gEfiFirmwareVolumeBlockProtocolGuid,\r
2616 TPL_CALLBACK,\r
2617 FvbNotificationEvent,\r
2618 (VOID *)SystemTable,\r
2619 &mFvbRegistration\r
2620 );\r
2621\r
2622 return EFI_SUCCESS;\r
2623}\r
2624\r