git-svn-id: https://edk2.svn.sourceforge.net/svnroot/edk2/trunk/edk2@1082 6f19259b...
[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 EFI_HOB_GUID_TYPE *GuidHob;
249 VARIABLE_STORE_HEADER *VariableStoreHeader;
250 VARIABLE_HEADER *Variable;
251 VARIABLE_HEADER *MaxIndex;
252 VARIABLE_INDEX_TABLE *IndexTable;
253 UINT32 Count;
254 UINT8 *VariableBase;
255
256 if (VariableName != 0 && VendorGuid == NULL) {
257 return EFI_INVALID_PARAMETER;
258 }
259 //
260 // No Variable Address equals zero, so 0 as initial value is safe.
261 //
262 MaxIndex = 0;
263
264 GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);
265 if (GuidHob == NULL) {
266 IndexTable = BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));
267 IndexTable->Length = 0;
268 IndexTable->StartPtr = NULL;
269 IndexTable->EndPtr = NULL;
270 IndexTable->GoneThrough = 0;
271 } else {
272 IndexTable = GET_GUID_HOB_DATA (GuidHob);
273 for (Count = 0; Count < IndexTable->Length; Count++)
274 {
275 #if ALIGNMENT <= 1
276 MaxIndex = (VARIABLE_HEADER *) (UINTN) (IndexTable->Index[Count] + ((UINTN) IndexTable->StartPtr & 0xFFFF0000));
277 #else
278 #if ALIGNMENT >= 4
279 MaxIndex = (VARIABLE_HEADER *) (UINTN) ((((UINT32)IndexTable->Index[Count]) << 2) + ((UINT32)(UINTN)IndexTable->StartPtr & 0xFFFC0000) );
280 #endif
281 #endif
282 if (CompareWithValidVariable (MaxIndex, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
283 PtrTrack->StartPtr = IndexTable->StartPtr;
284 PtrTrack->EndPtr = IndexTable->EndPtr;
285
286 return EFI_SUCCESS;
287 }
288 }
289
290 if (IndexTable->GoneThrough) {
291 return EFI_NOT_FOUND;
292 }
293 }
294 //
295 // If not found in HOB, then let's start from the MaxIndex we've found.
296 //
297 if (MaxIndex != NULL) {
298 Variable = GetNextVariablePtr (MaxIndex);
299 } else {
300 if (IndexTable->StartPtr || IndexTable->EndPtr) {
301 Variable = IndexTable->StartPtr;
302 } else {
303 VariableBase = (UINT8 *) (UINTN) PcdGet32 (PcdFlashNvStorageVariableBase);
304 VariableStoreHeader = (VARIABLE_STORE_HEADER *) (VariableBase + \
305 ((EFI_FIRMWARE_VOLUME_HEADER *) (VariableBase)) -> HeaderLength);
306
307 if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {
308 return EFI_UNSUPPORTED;
309 }
310
311 if (~VariableStoreHeader->Size == 0) {
312 return EFI_NOT_FOUND;
313 }
314 //
315 // Find the variable by walk through non-volatile variable store
316 //
317 IndexTable->StartPtr = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
318 IndexTable->EndPtr = (VARIABLE_HEADER *) ((UINTN) VariableStoreHeader + VariableStoreHeader->Size);
319
320 //
321 // Start Pointers for the variable.
322 // Actual Data Pointer where data can be written.
323 //
324 Variable = IndexTable->StartPtr;
325 }
326 }
327 //
328 // Find the variable by walk through non-volatile variable store
329 //
330 PtrTrack->StartPtr = IndexTable->StartPtr;
331 PtrTrack->EndPtr = IndexTable->EndPtr;
332
333 while (IsValidVariableHeader (Variable) && (Variable <= IndexTable->EndPtr)) {
334 if (Variable->State == VAR_ADDED) {
335 //
336 // Record Variable in VariableIndex HOB
337 //
338 if (IndexTable->Length < VARIABLE_INDEX_TABLE_VOLUME)
339 {
340 #if ALIGNMENT <= 1
341 IndexTable->Index[IndexTable->Length++] = (UINT16) (UINTN) Variable;
342 #else
343 #if ALIGNMENT >= 4
344 IndexTable->Index[IndexTable->Length++] = (UINT16) (((UINT32)(UINTN) Variable) >> 2);
345 #endif
346 #endif
347 }
348
349 if (CompareWithValidVariable (Variable, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
350 return EFI_SUCCESS;
351 }
352 }
353
354 Variable = GetNextVariablePtr (Variable);
355 }
356 //
357 // If gone through the VariableStore, that means we never find in Firmware any more.
358 //
359 if (IndexTable->Length < VARIABLE_INDEX_TABLE_VOLUME) {
360 IndexTable->GoneThrough = 1;
361 }
362
363 PtrTrack->CurrPtr = NULL;
364
365 return EFI_NOT_FOUND;
366 }
367
368 EFI_STATUS
369 EFIAPI
370 PeiGetVariable (
371 IN EFI_PEI_SERVICES **PeiServices,
372 IN CHAR16 *VariableName,
373 IN EFI_GUID * VendorGuid,
374 OUT UINT32 *Attributes OPTIONAL,
375 IN OUT UINTN *DataSize,
376 OUT VOID *Data
377 )
378 /*++
379
380 Routine Description:
381
382 Provide the read variable functionality of the variable services.
383
384 Arguments:
385
386 PeiServices - General purpose services available to every PEIM.
387
388 VariableName - The variable name
389
390 VendorGuid - The vendor's GUID
391
392 Attributes - Pointer to the attribute
393
394 DataSize - Size of data
395
396 Data - Pointer to data
397
398 Returns:
399
400 EFI_SUCCESS - The interface could be successfully installed
401
402 EFI_NOT_FOUND - The variable could not be discovered
403
404 EFI_BUFFER_TOO_SMALL - The caller buffer is not large enough
405
406 --*/
407 {
408 VARIABLE_POINTER_TRACK Variable;
409 UINTN VarDataSize;
410 EFI_STATUS Status;
411
412 if (VariableName == NULL || VendorGuid == NULL) {
413 return EFI_INVALID_PARAMETER;
414 }
415 //
416 // Find existing variable
417 //
418 Status = FindVariable (PeiServices, VariableName, VendorGuid, &Variable);
419
420 if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) {
421 return Status;
422 }
423 //
424 // Get data size
425 //
426 VarDataSize = Variable.CurrPtr->DataSize;
427 if (*DataSize >= VarDataSize) {
428 (*PeiServices)->CopyMem (Data, GET_VARIABLE_DATA_PTR (Variable.CurrPtr), VarDataSize);
429
430 if (Attributes != NULL) {
431 *Attributes = Variable.CurrPtr->Attributes;
432 }
433
434 *DataSize = VarDataSize;
435 return EFI_SUCCESS;
436 } else {
437 *DataSize = VarDataSize;
438 return EFI_BUFFER_TOO_SMALL;
439 }
440 }
441
442 EFI_STATUS
443 EFIAPI
444 PeiGetNextVariableName (
445 IN EFI_PEI_SERVICES **PeiServices,
446 IN OUT UINTN *VariableNameSize,
447 IN OUT CHAR16 *VariableName,
448 IN OUT EFI_GUID *VendorGuid
449 )
450 /*++
451
452 Routine Description:
453
454 Provide the get next variable functionality of the variable services.
455
456 Arguments:
457
458 PeiServices - General purpose services available to every PEIM.
459 VariabvleNameSize - The variable name's size.
460 VariableName - A pointer to the variable's name.
461 VendorGuid - A pointer to the EFI_GUID structure.
462
463 VariableNameSize - Size of the variable name
464
465 VariableName - The variable name
466
467 VendorGuid - The vendor's GUID
468
469 Returns:
470
471 EFI_SUCCESS - The interface could be successfully installed
472
473 EFI_NOT_FOUND - The variable could not be discovered
474
475 --*/
476 {
477 VARIABLE_POINTER_TRACK Variable;
478 UINTN VarNameSize;
479 EFI_STATUS Status;
480
481 if (VariableName == NULL) {
482 return EFI_INVALID_PARAMETER;
483 }
484
485 Status = FindVariable (PeiServices, VariableName, VendorGuid, &Variable);
486
487 if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) {
488 return Status;
489 }
490
491 if (VariableName[0] != 0) {
492 //
493 // If variable name is not NULL, get next variable
494 //
495 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
496 }
497
498 while (!(Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL)) {
499 if (IsValidVariableHeader (Variable.CurrPtr)) {
500 if (Variable.CurrPtr->State == VAR_ADDED) {
501 VarNameSize = (UINTN) Variable.CurrPtr->NameSize;
502 if (VarNameSize <= *VariableNameSize) {
503 (*PeiServices)->CopyMem (VariableName, GET_VARIABLE_NAME_PTR (Variable.CurrPtr), VarNameSize);
504
505 (*PeiServices)->CopyMem (VendorGuid, &Variable.CurrPtr->VendorGuid, sizeof (EFI_GUID));
506
507 Status = EFI_SUCCESS;
508 } else {
509 Status = EFI_BUFFER_TOO_SMALL;
510 }
511
512 *VariableNameSize = VarNameSize;
513 return Status;
514 //
515 // Variable is found
516 //
517 } else {
518 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
519 }
520 } else {
521 break;
522 }
523 }
524
525 return EFI_NOT_FOUND;
526 }