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