]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Universal/Variable/EmuRuntimeDxe/EmuVariable.c
use pcd to enable/disable variableInfo statistic feature in EmuRuntimeDxe driver.
[mirror_edk2.git] / MdeModulePkg / Universal / Variable / EmuRuntimeDxe / EmuVariable.c
1 /** @file
2
3 Emulation Variable services operate on the runtime volatile memory.
4 The nonvolatile variable space doesn't exist.
5
6 Copyright (c) 2006 - 2008, Intel Corporation
7 All rights reserved. This program and the accompanying materials
8 are licensed and made available under the terms and conditions of the BSD License
9 which accompanies this distribution. The full text of the license may be found at
10 http://opensource.org/licenses/bsd-license.php
11
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
14
15 **/
16
17 #include "Variable.h"
18
19 ///
20 /// Don't use module globals after the SetVirtualAddress map is signaled
21 ///
22 ESAL_VARIABLE_GLOBAL *mVariableModuleGlobal;
23
24 VARIABLE_INFO_ENTRY *gVariableInfo = NULL;
25
26 /**
27 Acquires lock only at boot time. Simply returns at runtime.
28
29 This is a temperary function which will be removed when
30 EfiAcquireLock() in UefiLib can handle the call in UEFI
31 Runtimer driver in RT phase.
32 It calls EfiAcquireLock() at boot time, and simply returns
33 at runtime
34
35 @param Lock A pointer to the lock to acquire
36
37 **/
38 VOID
39 AcquireLockOnlyAtBootTime (
40 IN EFI_LOCK *Lock
41 )
42 {
43 if (!EfiAtRuntime ()) {
44 EfiAcquireLock (Lock);
45 }
46 }
47
48 /**
49 Releases lock only at boot time. Simply returns at runtime.
50
51 This is a temperary function which will be removed when
52 EfiReleaseLock() in UefiLib can handle the call in UEFI
53 Runtimer driver in RT phase.
54 It calls EfiReleaseLock() at boot time, and simply returns
55 at runtime
56
57 @param Lock A pointer to the lock to release
58
59 **/
60 VOID
61 ReleaseLockOnlyAtBootTime (
62 IN EFI_LOCK *Lock
63 )
64 {
65 if (!EfiAtRuntime ()) {
66 EfiReleaseLock (Lock);
67 }
68 }
69
70 /**
71 Gets pointer to the variable data.
72
73 This function gets the pointer to the variable data according
74 to the input pointer to the variable header.
75
76 @param Variable Pointer to the variable header.
77
78 @return Pointer to variable data
79
80 **/
81 UINT8 *
82 GetVariableDataPtr (
83 IN VARIABLE_HEADER *Variable
84 )
85 {
86 if (Variable->StartId != VARIABLE_DATA) {
87 return NULL;
88 }
89 //
90 // Be careful about pad size for alignment
91 //
92 return (UINT8 *) ((UINTN) GET_VARIABLE_NAME_PTR (Variable) + Variable->NameSize + GET_PAD_SIZE (Variable->NameSize));
93 }
94
95 /**
96 Gets pointer to header of the next variable.
97
98 This function gets the pointer to the next variable header according
99 to the input point to the variable header.
100
101 @param Variable Pointer to header of the next variable
102
103 @return Pointer to next variable header.
104
105 **/
106 VARIABLE_HEADER *
107 GetNextVariablePtr (
108 IN VARIABLE_HEADER *Variable
109 )
110 {
111 VARIABLE_HEADER *VarHeader;
112
113 if (Variable->StartId != VARIABLE_DATA) {
114 return NULL;
115 }
116 //
117 // Be careful about pad size for alignment
118 //
119 VarHeader = (VARIABLE_HEADER *) (GetVariableDataPtr (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize));
120
121 if (VarHeader->StartId != VARIABLE_DATA ||
122 (sizeof (VARIABLE_HEADER) + VarHeader->DataSize + VarHeader->NameSize) > FixedPcdGet32(PcdMaxVariableSize)
123 ) {
124 return NULL;
125 }
126
127 return VarHeader;
128 }
129
130 /**
131 Gets pointer to the end of the variable storage area.
132
133 This function gets pointer to the end of the variable storage
134 area, according to the input variable store header.
135
136 @param VolHeader Pointer to the variale store header
137
138 @return Pointer to the end of the variable storage area.
139
140 **/
141 VARIABLE_HEADER *
142 GetEndPointer (
143 IN VARIABLE_STORE_HEADER *VolHeader
144 )
145 {
146 //
147 // The end of variable store
148 //
149 return (VARIABLE_HEADER *) ((UINTN) VolHeader + VolHeader->Size);
150 }
151
152 /**
153 Routine used to track statistical information about variable usage.
154 The data is stored in the EFI system table so it can be accessed later.
155 VariableInfo.efi can dump out the table. Only Boot Services variable
156 accesses are tracked by this code. The PcdVariableCollectStatistics
157 build flag controls if this feature is enabled.
158
159 A read that hits in the cache will have Read and Cache true for
160 the transaction. Data is allocated by this routine, but never
161 freed.
162
163 @param[in] VariableName Name of the Variable to track
164 @param[in] VendorGuid Guid of the Variable to track
165 @param[in] Volatile TRUE if volatile FALSE if non-volatile
166 @param[in] Read TRUE if GetVariable() was called
167 @param[in] Write TRUE if SetVariable() was called
168 @param[in] Delete TRUE if deleted via SetVariable()
169 @param[in] Cache TRUE for a cache hit.
170
171 **/
172 VOID
173 UpdateVariableInfo (
174 IN CHAR16 *VariableName,
175 IN EFI_GUID *VendorGuid,
176 IN BOOLEAN Volatile,
177 IN BOOLEAN Read,
178 IN BOOLEAN Write,
179 IN BOOLEAN Delete,
180 IN BOOLEAN Cache
181 )
182 {
183 VARIABLE_INFO_ENTRY *Entry;
184
185 if (FeaturePcdGet (PcdVariableCollectStatistics)) {
186
187 if (EfiAtRuntime ()) {
188 // Don't collect statistics at runtime
189 return;
190 }
191
192 if (gVariableInfo == NULL) {
193 //
194 // on the first call allocate a entry and place a pointer to it in
195 // the EFI System Table
196 //
197 gVariableInfo = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
198 ASSERT (gVariableInfo != NULL);
199
200 CopyGuid (&gVariableInfo->VendorGuid, VendorGuid);
201 gVariableInfo->Name = AllocatePool (StrLen (VariableName));
202 ASSERT (gVariableInfo->Name != NULL);
203 StrCpy (gVariableInfo->Name, VariableName);
204 gVariableInfo->Volatile = Volatile;
205
206 gBS->InstallConfigurationTable (&gEfiVariableGuid, gVariableInfo);
207 }
208
209
210 for (Entry = gVariableInfo; Entry != NULL; Entry = Entry->Next) {
211 if (CompareGuid (VendorGuid, &Entry->VendorGuid)) {
212 if (StrCmp (VariableName, Entry->Name) == 0) {
213 if (Read) {
214 Entry->ReadCount++;
215 }
216 if (Write) {
217 Entry->WriteCount++;
218 }
219 if (Delete) {
220 Entry->DeleteCount++;
221 }
222 if (Cache) {
223 Entry->CacheCount++;
224 }
225
226 return;
227 }
228 }
229
230 if (Entry->Next == NULL) {
231 //
232 // If the entry is not in the table add it.
233 // Next iteration of the loop will fill in the data
234 //
235 Entry->Next = AllocateZeroPool (sizeof (VARIABLE_INFO_ENTRY));
236 ASSERT (Entry->Next != NULL);
237
238 CopyGuid (&Entry->Next->VendorGuid, VendorGuid);
239 Entry->Next->Name = AllocatePool (StrLen (VariableName));
240 ASSERT (Entry->Next->Name != NULL);
241 StrCpy (Entry->Next->Name, VariableName);
242 Entry->Next->Volatile = Volatile;
243 }
244
245 }
246 }
247 }
248
249 /**
250 Finds variable in storage blocks of volatile and non-volatile storage areas.
251
252 This code finds variable in storage blocks of volatile and non-volatile storage areas.
253 If VariableName is an empty string, then we just return the first
254 qualified variable without comparing VariableName and VendorGuid.
255 Otherwise, VariableName and VendorGuid are compared.
256
257 @param VariableName Name of the variable to be found.
258 @param VendorGuid Vendor GUID to be found.
259 @param PtrTrack VARIABLE_POINTER_TRACK structure for output,
260 including the range searched and the target position.
261 @param Global Pointer to VARIABLE_GLOBAL structure, including
262 base of volatile variable storage area, base of
263 NV variable storage area, and a lock.
264
265 @retval EFI_INVALID_PARAMETER If VariableName is not an empty string, while
266 VendorGuid is NULL.
267 @retval EFI_SUCCESS Variable successfully found.
268 @retval EFI_NOT_FOUND Variable not found.
269
270 **/
271 EFI_STATUS
272 FindVariable (
273 IN CHAR16 *VariableName,
274 IN EFI_GUID *VendorGuid,
275 OUT VARIABLE_POINTER_TRACK *PtrTrack,
276 IN VARIABLE_GLOBAL *Global
277 )
278 {
279 VARIABLE_HEADER *Variable[2];
280 VARIABLE_STORE_HEADER *VariableStoreHeader[2];
281 UINTN Index;
282
283 //
284 // We aquire the lock at the entry of FindVariable as GetVariable, GetNextVariableName
285 // SetVariable all call FindVariable at entry point. Please move "Aquire Lock" to
286 // the correct places if this assumption does not hold TRUE anymore.
287 //
288 AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);
289
290 //
291 // 0: Non-Volatile, 1: Volatile
292 //
293 VariableStoreHeader[0] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase);
294 VariableStoreHeader[1] = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);
295
296 //
297 // Start Pointers for the variable.
298 // Actual Data Pointer where data can be written.
299 //
300 Variable[0] = (VARIABLE_HEADER *) (VariableStoreHeader[0] + 1);
301 Variable[1] = (VARIABLE_HEADER *) (VariableStoreHeader[1] + 1);
302
303 if (VariableName[0] != 0 && VendorGuid == NULL) {
304 return EFI_INVALID_PARAMETER;
305 }
306 //
307 // Find the variable by walk through non-volatile and volatile variable store
308 //
309 for (Index = 0; Index < 2; Index++) {
310 PtrTrack->StartPtr = (VARIABLE_HEADER *) (VariableStoreHeader[Index] + 1);
311 PtrTrack->EndPtr = GetEndPointer (VariableStoreHeader[Index]);
312
313 while ((Variable[Index] != NULL) && (Variable[Index] <= GetEndPointer (VariableStoreHeader[Index]))) {
314 if (Variable[Index]->StartId == VARIABLE_DATA && Variable[Index]->State == VAR_ADDED) {
315 if (!(EfiAtRuntime () && ((Variable[Index]->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0))) {
316 if (VariableName[0] == 0) {
317 PtrTrack->CurrPtr = Variable[Index];
318 PtrTrack->Volatile = (BOOLEAN) Index;
319 return EFI_SUCCESS;
320 } else {
321 if (CompareGuid (VendorGuid, &Variable[Index]->VendorGuid)) {
322 if (CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable[Index]), Variable[Index]->NameSize) == 0) {
323 PtrTrack->CurrPtr = Variable[Index];
324 PtrTrack->Volatile = (BOOLEAN) Index;
325 return EFI_SUCCESS;
326 }
327 }
328 }
329 }
330 }
331
332 Variable[Index] = GetNextVariablePtr (Variable[Index]);
333 }
334 }
335 PtrTrack->CurrPtr = NULL;
336 return EFI_NOT_FOUND;
337 }
338
339 /**
340 This code finds variable in storage blocks (Volatile or Non-Volatile).
341
342 @param VariableName A Null-terminated Unicode string that is the name of
343 the vendor's variable.
344 @param VendorGuid A unique identifier for the vendor.
345 @param Attributes If not NULL, a pointer to the memory location to return the
346 attributes bitmask for the variable.
347 @param DataSize Size of Data found. If size is less than the
348 data, this value contains the required size.
349 @param Data On input, the size in bytes of the return Data buffer.
350 On output, the size of data returned in Data.
351 @param Global Pointer to VARIABLE_GLOBAL structure
352 @param Instance Instance of the Firmware Volume.
353
354 @retval EFI_SUCCESS The function completed successfully.
355 @retval EFI_NOT_FOUND The variable was not found.
356 @retval EFI_BUFFER_TOO_SMALL DataSize is too small for the result. DataSize has
357 been updated with the size needed to complete the request.
358 @retval EFI_INVALID_PARAMETER VariableName or VendorGuid or DataSize is NULL.
359
360 **/
361 EFI_STATUS
362 EFIAPI
363 GetVariable (
364 IN CHAR16 *VariableName,
365 IN EFI_GUID * VendorGuid,
366 OUT UINT32 *Attributes OPTIONAL,
367 IN OUT UINTN *DataSize,
368 OUT VOID *Data,
369 IN VARIABLE_GLOBAL * Global,
370 IN UINT32 Instance
371 )
372 {
373 VARIABLE_POINTER_TRACK Variable;
374 UINTN VarDataSize;
375 EFI_STATUS Status;
376
377 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
378 return EFI_INVALID_PARAMETER;
379 }
380 //
381 // Find existing variable
382 //
383 Status = FindVariable (VariableName, VendorGuid, &Variable, Global);
384
385 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
386 goto Done;
387 }
388 //
389 // Get data size
390 //
391 VarDataSize = Variable.CurrPtr->DataSize;
392 if (*DataSize >= VarDataSize) {
393 if (Data == NULL) {
394 Status = EFI_INVALID_PARAMETER;
395 goto Done;
396 }
397
398 CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);
399 if (Attributes != NULL) {
400 *Attributes = Variable.CurrPtr->Attributes;
401 }
402
403 *DataSize = VarDataSize;
404 UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, TRUE, FALSE, FALSE, FALSE);
405 Status = EFI_SUCCESS;
406 goto Done;
407 } else {
408 *DataSize = VarDataSize;
409 Status = EFI_BUFFER_TOO_SMALL;
410 goto Done;
411 }
412
413 Done:
414 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
415 return Status;
416 }
417
418 /**
419
420 This code Finds the Next available variable.
421
422 @param VariableNameSize Size of the variable.
423 @param VariableName On input, supplies the last VariableName that was returned by GetNextVariableName().
424 On output, returns the Null-terminated Unicode string of the current variable.
425 @param VendorGuid On input, supplies the last VendorGuid that was returned by GetNextVariableName().
426 On output, returns the VendorGuid of the current variable.
427 @param Global Pointer to VARIABLE_GLOBAL structure.
428 @param Instance Instance of the Firmware Volume.
429
430 @retval EFI_SUCCESS The function completed successfully.
431 @retval EFI_NOT_FOUND The next variable was not found.
432 @retval EFI_BUFFER_TOO_SMALL VariableNameSize is too small for the result.
433 VariableNameSize has been updated with the size needed to complete the request.
434 @retval EFI_INVALID_PARAMETER VariableNameSize or VariableName or VendorGuid is NULL.
435
436 **/
437 EFI_STATUS
438 EFIAPI
439 GetNextVariableName (
440 IN OUT UINTN *VariableNameSize,
441 IN OUT CHAR16 *VariableName,
442 IN OUT EFI_GUID *VendorGuid,
443 IN VARIABLE_GLOBAL *Global,
444 IN UINT32 Instance
445 )
446 {
447 VARIABLE_POINTER_TRACK Variable;
448 UINTN VarNameSize;
449 EFI_STATUS Status;
450
451 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
452 return EFI_INVALID_PARAMETER;
453 }
454
455 Status = FindVariable (VariableName, VendorGuid, &Variable, Global);
456
457 if (Variable.CurrPtr == NULL || EFI_ERROR (Status)) {
458 goto Done;
459 }
460
461 while (TRUE) {
462 if (VariableName[0] != 0) {
463 //
464 // If variable name is not NULL, get next variable
465 //
466 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
467 }
468 //
469 // If both volatile and non-volatile variable store are parsed,
470 // return not found
471 //
472 if (Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL) {
473 Variable.Volatile = (BOOLEAN) (Variable.Volatile ^ ((BOOLEAN) 0x1));
474 if (Variable.Volatile) {
475 Variable.StartPtr = (VARIABLE_HEADER *) ((UINTN) (Global->VolatileVariableBase + sizeof (VARIABLE_STORE_HEADER)));
476 Variable.EndPtr = (VARIABLE_HEADER *) GetEndPointer ((VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase));
477 } else {
478 Status = EFI_NOT_FOUND;
479 goto Done;
480 }
481
482 Variable.CurrPtr = Variable.StartPtr;
483 if (Variable.CurrPtr->StartId != VARIABLE_DATA) {
484 continue;
485 }
486 }
487 //
488 // Variable is found
489 //
490 if (Variable.CurrPtr->StartId == VARIABLE_DATA && Variable.CurrPtr->State == VAR_ADDED) {
491 if (!(EfiAtRuntime () && ((Variable.CurrPtr->Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0))) {
492 VarNameSize = Variable.CurrPtr->NameSize;
493 if (VarNameSize <= *VariableNameSize) {
494 CopyMem (
495 VariableName,
496 GET_VARIABLE_NAME_PTR (Variable.CurrPtr),
497 VarNameSize
498 );
499 CopyMem (
500 VendorGuid,
501 &Variable.CurrPtr->VendorGuid,
502 sizeof (EFI_GUID)
503 );
504 Status = EFI_SUCCESS;
505 } else {
506 Status = EFI_BUFFER_TOO_SMALL;
507 }
508
509 *VariableNameSize = VarNameSize;
510 goto Done;
511 }
512 }
513 }
514
515 Done:
516 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
517 return Status;
518
519 }
520
521 /**
522
523 This code sets variable in storage blocks (Volatile or Non-Volatile).
524
525 @param VariableName A Null-terminated Unicode string that is the name of the vendor's
526 variable. Each VariableName is unique for each
527 VendorGuid. VariableName must contain 1 or more
528 Unicode characters. If VariableName is an empty Unicode
529 string, then EFI_INVALID_PARAMETER is returned.
530 @param VendorGuid A unique identifier for the vendor
531 @param Attributes Attributes bitmask to set for the variable
532 @param DataSize The size in bytes of the Data buffer. A size of zero causes the
533 variable to be deleted.
534 @param Data The contents for the variable
535 @param Global Pointer to VARIABLE_GLOBAL structure
536 @param VolatileOffset The offset of last volatile variable
537 @param NonVolatileOffset The offset of last non-volatile variable
538 @param Instance Instance of the Firmware Volume.
539
540 @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
541 defined by the Attributes.
542 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied, or the
543 DataSize exceeds the maximum allowed, or VariableName is an empty
544 Unicode string, or VendorGuid is NULL.
545 @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
546 @retval EFI_DEVICE_ERROR The variable could not be saved due to a hardware failure.
547 @retval EFI_WRITE_PROTECTED The variable in question is read-only or cannot be deleted.
548 @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
549
550 **/
551 EFI_STATUS
552 EFIAPI
553 SetVariable (
554 IN CHAR16 *VariableName,
555 IN EFI_GUID *VendorGuid,
556 IN UINT32 Attributes,
557 IN UINTN DataSize,
558 IN VOID *Data,
559 IN VARIABLE_GLOBAL *Global,
560 IN UINTN *VolatileOffset,
561 IN UINTN *NonVolatileOffset,
562 IN UINT32 Instance
563 )
564 {
565 VARIABLE_POINTER_TRACK Variable;
566 EFI_STATUS Status;
567 VARIABLE_HEADER *NextVariable;
568 UINTN VarNameSize;
569 UINTN VarNameOffset;
570 UINTN VarDataOffset;
571 UINTN VarSize;
572
573 //
574 // Check input parameters
575 //
576 if (VariableName == NULL || VariableName[0] == 0 || VendorGuid == NULL) {
577 return EFI_INVALID_PARAMETER;
578 }
579 //
580 // Make sure if runtime bit is set, boot service bit is set also
581 //
582 if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
583 return EFI_INVALID_PARAMETER;
584 }
585 //
586 // The size of the VariableName, including the Unicode Null in bytes plus
587 // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxHardwareErrorVariableSize)
588 // bytes for HwErrRec, and FixedPcdGet32(PcdMaxVariableSize) bytes for the others.
589 //
590 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
591 if ((DataSize > FixedPcdGet32(PcdMaxHardwareErrorVariableSize)) ||
592 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > FixedPcdGet32(PcdMaxHardwareErrorVariableSize))) {
593 return EFI_INVALID_PARAMETER;
594 }
595 } else {
596 //
597 // The size of the VariableName, including the Unicode Null in bytes plus
598 // the DataSize is limited to maximum size of FixedPcdGet32(PcdMaxVariableSize) bytes.
599 //
600 if ((DataSize > FixedPcdGet32(PcdMaxVariableSize)) ||
601 (sizeof (VARIABLE_HEADER) + StrSize (VariableName) + DataSize > FixedPcdGet32(PcdMaxVariableSize))) {
602 return EFI_INVALID_PARAMETER;
603 }
604 }
605 //
606 // Check whether the input variable is already existed
607 //
608
609 Status = FindVariable (VariableName, VendorGuid, &Variable, Global);
610
611 if (Status == EFI_SUCCESS && Variable.CurrPtr != NULL) {
612 //
613 // Update/Delete existing variable
614 //
615
616 if (EfiAtRuntime ()) {
617 //
618 // If EfiAtRuntime and the variable is Volatile and Runtime Access,
619 // the volatile is ReadOnly, and SetVariable should be aborted and
620 // return EFI_WRITE_PROTECTED.
621 //
622 if (Variable.Volatile) {
623 Status = EFI_WRITE_PROTECTED;
624 goto Done;
625 }
626 //
627 // Only variable have NV attribute can be updated/deleted in Runtime
628 //
629 if ((Variable.CurrPtr->Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
630 Status = EFI_INVALID_PARAMETER;
631 goto Done;
632 }
633 }
634
635 //
636 // Setting a data variable with no access, or zero DataSize attributes
637 // specified causes it to be deleted.
638 //
639 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
640 Variable.CurrPtr->State &= VAR_DELETED;
641 UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, FALSE, FALSE, TRUE, FALSE);
642 Status = EFI_SUCCESS;
643 goto Done;
644 }
645
646 //
647 // If the variable is marked valid and the same data has been passed in
648 // then return to the caller immediately.
649 //
650 if (Variable.CurrPtr->DataSize == DataSize &&
651 CompareMem (Data, GetVariableDataPtr (Variable.CurrPtr), DataSize) == 0
652 ) {
653 Status = EFI_SUCCESS;
654 goto Done;
655 } else if (Variable.CurrPtr->State == VAR_ADDED) {
656 //
657 // Mark the old variable as in delete transition
658 //
659 Variable.CurrPtr->State &= VAR_IN_DELETED_TRANSITION;
660 }
661
662 } else if (Status == EFI_NOT_FOUND) {
663 //
664 // Create a new variable
665 //
666
667 //
668 // Make sure we are trying to create a new variable.
669 // Setting a data variable with no access, or zero DataSize attributes means to delete it.
670 //
671 if (DataSize == 0 || (Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == 0) {
672 Status = EFI_NOT_FOUND;
673 goto Done;
674 }
675
676 //
677 // Only variable have NV|RT attribute can be created in Runtime
678 //
679 if (EfiAtRuntime () &&
680 (((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0) || ((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0))) {
681 Status = EFI_INVALID_PARAMETER;
682 goto Done;
683 }
684 } else {
685 //
686 // Status should be EFI_INVALID_PARAMETER here according to return status of FindVariable().
687 //
688 ASSERT (Status == EFI_INVALID_PARAMETER);
689 goto Done;
690 }
691
692 //
693 // Function part - create a new variable and copy the data.
694 // Both update a variable and create a variable will come here.
695 //
696
697 VarNameOffset = sizeof (VARIABLE_HEADER);
698 VarNameSize = StrSize (VariableName);
699 VarDataOffset = VarNameOffset + VarNameSize + GET_PAD_SIZE (VarNameSize);
700 VarSize = VarDataOffset + DataSize + GET_PAD_SIZE (DataSize);
701
702 if ((Attributes & EFI_VARIABLE_NON_VOLATILE) != 0) {
703 if ((UINT32) (VarSize +*NonVolatileOffset) >
704 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->NonVolatileVariableBase)))->Size
705 ) {
706 Status = EFI_OUT_OF_RESOURCES;
707 goto Done;
708 }
709
710 NextVariable = (VARIABLE_HEADER *) (UINT8 *) (*NonVolatileOffset + (UINTN) Global->NonVolatileVariableBase);
711 *NonVolatileOffset = *NonVolatileOffset + VarSize;
712 } else {
713 if ((UINT32) (VarSize +*VolatileOffset) >
714 ((VARIABLE_STORE_HEADER *) ((UINTN) (Global->VolatileVariableBase)))->Size
715 ) {
716 Status = EFI_OUT_OF_RESOURCES;
717 goto Done;
718 }
719
720 NextVariable = (VARIABLE_HEADER *) (UINT8 *) (*VolatileOffset + (UINTN) Global->VolatileVariableBase);
721 *VolatileOffset = *VolatileOffset + VarSize;
722 }
723
724 NextVariable->StartId = VARIABLE_DATA;
725 NextVariable->Attributes = Attributes;
726 NextVariable->State = VAR_ADDED;
727 NextVariable->Reserved = 0;
728
729 //
730 // There will be pad bytes after Data, the NextVariable->NameSize and
731 // NextVariable->NameSize should not include pad size so that variable
732 // service can get actual size in GetVariable
733 //
734 NextVariable->NameSize = (UINT32)VarNameSize;
735 NextVariable->DataSize = (UINT32)DataSize;
736
737 CopyMem (&NextVariable->VendorGuid, VendorGuid, sizeof (EFI_GUID));
738 CopyMem (
739 (UINT8 *) ((UINTN) NextVariable + VarNameOffset),
740 VariableName,
741 VarNameSize
742 );
743 CopyMem (
744 (UINT8 *) ((UINTN) NextVariable + VarDataOffset),
745 Data,
746 DataSize
747 );
748
749 //
750 // Mark the old variable as deleted
751 //
752 if (!EFI_ERROR (Status)) {
753 Variable.CurrPtr->State &= VAR_DELETED;
754 }
755
756 UpdateVariableInfo (VariableName, VendorGuid, Variable.Volatile, FALSE, TRUE, FALSE, FALSE);
757
758 Status = EFI_SUCCESS;
759 Done:
760 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
761 return Status;
762 }
763
764 /**
765
766 This code returns information about the EFI variables.
767
768 @param Attributes Attributes bitmask to specify the type of variables
769 on which to return information.
770 @param MaximumVariableStorageSize On output the maximum size of the storage space available for
771 the EFI variables associated with the attributes specified.
772 @param RemainingVariableStorageSize Returns the remaining size of the storage space available for EFI
773 variables associated with the attributes specified.
774 @param MaximumVariableSize Returns the maximum size of an individual EFI variable
775 associated with the attributes specified.
776 @param Global Pointer to VARIABLE_GLOBAL structure.
777 @param Instance Instance of the Firmware Volume.
778
779 @retval EFI_SUCCESS Valid answer returned.
780 @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits was supplied
781 @retval EFI_UNSUPPORTED The attribute is not supported on this platform, and the
782 MaximumVariableStorageSize, RemainingVariableStorageSize,
783 MaximumVariableSize are undefined.
784
785 **/
786 EFI_STATUS
787 EFIAPI
788 QueryVariableInfo (
789 IN UINT32 Attributes,
790 OUT UINT64 *MaximumVariableStorageSize,
791 OUT UINT64 *RemainingVariableStorageSize,
792 OUT UINT64 *MaximumVariableSize,
793 IN VARIABLE_GLOBAL *Global,
794 IN UINT32 Instance
795 )
796 {
797 VARIABLE_HEADER *Variable;
798 VARIABLE_HEADER *NextVariable;
799 UINT64 VariableSize;
800 VARIABLE_STORE_HEADER *VariableStoreHeader;
801
802 if(MaximumVariableStorageSize == NULL || RemainingVariableStorageSize == NULL || MaximumVariableSize == NULL || Attributes == 0) {
803 return EFI_INVALID_PARAMETER;
804 }
805
806 if((Attributes & (EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_HARDWARE_ERROR_RECORD)) == 0) {
807 //
808 // Make sure the Attributes combination is supported by the platform.
809 //
810 return EFI_UNSUPPORTED;
811 } else if ((Attributes & (EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS)) == EFI_VARIABLE_RUNTIME_ACCESS) {
812 //
813 // Make sure if runtime bit is set, boot service bit is set also.
814 //
815 return EFI_INVALID_PARAMETER;
816 } else if (EfiAtRuntime () && ((Attributes & EFI_VARIABLE_RUNTIME_ACCESS) == 0)) {
817 //
818 // Make sure RT Attribute is set if we are in Runtime phase.
819 //
820 return EFI_INVALID_PARAMETER;
821 }
822
823 AcquireLockOnlyAtBootTime(&Global->VariableServicesLock);
824
825 if((Attributes & EFI_VARIABLE_NON_VOLATILE) == 0) {
826 //
827 // Query is Volatile related.
828 //
829 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) Global->VolatileVariableBase);
830 } else {
831 //
832 // Query is Non-Volatile related.
833 //
834 VariableStoreHeader = (VARIABLE_STORE_HEADER *) ((UINTN) Global->NonVolatileVariableBase);
835 }
836
837 //
838 // Now let's fill *MaximumVariableStorageSize *RemainingVariableStorageSize
839 // with the storage size (excluding the storage header size)
840 //
841 *MaximumVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
842 *RemainingVariableStorageSize = VariableStoreHeader->Size - sizeof (VARIABLE_STORE_HEADER);
843
844 //
845 // Let *MaximumVariableSize be FixedPcdGet32(PcdMaxVariableSize) with the exception of the variable header size.
846 //
847 *MaximumVariableSize = FixedPcdGet32(PcdMaxVariableSize) - sizeof (VARIABLE_HEADER);
848
849 //
850 // Harware error record variable needs larger size.
851 //
852 if ((Attributes & EFI_VARIABLE_HARDWARE_ERROR_RECORD) == EFI_VARIABLE_HARDWARE_ERROR_RECORD) {
853 *MaximumVariableSize = FixedPcdGet32(PcdMaxHardwareErrorVariableSize) - sizeof (VARIABLE_HEADER);
854 }
855
856 //
857 // Point to the starting address of the variables.
858 //
859 Variable = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
860
861 //
862 // Now walk through the related variable store.
863 //
864 while (Variable < GetEndPointer (VariableStoreHeader)) {
865 if (Variable->StartId != VARIABLE_DATA) {
866 break;
867 }
868
869 NextVariable = (VARIABLE_HEADER *) (GetVariableDataPtr (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize));
870 VariableSize = (UINT64) (UINTN) NextVariable - (UINT64) (UINTN) Variable;
871
872 if (Variable->State == VAR_ADDED) {
873 *RemainingVariableStorageSize -= VariableSize;
874 }
875
876 //
877 // Go to the next one.
878 //
879 Variable = NextVariable;
880 }
881
882 if (*RemainingVariableStorageSize < sizeof (VARIABLE_HEADER)) {
883 *MaximumVariableSize = 0;
884 } else if ((*RemainingVariableStorageSize - sizeof (VARIABLE_HEADER)) < *MaximumVariableSize) {
885 *MaximumVariableSize = *RemainingVariableStorageSize - sizeof (VARIABLE_HEADER);
886 }
887
888 ReleaseLockOnlyAtBootTime (&Global->VariableServicesLock);
889 return EFI_SUCCESS;
890 }
891
892 /**
893 Initializes variable store area.
894
895 This function allocates memory space for variable store area and initializes its attributes.
896
897 @param VariableBase Base of the variable store area created
898 @param LastVariableOffset Size of VARIABLE_STORE_HEADER
899
900 **/
901 EFI_STATUS
902 InitializeVariableStore (
903 OUT EFI_PHYSICAL_ADDRESS *VariableBase,
904 OUT UINTN *LastVariableOffset
905 )
906 {
907 VARIABLE_STORE_HEADER *VariableStore;
908
909 //
910 // Allocate memory for volatile variable store
911 //
912 VariableStore = (VARIABLE_STORE_HEADER *) AllocateRuntimePool (
913 FixedPcdGet32(PcdVariableStoreSize)
914 );
915 if (NULL == VariableStore) {
916 return EFI_OUT_OF_RESOURCES;
917 }
918
919 SetMem (VariableStore, FixedPcdGet32(PcdVariableStoreSize), 0xff);
920
921 //
922 // Variable Specific Data
923 //
924 *VariableBase = (EFI_PHYSICAL_ADDRESS) (UINTN) VariableStore;
925 *LastVariableOffset = sizeof (VARIABLE_STORE_HEADER);
926
927 CopyGuid (&VariableStore->Signature, &gEfiVariableGuid);
928 VariableStore->Size = FixedPcdGet32(PcdVariableStoreSize);
929 VariableStore->Format = VARIABLE_STORE_FORMATTED;
930 VariableStore->State = VARIABLE_STORE_HEALTHY;
931 VariableStore->Reserved = 0;
932 VariableStore->Reserved1 = 0;
933
934 return EFI_SUCCESS;
935 }
936
937 /**
938 Initializes variable store area for non-volatile and volatile variable.
939
940 This function allocates and initializes memory space for global context of ESAL
941 variable service and variable store area for non-volatile and volatile variable.
942
943 @param ImageHandle The Image handle of this driver.
944 @param SystemTable The pointer of EFI_SYSTEM_TABLE.
945
946 @retval EFI_SUCCESS Function successfully executed.
947 @retval EFI_OUT_OF_RESOURCES Fail to allocate enough memory resource.
948
949 **/
950 EFI_STATUS
951 EFIAPI
952 VariableCommonInitialize (
953 IN EFI_HANDLE ImageHandle,
954 IN EFI_SYSTEM_TABLE *SystemTable
955 )
956 {
957 EFI_STATUS Status;
958
959 //
960 // Allocate memory for mVariableModuleGlobal
961 //
962 mVariableModuleGlobal = (ESAL_VARIABLE_GLOBAL *) AllocateRuntimePool (
963 sizeof (ESAL_VARIABLE_GLOBAL)
964 );
965 if (NULL == mVariableModuleGlobal) {
966 return EFI_OUT_OF_RESOURCES;
967 }
968
969 EfiInitializeLock(&mVariableModuleGlobal->VariableGlobal[Physical].VariableServicesLock, TPL_NOTIFY);
970
971 //
972 // Intialize volatile variable store
973 //
974 Status = InitializeVariableStore (
975 &mVariableModuleGlobal->VariableGlobal[Physical].VolatileVariableBase,
976 &mVariableModuleGlobal->VolatileLastVariableOffset
977 );
978
979 if (EFI_ERROR (Status)) {
980 return Status;
981 }
982 //
983 // Intialize non volatile variable store
984 //
985 Status = InitializeVariableStore (
986 &mVariableModuleGlobal->VariableGlobal[Physical].NonVolatileVariableBase,
987 &mVariableModuleGlobal->NonVolatileLastVariableOffset
988 );
989
990 return Status;
991 }