]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - SecurityPkg/VariableAuthenticated/EsalVariableDxeSal/Variable.c
Add pointer check for NULL before dereference it.
[mirror_edk2.git] / SecurityPkg / VariableAuthenticated / EsalVariableDxeSal / Variable.c
... / ...
CommitLineData
1/** @file\r
2 The implementation of Extended SAL variable services.\r
3\r
4Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
5This program and the accompanying materials \r
6are licensed and made available under the terms and conditions of the BSD License \r
7which accompanies this distribution. The full text of the license may be found at \r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include "Variable.h"\r
16#include "AuthService.h"\r
17\r
18//\r
19// Don't use module globals after the SetVirtualAddress map is signaled\r
20//\r
21ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal;\r
22CHAR16 *mVariableName[NUM_VAR_NAME] = {\r
23 L"PlatformLangCodes",\r
24 L"LangCodes",\r
25 L"PlatformLang",\r
26 L"Lang",\r
27 L"HwErrRec",\r
28 AUTHVAR_KEYDB_NAME,\r
29 EFI_SETUP_MODE_NAME,\r
30 EFI_PLATFORM_KEY_NAME,\r
31 EFI_KEY_EXCHANGE_KEY_NAME\r
32};\r
33\r
34GLOBAL_REMOVE_IF_UNREFERENCED VARIABLE_INFO_ENTRY *gVariableInfo = NULL;\r
35\r
36//\r
37// The current Hii implementation accesses this variable a larg # of times on every boot.\r
38// Other common variables are only accessed a single time. This is why this cache algorithm\r
39// only targets a single variable. Probably to get an performance improvement out of\r
40// a Cache you would need a cache that improves the search performance for a variable.\r
41//\r
42VARIABLE_CACHE_ENTRY mVariableCache[] = {\r
43 {\r
44 &gEfiGlobalVariableGuid,\r
45 L"Lang",\r
46 0x00000000,\r
47 0x00,\r
48 NULL\r
49 },\r
50 {\r
51 &gEfiGlobalVariableGuid,\r
52 L"PlatformLang",\r
53 0x00000000,\r
54 0x00,\r
55 NULL\r
56 }\r
57};\r
58\r
59/**\r
60 Acquires lock only at boot time. Simply returns at runtime.\r
61\r
62 This is a temperary function which will be removed when\r
63 EfiAcquireLock() in UefiLib can handle the call in UEFI\r
64 Runtimer driver in RT phase.\r
65 It calls EfiAcquireLock() at boot time, and simply returns\r
66 at runtime.\r
67\r
68 @param[in] Lock A pointer to the lock to acquire.\r
69\r
70**/\r
71VOID\r
72AcquireLockOnlyAtBootTime (\r
73 IN EFI_LOCK *Lock\r
74 )\r
75{\r
76 if (!EfiAtRuntime ()) {\r
77 EfiAcquireLock (Lock);\r
78 }\r
79}\r
80\r
81/**\r
82 Releases lock only at boot time. Simply returns at runtime.\r
83\r
84 This is a temperary function which will be removed when\r
85 EfiReleaseLock() in UefiLib can handle the call in UEFI\r
86 Runtimer driver in RT phase.\r
87 It calls EfiReleaseLock() at boot time, and simply returns\r
88 at runtime\r
89\r
90 @param[in] Lock A pointer to the lock to release.\r
91\r
92**/\r
93VOID\r
94ReleaseLockOnlyAtBootTime (\r
95 IN EFI_LOCK *Lock\r
96 )\r
97{\r
98 if (!EfiAtRuntime ()) {\r
99 EfiReleaseLock (Lock);\r
100 }\r
101}\r
102\r
103/**\r
104 Reads/Writes variable storage, volatile or non-volatile.\r
105\r
106 This function reads or writes volatile or non-volatile variable stroage.\r
107 For volatile storage, it performs memory copy.\r
108 For non-volatile storage, it accesses data on firmware storage. Data\r
109 area to access can span multiple firmware blocks.\r
110\r
111 @param[in] Write TRUE - Write variable store.\r
112 FALSE - Read variable store.\r
113 @param[in] Global Pointer to VARAIBLE_GLOBAL structure.\r
114 @param[in] Volatile TRUE - Variable is volatile.\r
115 FALSE - Variable is non-volatile.\r
116 @param[in] Instance Instance of FV Block services.\r
117 @param[in] StartAddress Start address of data to access.\r
118 @param[in] DataSize Size of data to access.\r
119 @param[in, out] Buffer For write, pointer to the buffer from which data is written.\r
120 For read, pointer to the buffer to hold the data read.\r
121\r
122 @retval EFI_SUCCESS Variable store successfully accessed.\r
123 @retval EFI_INVALID_PARAMETER Data area to access exceeds valid variable storage.\r
124\r
125**/\r
126EFI_STATUS\r
127AccessVariableStore (\r
128 IN BOOLEAN Write,\r
129 IN VARIABLE_GLOBAL *Global,\r
130 IN BOOLEAN Volatile,\r
131 IN UINTN Instance,\r
132 IN EFI_PHYSICAL_ADDRESS StartAddress,\r
133 IN UINT32 DataSize,\r
134 IN OUT VOID *Buffer\r
135 )\r
136{\r
137 EFI_FV_BLOCK_MAP_ENTRY *PtrBlockMapEntry;\r
138 UINTN BlockIndex;\r
139 UINTN LinearOffset;\r
140 UINTN CurrWriteSize;\r
141 UINTN CurrWritePtr;\r
142 UINT8 *CurrBuffer;\r
143 EFI_LBA LbaNumber;\r
144 UINTN Size;\r
145 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
146 VARIABLE_STORE_HEADER *VolatileBase;\r
147 EFI_PHYSICAL_ADDRESS FvVolHdr;\r
148 EFI_STATUS Status;\r
149 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
150\r
151 FvVolHdr = 0;\r
152 FwVolHeader = NULL;\r
153\r
154 if (Volatile) {\r
155 //\r
156 // If data is volatile, simply calculate the data pointer and copy memory.\r
157 // Data pointer should point to the actual address where data is to be\r
158 // accessed.\r
159 //\r
160 VolatileBase = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);\r
161\r
162 if ((StartAddress + DataSize) > ((UINTN) ((UINT8 *) VolatileBase + VolatileBase->Size))) {\r
163 return EFI_INVALID_PARAMETER;\r
164 }\r
165 \r
166 //\r
167 // For volatile variable, a simple memory copy is enough.\r
168 //\r
169 if (Write) {\r
170 CopyMem ((VOID *) StartAddress, Buffer, DataSize);\r
171 } else {\r
172 CopyMem (Buffer, (VOID *) StartAddress, DataSize);\r
173 }\r
174\r
175 return EFI_SUCCESS;\r
176 }\r
177\r
178 //\r
179 // If data is non-volatile, calculate firmware volume header and data pointer.\r
180 //\r
181 Status = (EFI_STATUS) EsalCall (\r
182 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,\r
183 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,\r
184 GetPhysicalAddressFunctionId, \r
185 Instance, \r
186 (UINT64) &FvVolHdr, \r
187 0, \r
188 0, \r
189 0, \r
190 0, \r
191 0\r
192 ).Status;\r
193 ASSERT_EFI_ERROR (Status);\r
194\r
195 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);\r
196 ASSERT (FwVolHeader != NULL);\r
197 VariableStoreHeader = (VARIABLE_STORE_HEADER *)(FwVolHeader + 1);\r
198\r
199 if ((StartAddress + DataSize) > ((EFI_PHYSICAL_ADDRESS) (UINTN) ((CHAR8 *)VariableStoreHeader + VariableStoreHeader->Size))) {\r
200 return EFI_INVALID_PARAMETER;\r
201 }\r
202 \r
203 LinearOffset = (UINTN) FwVolHeader;\r
204 CurrWritePtr = StartAddress;\r
205 CurrWriteSize = DataSize;\r
206 CurrBuffer = Buffer;\r
207 LbaNumber = 0;\r
208\r
209 if (CurrWritePtr < LinearOffset) {\r
210 return EFI_INVALID_PARAMETER;\r
211 }\r
212\r
213 //\r
214 // Traverse data blocks of this firmware storage to find the one where CurrWritePtr locates\r
215 //\r
216 for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {\r
217 for (BlockIndex = 0; BlockIndex < PtrBlockMapEntry->NumBlocks; BlockIndex++) {\r
218 if ((CurrWritePtr >= LinearOffset) && (CurrWritePtr < LinearOffset + PtrBlockMapEntry->Length)) {\r
219 //\r
220 // Check to see if the data area to access spans multiple blocks.\r
221 //\r
222 if ((CurrWritePtr + CurrWriteSize) <= (LinearOffset + PtrBlockMapEntry->Length)) {\r
223 //\r
224 // If data area to access is contained in one block, just access and return.\r
225 //\r
226 if (Write) {\r
227 Status = (EFI_STATUS) EsalCall (\r
228 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,\r
229 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,\r
230 WriteFunctionId, \r
231 Instance, \r
232 LbaNumber, \r
233 (CurrWritePtr - LinearOffset), \r
234 (UINT64) &CurrWriteSize, \r
235 (UINT64) CurrBuffer, \r
236 0, \r
237 0\r
238 ).Status;\r
239 } else {\r
240 Status = (EFI_STATUS) EsalCall (\r
241 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,\r
242 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,\r
243 ReadFunctionId, \r
244 Instance, \r
245 LbaNumber, \r
246 (CurrWritePtr - LinearOffset), \r
247 (UINT64) &CurrWriteSize, \r
248 (UINT64) CurrBuffer, \r
249 0, \r
250 0\r
251 ).Status;\r
252 }\r
253 return Status;\r
254 } else {\r
255 //\r
256 // If data area to access spans multiple blocks, access this one and adjust for the next one.\r
257 //\r
258 Size = (UINT32) (LinearOffset + PtrBlockMapEntry->Length - CurrWritePtr);\r
259 if (Write) {\r
260 Status = (EFI_STATUS) EsalCall (\r
261 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,\r
262 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,\r
263 WriteFunctionId, \r
264 Instance, \r
265 LbaNumber, \r
266 (CurrWritePtr - LinearOffset), \r
267 (UINT64) &Size, \r
268 (UINT64) CurrBuffer, \r
269 0, \r
270 0\r
271 ).Status;\r
272 } else {\r
273 Status = (EFI_STATUS) EsalCall (\r
274 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,\r
275 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,\r
276 ReadFunctionId, \r
277 Instance, \r
278 LbaNumber, \r
279 (CurrWritePtr - LinearOffset), \r
280 (UINT64) &Size, \r
281 (UINT64) CurrBuffer, \r
282 0, \r
283 0\r
284 ).Status;\r
285 }\r
286 if (EFI_ERROR (Status)) {\r
287 return Status;\r
288 }\r
289 //\r
290 // Adjust for the remaining data.\r
291 //\r
292 CurrWritePtr = LinearOffset + PtrBlockMapEntry->Length;\r
293 CurrBuffer = CurrBuffer + Size;\r
294 CurrWriteSize = CurrWriteSize - Size;\r
295 }\r
296 }\r
297\r
298 LinearOffset += PtrBlockMapEntry->Length;\r
299 LbaNumber++;\r
300 }\r
301 }\r
302\r
303 return EFI_SUCCESS;\r
304}\r
305\r
306/**\r
307 Retrieves header of volatile or non-volatile variable stroage.\r
308\r
309 @param[in] VarStoreAddress Start address of variable storage.\r
310 @param[in] Volatile TRUE - Variable storage is volatile.\r
311 FALSE - Variable storage is non-volatile.\r
312 @param[in] Global Pointer to VARAIBLE_GLOBAL structure.\r
313 @param[in] Instance Instance of FV Block services.\r
314 @param[out] VarStoreHeader Pointer to VARIABLE_STORE_HEADER for output.\r
315\r
316**/\r
317VOID\r
318GetVarStoreHeader (\r
319 IN EFI_PHYSICAL_ADDRESS VarStoreAddress,\r
320 IN BOOLEAN Volatile,\r
321 IN VARIABLE_GLOBAL *Global,\r
322 IN UINTN Instance,\r
323 OUT VARIABLE_STORE_HEADER *VarStoreHeader\r
324 )\r
325{\r
326 EFI_STATUS Status;\r
327\r
328 Status = AccessVariableStore (\r
329 FALSE,\r
330 Global,\r
331 Volatile,\r
332 Instance,\r
333 VarStoreAddress,\r
334 sizeof (VARIABLE_STORE_HEADER),\r
335 VarStoreHeader \r
336 );\r
337 ASSERT_EFI_ERROR (Status);\r
338}\r
339\r
340/**\r
341 Checks variable header.\r
342\r
343 This function checks if variable header is valid or not.\r
344\r
345 @param[in] VariableAddress Start address of variable header.\r
346 @param[in] Volatile TRUE - Variable is volatile.\r
347 FALSE - Variable is non-volatile.\r
348 @param[in] Global Pointer to VARAIBLE_GLOBAL structure.\r
349 @param[in] Instance Instance of FV Block services.\r
350 @param[out] VariableHeader Pointer to VARIABLE_HEADER for output.\r
351\r
352 @retval TRUE Variable header is valid.\r
353 @retval FALSE Variable header is not valid.\r
354\r
355**/\r
356BOOLEAN\r
357IsValidVariableHeader (\r
358 IN EFI_PHYSICAL_ADDRESS VariableAddress,\r
359 IN BOOLEAN Volatile,\r
360 IN VARIABLE_GLOBAL *Global,\r
361 IN UINTN Instance,\r
362 OUT VARIABLE_HEADER *VariableHeader OPTIONAL\r
363 )\r
364{\r
365 EFI_STATUS Status;\r
366 VARIABLE_HEADER LocalVariableHeader;\r
367\r
368 Status = AccessVariableStore (\r
369 FALSE,\r
370 Global,\r
371 Volatile,\r
372 Instance,\r
373 VariableAddress,\r
374 sizeof (VARIABLE_HEADER),\r
375 &LocalVariableHeader \r
376 );\r
377\r
378 if (EFI_ERROR (Status) || LocalVariableHeader.StartId != VARIABLE_DATA) {\r
379 return FALSE;\r
380 }\r
381\r
382 if (VariableHeader != NULL) {\r
383 CopyMem (VariableHeader, &LocalVariableHeader, sizeof (VARIABLE_HEADER));\r
384 }\r
385\r
386 return TRUE;\r
387}\r
388\r
389/**\r
390 Gets status of variable store.\r
391\r
392 This function gets the current status of variable store.\r
393\r
394 @param[in] VarStoreHeader Pointer to header of variable store.\r
395\r
396 @retval EfiRaw Variable store status is raw.\r
397 @retval EfiValid Variable store status is valid.\r
398 @retval EfiInvalid Variable store status is invalid.\r
399\r
400**/\r
401VARIABLE_STORE_STATUS\r
402GetVariableStoreStatus (\r
403 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
404 )\r
405{\r
406\r
407 if (CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) &&\r
408 VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&\r
409 VarStoreHeader->State == VARIABLE_STORE_HEALTHY\r
410 ) {\r
411\r
412 return EfiValid;\r
413 } else if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff &&\r
414 ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff &&\r
415 ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff &&\r
416 ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff &&\r
417 VarStoreHeader->Size == 0xffffffff &&\r
418 VarStoreHeader->Format == 0xff &&\r
419 VarStoreHeader->State == 0xff\r
420 ) {\r
421\r
422 return EfiRaw;\r
423 } else {\r
424 return EfiInvalid;\r
425 }\r
426}\r
427\r
428/**\r
429 Gets the size of variable name.\r
430\r
431 This function gets the size of variable name.\r
432 The variable is specified by its variable header.\r
433 If variable header contains raw data, just return 0.\r
434\r
435 @param[in] Variable Pointer to the variable header.\r
436\r
437 @return Size of variable name in bytes.\r
438\r
439**/\r
440UINTN\r
441NameSizeOfVariable (\r
442 IN VARIABLE_HEADER *Variable\r
443 )\r
444{\r
445 if (Variable->State == (UINT8) (-1) ||\r
446 Variable->DataSize == (UINT32) -1 ||\r
447 Variable->NameSize == (UINT32) -1 ||\r
448 Variable->Attributes == (UINT32) -1) {\r
449 return 0;\r
450 }\r
451 return (UINTN) Variable->NameSize;\r
452}\r
453\r
454/**\r
455 Gets the size of variable data area.\r
456\r
457 This function gets the size of variable data area.\r
458 The variable is specified by its variable header.\r
459 If variable header contains raw data, just return 0.\r
460\r
461 @param[in] Variable Pointer to the variable header.\r
462\r
463 @return Size of variable data area in bytes.\r
464\r
465**/\r
466UINTN\r
467DataSizeOfVariable (\r
468 IN VARIABLE_HEADER *Variable\r
469 )\r
470{\r
471 if (Variable->State == (UINT8) -1 ||\r
472 Variable->DataSize == (UINT32) -1 ||\r
473 Variable->NameSize == (UINT32) -1 ||\r
474 Variable->Attributes == (UINT32) -1) {\r
475 return 0;\r
476 }\r
477 return (UINTN) Variable->DataSize;\r
478}\r
479\r
480/**\r
481 Gets the pointer to variable name.\r
482\r
483 This function gets the pointer to variable name.\r
484 The variable is specified by its variable header.\r
485\r
486 @param[in] VariableAddress Start address of variable header.\r
487 @param[in] Volatile TRUE - Variable is volatile.\r
488 FALSE - Variable is non-volatile.\r
489 @param[in] Global Pointer to VARAIBLE_GLOBAL structure.\r
490 @param[in] Instance Instance of FV Block services.\r
491 @param[out] VariableName Buffer to hold variable name for output.\r
492\r
493**/\r
494VOID\r
495GetVariableNamePtr (\r
496 IN EFI_PHYSICAL_ADDRESS VariableAddress,\r
497 IN BOOLEAN Volatile,\r
498 IN VARIABLE_GLOBAL *Global,\r
499 IN UINTN Instance,\r
500 OUT CHAR16 *VariableName\r
501 )\r
502{\r
503 EFI_STATUS Status;\r
504 EFI_PHYSICAL_ADDRESS Address;\r
505 VARIABLE_HEADER VariableHeader;\r
506 BOOLEAN IsValid;\r
507\r
508 IsValid = IsValidVariableHeader (VariableAddress, Volatile, Global, Instance, &VariableHeader);\r
509 ASSERT (IsValid);\r
510\r
511 //\r
512 // Name area follows variable header.\r
513 //\r
514 Address = VariableAddress + sizeof (VARIABLE_HEADER);\r
515\r
516 Status = AccessVariableStore (\r
517 FALSE,\r
518 Global,\r
519 Volatile,\r
520 Instance,\r
521 Address,\r
522 VariableHeader.NameSize,\r
523 VariableName \r
524 );\r
525 ASSERT_EFI_ERROR (Status);\r
526}\r
527\r
528/**\r
529 Gets the pointer to variable data area.\r
530\r
531 This function gets the pointer to variable data area.\r
532 The variable is specified by its variable header.\r
533\r
534 @param[in] VariableAddress Start address of variable header.\r
535 @param[in] Volatile TRUE - Variable is volatile.\r
536 FALSE - Variable is non-volatile.\r
537 @param[in] Global Pointer to VARAIBLE_GLOBAL structure.\r
538 @param[in] Instance Instance of FV Block services.\r
539 @param[out] VariableData Buffer to hold variable data for output.\r
540\r
541**/\r
542VOID\r
543GetVariableDataPtr (\r
544 IN EFI_PHYSICAL_ADDRESS VariableAddress,\r
545 IN BOOLEAN Volatile,\r
546 IN VARIABLE_GLOBAL *Global,\r
547 IN UINTN Instance,\r
548 OUT CHAR16 *VariableData\r
549 )\r
550{\r
551 EFI_STATUS Status;\r
552 EFI_PHYSICAL_ADDRESS Address;\r
553 VARIABLE_HEADER VariableHeader;\r
554 BOOLEAN IsValid;\r
555\r
556 IsValid = IsValidVariableHeader (VariableAddress, Volatile, Global, Instance, &VariableHeader);\r
557 ASSERT (IsValid);\r
558\r
559 //\r
560 // Data area follows variable name.\r
561 // Be careful about pad size for alignment\r
562 //\r
563 Address = VariableAddress + sizeof (VARIABLE_HEADER);\r
564 Address += NameSizeOfVariable (&VariableHeader);\r
565 Address += GET_PAD_SIZE (NameSizeOfVariable (&VariableHeader));\r
566\r
567 Status = AccessVariableStore (\r
568 FALSE,\r
569 Global,\r
570 Volatile,\r
571 Instance,\r
572 Address,\r
573 VariableHeader.DataSize,\r
574 VariableData \r
575 );\r
576 ASSERT_EFI_ERROR (Status);\r
577}\r
578\r
579\r
580/**\r
581 Gets the pointer to the next variable header.\r
582\r
583 This function gets the pointer to the next variable header.\r
584 The variable is specified by its variable header.\r
585\r
586 @param[in] VariableAddress Start address of variable header.\r
587 @param[in] Volatile TRUE - Variable is volatile.\r
588 FALSE - Variable is non-volatile.\r
589 @param[in] Global Pointer to VARAIBLE_GLOBAL structure.\r
590 @param[in] Instance Instance of FV Block services.\r
591\r
592 @return Pointer to the next variable header.\r
593 NULL if variable header is invalid.\r
594\r
595**/\r
596EFI_PHYSICAL_ADDRESS\r
597GetNextVariablePtr (\r
598 IN EFI_PHYSICAL_ADDRESS VariableAddress,\r
599 IN BOOLEAN Volatile,\r
600 IN VARIABLE_GLOBAL *Global,\r
601 IN UINTN Instance\r
602 )\r
603{\r
604 EFI_PHYSICAL_ADDRESS Address;\r
605 VARIABLE_HEADER VariableHeader;\r
606\r
607 if (!IsValidVariableHeader (VariableAddress, Volatile, Global, Instance, &VariableHeader)) {\r
608 return 0x0;\r
609 }\r
610\r
611 //\r
612 // Header of next variable follows data area of this variable\r
613 //\r
614 Address = VariableAddress + sizeof (VARIABLE_HEADER);\r
615 Address += NameSizeOfVariable (&VariableHeader);\r
616 Address += GET_PAD_SIZE (NameSizeOfVariable (&VariableHeader));\r
617 Address += DataSizeOfVariable (&VariableHeader);\r
618 Address += GET_PAD_SIZE (DataSizeOfVariable (&VariableHeader));\r
619\r
620 //\r
621 // Be careful about pad size for alignment\r
622 //\r
623 return HEADER_ALIGN (Address);\r
624}\r
625\r
626/**\r
627 Gets the pointer to the first variable header in given variable store area.\r
628\r
629 This function gets the pointer to the first variable header in given variable \r
630 store area. The variable store area is given by its start address.\r
631\r
632 @param[in] VarStoreHeaderAddress Pointer to the header of variable store area.\r
633\r
634 @return Pointer to the first variable header.\r
635\r
636**/\r
637EFI_PHYSICAL_ADDRESS\r
638GetStartPointer (\r
639 IN EFI_PHYSICAL_ADDRESS VarStoreHeaderAddress\r
640 )\r
641{\r
642 return HEADER_ALIGN (VarStoreHeaderAddress + sizeof (VARIABLE_STORE_HEADER));\r
643}\r
644\r
645/**\r
646 Gets the pointer to the end of given variable store area.\r
647\r
648 This function gets the pointer to the end of given variable store area.\r
649 The variable store area is given by its start address.\r
650\r
651 @param[in] VarStoreHeaderAddress Pointer to the header of variable store area.\r
652 @param[in] Volatile TRUE - Variable is volatile.\r
653 FALSE - Variable is non-volatile.\r
654 @param[in] Global Pointer to VARAIBLE_GLOBAL structure.\r
655 @param[in] Instance Instance of FV Block services.\r
656\r
657 @return Pointer to the end of given variable store area.\r
658\r
659**/\r
660EFI_PHYSICAL_ADDRESS\r
661GetEndPointer (\r
662 IN EFI_PHYSICAL_ADDRESS VarStoreHeaderAddress,\r
663 IN BOOLEAN Volatile,\r
664 IN VARIABLE_GLOBAL *Global,\r
665 IN UINTN Instance\r
666 )\r
667{\r
668 EFI_STATUS Status;\r
669 VARIABLE_STORE_HEADER VariableStoreHeader;\r
670\r
671 Status = AccessVariableStore (\r
672 FALSE,\r
673 Global,\r
674 Volatile,\r
675 Instance,\r
676 VarStoreHeaderAddress,\r
677 sizeof (VARIABLE_STORE_HEADER),\r
678 &VariableStoreHeader \r
679 );\r
680\r
681 ASSERT_EFI_ERROR (Status);\r
682 return HEADER_ALIGN (VarStoreHeaderAddress + VariableStoreHeader.Size);\r
683}\r
684\r
685/**\r
686 Updates variable info entry in EFI system table for statistical information.\r
687\r
688 Routine used to track statistical information about variable usage. \r
689 The data is stored in the EFI system table so it can be accessed later.\r
690 VariableInfo.efi can dump out the table. Only Boot Services variable \r
691 accesses are tracked by this code. The PcdVariableCollectStatistics\r
692 build flag controls if this feature is enabled. \r
693 A read that hits in the cache will have Read and Cache true for \r
694 the transaction. Data is allocated by this routine, but never\r
695 freed.\r
696\r
697 @param[in] VariableName Name of the Variable to track.\r
698 @param[in] VendorGuid Guid of the Variable to track.\r
699 @param[in] Volatile TRUE if volatile FALSE if non-volatile.\r
700 @param[in] Read TRUE if GetVariable() was called.\r
701 @param[in] Write TRUE if SetVariable() was called.\r
702 @param[in] Delete TRUE if deleted via SetVariable().\r
703 @param[in] Cache TRUE for a cache hit.\r
704\r
705**/\r
706VOID\r
707UpdateVariableInfo (\r
708 IN CHAR16 *VariableName,\r
709 IN EFI_GUID *VendorGuid,\r
710 IN BOOLEAN Volatile,\r
711 IN BOOLEAN Read,\r
712 IN BOOLEAN Write,\r
713 IN BOOLEAN Delete,\r
714 IN BOOLEAN Cache\r
715 )\r
716{\r
717 VARIABLE_INFO_ENTRY *Entry;\r
718\r
719 if (FeaturePcdGet (PcdVariableCollectStatistics)) {\r
720\r
721 if (EfiAtRuntime ()) {\r
722 //\r
723 // Don't collect statistics at runtime\r
724 //\r
725 return;\r
726 }\r
727\r
728 if (gVariableInfo == NULL) {\r
729 //\r
730 // on the first call allocate a entry and place a pointer to it in\r
731 // the EFI System Table\r
732 //\r
733 gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
734 ASSERT (gVariableInfo != NULL);\r
735\r
736 CopyGuid (&gVariableInfo->VendorGuid, VendorGuid);\r
737 gVariableInfo->Name = AllocatePool (StrSize (VariableName));\r
738 ASSERT (gVariableInfo->Name != NULL);\r
739 StrCpy (gVariableInfo->Name, VariableName);\r
740 gVariableInfo->Volatile = Volatile;\r
741\r
742 gBS->InstallConfigurationTable (&gEfiAuthenticatedVariableGuid, gVariableInfo);\r
743 }\r
744\r
745 \r
746 for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) {\r
747 if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {\r
748 if (StrCmp (VariableName, Entry->Name) == 0) {\r
749 //\r
750 // Find the entry matching both variable name and vender GUID,\r
751 // and update counters for all types.\r
752 //\r
753 if (Read) {\r
754 Entry->ReadCount++;\r
755 }\r
756 if (Write) {\r
757 Entry->WriteCount++;\r
758 }\r
759 if (Delete) {\r
760 Entry->DeleteCount++;\r
761 }\r
762 if (Cache) {\r
763 Entry->CacheCount++;\r
764 }\r
765\r
766 return;\r
767 }\r
768 }\r
769\r
770 if (Entry->Next == NULL) {\r
771 //\r
772 // If the entry is not in the table add it.\r
773 // Next iteration of the loop will fill in the data\r
774 //\r
775 Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));\r
776 ASSERT (Entry->Next != NULL);\r
777\r
778 CopyGuid (&Entry->Next->VendorGuid, VendorGuid);\r
779 Entry->Next->Name = AllocatePool (StrSize (VariableName));\r
780 ASSERT (Entry->Next->Name != NULL);\r
781 StrCpy (Entry->Next->Name, VariableName);\r
782 Entry->Next->Volatile = Volatile;\r
783 }\r
784\r
785 }\r
786 }\r
787}\r
788\r
789/**\r
790 Updates variable in cache.\r
791\r
792 This function searches the variable cache. If the variable to set exists in the cache,\r
793 it updates the variable in cache. It has the same parameters with UEFI SetVariable()\r
794 service.\r
795\r
796 @param[in] VariableName A Null-terminated Unicode string that is the name of the vendor's\r
797 variable. Each VariableName is unique for each VendorGuid.\r
798 @param[in] VendorGuid A unique identifier for the vendor.\r
799 @param[in] Attributes Attributes bitmask to set for the variable.\r
800 @param[in] DataSize The size in bytes of the Data buffer. A size of zero causes the\r
801 variable to be deleted.\r
802 @param[in] Data The contents for the variable.\r
803\r
804**/\r
805VOID\r
806UpdateVariableCache (\r
807 IN CHAR16 *VariableName,\r
808 IN EFI_GUID *VendorGuid,\r
809 IN UINT32 Attributes,\r
810 IN UINTN DataSize,\r
811 IN VOID *Data\r
812 )\r
813{\r
814 VARIABLE_CACHE_ENTRY *Entry;\r
815 UINTN Index;\r
816\r
817 if (EfiAtRuntime ()) {\r
818 //\r
819 // Don't use the cache at runtime\r
820 //\r
821 return;\r
822 }\r
823\r
824 //\r
825 // Searches cache for the variable to update. If it exists, update it.\r
826 //\r
827 for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {\r
828 if (CompareGuid (VendorGuid, Entry->Guid)) {\r
829 if (StrCmp (VariableName, Entry->Name) == 0) { \r
830 Entry->Attributes = Attributes;\r
831 if (DataSize == 0) {\r
832 //\r
833 // If DataSize is 0, delete the variable.\r
834 //\r
835 if (Entry->DataSize != 0) {\r
836 FreePool (Entry->Data);\r
837 }\r
838 Entry->DataSize = DataSize;\r
839 } else if (DataSize == Entry->DataSize) {\r
840 //\r
841 // If size of data does not change, simply copy data\r
842 //\r
843 CopyMem (Entry->Data, Data, DataSize);\r
844 } else {\r
845 //\r
846 // If size of data changes, allocate pool and copy data.\r
847 //\r
848 Entry->Data = AllocatePool (DataSize);\r
849 ASSERT (Entry->Data != NULL);\r
850 Entry->DataSize = DataSize;\r
851 CopyMem (Entry->Data, Data, DataSize);\r
852 }\r
853 }\r
854 }\r
855 }\r
856}\r
857\r
858\r
859/**\r
860 Search the cache to check if the variable is in it.\r
861\r
862 This function searches the variable cache. If the variable to find exists, return its data\r
863 and attributes.\r
864\r
865 @param[in] VariableName A Null-terminated Unicode string that is the name of the vendor's\r
866 variable. Each VariableName is unique for each VendorGuid.\r
867 @param[in] VendorGuid A unique identifier for the vendor\r
868 @param[out] Attributes Pointer to the attributes bitmask of the variable for output.\r
869 @param[in, out] DataSize On input, size of the buffer of Data.\r
870 On output, size of the variable's data.\r
871 @param[out] Data Pointer to the data buffer for output.\r
872\r
873 @retval EFI_SUCCESS VariableGuid & VariableName data was returned.\r
874 @retval EFI_NOT_FOUND No matching variable found in cache.\r
875 @retval EFI_BUFFER_TOO_SMALL *DataSize is smaller than size of the variable's data to return.\r
876\r
877**/\r
878EFI_STATUS\r
879FindVariableInCache (\r
880 IN CHAR16 *VariableName,\r
881 IN EFI_GUID *VendorGuid,\r
882 OUT UINT32 *Attributes OPTIONAL,\r
883 IN OUT UINTN *DataSize,\r
884 OUT VOID *Data\r
885 )\r
886{\r
887 VARIABLE_CACHE_ENTRY *Entry;\r
888 UINTN Index;\r
889\r
890 if (EfiAtRuntime ()) {\r
891 //\r
892 // Don't use the cache at runtime\r
893 //\r
894 return EFI_NOT_FOUND;\r
895 }\r
896\r
897 //\r
898 // Searches cache for the variable\r
899 //\r
900 for (Index = 0, Entry = mVariableCache; Index < sizeof (mVariableCache)/sizeof (VARIABLE_CACHE_ENTRY); Index++, Entry++) {\r
901 if (CompareGuid (VendorGuid, Entry->Guid)) {\r
902 if (StrCmp (VariableName, Entry->Name) == 0) {\r
903 if (Entry->DataSize == 0) {\r
904 //\r
905 // Variable has been deleted so return EFI_NOT_FOUND\r
906 //\r
907 return EFI_NOT_FOUND;\r
908 } else if (Entry->DataSize > *DataSize) {\r
909 //\r
910 // If buffer is too small, return the size needed and EFI_BUFFER_TOO_SMALL\r
911 //\r
912 *DataSize = Entry->DataSize;\r
913 return EFI_BUFFER_TOO_SMALL;\r
914 } else {\r
915 //\r
916 // If buffer is large enough, return the data\r
917 //\r
918 *DataSize = Entry->DataSize;\r
919 CopyMem (Data, Entry->Data, Entry->DataSize);\r
920 //\r
921 // If Attributes is not NULL, return the variable's attribute.\r
922 //\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 volatile and non-volatile storage areas.\r
937\r
938 This code finds variable in 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[in] VariableName Name of the variable to be found.\r
944 @param[in] VendorGuid Vendor GUID to be found.\r
945 @param[out] PtrTrack VARIABLE_POINTER_TRACK structure for output,\r
946 including the range searched and the target position.\r
947 @param[in] 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 @param[in] Instance Instance of FV Block services.\r
951\r
952 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while\r
953 VendorGuid is NULL.\r
954 @retval EFI_SUCCESS Variable successfully found.\r
955 @retval EFI_INVALID_PARAMETER Variable not found.\r
956\r
957**/\r
958EFI_STATUS\r
959FindVariable (\r
960 IN CHAR16 *VariableName,\r
961 IN EFI_GUID *VendorGuid,\r
962 OUT VARIABLE_POINTER_TRACK *PtrTrack,\r
963 IN VARIABLE_GLOBAL *Global,\r
964 IN UINTN Instance\r
965 )\r
966{\r
967 EFI_PHYSICAL_ADDRESS Variable[2];\r
968 EFI_PHYSICAL_ADDRESS InDeletedVariable;\r
969 EFI_PHYSICAL_ADDRESS VariableStoreHeader[2];\r
970 UINTN InDeletedStorageIndex;\r
971 UINTN Index;\r
972 CHAR16 LocalVariableName[MAX_NAME_SIZE];\r
973 BOOLEAN Volatile;\r
974 VARIABLE_HEADER VariableHeader;\r
975\r
976 //\r
977 // 0: Volatile, 1: Non-Volatile\r
978 // The index and attributes mapping must be kept in this order as RuntimeServiceGetNextVariableName\r
979 // make use of this mapping to implement search algorithme.\r
980 //\r
981 VariableStoreHeader[0] = Global->VolatileVariableBase;\r
982 VariableStoreHeader[1] = Global->NonVolatileVariableBase;\r
983\r
984 //\r
985 // Start Pointers for the variable.\r
986 // Actual Data Pointer where data can be written.\r
987 //\r
988 Variable[0] = GetStartPointer (VariableStoreHeader[0]);\r
989 Variable[1] = GetStartPointer (VariableStoreHeader[1]);\r
990\r
991 if (VariableName[0] != 0 && VendorGuid == NULL) {\r
992 return EFI_INVALID_PARAMETER;\r
993 }\r
994\r
995 //\r
996 // Find the variable by walk through volatile and then non-volatile variable store\r
997 //\r
998 InDeletedVariable = 0x0;\r
999 InDeletedStorageIndex = 0;\r
1000 Volatile = TRUE;\r
1001 for (Index = 0; Index < 2; Index++) {\r
1002 if (Index == 1) {\r
1003 Volatile = FALSE;\r
1004 }\r
1005 while (IsValidVariableHeader (Variable[Index], Volatile, Global, Instance, &VariableHeader)) {\r
1006 if (VariableHeader.State == VAR_ADDED || \r
1007 VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
1008 ) {\r
1009 if (!EfiAtRuntime () || ((VariableHeader.Attributes & EFI_VARIABLE_RUNTIME_ACCESS) != 0)) {\r
1010 if (VariableName[0] == 0) {\r
1011 //\r
1012 // If VariableName is an empty string, then we just find the first qualified variable\r
1013 // without comparing VariableName and VendorGuid\r
1014 //\r
1015 if (VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
1016 //\r
1017 // If variable is in delete transition, record it.\r
1018 //\r
1019 InDeletedVariable = Variable[Index];\r
1020 InDeletedStorageIndex = Index;\r
1021 } else {\r
1022 //\r
1023 // If variable is not in delete transition, return it.\r
1024 //\r
1025 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]);\r
1026 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index], Volatile, Global, Instance);\r
1027 PtrTrack->CurrPtr = Variable[Index];\r
1028 PtrTrack->Volatile = Volatile;\r
1029\r
1030 return EFI_SUCCESS;\r
1031 }\r
1032 } else {\r
1033 //\r
1034 // If VariableName is not an empty string, then VariableName and VendorGuid are compared.\r
1035 //\r
1036 if (CompareGuid (VendorGuid, &VariableHeader.VendorGuid)) {\r
1037 GetVariableNamePtr (\r
1038 Variable[Index],\r
1039 Volatile,\r
1040 Global,\r
1041 Instance,\r
1042 LocalVariableName\r
1043 );\r
1044\r
1045 ASSERT (NameSizeOfVariable (&VariableHeader) != 0);\r
1046 if (CompareMem (VariableName, LocalVariableName, NameSizeOfVariable (&VariableHeader)) == 0) {\r
1047 if (VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
1048 //\r
1049 // If variable is in delete transition, record it.\r
1050 // We will use if only no VAR_ADDED variable is found.\r
1051 //\r
1052 InDeletedVariable = Variable[Index];\r
1053 InDeletedStorageIndex = Index;\r
1054 } else {\r
1055 //\r
1056 // If variable is not in delete transition, return it.\r
1057 //\r
1058 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[Index]);\r
1059 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index], Volatile, Global, Instance);\r
1060 PtrTrack->CurrPtr = Variable[Index];\r
1061 PtrTrack->Volatile = Volatile;\r
1062\r
1063 return EFI_SUCCESS;\r
1064 }\r
1065 }\r
1066 }\r
1067 }\r
1068 }\r
1069 }\r
1070\r
1071 Variable[Index] = GetNextVariablePtr (\r
1072 Variable[Index],\r
1073 Volatile,\r
1074 Global,\r
1075 Instance\r
1076 );\r
1077 }\r
1078 if (InDeletedVariable != 0x0) {\r
1079 //\r
1080 // If no VAR_ADDED variable is found, and only variable in delete transition, then use this one.\r
1081 //\r
1082 PtrTrack->StartPtr = GetStartPointer (VariableStoreHeader[InDeletedStorageIndex]);\r
1083 PtrTrack->EndPtr = GetEndPointer (\r
1084 VariableStoreHeader[InDeletedStorageIndex],\r
1085 (BOOLEAN)(InDeletedStorageIndex == 0),\r
1086 Global,\r
1087 Instance\r
1088 );\r
1089 PtrTrack->CurrPtr = InDeletedVariable;\r
1090 PtrTrack->Volatile = (BOOLEAN)(InDeletedStorageIndex == 0);\r
1091 return EFI_SUCCESS;\r
1092 }\r
1093 }\r
1094 PtrTrack->CurrPtr = 0x0;\r
1095 return EFI_NOT_FOUND;\r
1096}\r
1097\r
1098/**\r
1099 Variable store garbage collection and reclaim operation.\r
1100\r
1101 @param[in] VariableBase Base address of variable store area.\r
1102 @param[out] LastVariableOffset Offset of last variable.\r
1103 @param[in] IsVolatile The variable store is volatile or not,\r
1104 if it is non-volatile, need FTW.\r
1105 @param[in] VirtualMode Current calling mode for this function.\r
1106 @param[in] Global Context of this Extended SAL Variable Services Class call.\r
1107 @param[in] UpdatingVariable Pointer to header of the variable that is being updated.\r
1108\r
1109 @retval EFI_SUCCESS Variable store successfully reclaimed.\r
1110 @retval EFI_OUT_OF_RESOURCES Fail to allocate memory buffer to hold all valid variables.\r
1111\r
1112**/\r
1113EFI_STATUS\r
1114Reclaim (\r
1115 IN EFI_PHYSICAL_ADDRESS VariableBase,\r
1116 OUT UINTN *LastVariableOffset,\r
1117 IN BOOLEAN IsVolatile,\r
1118 IN BOOLEAN VirtualMode,\r
1119 IN ESAL_VARIABLE_GLOBAL *Global,\r
1120 IN EFI_PHYSICAL_ADDRESS UpdatingVariable\r
1121 )\r
1122{\r
1123 EFI_PHYSICAL_ADDRESS Variable;\r
1124 EFI_PHYSICAL_ADDRESS AddedVariable;\r
1125 EFI_PHYSICAL_ADDRESS NextVariable;\r
1126 EFI_PHYSICAL_ADDRESS NextAddedVariable;\r
1127 VARIABLE_STORE_HEADER VariableStoreHeader;\r
1128 VARIABLE_HEADER VariableHeader;\r
1129 VARIABLE_HEADER AddedVariableHeader;\r
1130 CHAR16 VariableName[MAX_NAME_SIZE];\r
1131 CHAR16 AddedVariableName[MAX_NAME_SIZE];\r
1132 UINT8 *ValidBuffer;\r
1133 UINTN MaximumBufferSize;\r
1134 UINTN VariableSize;\r
1135 UINTN NameSize;\r
1136 UINT8 *CurrPtr;\r
1137 BOOLEAN FoundAdded;\r
1138 EFI_STATUS Status;\r
1139 VARIABLE_GLOBAL *VariableGlobal;\r
1140 UINT32 Instance;\r
1141\r
1142 VariableGlobal = &Global->VariableGlobal[VirtualMode];\r
1143 Instance = Global->FvbInstance;\r
1144\r
1145 GetVarStoreHeader (VariableBase, IsVolatile, VariableGlobal, Instance, &VariableStoreHeader);\r
1146 //\r
1147 // recaluate the total size of Common/HwErr type variables in non-volatile area.\r
1148 //\r
1149 if (!IsVolatile) {\r
1150 Global->CommonVariableTotalSize = 0;\r
1151 Global->HwErrVariableTotalSize = 0;\r
1152 }\r
1153\r
1154 //\r
1155 // Calculate the size of buffer needed to gather all valid variables\r
1156 //\r
1157 Variable = GetStartPointer (VariableBase);\r
1158 MaximumBufferSize = sizeof (VARIABLE_STORE_HEADER);\r
1159\r
1160 while (IsValidVariableHeader (Variable, IsVolatile, VariableGlobal, Instance, &VariableHeader)) {\r
1161 NextVariable = GetNextVariablePtr (Variable, IsVolatile, VariableGlobal, Instance);\r
1162 //\r
1163 // Collect VAR_ADDED variables, and variables in delete transition status.\r
1164 //\r
1165 if (VariableHeader.State == VAR_ADDED || \r
1166 VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)\r
1167 ) {\r
1168 VariableSize = NextVariable - Variable;\r
1169 MaximumBufferSize += VariableSize;\r
1170 }\r
1171\r
1172 Variable = NextVariable;\r
1173 }\r
1174\r
1175 //\r
1176 // Reserve the 1 Bytes with Oxff to identify the \r
1177 // end of the variable buffer. \r
1178 // \r
1179 MaximumBufferSize += 1;\r
1180 ValidBuffer = AllocatePool (MaximumBufferSize);\r
1181 if (ValidBuffer == NULL) {\r
1182 return EFI_OUT_OF_RESOURCES;\r
1183 }\r
1184\r
1185 SetMem (ValidBuffer, MaximumBufferSize, 0xff);\r
1186\r
1187 //\r
1188 // Copy variable store header\r
1189 //\r
1190 CopyMem (ValidBuffer, &VariableStoreHeader, sizeof (VARIABLE_STORE_HEADER));\r
1191 CurrPtr = (UINT8 *) GetStartPointer ((EFI_PHYSICAL_ADDRESS) ValidBuffer);\r
1192\r
1193 //\r
1194 // Reinstall all ADDED variables\r
1195 // \r
1196 Variable = GetStartPointer (VariableBase);\r
1197 while (IsValidVariableHeader (Variable, IsVolatile, VariableGlobal, Instance, &VariableHeader)) {\r
1198 NextVariable = GetNextVariablePtr (Variable, IsVolatile, VariableGlobal, Instance);\r
1199 if (VariableHeader.State == VAR_ADDED) {\r
1200 VariableSize = NextVariable - Variable;\r
1201 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
1202 CurrPtr += VariableSize;\r
1203 if ((!IsVolatile) && ((((VARIABLE_HEADER*)Variable)->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
1204 Global->HwErrVariableTotalSize += VariableSize;\r
1205 } else if ((!IsVolatile) && ((((VARIABLE_HEADER*)Variable)->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
1206 Global->CommonVariableTotalSize += VariableSize;\r
1207 }\r
1208 }\r
1209 Variable = NextVariable;\r
1210 }\r
1211 //\r
1212 // Reinstall in delete transition variables\r
1213 // \r
1214 Variable = GetStartPointer (VariableBase);\r
1215 while (IsValidVariableHeader (Variable, IsVolatile, VariableGlobal, Instance, &VariableHeader)) {\r
1216 NextVariable = GetNextVariablePtr (Variable, IsVolatile, VariableGlobal, Instance);\r
1217 if (VariableHeader.State == (VAR_IN_DELETED_TRANSITION & VAR_ADDED)) {\r
1218\r
1219 //\r
1220 // Buffer has cached all ADDED variable. \r
1221 // Per IN_DELETED variable, we have to guarantee that\r
1222 // no ADDED one in previous buffer. \r
1223 // \r
1224 FoundAdded = FALSE;\r
1225 AddedVariable = GetStartPointer ((EFI_PHYSICAL_ADDRESS) ValidBuffer);\r
1226 while (IsValidVariableHeader (AddedVariable, IsVolatile, VariableGlobal, Instance, &AddedVariableHeader)) {\r
1227 NextAddedVariable = GetNextVariablePtr (AddedVariable, IsVolatile, VariableGlobal, Instance);\r
1228 NameSize = NameSizeOfVariable (&AddedVariableHeader);\r
1229 if (CompareGuid (&AddedVariableHeader.VendorGuid, &VariableHeader.VendorGuid) &&\r
1230 NameSize == NameSizeOfVariable (&VariableHeader)\r
1231 ) {\r
1232 GetVariableNamePtr (Variable, IsVolatile, VariableGlobal, Instance, VariableName);\r
1233 GetVariableNamePtr (AddedVariable, IsVolatile, VariableGlobal, Instance, AddedVariableName);\r
1234 if (CompareMem (VariableName, AddedVariableName, NameSize) == 0) {\r
1235 //\r
1236 // If ADDED variable with the same name and vender GUID has been reinstalled,\r
1237 // then discard this IN_DELETED copy.\r
1238 //\r
1239 FoundAdded = TRUE;\r
1240 break;\r
1241 }\r
1242 }\r
1243 AddedVariable = NextAddedVariable;\r
1244 }\r
1245 //\r
1246 // Add IN_DELETE variables that have not been added to buffer\r
1247 //\r
1248 if (!FoundAdded) {\r
1249 VariableSize = NextVariable - Variable;\r
1250 CopyMem (CurrPtr, (UINT8 *) Variable, VariableSize);\r
1251 if (Variable != UpdatingVariable) {\r
1252 //\r
1253 // Make this IN_DELETE instance valid if:\r
1254 // 1. No valid instance of this variable exists.\r
1255 // 2. It is not the variable that is going to be updated.\r
1256 //\r
1257 ((VARIABLE_HEADER *) CurrPtr)->State = VAR_ADDED;\r
1258 }\r
1259 CurrPtr += VariableSize;\r
1260 if ((!IsVolatile) && ((((VARIABLE_HEADER*)Variable)->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
1261 Global->HwErrVariableTotalSize += VariableSize;\r
1262 } else if ((!IsVolatile) && ((((VARIABLE_HEADER*)Variable)->Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
1263 Global->CommonVariableTotalSize += VariableSize;\r
1264 }\r
1265 }\r
1266 }\r
1267 Variable = NextVariable;\r
1268 }\r
1269\r
1270 if (IsVolatile) {\r
1271 //\r
1272 // If volatile variable store, just copy valid buffer\r
1273 //\r
1274 SetMem ((UINT8 *) (UINTN) VariableBase, VariableStoreHeader.Size, 0xff);\r
1275 CopyMem ((UINT8 *) (UINTN) VariableBase, ValidBuffer, (UINTN) (CurrPtr - (UINT8 *) ValidBuffer));\r
1276 Status = EFI_SUCCESS;\r
1277 } else {\r
1278 //\r
1279 // If non-volatile variable store, perform FTW here.\r
1280 // Write ValidBuffer to destination specified by VariableBase.\r
1281 //\r
1282 Status = FtwVariableSpace (\r
1283 VariableBase,\r
1284 ValidBuffer,\r
1285 (UINTN) (CurrPtr - (UINT8 *) ValidBuffer)\r
1286 );\r
1287 }\r
1288 if (!EFI_ERROR (Status)) {\r
1289 *LastVariableOffset = (UINTN) (CurrPtr - (UINT8 *) ValidBuffer);\r
1290 } else {\r
1291 *LastVariableOffset = 0;\r
1292 }\r
1293\r
1294 FreePool (ValidBuffer);\r
1295\r
1296 return Status;\r
1297}\r
1298\r
1299/**\r
1300 Get index from supported language codes according to language string.\r
1301\r
1302 This code is used to get corresponding index in supported language codes. It can handle\r
1303 RFC4646 and ISO639 language tags.\r
1304 In ISO639 language tags, take 3-characters as a delimitation to find matched string and calculate the index.\r
1305 In RFC4646 language tags, take semicolon as a delimitation to find matched string and calculate the index.\r
1306\r
1307 For example:\r
1308 SupportedLang = "engfraengfra"\r
1309 Lang = "eng"\r
1310 Iso639Language = TRUE\r
1311 The return value is "0".\r
1312 Another example:\r
1313 SupportedLang = "en;fr;en-US;fr-FR"\r
1314 Lang = "fr-FR"\r
1315 Iso639Language = FALSE\r
1316 The return value is "3".\r
1317\r
1318 @param[in] SupportedLang Platform supported language codes.\r
1319 @param[in] Lang Configured language.\r
1320 @param[in] Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
1321\r
1322 @return The index of language in the language codes.\r
1323\r
1324**/\r
1325UINTN\r
1326GetIndexFromSupportedLangCodes(\r
1327 IN CHAR8 *SupportedLang,\r
1328 IN CHAR8 *Lang,\r
1329 IN BOOLEAN Iso639Language\r
1330 ) \r
1331{\r
1332 UINTN Index;\r
1333 UINTN CompareLength;\r
1334 UINTN LanguageLength;\r
1335\r
1336 if (Iso639Language) {\r
1337 CompareLength = ISO_639_2_ENTRY_SIZE;\r
1338 for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {\r
1339 if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {\r
1340 //\r
1341 // Successfully find the index of Lang string in SupportedLang string.\r
1342 //\r
1343 Index = Index / CompareLength;\r
1344 return Index;\r
1345 }\r
1346 }\r
1347 ASSERT (FALSE);\r
1348 return 0;\r
1349 } else {\r
1350 //\r
1351 // Compare RFC4646 language code\r
1352 //\r
1353 Index = 0;\r
1354 for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++);\r
1355\r
1356 for (Index = 0; *SupportedLang != '\0'; Index++, SupportedLang += CompareLength) {\r
1357 //\r
1358 // Skip ';' characters in SupportedLang\r
1359 //\r
1360 for (; *SupportedLang != '\0' && *SupportedLang == ';'; SupportedLang++);\r
1361 //\r
1362 // Determine the length of the next language code in SupportedLang\r
1363 //\r
1364 for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++);\r
1365 \r
1366 if ((CompareLength == LanguageLength) && \r
1367 (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0)) {\r
1368 //\r
1369 // Successfully find the index of Lang string in SupportedLang string.\r
1370 //\r
1371 return Index;\r
1372 }\r
1373 }\r
1374 ASSERT (FALSE);\r
1375 return 0;\r
1376 }\r
1377}\r
1378\r
1379/**\r
1380 Get language string from supported language codes according to index.\r
1381\r
1382 This code is used to get corresponding language string in supported language codes. It can handle\r
1383 RFC4646 and ISO639 language tags.\r
1384 In ISO639 language tags, take 3-characters as a delimitation. Find language string according to the index.\r
1385 In RFC4646 language tags, take semicolon as a delimitation. Find language string according to the index.\r
1386\r
1387 For example:\r
1388 SupportedLang = "engfraengfra"\r
1389 Index = "1"\r
1390 Iso639Language = TRUE\r
1391 The return value is "fra".\r
1392 Another example:\r
1393 SupportedLang = "en;fr;en-US;fr-FR"\r
1394 Index = "1"\r
1395 Iso639Language = FALSE\r
1396 The return value is "fr".\r
1397\r
1398 @param[in] SupportedLang Platform supported language codes.\r
1399 @param[in] Index the index in supported language codes.\r
1400 @param[in] Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.\r
1401 @param[in] VirtualMode Current calling mode for this function.\r
1402 @param[in] Global Context of this Extended SAL Variable Services Class call.\r
1403\r
1404 @return The language string in the language codes.\r
1405\r
1406**/\r
1407CHAR8 *\r
1408GetLangFromSupportedLangCodes (\r
1409 IN CHAR8 *SupportedLang,\r
1410 IN UINTN Index,\r
1411 IN BOOLEAN Iso639Language,\r
1412 IN BOOLEAN VirtualMode,\r
1413 IN ESAL_VARIABLE_GLOBAL *Global\r
1414 )\r
1415{\r
1416 UINTN SubIndex;\r
1417 UINTN CompareLength;\r
1418 CHAR8 *Supported;\r
1419\r
1420 SubIndex = 0;\r
1421 Supported = SupportedLang;\r
1422 if (Iso639Language) {\r
1423 //\r
1424 // according to the index of Lang string in SupportedLang string to get the language.\r
1425 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.\r
1426 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
1427 //\r
1428 CompareLength = ISO_639_2_ENTRY_SIZE;\r
1429 Global->Lang[CompareLength] = '\0';\r
1430 return CopyMem (Global->Lang, SupportedLang + Index * CompareLength, CompareLength);\r
1431\r
1432 } else {\r
1433 while (TRUE) {\r
1434 //\r
1435 // take semicolon as delimitation, sequentially traverse supported language codes.\r
1436 //\r
1437 for (CompareLength = 0; *Supported != ';' && *Supported != '\0'; CompareLength++) {\r
1438 Supported++;\r
1439 }\r
1440 if ((*Supported == '\0') && (SubIndex != Index)) {\r
1441 //\r
1442 // Have completed the traverse, but not find corrsponding string.\r
1443 // This case is not allowed to happen.\r
1444 //\r
1445 ASSERT(FALSE);\r
1446 return NULL;\r
1447 }\r
1448 if (SubIndex == Index) {\r
1449 //\r
1450 // according to the index of Lang string in SupportedLang string to get the language.\r
1451 // As this code will be invoked in RUNTIME, therefore there is not memory allocate/free operation.\r
1452 // In driver entry, it pre-allocates a runtime attribute memory to accommodate this string.\r
1453 //\r
1454 Global->PlatformLang[VirtualMode][CompareLength] = '\0';\r
1455 return CopyMem (Global->PlatformLang[VirtualMode], Supported - CompareLength, CompareLength);\r
1456 }\r
1457 SubIndex++;\r
1458\r
1459 //\r
1460 // Skip ';' characters in Supported\r
1461 //\r
1462 for (; *Supported != '\0' && *Supported == ';'; Supported++);\r
1463 }\r
1464 }\r
1465}\r
1466\r
1467/**\r
1468 Returns a pointer to an allocated buffer that contains the best matching language \r
1469 from a set of supported languages. \r
1470 \r
1471 This function supports both ISO 639-2 and RFC 4646 language codes, but language \r
1472 code types may not be mixed in a single call to this function. This function\r
1473 supports a variable argument list that allows the caller to pass in a prioritized\r
1474 list of language codes to test against all the language codes in SupportedLanguages.\r
1475\r
1476 If SupportedLanguages is NULL, then ASSERT().\r
1477\r
1478 @param[in] SupportedLanguages A pointer to a Null-terminated ASCII string that\r
1479 contains a set of language codes in the format \r
1480 specified by Iso639Language.\r
1481 @param[in] Iso639Language If TRUE, then all language codes are assumed to be\r
1482 in ISO 639-2 format. If FALSE, then all language\r
1483 codes are assumed to be in RFC 4646 language format.\r
1484 @param[in] VirtualMode Current calling mode for this function.\r
1485 @param[in] ... A variable argument list that contains pointers to \r
1486 Null-terminated ASCII strings that contain one or more\r
1487 language codes in the format specified by Iso639Language.\r
1488 The first language code from each of these language\r
1489 code lists is used to determine if it is an exact or\r
1490 close match to any of the language codes in \r
1491 SupportedLanguages. Close matches only apply to RFC 4646\r
1492 language codes, and the matching algorithm from RFC 4647\r
1493 is used to determine if a close match is present. If \r
1494 an exact or close match is found, then the matching\r
1495 language code from SupportedLanguages is returned. If\r
1496 no matches are found, then the next variable argument\r
1497 parameter is evaluated. The variable argument list \r
1498 is terminated by a NULL.\r
1499\r
1500 @retval NULL The best matching language could not be found in SupportedLanguages.\r
1501 @retval NULL There are not enough resources available to return the best matching \r
1502 language.\r
1503 @retval Other A pointer to a Null-terminated ASCII string that is the best matching \r
1504 language in SupportedLanguages.\r
1505\r
1506**/\r
1507CHAR8 *\r
1508VariableGetBestLanguage (\r
1509 IN CONST CHAR8 *SupportedLanguages, \r
1510 IN BOOLEAN Iso639Language,\r
1511 IN BOOLEAN VirtualMode,\r
1512 ...\r
1513 )\r
1514{\r
1515 VA_LIST Args;\r
1516 CHAR8 *Language;\r
1517 UINTN CompareLength;\r
1518 UINTN LanguageLength;\r
1519 CONST CHAR8 *Supported;\r
1520 CHAR8 *Buffer;\r
1521\r
1522 ASSERT (SupportedLanguages != NULL);\r
1523\r
1524 VA_START (Args, VirtualMode);\r
1525 while ((Language = VA_ARG (Args, CHAR8 *)) != NULL) {\r
1526 //\r
1527 // Default to ISO 639-2 mode\r
1528 //\r
1529 CompareLength = 3;\r
1530 LanguageLength = MIN (3, AsciiStrLen (Language));\r
1531\r
1532 //\r
1533 // If in RFC 4646 mode, then determine the length of the first RFC 4646 language code in Language\r
1534 //\r
1535 if (!Iso639Language) {\r
1536 for (LanguageLength = 0; Language[LanguageLength] != 0 && Language[LanguageLength] != ';'; LanguageLength++);\r
1537 }\r
1538\r
1539 //\r
1540 // Trim back the length of Language used until it is empty\r
1541 //\r
1542 while (LanguageLength > 0) {\r
1543 //\r
1544 // Loop through all language codes in SupportedLanguages\r
1545 //\r
1546 for (Supported = SupportedLanguages; *Supported != '\0'; Supported += CompareLength) {\r
1547 //\r
1548 // In RFC 4646 mode, then Loop through all language codes in SupportedLanguages\r
1549 //\r
1550 if (!Iso639Language) {\r
1551 //\r
1552 // Skip ';' characters in Supported\r
1553 //\r
1554 for (; *Supported != '\0' && *Supported == ';'; Supported++);\r
1555 //\r
1556 // Determine the length of the next language code in Supported\r
1557 //\r
1558 for (CompareLength = 0; Supported[CompareLength] != 0 && Supported[CompareLength] != ';'; CompareLength++);\r
1559 //\r
1560 // If Language is longer than the Supported, then skip to the next language\r
1561 //\r
1562 if (LanguageLength > CompareLength) {\r
1563 continue;\r
1564 }\r
1565 }\r
1566 //\r
1567 // See if the first LanguageLength characters in Supported match Language\r
1568 //\r
1569 if (AsciiStrnCmp (Supported, Language, LanguageLength) == 0) {\r
1570 VA_END (Args);\r
1571\r
1572 Buffer = Iso639Language ? mVariableModuleGlobal->Lang : mVariableModuleGlobal->PlatformLang[VirtualMode];\r
1573 Buffer[CompareLength] = '\0';\r
1574 return CopyMem (Buffer, Supported, CompareLength);\r
1575 }\r
1576 }\r
1577\r
1578 if (Iso639Language) {\r
1579 //\r
1580 // If ISO 639 mode, then each language can only be tested once\r
1581 //\r
1582 LanguageLength = 0;\r
1583 } else {\r
1584 //\r
1585 // If RFC 4646 mode, then trim Language from the right to the next '-' character \r
1586 //\r
1587 for (LanguageLength--; LanguageLength > 0 && Language[LanguageLength] != '-'; LanguageLength--);\r
1588 }\r
1589 }\r
1590 }\r
1591 VA_END (Args);\r
1592\r
1593 //\r
1594 // No matches were found \r
1595 //\r
1596 return NULL;\r
1597}\r
1598\r
1599/**\r
1600 Hook the operations in PlatformLangCodes, LangCodes, PlatformLang and Lang.\r
1601\r
1602 When setting Lang/LangCodes, simultaneously update PlatformLang/PlatformLangCodes.\r
1603 According to UEFI spec, PlatformLangCodes/LangCodes are only set once in firmware initialization,\r
1604 and are read-only. Therefore, in variable driver, only store the original value for other use.\r
1605\r
1606 @param[in] VariableName Name of variable.\r
1607 @param[in] Data Variable data.\r
1608 @param[in] DataSize Size of data. 0 means delete.\r
1609 @param[in] VirtualMode Current calling mode for this function.\r
1610 @param[in] Global Context of this Extended SAL Variable Services Class call.\r
1611\r
1612**/\r
1613VOID\r
1614AutoUpdateLangVariable(\r
1615 IN CHAR16 *VariableName,\r
1616 IN VOID *Data,\r
1617 IN UINTN DataSize,\r
1618 IN BOOLEAN VirtualMode,\r
1619 IN ESAL_VARIABLE_GLOBAL *Global\r
1620 )\r
1621{\r
1622 EFI_STATUS Status;\r
1623 CHAR8 *BestPlatformLang;\r
1624 CHAR8 *BestLang;\r
1625 UINTN Index;\r
1626 UINT32 Attributes;\r
1627 VARIABLE_POINTER_TRACK Variable;\r
1628 BOOLEAN SetLanguageCodes;\r
1629 CHAR16 **PredefinedVariableName;\r
1630 VARIABLE_GLOBAL *VariableGlobal;\r
1631 UINT32 Instance;\r
1632\r
1633 //\r
1634 // Don't do updates for delete operation\r
1635 //\r
1636 if (DataSize == 0) {\r
1637 return;\r
1638 }\r
1639\r
1640 SetLanguageCodes = FALSE;\r
1641 VariableGlobal = &Global->VariableGlobal[VirtualMode];\r
1642 Instance = Global->FvbInstance;\r
1643\r
1644\r
1645 PredefinedVariableName = &Global->VariableName[VirtualMode][0];\r
1646 if (StrCmp (VariableName, PredefinedVariableName[VAR_PLATFORM_LANG_CODES]) == 0) {\r
1647 //\r
1648 // PlatformLangCodes is a volatile variable, so it can not be updated at runtime.\r
1649 //\r
1650 if (EfiAtRuntime ()) {\r
1651 return;\r
1652 }\r
1653\r
1654 SetLanguageCodes = TRUE;\r
1655\r
1656 //\r
1657 // According to UEFI spec, PlatformLangCodes is only set once in firmware initialization, and is read-only\r
1658 // Therefore, in variable driver, only store the original value for other use.\r
1659 //\r
1660 if (Global->PlatformLangCodes[VirtualMode] != NULL) {\r
1661 FreePool (Global->PlatformLangCodes[VirtualMode]);\r
1662 }\r
1663 Global->PlatformLangCodes[VirtualMode] = AllocateRuntimeCopyPool (DataSize, Data);\r
1664 ASSERT (mVariableModuleGlobal->PlatformLangCodes[VirtualMode] != NULL);\r
1665\r
1666 //\r
1667 // PlatformLang holds a single language from PlatformLangCodes, \r
1668 // so the size of PlatformLangCodes is enough for the PlatformLang.\r
1669 //\r
1670 if (Global->PlatformLang[VirtualMode] != NULL) {\r
1671 FreePool (Global->PlatformLang[VirtualMode]);\r
1672 }\r
1673 Global->PlatformLang[VirtualMode] = AllocateRuntimePool (DataSize);\r
1674 ASSERT (Global->PlatformLang[VirtualMode] != NULL);\r
1675\r
1676 } else if (StrCmp (VariableName, PredefinedVariableName[VAR_LANG_CODES]) == 0) {\r
1677 //\r
1678 // LangCodes is a volatile variable, so it can not be updated at runtime.\r
1679 //\r
1680 if (EfiAtRuntime ()) {\r
1681 return;\r
1682 }\r
1683\r
1684 SetLanguageCodes = TRUE;\r
1685\r
1686 //\r
1687 // According to UEFI spec, LangCodes is only set once in firmware initialization, and is read-only\r
1688 // Therefore, in variable driver, only store the original value for other use.\r
1689 //\r
1690 if (Global->LangCodes[VirtualMode] != NULL) {\r
1691 FreePool (Global->LangCodes[VirtualMode]);\r
1692 }\r
1693 Global->LangCodes[VirtualMode] = AllocateRuntimeCopyPool (DataSize, Data);\r
1694 ASSERT (Global->LangCodes[VirtualMode] != NULL);\r
1695 }\r
1696\r
1697 if (SetLanguageCodes \r
1698 && (Global->PlatformLangCodes[VirtualMode] != NULL)\r
1699 && (Global->LangCodes[VirtualMode] != NULL)) {\r
1700 //\r
1701 // Update Lang if PlatformLang is already set\r
1702 // Update PlatformLang if Lang is already set\r
1703 //\r
1704 Status = FindVariable (PredefinedVariableName[VAR_PLATFORM_LANG], Global->GlobalVariableGuid[VirtualMode], &Variable, VariableGlobal, Instance);\r
1705 if (!EFI_ERROR (Status)) {\r
1706 //\r
1707 // Update Lang\r
1708 //\r
1709 VariableName = PredefinedVariableName[VAR_PLATFORM_LANG];\r
1710 } else {\r
1711 Status = FindVariable (PredefinedVariableName[VAR_LANG], Global->GlobalVariableGuid[VirtualMode], &Variable, VariableGlobal, Instance);\r
1712 if (!EFI_ERROR (Status)) {\r
1713 //\r
1714 // Update PlatformLang\r
1715 //\r
1716 VariableName = PredefinedVariableName[VAR_LANG];\r
1717 } else {\r
1718 //\r
1719 // Neither PlatformLang nor Lang is set, directly return\r
1720 //\r
1721 return;\r
1722 }\r
1723 }\r
1724 Data = (VOID *) GetEndPointer (VariableGlobal->VolatileVariableBase, TRUE, VariableGlobal, Instance);\r
1725 GetVariableDataPtr ((EFI_PHYSICAL_ADDRESS) Variable.CurrPtr, Variable.Volatile, VariableGlobal, Instance, (CHAR16 *) Data);\r
1726\r
1727 Status = AccessVariableStore (\r
1728 FALSE,\r
1729 VariableGlobal,\r
1730 Variable.Volatile,\r
1731 Instance,\r
1732 (UINTN) &(((VARIABLE_HEADER *)Variable.CurrPtr)->DataSize),\r
1733 sizeof (DataSize),\r
1734 &DataSize\r
1735 ); \r
1736 ASSERT_EFI_ERROR (Status);\r
1737 }\r
1738\r
1739 //\r
1740 // According to UEFI spec, "Lang" and "PlatformLang" is NV|BS|RT attributions.\r
1741 //\r
1742 Attributes = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;\r
1743\r
1744 if (StrCmp (VariableName, PredefinedVariableName[VAR_PLATFORM_LANG]) == 0) {\r
1745 //\r
1746 // Update Lang when PlatformLangCodes/LangCodes were set.\r
1747 //\r
1748 if ((Global->PlatformLangCodes[VirtualMode] != NULL) && (Global->LangCodes[VirtualMode] != NULL)) {\r
1749 //\r
1750 // When setting PlatformLang, firstly get most matched language string from supported language codes.\r
1751 //\r
1752 BestPlatformLang = VariableGetBestLanguage (Global->PlatformLangCodes[VirtualMode], FALSE, VirtualMode, Data, NULL);\r
1753 if (BestPlatformLang != NULL) {\r
1754 //\r
1755 // Get the corresponding index in language codes.\r
1756 //\r
1757 Index = GetIndexFromSupportedLangCodes (Global->PlatformLangCodes[VirtualMode], BestPlatformLang, FALSE);\r
1758\r
1759 //\r
1760 // Get the corresponding ISO639 language tag according to RFC4646 language tag.\r
1761 //\r
1762 BestLang = GetLangFromSupportedLangCodes (Global->LangCodes[VirtualMode], Index, TRUE, VirtualMode, Global);\r
1763\r
1764 //\r
1765 // Successfully convert PlatformLang to Lang, and set the BestLang value into Lang variable simultaneously.\r
1766 //\r
1767 FindVariable (PredefinedVariableName[VAR_LANG], Global->GlobalVariableGuid[VirtualMode], &Variable, VariableGlobal, Instance);\r
1768\r
1769 Status = UpdateVariable (\r
1770 PredefinedVariableName[VAR_LANG],\r
1771 Global->GlobalVariableGuid[VirtualMode],\r
1772 BestLang,\r
1773 ISO_639_2_ENTRY_SIZE + 1,\r
1774 Attributes,\r
1775 0,\r
1776 0,\r
1777 VirtualMode,\r
1778 Global,\r
1779 &Variable\r
1780 );\r
1781\r
1782 DEBUG ((EFI_D_INFO, "Variable Driver Auto Update PlatformLang, PlatformLang:%a, Lang:%a\n", BestPlatformLang, BestLang));\r
1783\r
1784 ASSERT_EFI_ERROR (Status);\r
1785 }\r
1786 }\r
1787\r
1788 } else if (StrCmp (VariableName, PredefinedVariableName[VAR_LANG]) == 0) {\r
1789 //\r
1790 // Update PlatformLang when PlatformLangCodes/LangCodes were set.\r
1791 //\r
1792 if ((Global->PlatformLangCodes[VirtualMode] != NULL) && (Global->LangCodes[VirtualMode] != NULL)) {\r
1793 //\r
1794 // When setting Lang, firstly get most matched language string from supported language codes.\r
1795 //\r
1796 BestLang = VariableGetBestLanguage (Global->LangCodes[VirtualMode], TRUE, VirtualMode, Data, NULL);\r
1797 if (BestLang != NULL) {\r
1798 //\r
1799 // Get the corresponding index in language codes.\r
1800 //\r
1801 Index = GetIndexFromSupportedLangCodes (Global->LangCodes[VirtualMode], BestLang, TRUE);\r
1802\r
1803 //\r
1804 // Get the corresponding RFC4646 language tag according to ISO639 language tag.\r
1805 //\r
1806 BestPlatformLang = GetLangFromSupportedLangCodes (Global->PlatformLangCodes[VirtualMode], Index, FALSE, VirtualMode, Global);\r
1807\r
1808 //\r
1809 // Successfully convert Lang to PlatformLang, and set the BestPlatformLang value into PlatformLang variable simultaneously.\r
1810 //\r
1811 FindVariable (PredefinedVariableName[VAR_PLATFORM_LANG], Global->GlobalVariableGuid[VirtualMode], &Variable, VariableGlobal, Instance);\r
1812\r
1813 Status = UpdateVariable (\r
1814 PredefinedVariableName[VAR_PLATFORM_LANG], \r
1815 Global->GlobalVariableGuid[VirtualMode], \r
1816 BestPlatformLang, \r
1817 AsciiStrSize (BestPlatformLang), \r
1818 Attributes, \r
1819 0,\r
1820 0,\r
1821 VirtualMode, \r
1822 Global, \r
1823 &Variable\r
1824 );\r
1825\r
1826 DEBUG ((EFI_D_INFO, "Variable Driver Auto Update Lang, Lang:%a, PlatformLang:%a\n", BestLang, BestPlatformLang));\r
1827 ASSERT_EFI_ERROR (Status);\r
1828 }\r
1829 }\r
1830 }\r
1831}\r
1832\r
1833/**\r
1834 Update the variable region with Variable information. These are the same \r
1835 arguments as the EFI Variable services.\r
1836\r
1837 @param[in] VariableName Name of variable.\r
1838 @param[in] VendorGuid Guid of variable.\r
1839 @param[in] Data Variable data.\r
1840 @param[in] DataSize Size of data. 0 means delete.\r
1841 @param[in] Attributes Attributes of the variable.\r
1842 @param[in] KeyIndex Index of associated public key.\r
1843 @param[in] MonotonicCount Value of associated monotonic count. \r
1844 @param[in] VirtualMode Current calling mode for this function.\r
1845 @param[in] Global Context of this Extended SAL Variable Services Class call.\r
1846 @param[in] Variable The variable information which is used to keep track of variable usage.\r
1847\r
1848 @retval EFI_SUCCESS The update operation is success.\r
1849 @retval EFI_OUT_OF_RESOURCES Variable region is full, can not write other data into this region.\r
1850\r
1851**/\r
1852EFI_STATUS\r
1853EFIAPI\r
1854UpdateVariable (\r
1855 IN CHAR16 *VariableName,\r
1856 IN EFI_GUID *VendorGuid,\r
1857 IN VOID *Data,\r
1858 IN UINTN DataSize,\r
1859 IN UINT32 Attributes OPTIONAL, \r
1860 IN UINT32 KeyIndex OPTIONAL,\r
1861 IN UINT64 MonotonicCount OPTIONAL,\r
1862 IN BOOLEAN VirtualMode,\r
1863 IN ESAL_VARIABLE_GLOBAL *Global,\r
1864 IN VARIABLE_POINTER_TRACK *Variable\r
1865 )\r
1866{\r
1867 EFI_STATUS Status;\r
1868 VARIABLE_HEADER *NextVariable;\r
1869 UINTN VarNameOffset;\r
1870 UINTN VarDataOffset;\r
1871 UINTN VarNameSize;\r
1872 UINTN VarSize;\r
1873 BOOLEAN Volatile;\r
1874 UINT8 State;\r
1875 VARIABLE_HEADER VariableHeader;\r
1876 VARIABLE_HEADER *NextVariableHeader;\r
1877 BOOLEAN Valid;\r
1878 BOOLEAN Reclaimed;\r
1879 VARIABLE_STORE_HEADER VariableStoreHeader;\r
1880 UINTN ScratchSize;\r
1881 VARIABLE_GLOBAL *VariableGlobal;\r
1882 UINT32 Instance;\r
1883\r
1884 VariableGlobal = &Global->VariableGlobal[VirtualMode];\r
1885 Instance = Global->FvbInstance;\r
1886\r
1887 Reclaimed = FALSE;\r
1888\r
1889 if (Variable->CurrPtr != 0) {\r
1890\r
1891 Valid = IsValidVariableHeader (Variable->CurrPtr, Variable->Volatile, VariableGlobal, Instance, &VariableHeader);\r
1892 if (!Valid) {\r
1893 Status = EFI_NOT_FOUND;\r
1894 goto Done;\r
1895 }\r
1896\r
1897 //\r
1898 // Update/Delete existing variable\r
1899 //\r
1900 Volatile = Variable->Volatile;\r
1901 \r
1902 if (EfiAtRuntime ()) { \r
1903 //\r
1904 // If EfiAtRuntime and the variable is Volatile and Runtime Access, \r
1905 // the volatile is ReadOnly, and SetVariable should be aborted and \r
1906 // return EFI_WRITE_PROTECTED.\r
1907 //\r
1908 if (Variable->Volatile) {\r
1909 Status = EFI_WRITE_PROTECTED;\r
1910 goto Done;\r
1911 }\r
1912 //\r
1913 // Only variable have NV attribute can be updated/deleted in Runtime\r
1914 //\r
1915 if ((VariableHeader.Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
1916 Status = EFI_INVALID_PARAMETER;\r
1917 goto Done; \r
1918 }\r
1919 }\r
1920 //\r
1921 // Setting a data variable with no access, or zero DataSize attributes\r
1922 // specified causes it to be deleted.\r
1923 //\r
1924 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) { \r
1925 State = VariableHeader.State;\r
1926 State &= VAR_DELETED;\r
1927\r
1928 Status = AccessVariableStore (\r
1929 TRUE,\r
1930 VariableGlobal,\r
1931 Variable->Volatile,\r
1932 Instance,\r
1933 (UINTN) &(((VARIABLE_HEADER *)Variable->CurrPtr)->State),\r
1934 sizeof (UINT8),\r
1935 &State\r
1936 ); \r
1937 if (!EFI_ERROR (Status)) {\r
1938 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, FALSE, TRUE, FALSE);\r
1939 UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
1940 }\r
1941 goto Done; \r
1942 }\r
1943 //\r
1944 // Logic comes here to update variable.\r
1945 // If the variable is marked valid and the same data has been passed in\r
1946 // then return to the caller immediately.\r
1947 //\r
1948 if (DataSizeOfVariable (&VariableHeader) == DataSize) {\r
1949 NextVariable = (VARIABLE_HEADER *)GetEndPointer (VariableGlobal->VolatileVariableBase, TRUE, VariableGlobal, Instance);\r
1950 GetVariableDataPtr (Variable->CurrPtr, Variable->Volatile, VariableGlobal, Instance, (CHAR16 *) NextVariable);\r
1951 if (CompareMem (Data, (VOID *) NextVariable, DataSize) == 0) {\r
1952 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
1953 Status = EFI_SUCCESS;\r
1954 goto Done;\r
1955 }\r
1956 }\r
1957 if ((VariableHeader.State == VAR_ADDED) ||\r
1958 (VariableHeader.State == (VAR_ADDED & VAR_IN_DELETED_TRANSITION))) {\r
1959 //\r
1960 // If new data is different from the old one, mark the old one as VAR_IN_DELETED_TRANSITION.\r
1961 // It will be deleted if new variable is successfully written.\r
1962 //\r
1963 State = VariableHeader.State;\r
1964 State &= VAR_IN_DELETED_TRANSITION;\r
1965\r
1966 Status = AccessVariableStore (\r
1967 TRUE,\r
1968 VariableGlobal,\r
1969 Variable->Volatile,\r
1970 Instance,\r
1971 (UINTN) &(((VARIABLE_HEADER *)Variable->CurrPtr)->State),\r
1972 sizeof (UINT8),\r
1973 &State\r
1974 ); \r
1975 if (EFI_ERROR (Status)) {\r
1976 goto Done; \r
1977 }\r
1978 } \r
1979 } else {\r
1980 //\r
1981 // Create a new variable\r
1982 // \r
1983 \r
1984 //\r
1985 // Make sure we are trying to create a new variable.\r
1986 // Setting a data variable with no access, or zero DataSize attributes means to delete it. \r
1987 //\r
1988 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {\r
1989 Status = EFI_NOT_FOUND;\r
1990 goto Done;\r
1991 }\r
1992 \r
1993 //\r
1994 // Only variable have NV|RT attribute can be created in Runtime\r
1995 //\r
1996 if (EfiAtRuntime () &&\r
1997 (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {\r
1998 Status = EFI_INVALID_PARAMETER;\r
1999 goto Done;\r
2000 } \r
2001 }\r
2002\r
2003 //\r
2004 // Function part - create a new variable and copy the data.\r
2005 // Both update a variable and create a variable will come here.\r
2006 //\r
2007 // Tricky part: Use scratch data area at the end of volatile variable store\r
2008 // as a temporary storage.\r
2009 //\r
2010 NextVariable = (VARIABLE_HEADER *)GetEndPointer (VariableGlobal->VolatileVariableBase, TRUE, VariableGlobal, Instance);\r
2011 ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
2012 NextVariableHeader = (VARIABLE_HEADER *) NextVariable;\r
2013\r
2014 SetMem (NextVariableHeader, ScratchSize, 0xff);\r
2015\r
2016 NextVariableHeader->StartId = VARIABLE_DATA;\r
2017 NextVariableHeader->Attributes = Attributes;\r
2018 NextVariableHeader->PubKeyIndex = KeyIndex;\r
2019 NextVariableHeader->MonotonicCount = MonotonicCount;\r
2020 NextVariableHeader->Reserved = 0;\r
2021 VarNameOffset = sizeof (VARIABLE_HEADER);\r
2022 VarNameSize = StrSize (VariableName);\r
2023 CopyMem (\r
2024 (UINT8 *) ((UINTN)NextVariable + VarNameOffset),\r
2025 VariableName,\r
2026 VarNameSize\r
2027 );\r
2028 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);\r
2029 CopyMem (\r
2030 (UINT8 *) ((UINTN)NextVariable + VarDataOffset),\r
2031 Data,\r
2032 DataSize\r
2033 );\r
2034 CopyMem (&NextVariableHeader->VendorGuid, VendorGuid, sizeof (EFI_GUID));\r
2035 //\r
2036 // There will be pad bytes after Data, the NextVariable->NameSize and\r
2037 // NextVariable->DataSize should not include pad size so that variable\r
2038 // service can get actual size in GetVariable.\r
2039 //\r
2040 NextVariableHeader->NameSize = (UINT32)VarNameSize;\r
2041 NextVariableHeader->DataSize = (UINT32)DataSize;\r
2042\r
2043 //\r
2044 // The actual size of the variable that stores in storage should\r
2045 // include pad size.\r
2046 //\r
2047 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);\r
2048 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
2049 //\r
2050 // Create a nonvolatile variable\r
2051 //\r
2052 Volatile = FALSE;\r
2053 \r
2054 GetVarStoreHeader (VariableGlobal->NonVolatileVariableBase, FALSE, VariableGlobal, Instance, &VariableStoreHeader);\r
2055 if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \r
2056 && ((HEADER_ALIGN (VarSize) + Global->HwErrVariableTotalSize) > PcdGet32(PcdHwErrStorageSize)))\r
2057 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
2058 && ((HEADER_ALIGN (VarSize) + Global->CommonVariableTotalSize) > VariableStoreHeader.Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize)))) {\r
2059 if (EfiAtRuntime ()) {\r
2060 Status = EFI_OUT_OF_RESOURCES;\r
2061 goto Done;\r
2062 }\r
2063 //\r
2064 // Perform garbage collection & reclaim operation\r
2065 //\r
2066 Status = Reclaim (VariableGlobal->NonVolatileVariableBase, &(Global->NonVolatileLastVariableOffset), FALSE, VirtualMode, Global, Variable->CurrPtr);\r
2067 if (EFI_ERROR (Status)) {\r
2068 goto Done;\r
2069 }\r
2070\r
2071 Reclaimed = TRUE;\r
2072 //\r
2073 // If still no enough space, return out of resources\r
2074 //\r
2075 if ((((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) \r
2076 && ((HEADER_ALIGN (VarSize) + Global->HwErrVariableTotalSize) > PcdGet32(PcdHwErrStorageSize)))\r
2077 || (((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == 0) \r
2078 && ((HEADER_ALIGN (VarSize) + Global->CommonVariableTotalSize) > VariableStoreHeader.Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize)))) {\r
2079 Status = EFI_OUT_OF_RESOURCES;\r
2080 goto Done;\r
2081 }\r
2082 }\r
2083 //\r
2084 // Four steps\r
2085 // 1. Write variable header\r
2086 // 2. Set variable state to header valid \r
2087 // 3. Write variable data\r
2088 // 4. Set variable state to valid\r
2089 //\r
2090 //\r
2091 // Step 1:\r
2092 //\r
2093 Status = AccessVariableStore (\r
2094 TRUE,\r
2095 VariableGlobal,\r
2096 FALSE,\r
2097 Instance,\r
2098 VariableGlobal->NonVolatileVariableBase + Global->NonVolatileLastVariableOffset,\r
2099 sizeof (VARIABLE_HEADER),\r
2100 (UINT8 *) NextVariable\r
2101 );\r
2102\r
2103 if (EFI_ERROR (Status)) {\r
2104 goto Done;\r
2105 }\r
2106\r
2107 //\r
2108 // Step 2:\r
2109 //\r
2110 NextVariableHeader->State = VAR_HEADER_VALID_ONLY;\r
2111 Status = AccessVariableStore (\r
2112 TRUE,\r
2113 VariableGlobal,\r
2114 FALSE,\r
2115 Instance,\r
2116 VariableGlobal->NonVolatileVariableBase + Global->NonVolatileLastVariableOffset,\r
2117 sizeof (VARIABLE_HEADER),\r
2118 (UINT8 *) NextVariable\r
2119 );\r
2120\r
2121 if (EFI_ERROR (Status)) {\r
2122 goto Done;\r
2123 }\r
2124 //\r
2125 // Step 3:\r
2126 //\r
2127 Status = AccessVariableStore (\r
2128 TRUE,\r
2129 VariableGlobal,\r
2130 FALSE,\r
2131 Instance,\r
2132 VariableGlobal->NonVolatileVariableBase + Global->NonVolatileLastVariableOffset + sizeof (VARIABLE_HEADER),\r
2133 (UINT32) VarSize - sizeof (VARIABLE_HEADER),\r
2134 (UINT8 *) NextVariable + sizeof (VARIABLE_HEADER)\r
2135 );\r
2136\r
2137 if (EFI_ERROR (Status)) {\r
2138 goto Done;\r
2139 }\r
2140 //\r
2141 // Step 4:\r
2142 //\r
2143 NextVariableHeader->State = VAR_ADDED;\r
2144 Status = AccessVariableStore (\r
2145 TRUE,\r
2146 VariableGlobal,\r
2147 FALSE,\r
2148 Instance,\r
2149 VariableGlobal->NonVolatileVariableBase + Global->NonVolatileLastVariableOffset,\r
2150 sizeof (VARIABLE_HEADER),\r
2151 (UINT8 *) NextVariable\r
2152 );\r
2153\r
2154 if (EFI_ERROR (Status)) {\r
2155 goto Done;\r
2156 }\r
2157\r
2158 Global->NonVolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
2159\r
2160 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) != 0) {\r
2161 Global->HwErrVariableTotalSize += HEADER_ALIGN (VarSize);\r
2162 } else {\r
2163 Global->CommonVariableTotalSize += HEADER_ALIGN (VarSize);\r
2164 }\r
2165 } else {\r
2166 //\r
2167 // Create a volatile variable\r
2168 // \r
2169 Volatile = TRUE;\r
2170\r
2171 if ((UINT32) (HEADER_ALIGN(VarSize) + Global->VolatileLastVariableOffset) >\r
2172 ((VARIABLE_STORE_HEADER *) ((UINTN) (VariableGlobal->VolatileVariableBase)))->Size) {\r
2173 //\r
2174 // Perform garbage collection & reclaim operation\r
2175 //\r
2176 Status = Reclaim (VariableGlobal->VolatileVariableBase, &Global->VolatileLastVariableOffset, TRUE, VirtualMode, Global, Variable->CurrPtr);\r
2177 if (EFI_ERROR (Status)) {\r
2178 goto Done;\r
2179 }\r
2180 //\r
2181 // If still no enough space, return out of resources\r
2182 //\r
2183 if ((UINT32) (HEADER_ALIGN (VarSize) + Global->VolatileLastVariableOffset) >\r
2184 ((VARIABLE_STORE_HEADER *) ((UINTN) (VariableGlobal->VolatileVariableBase)))->Size\r
2185 ) {\r
2186 Status = EFI_OUT_OF_RESOURCES;\r
2187 goto Done;\r
2188 }\r
2189 Reclaimed = TRUE;\r
2190 }\r
2191\r
2192 NextVariableHeader->State = VAR_ADDED;\r
2193 Status = AccessVariableStore (\r
2194 TRUE,\r
2195 VariableGlobal,\r
2196 TRUE,\r
2197 Instance,\r
2198 VariableGlobal->VolatileVariableBase + Global->VolatileLastVariableOffset,\r
2199 (UINT32) VarSize,\r
2200 (UINT8 *) NextVariable\r
2201 );\r
2202\r
2203 if (EFI_ERROR (Status)) {\r
2204 goto Done;\r
2205 }\r
2206\r
2207 Global->VolatileLastVariableOffset += HEADER_ALIGN (VarSize);\r
2208 }\r
2209 //\r
2210 // Mark the old variable as deleted\r
2211 // If storage has just been reclaimed, the old variable marked as VAR_IN_DELETED_TRANSITION\r
2212 // has already been eliminated, so no need to delete it.\r
2213 //\r
2214 if (!Reclaimed && !EFI_ERROR (Status) && Variable->CurrPtr != 0) {\r
2215 State = ((VARIABLE_HEADER *)Variable->CurrPtr)->State;\r
2216 State &= VAR_DELETED;\r
2217\r
2218 Status = AccessVariableStore (\r
2219 TRUE,\r
2220 VariableGlobal,\r
2221 Variable->Volatile,\r
2222 Instance,\r
2223 (UINTN) &(((VARIABLE_HEADER *)Variable->CurrPtr)->State),\r
2224 sizeof (UINT8),\r
2225 &State\r
2226 );\r
2227 }\r
2228\r
2229 if (!EFI_ERROR (Status)) {\r
2230 UpdateVariableInfo (VariableName, VendorGuid, Volatile, FALSE, TRUE, FALSE, FALSE);\r
2231 UpdateVariableCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
2232 }\r
2233\r
2234Done:\r
2235 return Status;\r
2236}\r
2237\r
2238/**\r
2239 Implements EsalGetVariable function of Extended SAL Variable Services Class.\r
2240\r
2241 This function implements EsalGetVariable function of Extended SAL Variable Services Class.\r
2242 It is equivalent in functionality to the EFI Runtime Service GetVariable().\r
2243 \r
2244 @param[in] VariableName A Null-terminated Unicode string that is the name of\r
2245 the vendor's variable.\r
2246 @param[in] VendorGuid A unique identifier for the vendor.\r
2247 @param[out] Attributes If not NULL, a pointer to the memory location to return the \r
2248 attributes bitmask for the variable.\r
2249 @param[in, out] DataSize Size of Data found. If size is less than the\r
2250 data, this value contains the required size.\r
2251 @param[out] Data On input, the size in bytes of the return Data buffer. \r
2252 On output, the size of data returned in Data.\r
2253 @param[in] VirtualMode Current calling mode for this function.\r
2254 @param[in] Global Context of this Extended SAL Variable Services Class call.\r
2255\r
2256 @retval EFI_SUCCESS The function completed successfully. \r
2257 @retval EFI_NOT_FOUND The variable was not found.\r
2258 @retval EFI_BUFFER_TOO_SMALL DataSize is too small for the result. DataSize has \r
2259 been updated with the size needed to complete the request.\r
2260 @retval EFI_INVALID_PARAMETER VariableName is NULL.\r
2261 @retval EFI_INVALID_PARAMETER VendorGuid is NULL.\r
2262 @retval EFI_INVALID_PARAMETER DataSize is NULL.\r
2263 @retval EFI_INVALID_PARAMETER DataSize is not too small and Data is NULL.\r
2264 @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.\r
2265 @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.\r
2266\r
2267**/\r
2268EFI_STATUS\r
2269EFIAPI\r
2270EsalGetVariable (\r
2271 IN CHAR16 *VariableName,\r
2272 IN EFI_GUID *VendorGuid,\r
2273 OUT UINT32 *Attributes OPTIONAL,\r
2274 IN OUT UINTN *DataSize,\r
2275 OUT VOID *Data,\r
2276 IN BOOLEAN VirtualMode,\r
2277 IN ESAL_VARIABLE_GLOBAL *Global\r
2278 )\r
2279{\r
2280 VARIABLE_POINTER_TRACK Variable;\r
2281 UINTN VarDataSize;\r
2282 EFI_STATUS Status;\r
2283 VARIABLE_HEADER VariableHeader;\r
2284 BOOLEAN Valid;\r
2285 VARIABLE_GLOBAL *VariableGlobal;\r
2286 UINT32 Instance;\r
2287\r
2288 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {\r
2289 return EFI_INVALID_PARAMETER;\r
2290 }\r
2291\r
2292 VariableGlobal = &Global->VariableGlobal[VirtualMode];\r
2293 Instance = Global->FvbInstance;\r
2294\r
2295 AcquireLockOnlyAtBootTime(&VariableGlobal->VariableServicesLock);\r
2296\r
2297 //\r
2298 // Check if this variable exists in cache.\r
2299 //\r
2300 Status = FindVariableInCache (VariableName, VendorGuid, Attributes, DataSize, Data);\r
2301 if ((Status == EFI_BUFFER_TOO_SMALL) || (Status == EFI_SUCCESS)){\r
2302 //\r
2303 // If variable exists in cache, just update statistical information for it and finish.\r
2304 // Here UpdateVariableInfo() has already retrieved data & attributes for output.\r
2305 //\r
2306 UpdateVariableInfo (VariableName, VendorGuid, FALSE, TRUE, FALSE, FALSE, TRUE);\r
2307 goto Done;\r
2308 }\r
2309 //\r
2310 // If variable does not exist in cache, search for it in variable storage area.\r
2311 //\r
2312 Status = FindVariable (VariableName, VendorGuid, &Variable, VariableGlobal, Instance);\r
2313 if (Variable.CurrPtr == 0x0 || EFI_ERROR (Status)) {\r
2314 //\r
2315 // If it cannot be found in variable storage area, goto Done.\r
2316 //\r
2317 goto Done;\r
2318 }\r
2319\r
2320 Valid = IsValidVariableHeader (Variable.CurrPtr, Variable.Volatile, VariableGlobal, Instance, &VariableHeader);\r
2321 if (!Valid) {\r
2322 Status = EFI_NOT_FOUND;\r
2323 goto Done;\r
2324 }\r
2325 //\r
2326 // If variable exists, but not in cache, get its data and attributes, update\r
2327 // statistical information, and update cache.\r
2328 //\r
2329 VarDataSize = DataSizeOfVariable (&VariableHeader);\r
2330 ASSERT (VarDataSize != 0);\r
2331\r
2332 if (*DataSize >= VarDataSize) {\r
2333 if (Data == NULL) {\r
2334 Status = EFI_INVALID_PARAMETER;\r
2335 goto Done;\r
2336 }\r
2337\r
2338 GetVariableDataPtr (\r
2339 Variable.CurrPtr,\r
2340 Variable.Volatile,\r
2341 VariableGlobal,\r
2342 Instance,\r
2343 Data\r
2344 );\r
2345 if (Attributes != NULL) {\r
2346 *Attributes = VariableHeader.Attributes;\r
2347 }\r
2348\r
2349 *DataSize = VarDataSize;\r
2350 UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);\r
2351 UpdateVariableCache (VariableName, VendorGuid, VariableHeader.Attributes, VarDataSize, Data);\r
2352 \r
2353 Status = EFI_SUCCESS;\r
2354 goto Done;\r
2355 } else {\r
2356 //\r
2357 // If DataSize is too small for the result, return EFI_BUFFER_TOO_SMALL.\r
2358 //\r
2359 *DataSize = VarDataSize;\r
2360 Status = EFI_BUFFER_TOO_SMALL;\r
2361 goto Done;\r
2362 }\r
2363\r
2364Done:\r
2365 ReleaseLockOnlyAtBootTime (&VariableGlobal->VariableServicesLock);\r
2366 return Status;\r
2367}\r
2368\r
2369/**\r
2370 Implements EsalGetNextVariableName function of Extended SAL Variable Services Class.\r
2371\r
2372 This function implements EsalGetNextVariableName function of Extended SAL Variable Services Class.\r
2373 It is equivalent in functionality to the EFI Runtime Service GetNextVariableName().\r
2374 \r
2375 @param[in, out] VariableNameSize Size of the variable\r
2376 @param[in, out] VariableName On input, supplies the last VariableName that was returned by GetNextVariableName().\r
2377 On output, returns the Null-terminated Unicode string of the current variable.\r
2378 @param[in, out] VendorGuid On input, supplies the last VendorGuid that was returned by GetNextVariableName().\r
2379 On output, returns the VendorGuid of the current variable. \r
2380 @param[in] VirtualMode Current calling mode for this function.\r
2381 @param[in] Global Context of this Extended SAL Variable Services Class call.\r
2382\r
2383 @retval EFI_SUCCESS The function completed successfully. \r
2384 @retval EFI_NOT_FOUND The next variable was not found.\r
2385 @retval EFI_BUFFER_TOO_SMALL VariableNameSize is too small for the result. \r
2386 VariableNameSize has been updated with the size needed to complete the request.\r
2387 @retval EFI_INVALID_PARAMETER VariableNameSize is NULL.\r
2388 @retval EFI_INVALID_PARAMETER VariableName is NULL.\r
2389 @retval EFI_INVALID_PARAMETER VendorGuid is NULL.\r
2390 @retval EFI_DEVICE_ERROR The variable name could not be retrieved due to a hardware error.\r
2391\r
2392**/\r
2393EFI_STATUS\r
2394EFIAPI\r
2395EsalGetNextVariableName (\r
2396 IN OUT UINTN *VariableNameSize,\r
2397 IN OUT CHAR16 *VariableName,\r
2398 IN OUT EFI_GUID *VendorGuid,\r
2399 IN BOOLEAN VirtualMode,\r
2400 IN ESAL_VARIABLE_GLOBAL *Global\r
2401 )\r
2402{\r
2403 VARIABLE_POINTER_TRACK Variable;\r
2404 UINTN VarNameSize;\r
2405 EFI_STATUS Status;\r
2406 VARIABLE_HEADER VariableHeader;\r
2407 VARIABLE_GLOBAL *VariableGlobal;\r
2408 UINT32 Instance;\r
2409\r
2410 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {\r
2411 return EFI_INVALID_PARAMETER;\r
2412 }\r
2413\r
2414 VariableGlobal = &Global->VariableGlobal[VirtualMode];\r
2415 Instance = Global->FvbInstance;\r
2416\r
2417 AcquireLockOnlyAtBootTime(&VariableGlobal->VariableServicesLock);\r
2418\r
2419 Status = FindVariable (VariableName, VendorGuid, &Variable, VariableGlobal, Instance);\r
2420 //\r
2421 // If the variable does not exist, goto Done and return.\r
2422 //\r
2423 if (Variable.CurrPtr == 0x0 || EFI_ERROR (Status)) {\r
2424 goto Done;\r
2425 }\r
2426\r
2427 if (VariableName[0] != 0) {\r
2428 //\r
2429 // If variable name is not NULL, get next variable\r
2430 //\r
2431 Variable.CurrPtr = GetNextVariablePtr (\r
2432 Variable.CurrPtr,\r
2433 Variable.Volatile,\r
2434 VariableGlobal,\r
2435 Instance\r
2436 );\r
2437 }\r
2438\r
2439 while (TRUE) {\r
2440 if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == 0x0) {\r
2441 //\r
2442 // If fail to find a variable in current area, reverse the volatile attribute of area to search.\r
2443 //\r
2444 Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));\r
2445 //\r
2446 // Here we depend on the searching sequence of FindVariable().\r
2447 // It first searches volatile area, then NV area.\r
2448 // So if the volatile attribute after switching is non-volatile, it means that we have finished searching volatile area,\r
2449 // and EFI_NOT_FOUND is returnd.\r
2450 // Otherwise, it means that we have finished searchig non-volatile area, and we will continue to search volatile area.\r
2451 //\r
2452 if (!Variable.Volatile) {\r
2453 Variable.StartPtr = GetStartPointer (VariableGlobal->NonVolatileVariableBase);\r
2454 Variable.EndPtr = GetEndPointer (VariableGlobal->NonVolatileVariableBase, FALSE, VariableGlobal, Instance);\r
2455 } else {\r
2456 Status = EFI_NOT_FOUND;\r
2457 goto Done;\r
2458 }\r
2459\r
2460 Variable.CurrPtr = Variable.StartPtr;\r
2461 if (!IsValidVariableHeader (Variable.CurrPtr, Variable.Volatile, VariableGlobal, Instance, NULL)) {\r
2462 continue;\r
2463 }\r
2464 }\r
2465 //\r
2466 // Variable is found\r
2467 //\r
2468 if (IsValidVariableHeader (Variable.CurrPtr, Variable.Volatile, VariableGlobal, Instance, &VariableHeader)) {\r
2469 if ((VariableHeader.State == VAR_ADDED) &&\r
2470 (!(EfiAtRuntime () && ((VariableHeader.Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)))) {\r
2471 VarNameSize = NameSizeOfVariable (&VariableHeader);\r
2472 ASSERT (VarNameSize != 0);\r
2473\r
2474 if (VarNameSize <= *VariableNameSize) {\r
2475 GetVariableNamePtr (\r
2476 Variable.CurrPtr,\r
2477 Variable.Volatile,\r
2478 VariableGlobal,\r
2479 Instance,\r
2480 VariableName\r
2481 );\r
2482 CopyMem (\r
2483 VendorGuid,\r
2484 &VariableHeader.VendorGuid,\r
2485 sizeof (EFI_GUID)\r
2486 );\r
2487 Status = EFI_SUCCESS;\r
2488 } else {\r
2489 Status = EFI_BUFFER_TOO_SMALL;\r
2490 }\r
2491\r
2492 *VariableNameSize = VarNameSize;\r
2493 goto Done;\r
2494 }\r
2495 }\r
2496\r
2497 Variable.CurrPtr = GetNextVariablePtr (\r
2498 Variable.CurrPtr,\r
2499 Variable.Volatile,\r
2500 VariableGlobal,\r
2501 Instance\r
2502 );\r
2503 }\r
2504\r
2505Done:\r
2506 ReleaseLockOnlyAtBootTime (&VariableGlobal->VariableServicesLock);\r
2507 return Status;\r
2508}\r
2509\r
2510/**\r
2511 Implements EsalSetVariable function of Extended SAL Variable Services Class.\r
2512\r
2513 This function implements EsalSetVariable function of Extended SAL Variable Services Class.\r
2514 It is equivalent in functionality to the EFI Runtime Service SetVariable().\r
2515 \r
2516 @param[in] VariableName A Null-terminated Unicode string that is the name of the vendor's\r
2517 variable. Each VariableName is unique for each \r
2518 VendorGuid. VariableName must contain 1 or more \r
2519 Unicode characters. If VariableName is an empty Unicode \r
2520 string, then EFI_INVALID_PARAMETER is returned.\r
2521 @param[in] VendorGuid A unique identifier for the vendor.\r
2522 @param[in] Attributes Attributes bitmask to set for the variable.\r
2523 @param[in] DataSize The size in bytes of the Data buffer. A size of zero causes the\r
2524 variable to be deleted.\r
2525 @param[in] Data The contents for the variable.\r
2526 @param[in] VirtualMode Current calling mode for this function.\r
2527 @param[in] Global Context of this Extended SAL Variable Services Class call.\r
2528\r
2529 @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as \r
2530 defined by the Attributes.\r
2531 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied, or the \r
2532 DataSize exceeds the maximum allowed.\r
2533 @retval EFI_INVALID_PARAMETER VariableName is an empty Unicode string.\r
2534 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.\r
2535 @retval EFI_DEVICE_ERROR The variable could not be saved due to a hardware failure.\r
2536 @retval EFI_WRITE_PROTECTED The variable in question is read-only.\r
2537 @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.\r
2538 @retval EFI_SECURITY_VIOLATION The variable could not be retrieved due to an authentication failure.\r
2539 @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.\r
2540\r
2541**/\r
2542EFI_STATUS\r
2543EFIAPI\r
2544EsalSetVariable (\r
2545 IN CHAR16 *VariableName,\r
2546 IN EFI_GUID *VendorGuid,\r
2547 IN UINT32 Attributes,\r
2548 IN UINTN DataSize,\r
2549 IN VOID *Data,\r
2550 IN BOOLEAN VirtualMode,\r
2551 IN ESAL_VARIABLE_GLOBAL *Global\r
2552 )\r
2553{\r
2554 VARIABLE_POINTER_TRACK Variable;\r
2555 EFI_STATUS Status;\r
2556 EFI_PHYSICAL_ADDRESS NextVariable;\r
2557 EFI_PHYSICAL_ADDRESS Point;\r
2558 VARIABLE_GLOBAL *VariableGlobal;\r
2559 UINT32 Instance;\r
2560 UINT32 KeyIndex;\r
2561 UINT64 MonotonicCount;\r
2562 UINTN PayloadSize;\r
2563\r
2564 //\r
2565 // Check input parameters\r
2566 //\r
2567 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {\r
2568 return EFI_INVALID_PARAMETER;\r
2569 } \r
2570\r
2571 if (DataSize != 0 && Data == NULL) {\r
2572 return EFI_INVALID_PARAMETER;\r
2573 }\r
2574\r
2575 //\r
2576 // EFI_VARIABLE_RUNTIME_ACCESS bit cannot be set without EFI_VARIABLE_BOOTSERVICE_ACCESS bit.\r
2577 //\r
2578 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
2579 return EFI_INVALID_PARAMETER;\r
2580 }\r
2581\r
2582 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) == EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) {\r
2583 if (DataSize < AUTHINFO_SIZE) {\r
2584 //\r
2585 // Try to write Authencated Variable without AuthInfo\r
2586 //\r
2587 return EFI_SECURITY_VIOLATION;\r
2588 } \r
2589 PayloadSize = DataSize - AUTHINFO_SIZE; \r
2590 } else {\r
2591 PayloadSize = DataSize; \r
2592 }\r
2593\r
2594 VariableGlobal = &Global->VariableGlobal[VirtualMode];\r
2595 Instance = Global->FvbInstance;\r
2596\r
2597 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2598 //\r
2599 // For variable for hardware error record, the size of the VariableName, including the Unicode Null\r
2600 // in bytes plus the DataSize is limited to maximum size of PcdGet32(PcdMaxHardwareErrorVariableSize) bytes.\r
2601 //\r
2602 if ((PayloadSize > PcdGet32(PcdMaxHardwareErrorVariableSize)) || \r
2603 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + PayloadSize > PcdGet32(PcdMaxHardwareErrorVariableSize))) {\r
2604 return EFI_INVALID_PARAMETER;\r
2605 }\r
2606 //\r
2607 // According to UEFI spec, HARDWARE_ERROR_RECORD variable name convention should be L"HwErrRecXXXX"\r
2608 //\r
2609 if (StrnCmp (VariableName, \\r
2610 Global->VariableName[VirtualMode][VAR_HW_ERR_REC], \\r
2611 StrLen(Global->VariableName[VirtualMode][VAR_HW_ERR_REC])) != 0) {\r
2612 return EFI_INVALID_PARAMETER;\r
2613 }\r
2614 } else {\r
2615 //\r
2616 // For variable not for hardware error record, the size of the VariableName, including the\r
2617 // Unicode Null in bytes plus the DataSize is limited to maximum size of PcdGet32(PcdMaxVariableSize) bytes.\r
2618 //\r
2619 if ((PayloadSize > PcdGet32(PcdMaxVariableSize)) ||\r
2620 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + PayloadSize > PcdGet32(PcdMaxVariableSize))) {\r
2621 return EFI_INVALID_PARAMETER;\r
2622 } \r
2623 } \r
2624\r
2625 AcquireLockOnlyAtBootTime(&VariableGlobal->VariableServicesLock);\r
2626\r
2627 //\r
2628 // Consider reentrant in MCA/INIT/NMI. It needs be reupdated;\r
2629 //\r
2630 if (InterlockedIncrement (&Global->ReentrantState) > 1) {\r
2631 Point = VariableGlobal->NonVolatileVariableBase;;\r
2632 //\r
2633 // Parse non-volatile variable data and get last variable offset\r
2634 //\r
2635 NextVariable = GetStartPointer (Point);\r
2636 while (IsValidVariableHeader (NextVariable, FALSE, VariableGlobal, Instance, NULL)) {\r
2637 NextVariable = GetNextVariablePtr (NextVariable, FALSE, VariableGlobal, Instance);\r
2638 }\r
2639 Global->NonVolatileLastVariableOffset = NextVariable - Point;\r
2640 }\r
2641\r
2642 //\r
2643 // Check whether the input variable exists\r
2644 //\r
2645\r
2646 Status = FindVariable (VariableName, VendorGuid, &Variable, VariableGlobal, Instance);\r
2647\r
2648 //\r
2649 // Hook the operation of setting PlatformLangCodes/PlatformLang and LangCodes/Lang\r
2650 //\r
2651 AutoUpdateLangVariable (VariableName, Data, PayloadSize, VirtualMode, Global);\r
2652\r
2653 //\r
2654 // Process PK, KEK, Sigdb seperately\r
2655 //\r
2656 if (CompareGuid (VendorGuid, Global->GlobalVariableGuid[VirtualMode]) && (StrCmp (VariableName, Global->VariableName[VirtualMode][VAR_PLATFORM_KEY]) == 0)) {\r
2657 Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, VirtualMode, Global, &Variable, Attributes, TRUE);\r
2658 } else if (CompareGuid (VendorGuid, Global->GlobalVariableGuid[VirtualMode]) && (StrCmp (VariableName, Global->VariableName[VirtualMode][VAR_KEY_EXCHANGE_KEY]) == 0)) {\r
2659 Status = ProcessVarWithPk (VariableName, VendorGuid, Data, DataSize, VirtualMode, Global, &Variable, Attributes, FALSE);\r
2660 } else if (CompareGuid (VendorGuid, Global->ImageSecurityDatabaseGuid[VirtualMode])) {\r
2661 Status = ProcessVarWithKek (VariableName, VendorGuid, Data, DataSize, VirtualMode, Global, &Variable, Attributes);\r
2662 } else {\r
2663 Status = VerifyVariable (Data, DataSize, VirtualMode, Global, &Variable, Attributes, &KeyIndex, &MonotonicCount);\r
2664 if (!EFI_ERROR(Status)) {\r
2665 //\r
2666 // Verification pass\r
2667 //\r
2668 if ((Attributes & EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
2669 //\r
2670 // Cut the certificate size before set\r
2671 //\r
2672 Status = UpdateVariable (\r
2673 VariableName, \r
2674 VendorGuid, \r
2675 (UINT8*)Data + AUTHINFO_SIZE, \r
2676 DataSize - AUTHINFO_SIZE, \r
2677 Attributes, \r
2678 KeyIndex, \r
2679 MonotonicCount, \r
2680 VirtualMode, \r
2681 Global, \r
2682 &Variable\r
2683 );\r
2684 } else {\r
2685 //\r
2686 // Update variable as usual \r
2687 //\r
2688 Status = UpdateVariable (\r
2689 VariableName, \r
2690 VendorGuid, \r
2691 Data, \r
2692 DataSize, \r
2693 Attributes, \r
2694 0, \r
2695 0, \r
2696 VirtualMode, \r
2697 Global, \r
2698 &Variable\r
2699 );\r
2700 }\r
2701 }\r
2702 }\r
2703\r
2704 InterlockedDecrement (&Global->ReentrantState);\r
2705 ReleaseLockOnlyAtBootTime (&VariableGlobal->VariableServicesLock);\r
2706 return Status;\r
2707}\r
2708\r
2709/**\r
2710 Implements EsalQueryVariableInfo function of Extended SAL Variable Services Class.\r
2711\r
2712 This function implements EsalQueryVariableInfo function of Extended SAL Variable Services Class.\r
2713 It is equivalent in functionality to the EFI Runtime Service QueryVariableInfo().\r
2714\r
2715 @param[in] Attributes Attributes bitmask to specify the type of variables\r
2716 on which to return information.\r
2717 @param[out] MaximumVariableStorageSize On output the maximum size of the storage space available for \r
2718 the EFI variables associated with the attributes specified. \r
2719 @param[out] RemainingVariableStorageSize Returns the remaining size of the storage space available for EFI \r
2720 variables associated with the attributes specified.\r
2721 @param[out] MaximumVariableSize Returns the maximum size of an individual EFI variable \r
2722 associated with the attributes specified.\r
2723 @param[in] VirtualMode Current calling mode for this function\r
2724 @param[in] Global Context of this Extended SAL Variable Services Class call\r
2725\r
2726 @retval EFI_SUCCESS Valid answer returned.\r
2727 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied.\r
2728 @retval EFI_UNSUPPORTED The attribute is not supported on this platform, and the \r
2729 MaximumVariableStorageSize, RemainingVariableStorageSize, \r
2730 MaximumVariableSize are undefined.\r
2731**/\r
2732EFI_STATUS\r
2733EFIAPI\r
2734EsalQueryVariableInfo (\r
2735 IN UINT32 Attributes,\r
2736 OUT UINT64 *MaximumVariableStorageSize,\r
2737 OUT UINT64 *RemainingVariableStorageSize,\r
2738 OUT UINT64 *MaximumVariableSize,\r
2739 IN BOOLEAN VirtualMode,\r
2740 IN ESAL_VARIABLE_GLOBAL *Global\r
2741 )\r
2742{\r
2743 EFI_PHYSICAL_ADDRESS Variable;\r
2744 EFI_PHYSICAL_ADDRESS NextVariable;\r
2745 UINT64 VariableSize;\r
2746 EFI_PHYSICAL_ADDRESS VariableStoreHeaderAddress;\r
2747 BOOLEAN Volatile;\r
2748 VARIABLE_STORE_HEADER VarStoreHeader;\r
2749 VARIABLE_HEADER VariableHeader;\r
2750 UINT64 CommonVariableTotalSize;\r
2751 UINT64 HwErrVariableTotalSize;\r
2752 VARIABLE_GLOBAL *VariableGlobal;\r
2753 UINT32 Instance;\r
2754\r
2755 CommonVariableTotalSize = 0;\r
2756 HwErrVariableTotalSize = 0;\r
2757\r
2758 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {\r
2759 return EFI_INVALID_PARAMETER;\r
2760 }\r
2761 \r
2762 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {\r
2763 //\r
2764 // Make sure the Attributes combination is supported by the platform.\r
2765 //\r
2766 return EFI_UNSUPPORTED; \r
2767 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {\r
2768 //\r
2769 // Make sure if runtime bit is set, boot service bit is set also.\r
2770 //\r
2771 return EFI_INVALID_PARAMETER;\r
2772 } else if (EfiAtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {\r
2773 //\r
2774 // Make sure RT Attribute is set if we are in Runtime phase.\r
2775 //\r
2776 return EFI_INVALID_PARAMETER;\r
2777 } else if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2778 //\r
2779 // Make sure Hw Attribute is set with NV.\r
2780 //\r
2781 return EFI_INVALID_PARAMETER;\r
2782 }\r
2783\r
2784 VariableGlobal = &Global->VariableGlobal[VirtualMode];\r
2785 Instance = Global->FvbInstance;\r
2786\r
2787 AcquireLockOnlyAtBootTime(&VariableGlobal->VariableServicesLock);\r
2788\r
2789 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {\r
2790 //\r
2791 // Query is Volatile related.\r
2792 //\r
2793 Volatile = TRUE;\r
2794 VariableStoreHeaderAddress = VariableGlobal->VolatileVariableBase;\r
2795 } else {\r
2796 //\r
2797 // Query is Non-Volatile related.\r
2798 //\r
2799 Volatile = FALSE;\r
2800 VariableStoreHeaderAddress = VariableGlobal->NonVolatileVariableBase;\r
2801 }\r
2802\r
2803 //\r
2804 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize\r
2805 // with the storage size (excluding the storage header size).\r
2806 //\r
2807 GetVarStoreHeader (VariableStoreHeaderAddress, Volatile, VariableGlobal, Instance, &VarStoreHeader);\r
2808\r
2809 *MaximumVariableStorageSize = VarStoreHeader.Size - sizeof (VARIABLE_STORE_HEADER);\r
2810\r
2811 // Harware error record variable needs larger size.\r
2812 //\r
2813 if ((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
2814 *MaximumVariableStorageSize = PcdGet32(PcdHwErrStorageSize);\r
2815 *MaximumVariableSize = PcdGet32(PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);\r
2816 } else {\r
2817 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {\r
2818 ASSERT (PcdGet32(PcdHwErrStorageSize) < VarStoreHeader.Size);\r
2819 *MaximumVariableStorageSize = VarStoreHeader.Size - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize);\r
2820 }\r
2821\r
2822 //\r
2823 // Let *MaximumVariableSize be PcdGet32(PcdMaxVariableSize) with the exception of the variable header size.\r
2824 //\r
2825 *MaximumVariableSize = PcdGet32(PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);\r
2826 }\r
2827\r
2828 //\r
2829 // Point to the starting address of the variables.\r
2830 //\r
2831 Variable = GetStartPointer (VariableStoreHeaderAddress);\r
2832\r
2833 //\r
2834 // Now walk through the related variable store.\r
2835 //\r
2836 while (IsValidVariableHeader (Variable, Volatile, VariableGlobal, Instance, &VariableHeader) &&\r
2837 (Variable < GetEndPointer (VariableStoreHeaderAddress, Volatile, VariableGlobal, Instance))) {\r
2838 NextVariable = GetNextVariablePtr (Variable, Volatile, VariableGlobal, Instance);\r
2839 VariableSize = NextVariable - Variable;\r
2840\r
2841 if (EfiAtRuntime ()) {\r
2842 //\r
2843 // we don't take the state of the variables in mind\r
2844 // when calculating RemainingVariableStorageSize,\r
2845 // since the space occupied by variables not marked with\r
2846 // VAR_ADDED is not allowed to be reclaimed in Runtime.\r
2847 //\r
2848 if ((VariableHeader.Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2849 HwErrVariableTotalSize += VariableSize;\r
2850 } else {\r
2851 CommonVariableTotalSize += VariableSize;\r
2852 }\r
2853 } else {\r
2854 //\r
2855 // Only care about Variables with State VAR_ADDED,because\r
2856 // the space not marked as VAR_ADDED is reclaimable now.\r
2857 //\r
2858 if (VariableHeader.State == VAR_ADDED) {\r
2859 if ((VariableHeader.Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {\r
2860 HwErrVariableTotalSize += VariableSize;\r
2861 } else {\r
2862 CommonVariableTotalSize += VariableSize;\r
2863 }\r
2864 }\r
2865 }\r
2866\r
2867 //\r
2868 // Go to the next one\r
2869 //\r
2870 Variable = NextVariable;\r
2871 }\r
2872\r
2873 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD){\r
2874 *RemainingVariableStorageSize = *MaximumVariableStorageSize - HwErrVariableTotalSize;\r
2875 }else {\r
2876 *RemainingVariableStorageSize = *MaximumVariableStorageSize - CommonVariableTotalSize;\r
2877 }\r
2878\r
2879 if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {\r
2880 *MaximumVariableSize = 0;\r
2881 } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {\r
2882 *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);\r
2883 }\r
2884\r
2885 ReleaseLockOnlyAtBootTime (&VariableGlobal->VariableServicesLock);\r
2886 return EFI_SUCCESS;\r
2887}\r
2888\r
2889/**\r
2890 Notification function of EVT_GROUP_READY_TO_BOOT event group.\r
2891\r
2892 This is a notification function registered on EVT_GROUP_READY_TO_BOOT event group.\r
2893 When the Boot Manager is about to load and execute a boot option, it reclaims variable\r
2894 storage if free size is below the threshold.\r
2895\r
2896 @param[in] Event Event whose notification function is being invoked.\r
2897 @param[in] Context Pointer to the notification function's context.\r
2898\r
2899**/\r
2900VOID\r
2901EFIAPI\r
2902ReclaimForOS(\r
2903 IN EFI_EVENT Event,\r
2904 IN VOID *Context\r
2905 )\r
2906{\r
2907 UINT32 VarSize;\r
2908 EFI_STATUS Status;\r
2909 UINTN CommonVariableSpace;\r
2910 UINTN RemainingCommonVariableSpace;\r
2911 UINTN RemainingHwErrVariableSpace;\r
2912\r
2913 VarSize = ((VARIABLE_STORE_HEADER *) ((UINTN) mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase))->Size;\r
2914 Status = EFI_SUCCESS; \r
2915 //\r
2916 //Allowable max size of common variable storage space\r
2917 //\r
2918 CommonVariableSpace = VarSize - sizeof (VARIABLE_STORE_HEADER) - PcdGet32(PcdHwErrStorageSize);\r
2919\r
2920 RemainingCommonVariableSpace = CommonVariableSpace - mVariableModuleGlobal->CommonVariableTotalSize;\r
2921 \r
2922 RemainingHwErrVariableSpace = PcdGet32 (PcdHwErrStorageSize) - mVariableModuleGlobal->HwErrVariableTotalSize;\r
2923 //\r
2924 // If the free area is below a threshold, then performs reclaim operation.\r
2925 //\r
2926 if ((RemainingCommonVariableSpace < PcdGet32 (PcdMaxVariableSize))\r
2927 || ((PcdGet32 (PcdHwErrStorageSize) != 0) && \r
2928 (RemainingHwErrVariableSpace < PcdGet32 (PcdMaxHardwareErrorVariableSize)))){\r
2929 Status = Reclaim (\r
2930 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,\r
2931 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
2932 FALSE,\r
2933 Physical,\r
2934 mVariableModuleGlobal,\r
2935 0x0\r
2936 );\r
2937 ASSERT_EFI_ERROR (Status);\r
2938 }\r
2939}\r
2940\r
2941/**\r
2942 Initializes variable store area for non-volatile and volatile variable.\r
2943\r
2944 This function allocates and initializes memory space for global context of ESAL\r
2945 variable service and variable store area for non-volatile and volatile variable.\r
2946\r
2947 @param[in] ImageHandle The Image handle of this driver.\r
2948 @param[in] SystemTable The pointer of EFI_SYSTEM_TABLE.\r
2949\r
2950 @retval EFI_SUCCESS Function successfully executed.\r
2951 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.\r
2952\r
2953**/\r
2954EFI_STATUS\r
2955VariableCommonInitialize (\r
2956 IN EFI_HANDLE ImageHandle,\r
2957 IN EFI_SYSTEM_TABLE *SystemTable\r
2958 )\r
2959{\r
2960 EFI_STATUS Status;\r
2961 EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;\r
2962 EFI_PHYSICAL_ADDRESS CurrPtr;\r
2963 VARIABLE_STORE_HEADER *VolatileVariableStore;\r
2964 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
2965 EFI_PHYSICAL_ADDRESS Variable;\r
2966 EFI_PHYSICAL_ADDRESS NextVariable;\r
2967 UINTN VariableSize;\r
2968 UINT32 Instance;\r
2969 EFI_PHYSICAL_ADDRESS FvVolHdr;\r
2970 EFI_PHYSICAL_ADDRESS TempVariableStoreHeader;\r
2971 EFI_GCD_MEMORY_SPACE_DESCRIPTOR GcdDescriptor;\r
2972 UINT64 BaseAddress;\r
2973 UINT64 Length;\r
2974 UINTN Index;\r
2975 UINT8 Data;\r
2976 EFI_PHYSICAL_ADDRESS VariableStoreBase;\r
2977 UINT64 VariableStoreLength;\r
2978 EFI_EVENT ReadyToBootEvent;\r
2979 UINTN ScratchSize;\r
2980\r
2981 //\r
2982 // Allocate memory for mVariableModuleGlobal\r
2983 //\r
2984 mVariableModuleGlobal = AllocateRuntimeZeroPool (sizeof (ESAL_VARIABLE_GLOBAL));\r
2985 if (mVariableModuleGlobal == NULL) {\r
2986 return EFI_OUT_OF_RESOURCES;\r
2987 }\r
2988\r
2989 mVariableModuleGlobal->GlobalVariableGuid[Physical] = &gEfiGlobalVariableGuid;\r
2990 CopyMem (\r
2991 mVariableModuleGlobal->VariableName[Physical],\r
2992 mVariableName,\r
2993 sizeof (mVariableName)\r
2994 );\r
2995\r
2996 EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal[Physical].VariableServicesLock, TPL_NOTIFY);\r
2997\r
2998 //\r
2999 // Note that in EdkII variable driver implementation, Hardware Error Record type variable\r
3000 // is stored with common variable in the same NV region. So the platform integrator should\r
3001 // ensure that the value of PcdHwErrStorageSize is less than or equal to the value of \r
3002 // PcdFlashNvStorageVariableSize.\r
3003 //\r
3004 ASSERT (PcdGet32(PcdHwErrStorageSize) <= PcdGet32 (PcdFlashNvStorageVariableSize));\r
3005\r
3006 //\r
3007 // Allocate memory for volatile variable store\r
3008 //\r
3009 ScratchSize = MAX (PcdGet32 (PcdMaxVariableSize), PcdGet32 (PcdMaxHardwareErrorVariableSize));\r
3010 VolatileVariableStore = AllocateRuntimePool (PcdGet32 (PcdVariableStoreSize) + ScratchSize);\r
3011 if (VolatileVariableStore == NULL) {\r
3012 FreePool (mVariableModuleGlobal);\r
3013 return EFI_OUT_OF_RESOURCES;\r
3014 }\r
3015\r
3016 SetMem (VolatileVariableStore, PcdGet32 (PcdVariableStoreSize) + ScratchSize, 0xff);\r
3017\r
3018 //\r
3019 // Variable Specific Data\r
3020 //\r
3021 mVariableModuleGlobal->VariableGlobal[Physical].VolatileVariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VolatileVariableStore;\r
3022 mVariableModuleGlobal->VolatileLastVariableOffset = (UINTN) GetStartPointer ((EFI_PHYSICAL_ADDRESS) VolatileVariableStore) - (UINTN) VolatileVariableStore;\r
3023\r
3024 CopyGuid (&VolatileVariableStore->Signature, &gEfiAuthenticatedVariableGuid);\r
3025 VolatileVariableStore->Size = PcdGet32 (PcdVariableStoreSize);\r
3026 VolatileVariableStore->Format = VARIABLE_STORE_FORMATTED;\r
3027 VolatileVariableStore->State = VARIABLE_STORE_HEALTHY;\r
3028 VolatileVariableStore->Reserved = 0;\r
3029 VolatileVariableStore->Reserved1 = 0;\r
3030\r
3031 //\r
3032 // Get non volatile varaible store\r
3033 //\r
3034 TempVariableStoreHeader = (UINT64) PcdGet32 (PcdFlashNvStorageVariableBase);\r
3035 VariableStoreBase = TempVariableStoreHeader + \\r
3036 (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);\r
3037 VariableStoreLength = (UINT64) PcdGet32 (PcdFlashNvStorageVariableSize) - \\r
3038 (((EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) (TempVariableStoreHeader)) -> HeaderLength);\r
3039 //\r
3040 // Mark the variable storage region of the FLASH as RUNTIME\r
3041 //\r
3042 BaseAddress = VariableStoreBase & (~EFI_PAGE_MASK);\r
3043 Length = VariableStoreLength + (VariableStoreBase - BaseAddress);\r
3044 Length = (Length + EFI_PAGE_SIZE - 1) & (~EFI_PAGE_MASK);\r
3045\r
3046 Status = gDS->GetMemorySpaceDescriptor (BaseAddress, &GcdDescriptor);\r
3047 if (EFI_ERROR (Status)) {\r
3048 goto Done;\r
3049 }\r
3050\r
3051 Status = gDS->SetMemorySpaceAttributes (\r
3052 BaseAddress,\r
3053 Length,\r
3054 GcdDescriptor.Attributes | EFI_MEMORY_RUNTIME\r
3055 );\r
3056 if (EFI_ERROR (Status)) {\r
3057 goto Done;\r
3058 }\r
3059 //\r
3060 // Get address of non volatile variable store base.\r
3061 //\r
3062 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = VariableStoreBase;\r
3063\r
3064 //\r
3065 // Check Integrity\r
3066 //\r
3067 //\r
3068 // Find the Correct Instance of the FV Block Service.\r
3069 //\r
3070 Instance = 0;\r
3071 CurrPtr = mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase;\r
3072\r
3073 do {\r
3074 FvVolHdr = 0;\r
3075 Status = (EFI_STATUS) EsalCall (\r
3076 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_LO,\r
3077 EFI_EXTENDED_SAL_FV_BLOCK_SERVICES_PROTOCOL_GUID_HI,\r
3078 GetPhysicalAddressFunctionId, \r
3079 Instance, \r
3080 (UINT64) &FvVolHdr, \r
3081 0, \r
3082 0, \r
3083 0, \r
3084 0, \r
3085 0\r
3086 ).Status;\r
3087 if (EFI_ERROR (Status)) {\r
3088 break;\r
3089 }\r
3090 FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) FvVolHdr);\r
3091 ASSERT (FwVolHeader != NULL);\r
3092 if (CurrPtr >= (EFI_PHYSICAL_ADDRESS) FwVolHeader &&\r
3093 CurrPtr < ((EFI_PHYSICAL_ADDRESS) FwVolHeader + FwVolHeader->FvLength)) {\r
3094 mVariableModuleGlobal->FvbInstance = Instance;\r
3095 break;\r
3096 }\r
3097\r
3098 Instance++;\r
3099 } while (Status == EFI_SUCCESS);\r
3100\r
3101 VariableStoreHeader = (VARIABLE_STORE_HEADER *) CurrPtr;\r
3102 if (GetVariableStoreStatus (VariableStoreHeader) == EfiValid) {\r
3103 if (~VariableStoreHeader->Size == 0) {\r
3104 Status = AccessVariableStore (\r
3105 TRUE,\r
3106 &mVariableModuleGlobal->VariableGlobal[Physical],\r
3107 FALSE,\r
3108 mVariableModuleGlobal->FvbInstance,\r
3109 (UINTN) &VariableStoreHeader->Size,\r
3110 sizeof (UINT32),\r
3111 (UINT8 *) &VariableStoreLength\r
3112 );\r
3113 //\r
3114 // As Variables are stored in NV storage, which are slow devices,such as flash.\r
3115 // Variable operation may skip checking variable program result to improve performance,\r
3116 // We can assume Variable program is OK through some check point.\r
3117 // Variable Store Size Setting should be the first Variable write operation,\r
3118 // We can assume all Read/Write is OK if we can set Variable store size successfully.\r
3119 // If write fail, we will assert here.\r
3120 //\r
3121 ASSERT(VariableStoreHeader->Size == VariableStoreLength);\r
3122\r
3123 if (EFI_ERROR (Status)) {\r
3124 goto Done;\r
3125 }\r
3126 }\r
3127\r
3128 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase = (EFI_PHYSICAL_ADDRESS) ((UINTN) CurrPtr);\r
3129 //\r
3130 // Parse non-volatile variable data and get last variable offset.\r
3131 //\r
3132 Variable = GetStartPointer (CurrPtr);\r
3133 Status = EFI_SUCCESS;\r
3134\r
3135 while (IsValidVariableHeader (Variable, FALSE, &(mVariableModuleGlobal->VariableGlobal[Physical]), Instance, NULL)) {\r
3136 NextVariable = GetNextVariablePtr (\r
3137 Variable,\r
3138 FALSE,\r
3139 &(mVariableModuleGlobal->VariableGlobal[Physical]),\r
3140 Instance\r
3141 );\r
3142 VariableSize = NextVariable - Variable;\r
3143 if ((((VARIABLE_HEADER *)Variable)->Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) {\r
3144 mVariableModuleGlobal->HwErrVariableTotalSize += VariableSize;\r
3145 } else {\r
3146 mVariableModuleGlobal->CommonVariableTotalSize += VariableSize;\r
3147 }\r
3148\r
3149 Variable = NextVariable;\r
3150 }\r
3151\r
3152 mVariableModuleGlobal->NonVolatileLastVariableOffset = (UINTN) Variable - (UINTN) CurrPtr;\r
3153\r
3154 //\r
3155 // Check if the free area is really free.\r
3156 //\r
3157 for (Index = mVariableModuleGlobal->NonVolatileLastVariableOffset; Index < VariableStoreHeader->Size; Index++) {\r
3158 Data = ((UINT8 *) (UINTN) mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase)[Index];\r
3159 if (Data != 0xff) {\r
3160 //\r
3161 // There must be something wrong in variable store, do reclaim operation.\r
3162 //\r
3163 Status = Reclaim (\r
3164 mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,\r
3165 &mVariableModuleGlobal->NonVolatileLastVariableOffset,\r
3166 FALSE,\r
3167 Physical,\r
3168 mVariableModuleGlobal,\r
3169 0x0\r
3170 );\r
3171 if (EFI_ERROR (Status)) {\r
3172 goto Done;\r
3173 }\r
3174 break;\r
3175 }\r
3176 }\r
3177\r
3178 //\r
3179 // Register the event handling function to reclaim variable for OS usage.\r
3180 //\r
3181 Status = EfiCreateEventReadyToBootEx (\r
3182 TPL_NOTIFY, \r
3183 ReclaimForOS, \r
3184 NULL, \r
3185 &ReadyToBootEvent\r
3186 );\r
3187 } else {\r
3188 Status = EFI_VOLUME_CORRUPTED;\r
3189 DEBUG((EFI_D_INFO, "Variable Store header is corrupted\n"));\r
3190 }\r
3191\r
3192Done:\r
3193 if (EFI_ERROR (Status)) {\r
3194 FreePool (mVariableModuleGlobal);\r
3195 FreePool (VolatileVariableStore);\r
3196 }\r
3197\r
3198 return Status;\r
3199}\r