]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/VariableAuthenticated/Pei/Variable.c
Add security package to repository.
[mirror_edk2.git] / SecurityPkg / VariableAuthenticated / Pei / Variable.c
CommitLineData
0c18794e 1/** @file\r
2 Implement ReadOnly Variable Services required by PEIM and install PEI\r
3 ReadOnly Varaiable2 PPI. These services operates the non-volatile \r
4 storage space.\r
5\r
6Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>\r
7This program and the accompanying materials \r
8are licensed and made available under the terms and conditions of the BSD License \r
9which accompanies this distribution. The full text of the license may be found at \r
10http://opensource.org/licenses/bsd-license.php\r
11\r
12THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, \r
13WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17\r
18#include "Variable.h"\r
19\r
20//\r
21// Module globals\r
22//\r
23EFI_PEI_READ_ONLY_VARIABLE2_PPI mVariablePpi = {\r
24 PeiGetVariable,\r
25 PeiGetNextVariableName\r
26};\r
27\r
28EFI_PEI_PPI_DESCRIPTOR mPpiListVariable = {\r
29 (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),\r
30 &gEfiPeiReadOnlyVariable2PpiGuid,\r
31 &mVariablePpi\r
32};\r
33\r
34\r
35/**\r
36 Provide the functionality of the variable services.\r
37 \r
38 @param FileHandle Handle of the file being invoked. \r
39 Type EFI_PEI_FILE_HANDLE is defined in FfsFindNextFile().\r
40 @param PeiServices General purpose services available to every PEIM.\r
41\r
42 @retval EFI_SUCCESS If the interface could be successfully installed\r
43 @retval Others Returned from PeiServicesInstallPpi()\r
44\r
45**/\r
46EFI_STATUS\r
47EFIAPI\r
48PeimInitializeVariableServices (\r
49 IN EFI_PEI_FILE_HANDLE FileHandle,\r
50 IN CONST EFI_PEI_SERVICES **PeiServices\r
51 )\r
52{\r
53 EFI_BOOT_MODE BootMode;\r
54 EFI_STATUS Status;\r
55\r
56 //\r
57 // Check if this is recovery boot path. If no, publish the variable access capability\r
58 // to other modules. If yes, the content of variable area is not reliable. Therefore,\r
59 // in this case we should not provide variable service to other pei modules. \r
60 // \r
61 Status = (*PeiServices)->GetBootMode (PeiServices, &BootMode);\r
62 ASSERT_EFI_ERROR (Status);\r
63 \r
64 if (BootMode == BOOT_IN_RECOVERY_MODE) {\r
65 return EFI_UNSUPPORTED;\r
66 }\r
67\r
68 return PeiServicesInstallPpi (&mPpiListVariable);\r
69\r
70}\r
71\r
72/**\r
73\r
74 Gets the pointer to the first variable header in given variable store area.\r
75\r
76 @param VarStoreHeader Pointer to the Variable Store Header.\r
77\r
78 @return Pointer to the first variable header\r
79\r
80**/\r
81VARIABLE_HEADER *\r
82GetStartPointer (\r
83 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
84 )\r
85{\r
86 //\r
87 // The end of variable store\r
88 //\r
89 return (VARIABLE_HEADER *) HEADER_ALIGN (VarStoreHeader + 1);\r
90}\r
91\r
92\r
93/**\r
94 This code gets the pointer to the last variable memory pointer byte.\r
95\r
96 @param VarStoreHeader Pointer to the Variable Store Header.\r
97\r
98 @return VARIABLE_HEADER* pointer to last unavailable Variable Header.\r
99\r
100**/\r
101VARIABLE_HEADER *\r
102GetEndPointer (\r
103 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
104 )\r
105{\r
106 //\r
107 // The end of variable store\r
108 //\r
109 return (VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) VarStoreHeader + VarStoreHeader->Size);\r
110}\r
111\r
112\r
113/**\r
114 This code checks if variable header is valid or not.\r
115\r
116 @param Variable Pointer to the Variable Header.\r
117\r
118 @retval TRUE Variable header is valid.\r
119 @retval FALSE Variable header is not valid.\r
120\r
121**/\r
122BOOLEAN\r
123IsValidVariableHeader (\r
124 IN VARIABLE_HEADER *Variable\r
125 )\r
126{\r
127 if (Variable == NULL || Variable->StartId != VARIABLE_DATA ) {\r
128 return FALSE;\r
129 }\r
130\r
131 return TRUE;\r
132}\r
133\r
134\r
135/**\r
136 This code gets the size of name of variable.\r
137\r
138 @param Variable Pointer to the Variable Header.\r
139\r
140 @return Size of variable in bytes in type UINTN.\r
141\r
142**/\r
143UINTN\r
144NameSizeOfVariable (\r
145 IN VARIABLE_HEADER *Variable\r
146 )\r
147{\r
148 if (Variable->State == (UINT8) (-1) ||\r
149 Variable->DataSize == (UINT32) (-1) ||\r
150 Variable->NameSize == (UINT32) (-1) ||\r
151 Variable->Attributes == (UINT32) (-1)) {\r
152 return 0;\r
153 }\r
154 return (UINTN) Variable->NameSize;\r
155}\r
156\r
157\r
158/**\r
159 This code gets the size of data of variable.\r
160\r
161 @param Variable Pointer to the Variable Header.\r
162\r
163 @return Size of variable in bytes in type UINTN.\r
164\r
165**/\r
166UINTN\r
167DataSizeOfVariable (\r
168 IN VARIABLE_HEADER *Variable\r
169 )\r
170{\r
171 if (Variable->State == (UINT8) (-1) ||\r
172 Variable->DataSize == (UINT32) (-1) ||\r
173 Variable->NameSize == (UINT32) (-1) ||\r
174 Variable->Attributes == (UINT32) (-1)) {\r
175 return 0;\r
176 }\r
177 return (UINTN) Variable->DataSize;\r
178}\r
179\r
180/**\r
181 This code gets the pointer to the variable name.\r
182\r
183 @param Variable Pointer to the Variable Header.\r
184\r
185 @return A CHAR16* pointer to Variable Name.\r
186\r
187**/\r
188CHAR16 *\r
189GetVariableNamePtr (\r
190 IN VARIABLE_HEADER *Variable\r
191 )\r
192{\r
193\r
194 return (CHAR16 *) (Variable + 1);\r
195}\r
196\r
197\r
198/**\r
199 This code gets the pointer to the variable data.\r
200\r
201 @param Variable Pointer to the Variable Header.\r
202\r
203 @return A UINT8* pointer to Variable Data.\r
204\r
205**/\r
206UINT8 *\r
207GetVariableDataPtr (\r
208 IN VARIABLE_HEADER *Variable\r
209 )\r
210{\r
211 UINTN Value;\r
212 \r
213 //\r
214 // Be careful about pad size for alignment\r
215 //\r
216 Value = (UINTN) GetVariableNamePtr (Variable);\r
217 Value += NameSizeOfVariable (Variable);\r
218 Value += GET_PAD_SIZE (NameSizeOfVariable (Variable));\r
219\r
220 return (UINT8 *) Value;\r
221}\r
222\r
223\r
224/**\r
225 This code gets the pointer to the next variable header.\r
226\r
227 @param Variable Pointer to the Variable Header.\r
228\r
229 @return A VARIABLE_HEADER* pointer to next variable header.\r
230\r
231**/\r
232VARIABLE_HEADER *\r
233GetNextVariablePtr (\r
234 IN VARIABLE_HEADER *Variable\r
235 )\r
236{\r
237 UINTN Value;\r
238\r
239 if (!IsValidVariableHeader (Variable)) {\r
240 return NULL;\r
241 }\r
242\r
243 Value = (UINTN) GetVariableDataPtr (Variable);\r
244 Value += DataSizeOfVariable (Variable);\r
245 Value += GET_PAD_SIZE (DataSizeOfVariable (Variable));\r
246\r
247 //\r
248 // Be careful about pad size for alignment\r
249 //\r
250 return (VARIABLE_HEADER *) HEADER_ALIGN (Value);\r
251}\r
252\r
253/**\r
254 This code gets the pointer to the variable name.\r
255\r
256 @param VarStoreHeader Pointer to the Variable Store Header.\r
257\r
258 @retval EfiRaw Variable store is raw\r
259 @retval EfiValid Variable store is valid\r
260 @retval EfiInvalid Variable store is invalid\r
261\r
262**/\r
263VARIABLE_STORE_STATUS\r
264GetVariableStoreStatus (\r
265 IN VARIABLE_STORE_HEADER *VarStoreHeader\r
266 )\r
267{\r
268 \r
269 if (CompareGuid (&VarStoreHeader->Signature, &gEfiAuthenticatedVariableGuid) &&\r
270 VarStoreHeader->Format == VARIABLE_STORE_FORMATTED &&\r
271 VarStoreHeader->State == VARIABLE_STORE_HEALTHY\r
272 ) {\r
273\r
274 return EfiValid;\r
275 }\r
276\r
277 if (((UINT32 *)(&VarStoreHeader->Signature))[0] == 0xffffffff &&\r
278 ((UINT32 *)(&VarStoreHeader->Signature))[1] == 0xffffffff &&\r
279 ((UINT32 *)(&VarStoreHeader->Signature))[2] == 0xffffffff &&\r
280 ((UINT32 *)(&VarStoreHeader->Signature))[3] == 0xffffffff &&\r
281 VarStoreHeader->Size == 0xffffffff &&\r
282 VarStoreHeader->Format == 0xff &&\r
283 VarStoreHeader->State == 0xff\r
284 ) {\r
285\r
286 return EfiRaw;\r
287 } else {\r
288 return EfiInvalid;\r
289 }\r
290}\r
291\r
292\r
293/**\r
294 This function compares a variable with variable entries in database.\r
295\r
296 @param Variable Pointer to the variable in our database\r
297 @param VariableName Name of the variable to compare to 'Variable'\r
298 @param VendorGuid GUID of the variable to compare to 'Variable'\r
299 @param PtrTrack Variable Track Pointer structure that contains Variable Information.\r
300\r
301 @retval EFI_SUCCESS Found match variable\r
302 @retval EFI_NOT_FOUND Variable not found\r
303\r
304**/\r
305EFI_STATUS\r
306CompareWithValidVariable (\r
307 IN VARIABLE_HEADER *Variable,\r
308 IN CONST CHAR16 *VariableName,\r
309 IN CONST EFI_GUID *VendorGuid,\r
310 OUT VARIABLE_POINTER_TRACK *PtrTrack\r
311 )\r
312{\r
313 VOID *Point;\r
314\r
315 if (VariableName[0] == 0) {\r
316 PtrTrack->CurrPtr = Variable;\r
317 return EFI_SUCCESS;\r
318 } else {\r
319 //\r
320 // Don't use CompareGuid function here for performance reasons.\r
321 // Instead we compare the GUID a UINT32 at a time and branch\r
322 // on the first failed comparison.\r
323 //\r
324 if ((((INT32 *) VendorGuid)[0] == ((INT32 *) &Variable->VendorGuid)[0]) &&\r
325 (((INT32 *) VendorGuid)[1] == ((INT32 *) &Variable->VendorGuid)[1]) &&\r
326 (((INT32 *) VendorGuid)[2] == ((INT32 *) &Variable->VendorGuid)[2]) &&\r
327 (((INT32 *) VendorGuid)[3] == ((INT32 *) &Variable->VendorGuid)[3])\r
328 ) {\r
329 ASSERT (NameSizeOfVariable (Variable) != 0);\r
330 Point = (VOID *) GetVariableNamePtr (Variable);\r
331 if (CompareMem (VariableName, Point, NameSizeOfVariable (Variable)) == 0) {\r
332 PtrTrack->CurrPtr = Variable;\r
333 return EFI_SUCCESS;\r
334 }\r
335 }\r
336 }\r
337\r
338 return EFI_NOT_FOUND;\r
339}\r
340\r
341\r
342/**\r
343 This code finds variable in storage blocks (Non-Volatile).\r
344\r
345 @param PeiServices General purpose services available to every PEIM.\r
346 @param VariableName Name of the variable to be found\r
347 @param VendorGuid Vendor GUID to be found.\r
348 @param PtrTrack Variable Track Pointer structure that contains Variable Information.\r
349\r
350 @retval EFI_SUCCESS Variable found successfully\r
351 @retval EFI_NOT_FOUND Variable not found\r
352 @retval EFI_INVALID_PARAMETER Invalid variable name\r
353\r
354**/\r
355EFI_STATUS\r
356FindVariable (\r
357 IN CONST EFI_PEI_SERVICES **PeiServices,\r
358 IN CONST CHAR16 *VariableName,\r
359 IN CONST EFI_GUID *VendorGuid,\r
360 OUT VARIABLE_POINTER_TRACK *PtrTrack\r
361 )\r
362{\r
363 EFI_HOB_GUID_TYPE *GuidHob;\r
364 VARIABLE_STORE_HEADER *VariableStoreHeader;\r
365 VARIABLE_HEADER *Variable;\r
366 VARIABLE_HEADER *LastVariable;\r
367 VARIABLE_HEADER *MaxIndex;\r
368 VARIABLE_INDEX_TABLE *IndexTable;\r
369 UINT32 Count;\r
370 UINT32 Offset;\r
371 UINT8 *VariableBase;\r
372 BOOLEAN StopRecord;\r
373\r
374 if (VariableName[0] != 0 && VendorGuid == NULL) {\r
375 return EFI_INVALID_PARAMETER;\r
376 }\r
377 //\r
378 // No Variable Address equals zero, so 0 as initial value is safe.\r
379 //\r
380 MaxIndex = 0;\r
381 StopRecord = FALSE;\r
382\r
383 GuidHob = GetFirstGuidHob (&gEfiVariableIndexTableGuid);\r
384 if (GuidHob == NULL) {\r
385 //\r
386 // If it's the first time to access variable region in flash, create a guid hob to record\r
387 // VAR_ADDED type variable info.\r
388 // Note that as the resource of PEI phase is limited, only store the number of \r
389 // VARIABLE_INDEX_TABLE_VOLUME of VAR_ADDED type variables to reduce access time.\r
390 //\r
391 IndexTable = BuildGuidHob (&gEfiVariableIndexTableGuid, sizeof (VARIABLE_INDEX_TABLE));\r
392 IndexTable->Length = 0;\r
393 IndexTable->StartPtr = NULL;\r
394 IndexTable->EndPtr = NULL;\r
395 IndexTable->GoneThrough = 0;\r
396 } else {\r
397 IndexTable = GET_GUID_HOB_DATA (GuidHob);\r
398 for (Offset = 0, Count = 0; Count < IndexTable->Length; Count++) {\r
399 //\r
400 // traverse the variable info list to look for varible.\r
401 // The IndexTable->Index[Count] records the distance of two neighbouring VAR_ADDED type variables.\r
402 //\r
403 ASSERT (Count < VARIABLE_INDEX_TABLE_VOLUME);\r
404 Offset += IndexTable->Index[Count];\r
405 MaxIndex = (VARIABLE_HEADER *)((CHAR8 *)(IndexTable->StartPtr) + Offset);\r
406 if (CompareWithValidVariable (MaxIndex, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {\r
407 PtrTrack->StartPtr = IndexTable->StartPtr;\r
408 PtrTrack->EndPtr = IndexTable->EndPtr;\r
409\r
410 return EFI_SUCCESS;\r
411 }\r
412 }\r
413\r
414 if (IndexTable->GoneThrough != 0) {\r
415 return EFI_NOT_FOUND;\r
416 }\r
417 }\r
418 //\r
419 // If not found in HOB, then let's start from the MaxIndex we've found.\r
420 //\r
421 if (MaxIndex != NULL) {\r
422 Variable = GetNextVariablePtr (MaxIndex);\r
423 LastVariable = MaxIndex;\r
424 } else {\r
425 if ((IndexTable->StartPtr != NULL) || (IndexTable->EndPtr != NULL)) {\r
426 Variable = IndexTable->StartPtr;\r
427 } else {\r
428 VariableBase = (UINT8 *) (UINTN) PcdGet64 (PcdFlashNvStorageVariableBase64);\r
429 if (VariableBase == NULL) {\r
430 VariableBase = (UINT8 *) (UINTN) PcdGet32 (PcdFlashNvStorageVariableBase);\r
431 }\r
432 \r
433 VariableStoreHeader = (VARIABLE_STORE_HEADER *) (VariableBase + \\r
434 ((EFI_FIRMWARE_VOLUME_HEADER *) (VariableBase)) -> HeaderLength);\r
435\r
436 if (GetVariableStoreStatus (VariableStoreHeader) != EfiValid) {\r
437 return EFI_UNSUPPORTED;\r
438 }\r
439\r
440 if (~VariableStoreHeader->Size == 0) {\r
441 return EFI_NOT_FOUND;\r
442 }\r
443 //\r
444 // Find the variable by walk through non-volatile variable store\r
445 //\r
446 IndexTable->StartPtr = GetStartPointer (VariableStoreHeader);\r
447 IndexTable->EndPtr = GetEndPointer (VariableStoreHeader);\r
448\r
449 //\r
450 // Start Pointers for the variable.\r
451 // Actual Data Pointer where data can be written.\r
452 //\r
453 Variable = IndexTable->StartPtr;\r
454 }\r
455\r
456 LastVariable = IndexTable->StartPtr;\r
457 }\r
458 //\r
459 // Find the variable by walk through non-volatile variable store\r
460 //\r
461 PtrTrack->StartPtr = IndexTable->StartPtr;\r
462 PtrTrack->EndPtr = IndexTable->EndPtr;\r
463\r
464 while ((Variable < IndexTable->EndPtr) && IsValidVariableHeader (Variable)) {\r
465 if (Variable->State == VAR_ADDED) {\r
466 //\r
467 // Record Variable in VariableIndex HOB\r
468 //\r
469 if (IndexTable->Length < VARIABLE_INDEX_TABLE_VOLUME && !StopRecord) {\r
470 Offset = (UINT32)((UINTN)Variable - (UINTN)LastVariable);\r
471 //\r
472 // The distance of two neighbouring VAR_ADDED variable is larger than 2^16, \r
473 // which is beyond the allowable scope(UINT16) of record. In such case, need not to\r
474 // record the subsequent VAR_ADDED type variables again.\r
475 //\r
476 if ((Offset & 0xFFFF0000UL) != 0) {\r
477 StopRecord = TRUE;\r
478 }\r
479\r
480 if (!StopRecord) {\r
481 IndexTable->Index[IndexTable->Length++] = (UINT16) Offset;\r
482 }\r
483 LastVariable = Variable;\r
484 }\r
485\r
486 if (CompareWithValidVariable (Variable, VariableName, VendorGuid, PtrTrack) == EFI_SUCCESS) {\r
487 return EFI_SUCCESS;\r
488 }\r
489 }\r
490\r
491 Variable = GetNextVariablePtr (Variable);\r
492 }\r
493 //\r
494 // If gone through the VariableStore, that means we never find in Firmware any more.\r
495 //\r
496 if ((IndexTable->Length < VARIABLE_INDEX_TABLE_VOLUME) && (!StopRecord)) {\r
497 IndexTable->GoneThrough = 1;\r
498 }\r
499\r
500 PtrTrack->CurrPtr = NULL;\r
501\r
502 return EFI_NOT_FOUND;\r
503}\r
504\r
505/**\r
506 This service retrieves a variable's value using its name and GUID.\r
507\r
508 Read the specified variable from the UEFI variable store. If the Data \r
509 buffer is too small to hold the contents of the variable, the error\r
510 EFI_BUFFER_TOO_SMALL is returned and DataSize is set to the required buffer\r
511 size to obtain the data.\r
512\r
513 @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.\r
514 @param VariableName A pointer to a null-terminated string that is the variable's name.\r
515 @param VariableGuid A pointer to an EFI_GUID that is the variable's GUID. The combination of\r
516 VariableGuid and VariableName must be unique.\r
517 @param Attributes If non-NULL, on return, points to the variable's attributes.\r
518 @param DataSize On entry, points to the size in bytes of the Data buffer.\r
519 On return, points to the size of the data returned in Data.\r
520 @param Data Points to the buffer which will hold the returned variable value.\r
521\r
522 @retval EFI_SUCCESS The variable was read successfully.\r
523 @retval EFI_NOT_FOUND The variable could not be found.\r
524 @retval EFI_BUFFER_TOO_SMALL The DataSize is too small for the resulting data. \r
525 DataSize is updated with the size required for \r
526 the specified variable.\r
527 @retval EFI_INVALID_PARAMETER VariableName, VariableGuid, DataSize or Data is NULL.\r
528 @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.\r
529\r
530**/\r
531EFI_STATUS\r
532EFIAPI\r
533PeiGetVariable (\r
534 IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,\r
535 IN CONST CHAR16 *VariableName,\r
536 IN CONST EFI_GUID *VariableGuid,\r
537 OUT UINT32 *Attributes,\r
538 IN OUT UINTN *DataSize,\r
539 OUT VOID *Data\r
540 )\r
541{\r
542 VARIABLE_POINTER_TRACK Variable;\r
543 UINTN VarDataSize;\r
544 EFI_STATUS Status;\r
545 CONST EFI_PEI_SERVICES **PeiServices;\r
546\r
547 PeiServices = GetPeiServicesTablePointer ();\r
548 if (VariableName == NULL || VariableGuid == NULL || DataSize == NULL) {\r
549 return EFI_INVALID_PARAMETER;\r
550 }\r
551 //\r
552 // Find existing variable\r
553 //\r
554 Status = FindVariable (PeiServices, VariableName, VariableGuid, &Variable);\r
555 if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) {\r
556 return Status;\r
557 }\r
558 //\r
559 // Get data size\r
560 //\r
561 VarDataSize = DataSizeOfVariable (Variable.CurrPtr);\r
562 if (*DataSize >= VarDataSize) {\r
563 if (Data == NULL) {\r
564 return EFI_INVALID_PARAMETER;\r
565 }\r
566\r
567 CopyMem (Data, GetVariableDataPtr (Variable.CurrPtr), VarDataSize);\r
568\r
569 if (Attributes != NULL) {\r
570 *Attributes = Variable.CurrPtr->Attributes;\r
571 }\r
572\r
573 *DataSize = VarDataSize;\r
574 return EFI_SUCCESS;\r
575 } else {\r
576 *DataSize = VarDataSize;\r
577 return EFI_BUFFER_TOO_SMALL;\r
578 }\r
579}\r
580\r
581/**\r
582 Return the next variable name and GUID.\r
583\r
584 This function is called multiple times to retrieve the VariableName \r
585 and VariableGuid of all variables currently available in the system. \r
586 On each call, the previous results are passed into the interface, \r
587 and, on return, the interface returns the data for the next \r
588 interface. When the entire variable list has been returned, \r
589 EFI_NOT_FOUND is returned.\r
590\r
591 @param This A pointer to this instance of the EFI_PEI_READ_ONLY_VARIABLE2_PPI.\r
592\r
593 @param VariableNameSize On entry, points to the size of the buffer pointed to by VariableName.\r
594 On return, the size of the variable name buffer.\r
595 @param VariableName On entry, a pointer to a null-terminated string that is the variable's name.\r
596 On return, points to the next variable's null-terminated name string.\r
597 @param VariableGuid On entry, a pointer to an EFI_GUID that is the variable's GUID. \r
598 On return, a pointer to the next variable's GUID.\r
599\r
600 @retval EFI_SUCCESS The variable was read successfully.\r
601 @retval EFI_NOT_FOUND The variable could not be found.\r
602 @retval EFI_BUFFER_TOO_SMALL The VariableNameSize is too small for the resulting\r
603 data. VariableNameSize is updated with the size\r
604 required for the specified variable.\r
605 @retval EFI_INVALID_PARAMETER VariableName, VariableGuid or\r
606 VariableNameSize is NULL.\r
607 @retval EFI_DEVICE_ERROR The variable could not be retrieved because of a device error.\r
608\r
609**/\r
610EFI_STATUS\r
611EFIAPI\r
612PeiGetNextVariableName (\r
613 IN CONST EFI_PEI_READ_ONLY_VARIABLE2_PPI *This,\r
614 IN OUT UINTN *VariableNameSize,\r
615 IN OUT CHAR16 *VariableName,\r
616 IN OUT EFI_GUID *VariableGuid\r
617 )\r
618{\r
619 VARIABLE_POINTER_TRACK Variable;\r
620 UINTN VarNameSize;\r
621 EFI_STATUS Status;\r
622 CONST EFI_PEI_SERVICES **PeiServices;\r
623\r
624 PeiServices = GetPeiServicesTablePointer ();\r
625 if (VariableName == NULL || VariableGuid == NULL || VariableNameSize == NULL) {\r
626 return EFI_INVALID_PARAMETER;\r
627 }\r
628\r
629 Status = FindVariable (PeiServices, VariableName, VariableGuid, &Variable);\r
630 if (Variable.CurrPtr == NULL || Status != EFI_SUCCESS) {\r
631 return Status;\r
632 }\r
633\r
634 if (VariableName[0] != 0) {\r
635 //\r
636 // If variable name is not NULL, get next variable\r
637 //\r
638 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
639 }\r
640\r
641 while (!(Variable.CurrPtr >= Variable.EndPtr || Variable.CurrPtr == NULL)) {\r
642 if (IsValidVariableHeader (Variable.CurrPtr)) {\r
643 if (Variable.CurrPtr->State == VAR_ADDED) {\r
644 ASSERT (NameSizeOfVariable (Variable.CurrPtr) != 0);\r
645\r
646 VarNameSize = (UINTN) NameSizeOfVariable (Variable.CurrPtr);\r
647 if (VarNameSize <= *VariableNameSize) {\r
648 CopyMem (VariableName, GetVariableNamePtr (Variable.CurrPtr), VarNameSize);\r
649\r
650 CopyMem (VariableGuid, &Variable.CurrPtr->VendorGuid, sizeof (EFI_GUID));\r
651\r
652 Status = EFI_SUCCESS;\r
653 } else {\r
654 Status = EFI_BUFFER_TOO_SMALL;\r
655 }\r
656\r
657 *VariableNameSize = VarNameSize;\r
658 return Status;\r
659 //\r
660 // Variable is found\r
661 //\r
662 } else {\r
663 Variable.CurrPtr = GetNextVariablePtr (Variable.CurrPtr);\r
664 }\r
665 } else {\r
666 break;\r
667 }\r
668 }\r
669\r
670 return EFI_NOT_FOUND;\r
671}\r