33772f8513ddb1ff3564deeee9d0ab7866090033
[mirror_edk2.git] / EdkModulePkg / Universal / Variable / Pei / Variable.c
1 /*++
2
3 Copyright (c) 2006 - 2007 Intel Corporation. <BR>
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 STATIC
72 VARIABLE_HEADER *
73 GetNextVariablePtr (
74 IN VARIABLE_HEADER *Variable
75 )
76 /*++
77
78 Routine Description:
79
80 This code checks if variable header is valid or not.
81
82 Arguments:
83 Variable Pointer to the Variable Header.
84
85 Returns:
86 TRUE Variable header is valid.
87 FALSE Variable header is not valid.
88
89 --*/
90 {
91 return (VARIABLE_HEADER *) ((UINTN) GET_VARIABLE_DATA_PTR (Variable) + Variable->DataSize + GET_PAD_SIZE (Variable->DataSize));
92 }
93
94 STATIC
95 BOOLEAN
96 EFIAPI
97 IsValidVariableHeader (
98 IN VARIABLE_HEADER *Variable
99 )
100 /*++
101
102 Routine Description:
103
104 This code checks if variable header is valid or not.
105
106 Arguments:
107 Variable Pointer to the Variable Header.
108
109 Returns:
110 TRUE Variable header is valid.
111 FALSE Variable header is not valid.
112
113 --*/
114 {
115 if (Variable == NULL ||
116 Variable->StartId != VARIABLE_DATA ||
117 (sizeof (VARIABLE_HEADER) + Variable->DataSize + Variable->NameSize) > MAX_VARIABLE_SIZE
118 ) {
119 return FALSE;
120 }
121
122 return TRUE;
123 }
124
125 STATIC
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 STATIC
170 EFI_STATUS
171 CompareWithValidVariable (
172 IN VARIABLE_HEADER *Variable,
173 IN CHAR16 *VariableName,
174 IN EFI_GUID *VendorGuid,
175 OUT VARIABLE_POINTER_TRACK *PtrTrack
176 )
177 /*++
178
179 Routine Description:
180
181 This function compares a variable with variable entries in database
182
183 Arguments:
184
185 Variable - Pointer to the variable in our database
186 VariableName - Name of the variable to compare to 'Variable'
187 VendorGuid - GUID of the variable to compare to 'Variable'
188 PtrTrack - Variable Track Pointer structure that contains
189 Variable Information.
190
191 Returns:
192
193 EFI_SUCCESS - Found match variable
194 EFI_NOT_FOUND - Variable not found
195
196 --*/
197 {
198 if (VariableName[0] == 0) {
199 PtrTrack->CurrPtr = Variable;
200 return EFI_SUCCESS;
201 } else {
202 //
203 // Don't use CompareGuid function here for performance reasons.
204 // Instead we compare the GUID a UINT32 at a time and branch
205 // on the first failed comparison.
206 //
207 if ((((INT32 *) VendorGuid)[0] == ((INT32 *) &Variable->VendorGuid)[0]) &&
208 (((INT32 *) VendorGuid)[1] == ((INT32 *) &Variable->VendorGuid)[1]) &&
209 (((INT32 *) VendorGuid)[2] == ((INT32 *) &Variable->VendorGuid)[2]) &&
210 (((INT32 *) VendorGuid)[3] == ((INT32 *) &Variable->VendorGuid)[3])
211 ) {
212 if (!CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable), Variable->NameSize)) {
213 PtrTrack->CurrPtr = Variable;
214 return EFI_SUCCESS;
215 }
216 }
217 }
218
219 return EFI_NOT_FOUND;
220 }
221
222 STATIC
223 EFI_STATUS
224 EFIAPI
225 FindVariable (
226 IN EFI_PEI_SERVICES **PeiServices,
227 IN CHAR16 *VariableName,
228 IN EFI_GUID *VendorGuid,
229 OUT VARIABLE_POINTER_TRACK *PtrTrack
230 )
231 /*++
232
233 Routine Description:
234
235 This code finds variable in storage blocks (Non-Volatile)
236
237 Arguments:
238
239 PeiServices - General purpose services available to every PEIM.
240 VariableName - Name of the variable to be found
241 VendorGuid - Vendor GUID to be found.
242 PtrTrack - Variable Track Pointer structure that contains
243 Variable Information.
244
245 Returns:
246
247 EFI_SUCCESS - Variable found successfully
248 EFI_NOT_FOUND - Variable not found
249 EFI_INVALID_PARAMETER - Invalid variable name
250
251 --*/
252 {
253 EFI_HOB_GUID_TYPE *GuidHob;
254 VARIABLE_STORE_HEADER *VariableStoreHeader;
255 VARIABLE_HEADER *Variable;
256 VARIABLE_HEADER *MaxIndex;
257 VARIABLE_INDEX_TABLE *IndexTable;
258 UINT32 Count;
259 UINT8 *VariableBase;
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 VariableBase = (UINT8 *) (UINTN) PcdGet32 (PcdFlashNvStorageVariableBase);
309 VariableStoreHeader = (VARIABLE_STORE_HEADER *) (VariableBase + \
310 ((EFI_FIRMWARE_VOLUME_HEADER *) (VariableBase)) -> HeaderLength);
311
312 if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {
313 return EFI_UNSUPPORTED;
314 }
315
316 if (~VariableStoreHeader->Size == 0) {
317 return EFI_NOT_FOUND;
318 }
319 //
320 // Find the variable by walk through non-volatile variable store
321 //
322 IndexTable->StartPtr = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
323 IndexTable->EndPtr = (VARIABLE_HEADER *) ((UINTN) VariableStoreHeader + VariableStoreHeader->Size);
324
325 //
326 // Start Pointers for the variable.
327 // Actual Data Pointer where data can be written.
328 //
329 Variable = IndexTable->StartPtr;
330 }
331 }
332 //
333 // Find the variable by walk through non-volatile variable store
334 //
335 PtrTrack->StartPtr = IndexTable->StartPtr;
336 PtrTrack->EndPtr = IndexTable->EndPtr;
337
338 while (IsValidVariableHeader (Variable) && (Variable <= IndexTable->EndPtr)) {
339 if (Variable->State == VAR_ADDED) {
340 //
341 // Record Variable in VariableIndex HOB
342 //
343 if (IndexTable->Length < VARIABLE_INDEX_TABLE_VOLUME)
344 {
345 #if ALIGNMENT <= 1
346 IndexTable->Index[IndexTable->Length++] = (UINT16) (UINTN) Variable;
347 #else
348 #if ALIGNMENT >= 4
349 IndexTable->Index[IndexTable->Length++] = (UINT16) (((UINT32)(UINTN) Variable) >> 2);
350 #endif
351 #endif
352 }
353
354 if (CompareWithValidVariable (Variable, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
355 return EFI_SUCCESS;
356 }
357 }
358
359 Variable = GetNextVariablePtr (Variable);
360 }
361 //
362 // If gone through the VariableStore, that means we never find in Firmware any more.
363 //
364 if (IndexTable->Length < VARIABLE_INDEX_TABLE_VOLUME) {
365 IndexTable->GoneThrough = 1;
366 }
367
368 PtrTrack->CurrPtr = NULL;
369
370 return EFI_NOT_FOUND;
371 }
372
373 EFI_STATUS
374 EFIAPI
375 PeiGetVariable (
376 IN EFI_PEI_SERVICES **PeiServices,
377 IN CHAR16 *VariableName,
378 IN EFI_GUID * VendorGuid,
379 OUT UINT32 *Attributes OPTIONAL,
380 IN OUT UINTN *DataSize,
381 OUT VOID *Data
382 )
383 /*++
384
385 Routine Description:
386
387 Provide the read variable functionality of the variable services.
388
389 Arguments:
390
391 PeiServices - General purpose services available to every PEIM.
392
393 VariableName - The variable name
394
395 VendorGuid - The vendor's GUID
396
397 Attributes - Pointer to the attribute
398
399 DataSize - Size of data
400
401 Data - Pointer to data
402
403 Returns:
404
405 EFI_SUCCESS - The interface could be successfully installed
406
407 EFI_NOT_FOUND - The variable could not be discovered
408
409 EFI_BUFFER_TOO_SMALL - The caller buffer is not large enough
410
411 --*/
412 {
413 VARIABLE_POINTER_TRACK Variable;
414 UINTN VarDataSize;
415 EFI_STATUS Status;
416
417 if (VariableName == NULL || VendorGuid == NULL) {
418 return EFI_INVALID_PARAMETER;
419 }
420 //
421 // Find existing variable
422 //
423 Status = FindVariable (PeiServices, VariableName, VendorGuid, &Variable);
424
425 if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) {
426 return Status;
427 }
428 //
429 // Get data size
430 //
431 VarDataSize = Variable.CurrPtr->DataSize;
432 if (*DataSize >= VarDataSize) {
433 (*PeiServices)->CopyMem (Data, GET_VARIABLE_DATA_PTR (Variable.CurrPtr), VarDataSize);
434
435 if (Attributes != NULL) {
436 *Attributes = Variable.CurrPtr->Attributes;
437 }
438
439 *DataSize = VarDataSize;
440 return EFI_SUCCESS;
441 } else {
442 *DataSize = VarDataSize;
443 return EFI_BUFFER_TOO_SMALL;
444 }
445 }
446
447 EFI_STATUS
448 EFIAPI
449 PeiGetNextVariableName (
450 IN EFI_PEI_SERVICES **PeiServices,
451 IN OUT UINTN *VariableNameSize,
452 IN OUT CHAR16 *VariableName,
453 IN OUT EFI_GUID *VendorGuid
454 )
455 /*++
456
457 Routine Description:
458
459 Provide the get next variable functionality of the variable services.
460
461 Arguments:
462
463 PeiServices - General purpose services available to every PEIM.
464 VariabvleNameSize - The variable name's size.
465 VariableName - A pointer to the variable's name.
466 VendorGuid - A pointer to the EFI_GUID structure.
467
468 VariableNameSize - Size of the variable name
469
470 VariableName - The variable name
471
472 VendorGuid - The vendor's GUID
473
474 Returns:
475
476 EFI_SUCCESS - The interface could be successfully installed
477
478 EFI_NOT_FOUND - The variable could not be discovered
479
480 --*/
481 {
482 VARIABLE_POINTER_TRACK Variable;
483 UINTN VarNameSize;
484 EFI_STATUS Status;
485
486 if (VariableName == NULL) {
487 return EFI_INVALID_PARAMETER;
488 }
489
490 Status = FindVariable (PeiServices, VariableName, VendorGuid, &Variable);
491
492 if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) {
493 return Status;
494 }
495
496 if (VariableName[0] != 0) {
497 //
498 // If variable name is not NULL, get next variable
499 //
500 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
501 }
502
503 while (!(Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL)) {
504 if (IsValidVariableHeader (Variable.CurrPtr)) {
505 if (Variable.CurrPtr->State == VAR_ADDED) {
506 VarNameSize = (UINTN) Variable.CurrPtr->NameSize;
507 if (VarNameSize <= *VariableNameSize) {
508 (*PeiServices)->CopyMem (VariableName, GET_VARIABLE_NAME_PTR (Variable.CurrPtr), VarNameSize);
509
510 (*PeiServices)->CopyMem (VendorGuid, &Variable.CurrPtr->VendorGuid, sizeof (EFI_GUID));
511
512 Status = EFI_SUCCESS;
513 } else {
514 Status = EFI_BUFFER_TOO_SMALL;
515 }
516
517 *VariableNameSize = VarNameSize;
518 return Status;
519 //
520 // Variable is found
521 //
522 } else {
523 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
524 }
525 } else {
526 break;
527 }
528 }
529
530 return EFI_NOT_FOUND;
531 }