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