]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkModulePkg/Universal/VariablePei/Variable.c
d5881f5ce83957cb640733330870b812371a5884
[mirror_edk2.git] / IntelFrameworkModulePkg / Universal / VariablePei / Variable.c
1 /** @file
2 Framework PEIM to provide the Variable functionality
3
4 Copyright (c) 2006 - 2008 Intel Corporation. <BR>
5 All rights reserved. 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 Module Name:
13
14 **/
15
16
17 #include "Variable.h"
18
19 //
20 // Module globals
21 //
22 EFI_PEI_READ_ONLY_VARIABLE_PPI mVariablePpi = {
23 PeiGetVariable,
24 PeiGetNextVariableName
25 };
26
27 EFI_PEI_READ_ONLY_VARIABLE2_PPI mVariable2Ppi = {
28 PeiGetVariable2,
29 PeiGetNextVariableName2
30 };
31
32 EFI_PEI_PPI_DESCRIPTOR mPpiListVariable[] = {
33 {
34 (EFI_PEI_PPI_DESCRIPTOR_PPI),
35 &gEfiPeiReadOnlyVariable2PpiGuid,
36 &mVariable2Ppi
37 },
38 {
39 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
40 &gEfiPeiReadOnlyVariablePpiGuid,
41 &mVariablePpi
42 }
43 };
44
45 EFI_GUID mEfiVariableIndexTableGuid = EFI_VARIABLE_INDEX_TABLE_GUID;
46
47 /**
48 Provide the functionality of the variable services.
49
50 @param FileHandle Handle of the file being invoked.
51 @param PeiServices Describes the list of possible PEI Services.
52
53 @return EFI_SUCCESS If the interface could be successfully installed.
54 @return EFI_UNSUPPORTED If current boot path is in recovery mode, then does not
55 install this interface.
56
57 **/
58 EFI_STATUS
59 EFIAPI
60 PeimInitializeVariableServices (
61 IN EFI_PEI_FILE_HANDLE FileHandle,
62 IN CONST EFI_PEI_SERVICES **PeiServices
63 )
64 {
65 EFI_BOOT_MODE BootMode;
66 EFI_STATUS Status;
67
68 //
69 // Check if this is recovery boot path. If no, publish the variable access capability
70 // to other modules. If yes, the content of variable area is not reliable. Therefore,
71 // in this case we should not provide variable service to other pei modules.
72 //
73 Status = (*PeiServices)->GetBootMode (PeiServices, &BootMode);
74 ASSERT_EFI_ERROR (Status);
75
76 if (BootMode == BOOT_IN_RECOVERY_MODE) {
77 return EFI_UNSUPPORTED;
78 }
79
80 return (**PeiServices).InstallPpi (PeiServices, &mPpiListVariable[0]);
81
82 }
83
84 /**
85 This code gets the pointer to the first variable memory pointer byte
86
87 @param VarStoreHeader Pointer to the Variable Store Header.
88
89 @return VARIABLE_HEADER* Pointer to last unavailable Variable Header
90
91 **/
92 VARIABLE_HEADER *
93 GetStartPointer (
94 IN VARIABLE_STORE_HEADER *VarStoreHeader
95 )
96 {
97 //
98 // The end of variable store
99 //
100 return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);
101 }
102
103 /**
104 This code gets the pointer to the last variable memory pointer byte
105
106 @param VarStoreHeader Pointer to the Variable Store Header.
107
108 @return VARIABLE_HEADER* Pointer to last unavailable Variable Header
109
110 **/
111 VARIABLE_HEADER *
112 GetEndPointer (
113 IN VARIABLE_STORE_HEADER *VarStoreHeader
114 )
115
116 {
117 //
118 // The end of variable store
119 //
120 return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);
121 }
122
123 /**
124
125 This code checks if variable header is valid or not.
126
127 @param Variable Pointer to the Variable Header.
128
129 @retval TRUE Variable header is valid.
130 @retval FALSE Variable header is not valid.
131
132 **/
133 BOOLEAN
134 EFIAPI
135 IsValidVariableHeader (
136 IN VARIABLE_HEADER *Variable
137 )
138 {
139 if (Variable == NULL || Variable->StartId != VARIABLE_DATA ) {
140 return FALSE;
141 }
142
143 return TRUE;
144 }
145
146 /**
147 This code gets the size of name of variable.
148
149 @param Variable Pointer to the Variable Header.
150
151 @return UINTN Size of variable in bytes
152
153 **/
154 UINTN
155 NameSizeOfVariable (
156 IN VARIABLE_HEADER *Variable
157 )
158 {
159 if (Variable->State == (UINT8) (-1) ||
160 Variable->DataSize == (UINT32) -1 ||
161 Variable->NameSize == (UINT32) -1 ||
162 Variable->Attributes == (UINT32) -1) {
163 return 0;
164 }
165 return (UINTN) Variable->NameSize;
166 }
167
168 /**
169 This code gets the size of name of variable.
170
171 @param Variable Pointer to the Variable Header.
172
173 @return UINTN Size of variable in bytes
174
175 **/
176 UINTN
177 DataSizeOfVariable (
178 IN VARIABLE_HEADER *Variable
179 )
180 {
181 if (Variable->State == (UINT8) -1 ||
182 Variable->DataSize == (UINT32) -1 ||
183 Variable->NameSize == (UINT32) -1 ||
184 Variable->Attributes == (UINT32) -1) {
185 return 0;
186 }
187 return (UINTN) Variable->DataSize;
188 }
189
190 /**
191 This code gets the pointer to the variable name.
192
193 @param Variable Pointer to the Variable Header.
194
195 @return CHAR16* Pointer to Variable Name
196
197 **/
198 CHAR16 *
199 GetVariableNamePtr (
200 IN VARIABLE_HEADER *Variable
201 )
202
203 {
204
205 return (CHAR16 *) (Variable + 1);
206 }
207
208 /**
209 This code gets the pointer to the variable data.
210
211 @param Variable Pointer to the Variable Header.
212
213 @return UINT8* Pointer to Variable Data
214
215 **/
216 UINT8 *
217 GetVariableDataPtr (
218 IN VARIABLE_HEADER *Variable
219 )
220 {
221 UINTN Value;
222
223 //
224 // Be careful about pad size for alignment
225 //
226 Value = (UINTN) GetVariableNamePtr (Variable);
227 Value += NameSizeOfVariable (Variable);
228 Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));
229
230 return (UINT8 *) Value;
231 }
232
233 /**
234 This code gets the pointer to the next variable header.
235
236 @param Variable Pointer to the Variable Header.
237
238 @return VARIABLE_HEADER* Pointer to next variable header.
239
240 **/
241 VARIABLE_HEADER *
242 GetNextVariablePtr (
243 IN VARIABLE_HEADER *Variable
244 )
245
246 {
247 UINTN Value;
248
249 if (!IsValidVariableHeader (Variable)) {
250 return NULL;
251 }
252
253 Value = (UINTN) GetVariableDataPtr (Variable);
254 Value += DataSizeOfVariable (Variable);
255 Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));
256
257 //
258 // Be careful about pad size for alignment
259 //
260 return (VARIABLE_HEADER *) HEADER_ALIGN (Value);
261 }
262
263 /**
264 This code gets the pointer to the variable name.
265
266 @param VarStoreHeader Pointer to the Variable Store Header.
267
268 @retval EfiRaw Variable store is raw
269 @retval EfiValid Variable store is valid
270 @retval EfiInvalid Variable store is invalid
271
272 **/
273 VARIABLE_STORE_STATUS
274 EFIAPI
275 GetVariableStoreStatus (
276 IN VARIABLE_STORE_HEADER *VarStoreHeader
277 )
278
279 {
280 if (VarStoreHeader->Signature == VARIABLE_STORE_SIGNATURE &&
281 VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&
282 VarStoreHeader->State == VARIABLE_STORE_HEALTHY
283 ) {
284
285 return EfiValid;
286 }
287
288 if (VarStoreHeader->Signature == 0xffffffff &&
289 VarStoreHeader->Size == 0xffffffff &&
290 VarStoreHeader->Format == 0xff &&
291 VarStoreHeader->State == 0xff
292 ) {
293
294 return EfiRaw;
295 } else {
296 return EfiInvalid;
297 }
298 }
299
300 /**
301 This function compares a variable with variable entries in database
302
303 @param Variable - Pointer to the variable in our database
304 @param VariableName - Name of the variable to compare to 'Variable'
305 @param VendorGuid - GUID of the variable to compare to 'Variable'
306 @param PtrTrack - Variable Track Pointer structure that contains
307 Variable Information.
308
309 @retval EFI_SUCCESS - Found match variable
310 @retval EFI_NOT_FOUND - Variable not found
311
312 **/
313 EFI_STATUS
314 CompareWithValidVariable (
315 IN VARIABLE_HEADER *Variable,
316 IN CONST CHAR16 *VariableName,
317 IN CONST EFI_GUID *VendorGuid,
318 OUT VARIABLE_POINTER_TRACK *PtrTrack
319 )
320
321 {
322 VOID *Point;
323
324 if (VariableName[0] == 0) {
325 PtrTrack->CurrPtr = Variable;
326 return EFI_SUCCESS;
327 } else {
328 //
329 // Don't use CompareGuid function here for performance reasons.
330 // Instead we compare the GUID a UINT32 at a time and branch
331 // on the first failed comparison.
332 //
333 if ((((INT32 *) VendorGuid)[0] == ((INT32 *) &Variable->VendorGuid)[0]) &&
334 (((INT32 *) VendorGuid)[1] == ((INT32 *) &Variable->VendorGuid)[1]) &&
335 (((INT32 *) VendorGuid)[2] == ((INT32 *) &Variable->VendorGuid)[2]) &&
336 (((INT32 *) VendorGuid)[3] == ((INT32 *) &Variable->VendorGuid)[3])
337 ) {
338 ASSERT (NameSizeOfVariable (Variable) != 0);
339 Point = (VOID *) GetVariableNamePtr (Variable);
340 if (!CompareMem (VariableName, Point, NameSizeOfVariable (Variable))) {
341 PtrTrack->CurrPtr = Variable;
342 return EFI_SUCCESS;
343 }
344 }
345 }
346
347 return EFI_NOT_FOUND;
348 }
349
350 /**
351 This code finds variable in storage blocks (Non-Volatile)
352
353 @param PeiServices - General purpose services available to every PEIM.
354 @param VariableName - Name of the variable to be found
355 @param VendorGuid - Vendor GUID to be found.
356 @param PtrTrack - Variable Track Pointer structure that contains
357 Variable Information.
358
359 @retval EFI_SUCCESS - Variable found successfully
360 @retval EFI_NOT_FOUND - Variable not found
361 @retval EFI_INVALID_PARAMETER - Invalid variable name
362
363 **/
364 EFI_STATUS
365 EFIAPI
366 FindVariable (
367 IN EFI_PEI_SERVICES **PeiServices,
368 IN CONST CHAR16 *VariableName,
369 IN CONST EFI_GUID *VendorGuid,
370 OUT VARIABLE_POINTER_TRACK *PtrTrack
371 )
372
373 {
374 EFI_HOB_GUID_TYPE *GuidHob;
375 VARIABLE_STORE_HEADER *VariableStoreHeader;
376 VARIABLE_HEADER *Variable;
377 VARIABLE_HEADER *MaxIndex;
378 VARIABLE_INDEX_TABLE *IndexTable;
379 UINT32 Count;
380 UINT8 *VariableBase;
381
382 if (VariableName[0] != 0 && VendorGuid == NULL) {
383 return EFI_INVALID_PARAMETER;
384 }
385 //
386 // No Variable Address equals zero, so 0 as initial value is safe.
387 //
388 MaxIndex = 0;
389
390 GuidHob = GetFirstGuidHob (&mEfiVariableIndexTableGuid);
391 if (GuidHob == NULL) {
392 IndexTable = BuildGuidHob (&mEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));
393 IndexTable->Length = 0;
394 IndexTable->StartPtr = NULL;
395 IndexTable->EndPtr = NULL;
396 IndexTable->GoneThrough = 0;
397 } else {
398 IndexTable = GET_GUID_HOB_DATA (GuidHob);
399 for (Count = 0; Count < IndexTable->Length; Count++)
400 {
401 MaxIndex = GetVariableByIndex (IndexTable, Count);
402
403 if (CompareWithValidVariable (MaxIndex, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
404 PtrTrack->StartPtr = IndexTable->StartPtr;
405 PtrTrack->EndPtr = IndexTable->EndPtr;
406
407 return EFI_SUCCESS;
408 }
409 }
410
411 if (IndexTable->GoneThrough) {
412 return EFI_NOT_FOUND;
413 }
414 }
415 //
416 // If not found in HOB, then let's start from the MaxIndex we've found.
417 //
418 if (MaxIndex != NULL) {
419 Variable = GetNextVariablePtr (MaxIndex);
420 } else {
421 if (IndexTable->StartPtr || IndexTable->EndPtr) {
422 Variable = IndexTable->StartPtr;
423 } else {
424 VariableBase = (UINT8 *) (UINTN) PcdGet32 (PcdFlashNvStorageVariableBase);
425 VariableStoreHeader = (VARIABLE_STORE_HEADER *) (VariableBase + \
426 ((EFI_FIRMWARE_VOLUME_HEADER *) (VariableBase)) -> HeaderLength);
427
428 if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {
429 return EFI_UNSUPPORTED;
430 }
431
432 if (~VariableStoreHeader->Size == 0) {
433 return EFI_NOT_FOUND;
434 }
435 //
436 // Find the variable by walk through non-volatile variable store
437 //
438 IndexTable->StartPtr = GetStartPointer (VariableStoreHeader);
439 IndexTable->EndPtr = GetEndPointer (VariableStoreHeader);
440
441 //
442 // Start Pointers for the variable.
443 // Actual Data Pointer where data can be written.
444 //
445 Variable = IndexTable->StartPtr;
446 }
447 }
448 //
449 // Find the variable by walk through non-volatile variable store
450 //
451 PtrTrack->StartPtr = IndexTable->StartPtr;
452 PtrTrack->EndPtr = IndexTable->EndPtr;
453
454 while (IsValidVariableHeader (Variable) && (Variable <= IndexTable->EndPtr)) {
455 if (Variable->State == VAR_ADDED) {
456 //
457 // Record Variable in VariableIndex HOB
458 //
459 if (IndexTable->Length < VARIABLE_INDEX_TABLE_VOLUME)
460 {
461 VariableIndexTableUpdate (IndexTable, Variable);
462 }
463
464 if (CompareWithValidVariable (Variable, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
465 return EFI_SUCCESS;
466 }
467 }
468
469 Variable = GetNextVariablePtr (Variable);
470 }
471 //
472 // If gone through the VariableStore, that means we never find in Firmware any more.
473 //
474 if (IndexTable->Length < VARIABLE_INDEX_TABLE_VOLUME) {
475 IndexTable->GoneThrough = 1;
476 }
477
478 PtrTrack->CurrPtr = NULL;
479
480 return EFI_NOT_FOUND;
481 }
482
483 /**
484 Provide the read variable functionality of the variable services.
485
486 @param PeiServices - General purpose services available to every PEIM.
487
488 @param VariableName - The variable name
489
490 @param VendorGuid - The vendor's GUID
491
492 @param Attributes - Pointer to the attribute
493
494 @param DataSize - Size of data
495
496 @param Data - Pointer to data
497
498 @retval EFI_SUCCESS - The interface could be successfully installed
499
500 @retval EFI_NOT_FOUND - The variable could not be discovered
501
502 @retval EFI_BUFFER_TOO_SMALL - The caller buffer is not large enough
503
504 **/
505 EFI_STATUS
506 EFIAPI
507 PeiGetVariable (
508 IN EFI_PEI_SERVICES **PeiServices,
509 IN CHAR16 *VariableName,
510 IN EFI_GUID * VendorGuid,
511 OUT UINT32 *Attributes OPTIONAL,
512 IN OUT UINTN *DataSize,
513 OUT VOID *Data
514 )
515
516 {
517 VARIABLE_POINTER_TRACK Variable;
518 UINTN VarDataSize;
519 EFI_STATUS Status;
520
521 if (VariableName == NULL || VendorGuid == NULL || DataSize == NULL) {
522 return EFI_INVALID_PARAMETER;
523 }
524 //
525 // Find existing variable
526 //
527 Status = FindVariable (PeiServices, VariableName, VendorGuid, &Variable);
528
529 if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) {
530 return Status;
531 }
532 //
533 // Get data size
534 //
535 VarDataSize = DataSizeOfVariable (Variable.CurrPtr);
536 if (*DataSize >= VarDataSize) {
537 //
538 // PO-TKW: Address one checking in this place
539 //
540 if (Data == NULL) {
541 return EFI_INVALID_PARAMETER;
542 }
543
544 (*PeiServices)->CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);
545
546 if (Attributes != NULL) {
547 *Attributes = Variable.CurrPtr->Attributes;
548 }
549
550 *DataSize = VarDataSize;
551 return EFI_SUCCESS;
552 } else {
553 *DataSize = VarDataSize;
554 return EFI_BUFFER_TOO_SMALL;
555 }
556 }
557
558 /**
559 Provide the read variable functionality of the variable services.
560
561 @param PeiServices - General purpose services available to every PEIM.
562
563 @param VariableName - The variable name
564
565 @param VendorGuid - The vendor's GUID
566
567 @param Attributes - Pointer to the attribute
568
569 @param DataSize - Size of data
570
571 @param Data - Pointer to data
572
573 @retval EFI_SUCCESS - The interface could be successfully installed
574
575 @retval EFI_NOT_FOUND - The variable could not be discovered
576
577 @retval EFI_BUFFER_TOO_SMALL - The caller buffer is not large enough
578
579 **/
580 EFI_STATUS
581 EFIAPI
582 PeiGetVariable2 (
583 IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
584 IN CONST CHAR16 *VariableName,
585 IN CONST EFI_GUID *VariableGuid,
586 OUT UINT32 *Attributes,
587 IN OUT UINTN *DataSize,
588 OUT VOID *Data
589 )
590
591 {
592 return PeiGetVariable (
593 (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
594 (CHAR16*)VariableName,
595 (EFI_GUID*)VariableGuid,
596 Attributes,
597 DataSize,
598 Data
599 );
600 }
601
602 /**
603 Provide the get next variable functionality of the variable services.
604
605 @param PeiServices - General purpose services available to every PEIM.
606 @param VariabvleNameSize - The variable name's size.
607 @param VariableName - A pointer to the variable's name.
608 @param VendorGuid - A pointer to the EFI_GUID structure.
609
610 @param VariableNameSize - Size of the variable name
611
612 @param VariableName - The variable name
613
614 @param VendorGuid - The vendor's GUID
615
616 @retval EFI_SUCCESS - The interface could be successfully installed
617
618 @retval EFI_NOT_FOUND - The variable could not be discovered
619
620 **/
621 EFI_STATUS
622 EFIAPI
623 PeiGetNextVariableName (
624 IN EFI_PEI_SERVICES **PeiServices,
625 IN OUT UINTN *VariableNameSize,
626 IN OUT CHAR16 *VariableName,
627 IN OUT EFI_GUID *VendorGuid
628 )
629
630 {
631 VARIABLE_POINTER_TRACK Variable;
632 UINTN VarNameSize;
633 EFI_STATUS Status;
634
635 if (VariableNameSize == NULL || VariableName == NULL || VendorGuid == NULL) {
636 return EFI_INVALID_PARAMETER;
637 }
638
639 Status = FindVariable (PeiServices, VariableName, VendorGuid, &Variable);
640
641 if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) {
642 return Status;
643 }
644
645 if (VariableName[0] != 0) {
646 //
647 // If variable name is not NULL, get next variable
648 //
649 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
650 }
651
652 while (!(Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL)) {
653 if (IsValidVariableHeader (Variable.CurrPtr)) {
654 if (Variable.CurrPtr->State == VAR_ADDED) {
655 ASSERT (NameSizeOfVariable (Variable.CurrPtr) != 0);
656
657 VarNameSize = (UINTN) NameSizeOfVariable (Variable.CurrPtr);
658 if (VarNameSize <= *VariableNameSize) {
659 (*PeiServices)->CopyMem (VariableName, GetVariableNamePtr (Variable.CurrPtr), VarNameSize);
660
661 (*PeiServices)->CopyMem (VendorGuid, &Variable.CurrPtr->VendorGuid, sizeof (EFI_GUID));
662
663 Status = EFI_SUCCESS;
664 } else {
665 Status = EFI_BUFFER_TOO_SMALL;
666 }
667
668 *VariableNameSize = VarNameSize;
669 return Status;
670 //
671 // Variable is found
672 //
673 } else {
674 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
675 }
676 } else {
677 break;
678 }
679 }
680
681 return EFI_NOT_FOUND;
682 }
683
684 /**
685 Provide the get next variable functionality of the variable services.
686
687 @param PeiServices - General purpose services available to every PEIM.
688 @param VariabvleNameSize - The variable name's size.
689 @param VariableName - A pointer to the variable's name.
690 @param VariableGuid - A pointer to the EFI_GUID structure.
691
692 @param VariableNameSize - Size of the variable name
693
694 @param VariableName - The variable name
695
696 @param VendorGuid - The vendor's GUID
697
698
699 @retval EFI_SUCCESS - The interface could be successfully installed
700
701 @retval EFI_NOT_FOUND - The variable could not be discovered
702
703 **/
704 EFI_STATUS
705 EFIAPI
706 PeiGetNextVariableName2 (
707 IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,
708 IN OUT UINTN *VariableNameSize,
709 IN OUT CHAR16 *VariableName,
710 IN OUT EFI_GUID *VariableGuid
711 )
712
713 {
714 return PeiGetNextVariableName (
715 (EFI_PEI_SERVICES **) GetPeiServicesTablePointer (),
716 VariableNameSize,
717 VariableName,
718 VariableGuid
719 );
720 }
721