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