]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Universal/Variable/Pei/Variable.c
Initial import.
[mirror_edk2.git] / EdkModulePkg / Universal / Variable / Pei / Variable.c
1 /*++
2
3 Copyright (c) 2006, 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 Variable.c
15
16 Abstract:
17
18 Framework PEIM to provide the Variable functionality
19
20 --*/
21
22
23 #include <Ppi/ReadOnlyVariable.h>
24 #include <Variable.h>
25 #include <Library/BaseLib.h>
26
27 //
28 // Module globals
29 //
30 static EFI_PEI_READ_ONLY_VARIABLE_PPI mVariablePpi = {
31 PeiGetVariable,
32 PeiGetNextVariableName
33 };
34
35 static EFI_PEI_PPI_DESCRIPTOR mPpiListVariable = {
36 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
37 &gEfiPeiReadOnlyVariablePpiGuid,
38 &mVariablePpi
39 };
40
41 EFI_GUID gEfiVariableIndexTableGuid = EFI_VARIABLE_INDEX_TABLE_GUID;
42
43 EFI_STATUS
44 EFIAPI
45 PeimInitializeVariableServices (
46 IN EFI_FFS_FILE_HEADER *FfsHeader,
47 IN EFI_PEI_SERVICES **PeiServices
48 )
49 /*++
50
51 Routine Description:
52
53 Provide the functionality of the variable services.
54
55 Arguments:
56
57 FfsHeadher - The FFS file header
58 PeiServices - General purpose services available to every PEIM.
59
60 Returns:
61
62 Status - EFI_SUCCESS if the interface could be successfully
63 installed
64
65 --*/
66 {
67 //
68 // Publish the variable capability to other modules
69 //
70 return (**PeiServices).InstallPpi (PeiServices, &mPpiListVariable);
71
72 }
73
74 VARIABLE_HEADER *
75 GetNextVariablePtr (
76 IN VARIABLE_HEADER *Variable
77 )
78 /*++
79
80 Routine Description:
81
82 This code checks if variable header is valid or not.
83
84 Arguments:
85 Variable Pointer to the Variable Header.
86
87 Returns:
88 TRUE Variable header is valid.
89 FALSE Variable header is not valid.
90
91 --*/
92 {
93 return (VARIABLE_HEADER *) ((UINTN) GET_VARIABLE_DATA_PTR (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize));
94 }
95
96 BOOLEAN
97 EFIAPI
98 IsValidVariableHeader (
99 IN VARIABLE_HEADER *Variable
100 )
101 /*++
102
103 Routine Description:
104
105 This code checks if variable header is valid or not.
106
107 Arguments:
108 Variable Pointer to the Variable Header.
109
110 Returns:
111 TRUE Variable header is valid.
112 FALSE Variable header is not valid.
113
114 --*/
115 {
116 if (Variable == NULL ||
117 Variable->StartId != VARIABLE_DATA ||
118 (sizeof (VARIABLE_HEADER) + Variable->DataSize + Variable->NameSize) > MAX_VARIABLE_SIZE
119 ) {
120 return FALSE;
121 }
122
123 return TRUE;
124 }
125
126 VARIABLE_STORE_STATUS
127 EFIAPI
128 GetVariableStoreStatus (
129 IN VARIABLE_STORE_HEADER *VarStoreHeader
130 )
131 /*++
132
133 Routine Description:
134
135 This code gets the pointer to the variable name.
136
137 Arguments:
138
139 VarStoreHeader Pointer to the Variable Store Header.
140
141 Returns:
142
143 EfiRaw Variable store is raw
144 EfiValid Variable store is valid
145 EfiInvalid Variable store is invalid
146
147 --*/
148 {
149 if (VarStoreHeader->Signature == VARIABLE_STORE_SIGNATURE &&
150 VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&
151 VarStoreHeader->State == VARIABLE_STORE_HEALTHY
152 ) {
153
154 return EfiValid;
155 }
156
157 if (VarStoreHeader->Signature == 0xffffffff &&
158 VarStoreHeader->Size == 0xffffffff &&
159 VarStoreHeader->Format == 0xff &&
160 VarStoreHeader->State == 0xff
161 ) {
162
163 return EfiRaw;
164 } else {
165 return EfiInvalid;
166 }
167 }
168
169 EFI_STATUS
170 CompareWithValidVariable (
171 IN VARIABLE_HEADER *Variable,
172 IN CHAR16 *VariableName,
173 IN EFI_GUID *VendorGuid,
174 OUT VARIABLE_POINTER_TRACK *PtrTrack
175 )
176 /*++
177
178 Routine Description:
179
180 This function compares a variable with variable entries in database
181
182 Arguments:
183
184 Variable - Pointer to the variable in our database
185 VariableName - Name of the variable to compare to 'Variable'
186 VendorGuid - GUID of the variable to compare to 'Variable'
187 PtrTrack - Variable Track Pointer structure that contains
188 Variable Information.
189
190 Returns:
191
192 EFI_SUCCESS - Found match variable
193 EFI_NOT_FOUND - Variable not found
194
195 --*/
196 {
197 if (VariableName[0] == 0) {
198 PtrTrack->CurrPtr = Variable;
199 return EFI_SUCCESS;
200 } else {
201 //
202 // Don't use CompareGuid function here for performance reasons.
203 // Instead we compare the GUID a UINT32 at a time and branch
204 // on the first failed comparison.
205 //
206 if ((((INT32 *) VendorGuid)[0] == ((INT32 *) &Variable->VendorGuid)[0]) &&
207 (((INT32 *) VendorGuid)[1] == ((INT32 *) &Variable->VendorGuid)[1]) &&
208 (((INT32 *) VendorGuid)[2] == ((INT32 *) &Variable->VendorGuid)[2]) &&
209 (((INT32 *) VendorGuid)[3] == ((INT32 *) &Variable->VendorGuid)[3])
210 ) {
211 if (!StrCmp (VariableName, GET_VARIABLE_NAME_PTR (Variable))) {
212 PtrTrack->CurrPtr = Variable;
213 return EFI_SUCCESS;
214 }
215 }
216 }
217
218 return EFI_NOT_FOUND;
219 }
220
221 EFI_STATUS
222 EFIAPI
223 FindVariable (
224 IN EFI_PEI_SERVICES **PeiServices,
225 IN CHAR16 *VariableName,
226 IN EFI_GUID *VendorGuid,
227 OUT VARIABLE_POINTER_TRACK *PtrTrack
228 )
229 /*++
230
231 Routine Description:
232
233 This code finds variable in storage blocks (Non-Volatile)
234
235 Arguments:
236
237 PeiServices - General purpose services available to every PEIM.
238 VariableName - Name of the variable to be found
239 VendorGuid - Vendor GUID to be found.
240 PtrTrack - Variable Track Pointer structure that contains
241 Variable Information.
242
243 Returns:
244
245 EFI_SUCCESS - Variable found successfully
246 EFI_NOT_FOUND - Variable not found
247 EFI_INVALID_PARAMETER - Invalid variable name
248
249 --*/
250 {
251 PEI_FLASH_MAP_PPI *FlashMapPpi;
252 EFI_FLASH_SUBAREA_ENTRY *VariableStoreEntry;
253 UINT32 NumEntries;
254 EFI_HOB_GUID_TYPE *GuidHob;
255 VARIABLE_STORE_HEADER *VariableStoreHeader;
256 VARIABLE_HEADER *Variable;
257
258 EFI_STATUS Status;
259
260 VARIABLE_HEADER *MaxIndex;
261 VARIABLE_INDEX_TABLE *IndexTable;
262 UINT32 Count;
263
264 if (VariableName != 0 && VendorGuid == NULL) {
265 return EFI_INVALID_PARAMETER;
266 }
267 //
268 // No Variable Address equals zero, so 0 as initial value is safe.
269 //
270 MaxIndex = 0;
271
272 GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);
273 if (GuidHob == NULL) {
274 IndexTable = BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));
275 IndexTable->Length = 0;
276 IndexTable->StartPtr = NULL;
277 IndexTable->EndPtr = NULL;
278 IndexTable->GoneThrough = 0;
279 } else {
280 IndexTable = GET_GUID_HOB_DATA (GuidHob);
281 for (Count = 0; Count < IndexTable->Length; Count++)
282 {
283 #if ALIGNMENT <= 1
284 MaxIndex = (VARIABLE_HEADER *) (UINTN) (IndexTable->Index[Count] + ((UINTN) IndexTable->StartPtr & 0xFFFF0000));
285 #else
286 #if ALIGNMENT >= 4
287 MaxIndex = (VARIABLE_HEADER *) (UINTN) ((((UINT32)IndexTable->Index[Count]) << 2) + ((UINT32)(UINTN)IndexTable->StartPtr & 0xFFFC0000) );
288 #endif
289 #endif
290 if (CompareWithValidVariable (MaxIndex, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
291 PtrTrack->StartPtr = IndexTable->StartPtr;
292 PtrTrack->EndPtr = IndexTable->EndPtr;
293
294 return EFI_SUCCESS;
295 }
296 }
297
298 if (IndexTable->GoneThrough) {
299 return EFI_NOT_FOUND;
300 }
301 }
302 //
303 // If not found in HOB, then let's start from the MaxIndex we've found.
304 //
305 if (MaxIndex != NULL) {
306 Variable = GetNextVariablePtr (MaxIndex);
307 } else {
308 if (IndexTable->StartPtr || IndexTable->EndPtr) {
309 Variable = IndexTable->StartPtr;
310 } else {
311 //
312 // Locate FlashMap PPI
313 //
314 Status = (**PeiServices).LocatePpi (
315 PeiServices,
316 &gPeiFlashMapPpiGuid,
317 0,
318 NULL,
319 (VOID **) &FlashMapPpi
320 );
321 ASSERT_EFI_ERROR (Status);
322
323 //
324 // Get flash area info for variables
325 //
326 Status = FlashMapPpi->GetAreaInfo (
327 PeiServices,
328 FlashMapPpi,
329 EFI_FLASH_AREA_EFI_VARIABLES,
330 NULL,
331 &NumEntries,
332 &VariableStoreEntry
333 );
334
335 //
336 // Currently only one non-volatile variable store is supported
337 //
338 if (NumEntries != 1) {
339 return EFI_UNSUPPORTED;
340 }
341
342 VariableStoreHeader = (VARIABLE_STORE_HEADER *) (UINTN) (VariableStoreEntry->Base);
343
344 if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {
345 return EFI_UNSUPPORTED;
346 }
347
348 if (~VariableStoreHeader->Size == 0) {
349 return EFI_NOT_FOUND;
350 }
351 //
352 // Find the variable by walk through non-volatile variable store
353 //
354 IndexTable->StartPtr = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
355 IndexTable->EndPtr = (VARIABLE_HEADER *) ((UINTN) VariableStoreHeader + VariableStoreHeader->Size);
356
357 //
358 // Start Pointers for the variable.
359 // Actual Data Pointer where data can be written.
360 //
361 Variable = IndexTable->StartPtr;
362 }
363 }
364 //
365 // Find the variable by walk through non-volatile variable store
366 //
367 PtrTrack->StartPtr = IndexTable->StartPtr;
368 PtrTrack->EndPtr = IndexTable->EndPtr;
369
370 while (IsValidVariableHeader (Variable) && (Variable <= IndexTable->EndPtr)) {
371 if (Variable->State == VAR_ADDED) {
372 //
373 // Record Variable in VariableIndex HOB
374 //
375 if (IndexTable->Length < VARIABLE_INDEX_TABLE_VOLUME)
376 {
377 #if ALIGNMENT <= 1
378 IndexTable->Index[IndexTable->Length++] = (UINT16) (UINTN) Variable;
379 #else
380 #if ALIGNMENT >= 4
381 IndexTable->Index[IndexTable->Length++] = (UINT16) (((UINT32)(UINTN) Variable) >> 2);
382 #endif
383 #endif
384 }
385
386 if (CompareWithValidVariable (Variable, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
387 return EFI_SUCCESS;
388 }
389 }
390
391 Variable = GetNextVariablePtr (Variable);
392 }
393 //
394 // If gone through the VariableStore, that means we never find in Firmware any more.
395 //
396 if (IndexTable->Length < VARIABLE_INDEX_TABLE_VOLUME) {
397 IndexTable->GoneThrough = 1;
398 }
399
400 PtrTrack->CurrPtr = NULL;
401
402 return EFI_NOT_FOUND;
403 }
404
405 EFI_STATUS
406 EFIAPI
407 PeiGetVariable (
408 IN EFI_PEI_SERVICES **PeiServices,
409 IN CHAR16 *VariableName,
410 IN EFI_GUID * VendorGuid,
411 OUT UINT32 *Attributes OPTIONAL,
412 IN OUT UINTN *DataSize,
413 OUT VOID *Data
414 )
415 /*++
416
417 Routine Description:
418
419 Provide the read variable functionality of the variable services.
420
421 Arguments:
422
423 PeiServices - General purpose services available to every PEIM.
424
425 VariableName - The variable name
426
427 VendorGuid - The vendor's GUID
428
429 Attributes - Pointer to the attribute
430
431 DataSize - Size of data
432
433 Data - Pointer to data
434
435 Returns:
436
437 EFI_SUCCESS - The interface could be successfully installed
438
439 EFI_NOT_FOUND - The variable could not be discovered
440
441 EFI_BUFFER_TOO_SMALL - The caller buffer is not large enough
442
443 --*/
444 {
445 VARIABLE_POINTER_TRACK Variable;
446 UINTN VarDataSize;
447 EFI_STATUS Status;
448
449 if (VariableName == NULL || VendorGuid == NULL) {
450 return EFI_INVALID_PARAMETER;
451 }
452 //
453 // Find existing variable
454 //
455 Status = FindVariable (PeiServices, VariableName, VendorGuid, &Variable);
456
457 if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) {
458 return Status;
459 }
460 //
461 // Get data size
462 //
463 VarDataSize = Variable.CurrPtr->DataSize;
464 if (*DataSize >= VarDataSize) {
465 (*PeiServices)->CopyMem (Data, GET_VARIABLE_DATA_PTR (Variable.CurrPtr), VarDataSize);
466
467 if (Attributes != NULL) {
468 *Attributes = Variable.CurrPtr->Attributes;
469 }
470
471 *DataSize = VarDataSize;
472 return EFI_SUCCESS;
473 } else {
474 *DataSize = VarDataSize;
475 return EFI_BUFFER_TOO_SMALL;
476 }
477 }
478
479 EFI_STATUS
480 EFIAPI
481 PeiGetNextVariableName (
482 IN EFI_PEI_SERVICES **PeiServices,
483 IN OUT UINTN *VariableNameSize,
484 IN OUT CHAR16 *VariableName,
485 IN OUT EFI_GUID *VendorGuid
486 )
487 /*++
488
489 Routine Description:
490
491 Provide the get next variable functionality of the variable services.
492
493 Arguments:
494
495 PeiServices - General purpose services available to every PEIM.
496 VariabvleNameSize - The variable name's size.
497 VariableName - A pointer to the variable's name.
498 VendorGuid - A pointer to the EFI_GUID structure.
499
500 VariableNameSize - Size of the variable name
501
502 VariableName - The variable name
503
504 VendorGuid - The vendor's GUID
505
506 Returns:
507
508 EFI_SUCCESS - The interface could be successfully installed
509
510 EFI_NOT_FOUND - The variable could not be discovered
511
512 --*/
513 {
514 VARIABLE_POINTER_TRACK Variable;
515 UINTN VarNameSize;
516 EFI_STATUS Status;
517
518 if (VariableName == NULL) {
519 return EFI_INVALID_PARAMETER;
520 }
521
522 Status = FindVariable (PeiServices, VariableName, VendorGuid, &Variable);
523
524 if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) {
525 return Status;
526 }
527
528 if (VariableName[0] != 0) {
529 //
530 // If variable name is not NULL, get next variable
531 //
532 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
533 }
534
535 while (!(Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL)) {
536 if (IsValidVariableHeader (Variable.CurrPtr)) {
537 if (Variable.CurrPtr->State == VAR_ADDED) {
538 VarNameSize = (UINTN) Variable.CurrPtr->NameSize;
539 if (VarNameSize <= *VariableNameSize) {
540 (*PeiServices)->CopyMem (VariableName, GET_VARIABLE_NAME_PTR (Variable.CurrPtr), VarNameSize);
541
542 (*PeiServices)->CopyMem (VendorGuid, &Variable.CurrPtr->VendorGuid, sizeof (EFI_GUID));
543
544 Status = EFI_SUCCESS;
545 } else {
546 Status = EFI_BUFFER_TOO_SMALL;
547 }
548
549 *VariableNameSize = VarNameSize;
550 return Status;
551 //
552 // Variable is found
553 //
554 } else {
555 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
556 }
557 } else {
558 break;
559 }
560 }
561
562 return EFI_NOT_FOUND;
563 }