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