]> git.proxmox.com Git - mirror_edk2.git/blob - EdkModulePkg/Universal/Variable/Pei/Variable.c
06604195478b1ad29480d0b9754117815f6cccd9
[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 Module Name:
12
13 Variable.c
14
15 Abstract:
16
17 Framework PEIM to provide the Variable functionality
18
19 --*/
20
21 #include <Variable.h>
22
23 //
24 // Module globals
25 //
26 static EFI_PEI_READ_ONLY_VARIABLE_PPI mVariablePpi = {
27 PeiGetVariable,
28 PeiGetNextVariableName
29 };
30
31 static EFI_PEI_PPI_DESCRIPTOR mPpiListVariable = {
32 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
33 &gEfiPeiReadOnlyVariablePpiGuid,
34 &mVariablePpi
35 };
36
37 EFI_GUID gEfiVariableIndexTableGuid = EFI_VARIABLE_INDEX_TABLE_GUID;
38
39 EFI_STATUS
40 EFIAPI
41 PeimInitializeVariableServices (
42 IN EFI_FFS_FILE_HEADER *FfsHeader,
43 IN EFI_PEI_SERVICES **PeiServices
44 )
45 /*++
46
47 Routine Description:
48
49 Provide the functionality of the variable services.
50
51 Arguments:
52
53 FfsHeadher - The FFS file header
54 PeiServices - General purpose services available to every PEIM.
55
56 Returns:
57
58 Status - EFI_SUCCESS if the interface could be successfully
59 installed
60
61 --*/
62 {
63 //
64 // Publish the variable capability to other modules
65 //
66 return (**PeiServices).InstallPpi (PeiServices, &mPpiListVariable);
67
68 }
69
70 STATIC
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 STATIC
94 BOOLEAN
95 EFIAPI
96 IsValidVariableHeader (
97 IN VARIABLE_HEADER *Variable
98 )
99 /*++
100
101 Routine Description:
102
103 This code checks if variable header is valid or not.
104
105 Arguments:
106 Variable Pointer to the Variable Header.
107
108 Returns:
109 TRUE Variable header is valid.
110 FALSE Variable header is not valid.
111
112 --*/
113 {
114 if (Variable == NULL ||
115 Variable->StartId != VARIABLE_DATA ||
116 (sizeof (VARIABLE_HEADER) + Variable->DataSize + Variable->NameSize) > MAX_VARIABLE_SIZE
117 ) {
118 return FALSE;
119 }
120
121 return TRUE;
122 }
123
124 STATIC
125 VARIABLE_STORE_STATUS
126 EFIAPI
127 GetVariableStoreStatus (
128 IN VARIABLE_STORE_HEADER *VarStoreHeader
129 )
130 /*++
131
132 Routine Description:
133
134 This code gets the pointer to the variable name.
135
136 Arguments:
137
138 VarStoreHeader Pointer to the Variable Store Header.
139
140 Returns:
141
142 EfiRaw Variable store is raw
143 EfiValid Variable store is valid
144 EfiInvalid Variable store is invalid
145
146 --*/
147 {
148 if (VarStoreHeader->Signature == VARIABLE_STORE_SIGNATURE &&
149 VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&
150 VarStoreHeader->State == VARIABLE_STORE_HEALTHY
151 ) {
152
153 return EfiValid;
154 }
155
156 if (VarStoreHeader->Signature == 0xffffffff &&
157 VarStoreHeader->Size == 0xffffffff &&
158 VarStoreHeader->Format == 0xff &&
159 VarStoreHeader->State == 0xff
160 ) {
161
162 return EfiRaw;
163 } else {
164 return EfiInvalid;
165 }
166 }
167
168 STATIC
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 (!CompareMem (VariableName, GET_VARIABLE_NAME_PTR (Variable), Variable->NameSize)) {
212 PtrTrack->CurrPtr = Variable;
213 return EFI_SUCCESS;
214 }
215 }
216 }
217
218 return EFI_NOT_FOUND;
219 }
220
221 STATIC
222 EFI_STATUS
223 EFIAPI
224 FindVariable (
225 IN EFI_PEI_SERVICES **PeiServices,
226 IN CHAR16 *VariableName,
227 IN EFI_GUID *VendorGuid,
228 OUT VARIABLE_POINTER_TRACK *PtrTrack
229 )
230 /*++
231
232 Routine Description:
233
234 This code finds variable in storage blocks (Non-Volatile)
235
236 Arguments:
237
238 PeiServices - General purpose services available to every PEIM.
239 VariableName - Name of the variable to be found
240 VendorGuid - Vendor GUID to be found.
241 PtrTrack - Variable Track Pointer structure that contains
242 Variable Information.
243
244 Returns:
245
246 EFI_SUCCESS - Variable found successfully
247 EFI_NOT_FOUND - Variable not found
248 EFI_INVALID_PARAMETER - Invalid variable name
249
250 --*/
251 {
252 EFI_HOB_GUID_TYPE *GuidHob;
253 VARIABLE_STORE_HEADER *VariableStoreHeader;
254 VARIABLE_HEADER *Variable;
255 VARIABLE_HEADER *MaxIndex;
256 VARIABLE_INDEX_TABLE *IndexTable;
257 UINT32 Count;
258 UINT8 *VariableBase;
259
260 if (VariableName != 0 && VendorGuid == NULL) {
261 return EFI_INVALID_PARAMETER;
262 }
263 //
264 // No Variable Address equals zero, so 0 as initial value is safe.
265 //
266 MaxIndex = 0;
267
268 GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);
269 if (GuidHob == NULL) {
270 IndexTable = BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));
271 IndexTable->Length = 0;
272 IndexTable->StartPtr = NULL;
273 IndexTable->EndPtr = NULL;
274 IndexTable->GoneThrough = 0;
275 } else {
276 IndexTable = GET_GUID_HOB_DATA (GuidHob);
277 for (Count = 0; Count < IndexTable->Length; Count++)
278 {
279 MaxIndex = GetVariableByIndex (IndexTable, Count);
280
281 if (CompareWithValidVariable (MaxIndex, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
282 PtrTrack->StartPtr = IndexTable->StartPtr;
283 PtrTrack->EndPtr = IndexTable->EndPtr;
284
285 return EFI_SUCCESS;
286 }
287 }
288
289 if (IndexTable->GoneThrough) {
290 return EFI_NOT_FOUND;
291 }
292 }
293 //
294 // If not found in HOB, then let's start from the MaxIndex we've found.
295 //
296 if (MaxIndex != NULL) {
297 Variable = GetNextVariablePtr (MaxIndex);
298 } else {
299 if (IndexTable->StartPtr || IndexTable->EndPtr) {
300 Variable = IndexTable->StartPtr;
301 } else {
302 VariableBase = (UINT8 *) (UINTN) PcdGet32 (PcdFlashNvStorageVariableBase);
303 VariableStoreHeader = (VARIABLE_STORE_HEADER *) (VariableBase + \
304 ((EFI_FIRMWARE_VOLUME_HEADER *) (VariableBase)) -> HeaderLength);
305
306 if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {
307 return EFI_UNSUPPORTED;
308 }
309
310 if (~VariableStoreHeader->Size == 0) {
311 return EFI_NOT_FOUND;
312 }
313 //
314 // Find the variable by walk through non-volatile variable store
315 //
316 IndexTable->StartPtr = (VARIABLE_HEADER *) (VariableStoreHeader + 1);
317 IndexTable->EndPtr = (VARIABLE_HEADER *) ((UINTN) VariableStoreHeader + VariableStoreHeader->Size);
318
319 //
320 // Start Pointers for the variable.
321 // Actual Data Pointer where data can be written.
322 //
323 Variable = IndexTable->StartPtr;
324 }
325 }
326 //
327 // Find the variable by walk through non-volatile variable store
328 //
329 PtrTrack->StartPtr = IndexTable->StartPtr;
330 PtrTrack->EndPtr = IndexTable->EndPtr;
331
332 while (IsValidVariableHeader (Variable) && (Variable <= IndexTable->EndPtr)) {
333 if (Variable->State == VAR_ADDED) {
334 //
335 // Record Variable in VariableIndex HOB
336 //
337 if (IndexTable->Length < VARIABLE_INDEX_TABLE_VOLUME)
338 {
339 VariableIndexTableUpdate (IndexTable, Variable);
340 }
341
342 if (CompareWithValidVariable (Variable, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {
343 return EFI_SUCCESS;
344 }
345 }
346
347 Variable = GetNextVariablePtr (Variable);
348 }
349 //
350 // If gone through the VariableStore, that means we never find in Firmware any more.
351 //
352 if (IndexTable->Length < VARIABLE_INDEX_TABLE_VOLUME) {
353 IndexTable->GoneThrough = 1;
354 }
355
356 PtrTrack->CurrPtr = NULL;
357
358 return EFI_NOT_FOUND;
359 }
360
361 EFI_STATUS
362 EFIAPI
363 PeiGetVariable (
364 IN EFI_PEI_SERVICES **PeiServices,
365 IN CHAR16 *VariableName,
366 IN EFI_GUID * VendorGuid,
367 OUT UINT32 *Attributes OPTIONAL,
368 IN OUT UINTN *DataSize,
369 OUT VOID *Data
370 )
371 /*++
372
373 Routine Description:
374
375 Provide the read variable functionality of the variable services.
376
377 Arguments:
378
379 PeiServices - General purpose services available to every PEIM.
380
381 VariableName - The variable name
382
383 VendorGuid - The vendor's GUID
384
385 Attributes - Pointer to the attribute
386
387 DataSize - Size of data
388
389 Data - Pointer to data
390
391 Returns:
392
393 EFI_SUCCESS - The interface could be successfully installed
394
395 EFI_NOT_FOUND - The variable could not be discovered
396
397 EFI_BUFFER_TOO_SMALL - The caller buffer is not large enough
398
399 --*/
400 {
401 VARIABLE_POINTER_TRACK Variable;
402 UINTN VarDataSize;
403 EFI_STATUS Status;
404
405 if (VariableName == NULL || VendorGuid == NULL) {
406 return EFI_INVALID_PARAMETER;
407 }
408 //
409 // Find existing variable
410 //
411 Status = FindVariable (PeiServices, VariableName, VendorGuid, &Variable);
412
413 if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) {
414 return Status;
415 }
416 //
417 // Get data size
418 //
419 VarDataSize = Variable.CurrPtr->DataSize;
420 if (*DataSize >= VarDataSize) {
421 (*PeiServices)->CopyMem (Data, GET_VARIABLE_DATA_PTR (Variable.CurrPtr), VarDataSize);
422
423 if (Attributes != NULL) {
424 *Attributes = Variable.CurrPtr->Attributes;
425 }
426
427 *DataSize = VarDataSize;
428 return EFI_SUCCESS;
429 } else {
430 *DataSize = VarDataSize;
431 return EFI_BUFFER_TOO_SMALL;
432 }
433 }
434
435 EFI_STATUS
436 EFIAPI
437 PeiGetNextVariableName (
438 IN EFI_PEI_SERVICES **PeiServices,
439 IN OUT UINTN *VariableNameSize,
440 IN OUT CHAR16 *VariableName,
441 IN OUT EFI_GUID *VendorGuid
442 )
443 /*++
444
445 Routine Description:
446
447 Provide the get next variable functionality of the variable services.
448
449 Arguments:
450
451 PeiServices - General purpose services available to every PEIM.
452 VariabvleNameSize - The variable name's size.
453 VariableName - A pointer to the variable's name.
454 VendorGuid - A pointer to the EFI_GUID structure.
455
456 VariableNameSize - Size of the variable name
457
458 VariableName - The variable name
459
460 VendorGuid - The vendor's GUID
461
462 Returns:
463
464 EFI_SUCCESS - The interface could be successfully installed
465
466 EFI_NOT_FOUND - The variable could not be discovered
467
468 --*/
469 {
470 VARIABLE_POINTER_TRACK Variable;
471 UINTN VarNameSize;
472 EFI_STATUS Status;
473
474 if (VariableName == NULL) {
475 return EFI_INVALID_PARAMETER;
476 }
477
478 Status = FindVariable (PeiServices, VariableName, VendorGuid, &Variable);
479
480 if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) {
481 return Status;
482 }
483
484 if (VariableName[0] != 0) {
485 //
486 // If variable name is not NULL, get next variable
487 //
488 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
489 }
490
491 while (!(Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL)) {
492 if (IsValidVariableHeader (Variable.CurrPtr)) {
493 if (Variable.CurrPtr->State == VAR_ADDED) {
494 VarNameSize = (UINTN) Variable.CurrPtr->NameSize;
495 if (VarNameSize <= *VariableNameSize) {
496 (*PeiServices)->CopyMem (VariableName, GET_VARIABLE_NAME_PTR (Variable.CurrPtr), VarNameSize);
497
498 (*PeiServices)->CopyMem (VendorGuid, &Variable.CurrPtr->VendorGuid, sizeof (EFI_GUID));
499
500 Status = EFI_SUCCESS;
501 } else {
502 Status = EFI_BUFFER_TOO_SMALL;
503 }
504
505 *VariableNameSize = VarNameSize;
506 return Status;
507 //
508 // Variable is found
509 //
510 } else {
511 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);
512 }
513 } else {
514 break;
515 }
516 }
517
518 return EFI_NOT_FOUND;
519 }