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