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