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